Просмотр исходного кода

Merge pull request #331 from CIB/master

Clipboard support on linux!
Ivan Safrin 12 лет назад
Родитель
Сommit
55b322c833
3 измененных файлов с 408 добавлено и 5 удалено
  1. 0 2
      Core/Contents/CMakeLists.txt
  2. 407 2
      Core/Contents/Source/PolySDLCore.cpp
  3. 1 1
      IDE/Build/Linux/Makefile

+ 0 - 2
Core/Contents/CMakeLists.txt

@@ -249,9 +249,7 @@ IF("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
   endif()
   PKG_CHECK_MODULES(X11 x11)
   IF(${X11_FOUND})
-    LINK_DIRECTORIES(${X11_LIBRARY_DIRS})
     INCLUDE_DIRECTORIES(${X11_INCLUDE_DIRS})
-    TARGET_LINK_LIBRARIES(Polycore ${X11_LIBRARIES})
     SET_TARGET_PROPERTIES(Polycore PROPERTIES COMPILE_FLAGS "-DUSE_X11")
   ELSE()
     message( FATAL_ERROR "You seem to be using Linux, but X11 is not installed. Please install X11." )

+ 407 - 2
Core/Contents/Source/PolySDLCore.cpp

@@ -32,6 +32,10 @@
 #include "PolyRectangle.h"
 
 #include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+#include <stdio.h>
+#include <limits.h>
+
 #include <iostream>
 
 #include <unistd.h>
@@ -40,6 +44,17 @@
 #include <sys/wait.h>
 #include <pwd.h>
 
+#ifdef USE_X11
+	// SDL scrap
+	#define T(A, B, C, D)	(int)((A<<24)|(B<<16)|(C<<8)|(D<<0))
+
+	int init_scrap(void);
+	int lost_scrap(void);
+	void put_scrap(int type, int srclen, const char *src);
+	void get_scrap(int type, int *dstlen, char **dst);
+	// end SDL scrap
+#endif
+
 using namespace Polycode;
 using std::vector;
 
@@ -96,6 +111,11 @@ SDLCore::SDLCore(PolycodeView *view, int _xRes, int _yRes, bool fullScreen, bool
 		SDL_JoystickOpen(i);
 		input->addJoystick(i);
 	}
+	
+	// Start listening to clipboard events.
+	// (Yes on X11 you need to actively listen to
+	//  clipboard events and respond to them)
+	init_scrap();
 
 	((OpenGLRenderer*)renderer)->initOSSpecific();
 	CoreServices::getInstance()->installModule(new GLSLShaderModule());	
@@ -401,11 +421,21 @@ CoreMutex *SDLCore::createMutex() {
 }
 
 void SDLCore::copyStringToClipboard(const String& str) {
-
+#ifdef USE_X11
+	put_scrap(T('T', 'E', 'X', 'T'), str.size(), str.c_str());
+#endif
 }
 
 String SDLCore::getClipboardString() {
-	return "";
+#ifdef USE_X11
+	int dstlen;
+	char* buffer;
+	get_scrap(T('T', 'E', 'X', 'T'), &dstlen, &buffer);
+	
+	String rval(buffer, dstlen);
+	free(buffer);
+	return rval;
+#endif
 }
 
 void SDLCore::createFolder(const String& folderPath) {
@@ -456,3 +486,378 @@ void SDLCore::resizeTo(int xRes, int yRes) {
 	renderer->Resize(xRes, yRes);
 }
 
+
+#ifdef USE_X11
+// SDL_scrap.c
+// Credits to Sam Lantinga for making this
+// Changes include:
+// - All non-X11 stuff was removed
+// - Uses the X11 CLIPBOARD atom in addition to PRIMARY
+// =======================================
+
+
+/* Handle clipboard text and data in arbitrary formats */
+
+/* Miscellaneous defines */
+#define PUBLIC
+#define PRIVATE	static
+
+#define X11_SCRAP
+
+typedef Atom scrap_type;
+
+static Display *SDL_Display;
+static Window SDL_Window;
+static void (*Lock_Display)(void);
+static void (*Unlock_Display)(void);
+
+#define FORMAT_PREFIX	"SDL_scrap_0x"
+
+PRIVATE scrap_type
+convert_format(int type)
+{
+  switch (type)
+    {
+
+    case T('T', 'E', 'X', 'T'):
+      return XA_STRING;
+
+    default:
+      {
+        char format[sizeof(FORMAT_PREFIX)+8+1];
+
+        sprintf(format, "%s%08lx", FORMAT_PREFIX, (unsigned long)type);
+
+        return XInternAtom(SDL_Display, format, False);
+      }
+    }
+}
+
+/* Convert internal data to scrap format */
+PRIVATE int
+convert_data(int type, char *dst, const char *src, int srclen)
+{
+  int dstlen;
+
+  dstlen = 0;
+  switch (type)
+    {
+    case T('T', 'E', 'X', 'T'):
+      if ( dst )
+        {
+          while ( --srclen >= 0 )
+            {
+              if ( *src == '\r' )
+                {
+                  *dst++ = '\n';
+                  ++dstlen;
+                }
+              else
+                {
+                  *dst++ = *src;
+                  ++dstlen;
+                }
+              ++src;
+            }
+            *dst = '\0';
+            ++dstlen;
+        }
+      else
+        {
+          while ( --srclen >= 0 )
+            {
+              if ( *src == '\r' )
+                {
+                  ++dstlen;
+                }
+              else
+                {
+                  ++dstlen;
+                }
+              ++src;
+            }
+            ++dstlen;
+        }
+      break;
+
+    default:
+      if ( dst )
+        {
+          *(int *)dst = srclen;
+          dst += sizeof(int);
+          memcpy(dst, src, srclen);
+        }
+      dstlen = sizeof(int)+srclen;
+      break;
+    }
+    return(dstlen);
+}
+
+/* Convert scrap data to internal format */
+PRIVATE int
+convert_scrap(int type, char *dst, char *src, int srclen)
+{
+  int dstlen;
+
+  dstlen = 0;
+  switch (type)
+    {
+    case T('T', 'E', 'X', 'T'):
+      {
+        if ( srclen == 0 )
+          srclen = strlen(src);
+        if ( dst )
+          {
+            while ( --srclen >= 0 )
+              {
+                if ( *src == '\n' )
+                  {
+                    *dst++ = '\r';
+                    ++dstlen;
+                  }
+                else
+                  {
+                    *dst++ = *src;
+                    ++dstlen;
+                  }
+                ++src;
+              }
+              *dst = '\0';
+              ++dstlen;
+          }
+        else
+          {
+            while ( --srclen >= 0 )
+              {
+                ++dstlen;
+                ++src;
+              }
+              ++dstlen;
+          }
+        }
+      break;
+
+    default:
+      dstlen = *(int *)src;
+      if ( dst )
+        {
+          if ( srclen == 0 )
+            memcpy(dst, src+sizeof(int), dstlen);
+          else
+            memcpy(dst, src+sizeof(int), srclen-sizeof(int));
+        }
+      break;
+    }
+  return dstlen;
+}
+
+/* The system message filter function -- handle clipboard messages */
+PRIVATE int clipboard_filter(const SDL_Event *event);
+
+PUBLIC int
+init_scrap(void)
+{
+  SDL_SysWMinfo info;
+  int retval;
+
+  /* Grab the window manager specific information */
+  retval = -1;
+  SDL_SetError("SDL is not running on known window manager");
+
+  SDL_VERSION(&info.version);
+  if ( SDL_GetWMInfo(&info) )
+    {
+      /* Save the information for later use */
+/* * */
+      if ( info.subsystem == SDL_SYSWM_X11 )
+        {
+          SDL_Display = info.info.x11.display;
+          SDL_Window = info.info.x11.window;
+          Lock_Display = info.info.x11.lock_func;
+          Unlock_Display = info.info.x11.unlock_func;
+
+          /* Enable the special window hook events */
+          SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
+          SDL_SetEventFilter(clipboard_filter);
+
+          retval = 0;
+        }
+      else
+        {
+          SDL_SetError("SDL is not running on X11");
+        }
+    }
+  return(retval);
+}
+
+PUBLIC int
+lost_scrap(void)
+{
+  int retval;
+
+/* * */
+  Lock_Display();
+  retval = ( XGetSelectionOwner(SDL_Display, XA_PRIMARY) != SDL_Window );
+  Unlock_Display();
+
+  return(retval);
+}
+
+PUBLIC void
+put_scrap(int type, int srclen, const char *src)
+{
+  scrap_type format;
+  int dstlen;
+  char *dst;
+
+  format = convert_format(type);
+  dstlen = convert_data(type, NULL, src, srclen);
+
+/* * */
+  dst = (char *)malloc(dstlen);
+  if ( dst != NULL )
+    {
+      Lock_Display();
+      convert_data(type, dst, src, srclen);
+      XChangeProperty(SDL_Display, DefaultRootWindow(SDL_Display),
+        XA_CUT_BUFFER0, format, 8, PropModeReplace, (unsigned char*) dst, dstlen);
+      free(dst);
+      Atom XA_CLIPBOARD = XInternAtom(SDL_Display, "CLIPBOARD", 0);
+      if ( lost_scrap() ) {
+        XSetSelectionOwner(SDL_Display, XA_PRIMARY, SDL_Window, CurrentTime);
+        XSetSelectionOwner(SDL_Display, XA_CLIPBOARD, SDL_Window, CurrentTime);
+      }
+      Unlock_Display();
+    }
+
+}
+
+PUBLIC void
+get_scrap(int type, int *dstlen, char **dst)
+{
+  scrap_type format;
+
+  *dstlen = 0;
+  format = convert_format(type);
+
+/* * */
+  {
+    Window owner;
+    Atom selection;
+    Atom seln_type;
+    int seln_format;
+    unsigned long nbytes;
+    unsigned long overflow;
+    char *src;
+
+    Lock_Display();
+    Atom XA_CLIPBOARD = XInternAtom(SDL_Display, "CLIPBOARD", 0);
+    owner = XGetSelectionOwner(SDL_Display, XA_PRIMARY);
+    Unlock_Display();
+    if ( (owner == None) || (owner == SDL_Window) )
+      {
+        owner = DefaultRootWindow(SDL_Display);
+        selection = XA_CUT_BUFFER0;
+      }
+    else
+      {
+        int selection_response = 0;
+        SDL_Event event;
+
+        owner = SDL_Window;
+        Lock_Display();
+        selection = XInternAtom(SDL_Display, "SDL_SELECTION", False);
+        XConvertSelection(SDL_Display, XA_PRIMARY, format,
+                                        selection, owner, CurrentTime);
+        XConvertSelection(SDL_Display, XA_CLIPBOARD, format,
+                                        selection, owner, CurrentTime);
+        Unlock_Display();
+        while ( ! selection_response )
+          {
+            SDL_WaitEvent(&event);
+            if ( event.type == SDL_SYSWMEVENT )
+              {
+                XEvent xevent = event.syswm.msg->event.xevent;
+
+                if ( (xevent.type == SelectionNotify) &&
+                     (xevent.xselection.requestor == owner) )
+                    selection_response = 1;
+              }
+          }
+      }
+    Lock_Display();
+    if ( XGetWindowProperty(SDL_Display, owner, selection, 0, INT_MAX/4,
+                            False, format, &seln_type, &seln_format,
+                       &nbytes, &overflow, (unsigned char **)&src) == Success )
+      {
+        if ( seln_type == format )
+          {
+            *dstlen = convert_scrap(type, NULL, src, nbytes);
+            *dst = (char *)malloc(*dstlen);
+            if ( *dst == NULL )
+              *dstlen = 0;
+            else
+              convert_scrap(type, *dst, src, nbytes);
+          }
+        XFree(src);
+      }
+    }
+    Unlock_Display();
+}
+
+PRIVATE int clipboard_filter(const SDL_Event *event)
+{
+  /* Post all non-window manager specific events */
+  if ( event->type != SDL_SYSWMEVENT ) {
+    return(1);
+  }
+
+  /* Handle window-manager specific clipboard events */
+  switch (event->syswm.msg->event.xevent.type) {
+    /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
+    case SelectionRequest: {
+      XSelectionRequestEvent *req;
+      XEvent sevent;
+      int seln_format;
+      unsigned long nbytes;
+      unsigned long overflow;
+      unsigned char *seln_data;
+
+      req = &event->syswm.msg->event.xevent.xselectionrequest;
+      sevent.xselection.type = SelectionNotify;
+      sevent.xselection.display = req->display;
+      sevent.xselection.selection = req->selection;
+      sevent.xselection.target = None;
+      sevent.xselection.property = None;
+      sevent.xselection.requestor = req->requestor;
+      sevent.xselection.time = req->time;
+      if ( XGetWindowProperty(SDL_Display, DefaultRootWindow(SDL_Display),
+                              XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
+                              &sevent.xselection.target, &seln_format,
+                              &nbytes, &overflow, &seln_data) == Success )
+        {
+          if ( sevent.xselection.target == req->target )
+            {
+              if ( sevent.xselection.target == XA_STRING )
+                {
+                  if ( seln_data[nbytes-1] == '\0' )
+                    --nbytes;
+                }
+              XChangeProperty(SDL_Display, req->requestor, req->property,
+                sevent.xselection.target, seln_format, PropModeReplace,
+                                                      seln_data, nbytes);
+              sevent.xselection.property = req->property;
+            }
+          XFree(seln_data);
+        }
+      XSendEvent(SDL_Display,req->requestor,False,0,&sevent);
+      XSync(SDL_Display, False);
+    }
+    break;
+  }
+
+  /* Post the event for X11 clipboard reading above */
+  return(1);
+}
+
+#endif // USE_X11

+ 1 - 1
IDE/Build/Linux/Makefile

@@ -2,7 +2,7 @@ CC=g++
 CFLAGS=-I../../Contents/Include -I../../../Release/Linux/Framework/Core/Dependencies/include -I../../../Release/Linux/Framework/Core/Dependencies/include/AL -I../../../Release/Linux/Framework/Core/include -I../../../Release/Linux/Framework/Modules/include -I../../../Release/Linux/Framework/Modules/Dependencies/include -I../../../Release/Linux/Framework/Modules/Dependencies/include/bullet -DUSE_POLYCODEUI_FILE_DIALOGS -DUSE_POLYCODEUI_MENUBAR
 LDFLAGS=-lrt -ldl -lpthread ../../../Release/Linux/Framework/Core/lib/libPolycore.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libfreetype.a ../../../Release/Linux/Framework/Core/Dependencies/lib/liblibvorbisfile.a ../../../Release/Linux/Framework/Core/Dependencies/lib/liblibvorbis.a ../../../Release/Linux/Framework/Core/Dependencies/lib/liblibogg.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libopenal.so ../../../Release/Linux/Framework/Core/Dependencies/lib/libphysfs.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libpng15.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libz.a -lGL -lGLU -lSDL ../../../Release/Linux/Framework/Modules/lib/libPolycode2DPhysics.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libBox2D.a ../../../Release/Linux/Framework/Modules/lib/libPolycode3DPhysics.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libBulletDynamics.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libBulletCollision.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libLinearMath.a ../../../Release/Linux/Framework/Modules/lib/libPolycodeUI.a
 LDFLAGS_DEBUG=-lrt -ldl -lpthread ../../../Release/Linux/Framework/Core/lib/libPolycore_d.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libfreetype_d.a ../../../Release/Linux/Framework/Core/Dependencies/lib/liblibvorbisfiled.a ../../../Release/Linux/Framework/Core/Dependencies/lib/liblibvorbisd.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libliboggd.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libopenal.so ../../../Release/Linux/Framework/Core/Dependencies/lib/libphysfsd.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libpng15d.a ../../../Release/Linux/Framework/Core/Dependencies/lib/libz.a -lGL -lGLU -lSDL ../../../Release/Linux/Framework/Modules/lib/libPolycode2DPhysics_d.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libBox2D_d.a ../../../Release/Linux/Framework/Modules/lib/libPolycode3DPhysics_d.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libBulletDynamics_d.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libBulletCollision_d.a ../../../Release/Linux/Framework/Modules/Dependencies/lib/libLinearMath_d.a ../../../Release/Linux/Framework/Modules/lib/libPolycodeUI_d.a
-SRCS=../../Contents/Source/ExampleBrowserWindow.cpp ../../Contents/Source/PolycodeEditorManager.cpp  ../../Contents/Source/PolycodeProject.cpp        ../../Contents/Source/PolycodeScreenEditor.cpp ../../Contents/Source/ExportProjectWindow.cpp  ../../Contents/Source/PolycodeFontEditor.cpp     ../../Contents/Source/PolycodeProjectBrowser.cpp ../../Contents/Source/PolycodeSpriteEditor.cpp ../../Contents/Source/NewFileWindow.cpp        ../../Contents/Source/PolycodeFrame.cpp          ../../Contents/Source/PolycodeProjectEditor.cpp  ../../Contents/Source/PolycodeTextEditor.cpp ../../Contents/Source/NewProjectWindow.cpp     ../../Contents/Source/PolycodeIDEApp.cpp         ../../Contents/Source/PolycodeProjectManager.cpp ../../Contents/Source/PolycodeToolLauncher.cpp ../../Contents/Source/PolycodeConsole.cpp      ../../Contents/Source/PolycodeImageEditor.cpp    ../../Contents/Source/PolycodeProps.cpp          ../../Contents/Source/TextureBrowser.cpp ../../Contents/Source/PolycodeEditor.cpp       ../../Contents/Source/PolycodeMaterialEditor.cpp ../../Contents/Source/PolycodeRemoteDebugger.cpp ../../Contents/Source/ToolWindows.cpp ../../Contents/Source/PolycodeClipboard.cpp ../../Contents/Source/SettingsWindow.cpp
+SRCS=../../Contents/Source/ExampleBrowserWindow.cpp ../../Contents/Source/PolycodeEditorManager.cpp  ../../Contents/Source/PolycodeProject.cpp        ../../Contents/Source/PolycodeScreenEditor.cpp ../../Contents/Source/ExportProjectWindow.cpp  ../../Contents/Source/PolycodeFontEditor.cpp     ../../Contents/Source/PolycodeProjectBrowser.cpp ../../Contents/Source/PolycodeSpriteEditor.cpp ../../Contents/Source/NewFileWindow.cpp        ../../Contents/Source/PolycodeFrame.cpp          ../../Contents/Source/PolycodeProjectEditor.cpp  ../../Contents/Source/PolycodeTextEditor.cpp ../../Contents/Source/NewProjectWindow.cpp     ../../Contents/Source/PolycodeIDEApp.cpp         ../../Contents/Source/PolycodeProjectManager.cpp ../../Contents/Source/PolycodeToolLauncher.cpp ../../Contents/Source/PolycodeConsole.cpp      ../../Contents/Source/PolycodeImageEditor.cpp    ../../Contents/Source/PolycodeProps.cpp          ../../Contents/Source/TextureBrowser.cpp ../../Contents/Source/PolycodeEditor.cpp       ../../Contents/Source/PolycodeMaterialEditor.cpp ../../Contents/Source/PolycodeRemoteDebugger.cpp ../../Contents/Source/ToolWindows.cpp ../../Contents/Source/PolycodeClipboard.cpp ../../Contents/Source/SettingsWindow.cpp -lX11
 
 default:
 	mkdir -p ./Build