|
|
@@ -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
|