Atom X_ATOM_CLIPBOARD;\r
Atom X_ATOM_TARGETS;\r
Atom X_ATOM_UTF8_STRING;\r
+ Atom X_ATOM_UTF8_MIME_TYPE;\r
Atom X_ATOM_TEXT;\r
Atom X_ATOM_NETWM_MAXIMIZE_VERT;\r
Atom X_ATOM_NETWM_MAXIMIZE_HORZ;\r
\r
case SelectionRequest:\r
{\r
- XEvent respond;\r
XSelectionRequestEvent *req = &(event.xselectionrequest);\r
- if ( req->target == XA_STRING)\r
- {\r
- XChangeProperty (XDisplay,\r
+\r
+ auto send_response = [this, req](Atom property) {\r
+ XEvent response;\r
+ response.xselection.type = SelectionNotify;\r
+ response.xselection.display = req->display;\r
+ response.xselection.requestor = req->requestor;\r
+ response.xselection.selection = req->selection;\r
+ response.xselection.target = req->target;\r
+ response.xselection.property = property;\r
+ response.xselection.time = req->time;\r
+ XSendEvent (XDisplay, req->requestor, 0, 0, &response);\r
+ XFlush (XDisplay);\r
+ };\r
+ auto send_response_refuse = [&send_response] {\r
+ send_response(None);\r
+ };\r
+\r
+ // sets the required property to data of type type and\r
+ // sends the according response\r
+ auto set_property_and_notify = [this, req, &send_response]\r
+ (Atom type, int format, const void *data, u32 data_size) {\r
+ XChangeProperty(XDisplay,\r
req->requestor,\r
- req->property, req->target,\r
- 8, // format\r
+ req->property,\r
+ type,\r
+ format,\r
PropModeReplace,\r
- (unsigned char*) Clipboard.c_str(),\r
- Clipboard.size());\r
- respond.xselection.property = req->property;\r
+ (const unsigned char *)data,\r
+ data_size);\r
+ send_response(req->property);\r
+ };\r
+\r
+ if (req->selection != X_ATOM_CLIPBOARD ||\r
+ req->owner != XWindow) {\r
+ // we are not the owner, refuse request\r
+ send_response_refuse();\r
+ break;\r
}\r
- else if ( req->target == X_ATOM_TARGETS )\r
- {\r
- long data[2];\r
\r
- data[0] = X_ATOM_TEXT;\r
- data[1] = XA_STRING;\r
-\r
- XChangeProperty (XDisplay, req->requestor,\r
- req->property, req->target,\r
- 8, PropModeReplace,\r
- (unsigned char *) &data,\r
- sizeof (data));\r
- respond.xselection.property = req->property;\r
+ // for debugging:\r
+ //~ {\r
+ //~ char *target_name = XGetAtomName(XDisplay, req->target);\r
+ //~ fprintf(stderr, "CIrrDeviceLinux::run: target: %s (=%ld)\n",\r
+ //~ target_name, req->target);\r
+ //~ XFree(target_name);\r
+ //~ }\r
+\r
+ if (req->property == None) {\r
+ // req is from obsolete client, use target as property name\r
+ // and X_ATOM_UTF8_STRING as type\r
+ // Note: this was not tested and might be incorrect\r
+ os::Printer::log("CIrrDeviceLinux::run: SelectionRequest from obsolete client",\r
+ ELL_WARNING);\r
+ XChangeProperty(XDisplay,\r
+ req->requestor,\r
+ req->target, X_ATOM_UTF8_STRING,\r
+ 8, // format = 8-bit\r
+ PropModeReplace,\r
+ (unsigned char *)Clipboard.c_str(),\r
+ Clipboard.size());\r
+ send_response(req->target);\r
+ break;\r
}\r
- else\r
- {\r
- respond.xselection.property= None;\r
+\r
+ if (req->target == X_ATOM_TARGETS) {\r
+ Atom data[] = {\r
+ X_ATOM_TARGETS,\r
+ X_ATOM_TEXT,\r
+ X_ATOM_UTF8_STRING,\r
+ X_ATOM_UTF8_MIME_TYPE\r
+ };\r
+ set_property_and_notify(\r
+ XA_ATOM,\r
+ 32, // Atom is long, we need to set 32 for longs\r
+ &data,\r
+ sizeof(data) / sizeof(*data)\r
+ );\r
+\r
+ } else if (req->target == X_ATOM_TEXT ||\r
+ req->target == X_ATOM_UTF8_STRING ||\r
+ req->target == X_ATOM_UTF8_MIME_TYPE) {\r
+ set_property_and_notify(\r
+ X_ATOM_UTF8_STRING,\r
+ 8,\r
+ Clipboard.c_str(),\r
+ Clipboard.size()\r
+ );\r
+\r
+ } else {\r
+ // refuse the request\r
+ send_response_refuse();\r
}\r
- respond.xselection.type= SelectionNotify;\r
- respond.xselection.display= req->display;\r
- respond.xselection.requestor= req->requestor;\r
- respond.xselection.selection=req->selection;\r
- respond.xselection.target= req->target;\r
- respond.xselection.time = req->time;\r
- XSendEvent (XDisplay, req->requestor,0,0,&respond);\r
- XFlush (XDisplay);\r
}\r
break;\r
+\r
#if defined(_IRR_LINUX_X11_XINPUT2_)\r
- case GenericEvent:\r
+ case GenericEvent:\r
{\r
XGenericEventCookie *cookie = &event.xcookie;\r
if (XGetEventData(XDisplay, cookie) && cookie->extension == XI_EXTENSIONS_OPCODE && XI_EXTENSIONS_OPCODE\r
\r
\r
//! gets text from the clipboard\r
-//! \return Returns 0 if no string is in there.\r
-const c8* CIrrDeviceLinux::getTextFromClipboard() const\r
+//! \return Returns 0 if no string is in there, otherwise utf-8 text.\r
+const c8 *CIrrDeviceLinux::getTextFromClipboard() const\r
{\r
#if defined(_IRR_COMPILE_WITH_X11_)\r
- Window ownerWindow = XGetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD);\r
- if ( ownerWindow == XWindow )\r
- {\r
+ Window ownerWindow = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD);\r
+ if (ownerWindow == XWindow) {\r
return Clipboard.c_str();\r
}\r
+\r
Clipboard = "";\r
- if (ownerWindow != None )\r
- {\r
- XConvertSelection (XDisplay, X_ATOM_CLIPBOARD, XA_STRING, XA_PRIMARY, ownerWindow, CurrentTime);\r
- XFlush (XDisplay);\r
-\r
- // check for data\r
- Atom type;\r
- int format;\r
- unsigned long numItems, bytesLeft, dummy;\r
- unsigned char *data;\r
- XGetWindowProperty (XDisplay, ownerWindow,\r
- XA_PRIMARY, // property name\r
- 0, // offset\r
- 0, // length (we only check for data, so 0)\r
- 0, // Delete 0==false\r
- AnyPropertyType, // AnyPropertyType or property identifier\r
- &type, // return type\r
- &format, // return format\r
- &numItems, // number items\r
- &bytesLeft, // remaining bytes for partial reads\r
- &data); // data\r
- if ( bytesLeft > 0 )\r
- {\r
- // there is some data to get\r
- int result = XGetWindowProperty (XDisplay, ownerWindow, XA_PRIMARY, 0,\r
- bytesLeft, 0, AnyPropertyType, &type, &format,\r
- &numItems, &dummy, &data);\r
- if (result == Success)\r
- Clipboard = (irr::c8*)data;\r
- XFree (data);\r
- }\r
+\r
+ if (ownerWindow == None) {\r
+ return Clipboard.c_str();\r
+ }\r
+\r
+ // delete the property to be set beforehand\r
+ XDeleteProperty(XDisplay, XWindow, XA_PRIMARY);\r
+\r
+ XConvertSelection(XDisplay, X_ATOM_CLIPBOARD, X_ATOM_UTF8_STRING, XA_PRIMARY,\r
+ XWindow, CurrentTime);\r
+ XFlush(XDisplay);\r
+\r
+ // wait for event via a blocking call\r
+ XEvent event_ret;\r
+ XIfEvent(XDisplay, &event_ret, [](Display *_display, XEvent *event, XPointer arg) {\r
+ return (Bool) (event->type == SelectionNotify &&\r
+ event->xselection.requestor == *(Window *)arg &&\r
+ event->xselection.selection == X_ATOM_CLIPBOARD &&\r
+ event->xselection.target == X_ATOM_UTF8_STRING);\r
+ }, (XPointer)&XWindow);\r
+\r
+ _IRR_DEBUG_BREAK_IF(!(event_ret.type == SelectionNotify &&\r
+ event_ret.xselection.requestor == XWindow &&\r
+ event_ret.xselection.selection == X_ATOM_CLIPBOARD &&\r
+ event_ret.xselection.target == X_ATOM_UTF8_STRING));\r
+\r
+ Atom property_set = event_ret.xselection.property;\r
+ if (event_ret.xselection.property == None) {\r
+ // request failed => empty string\r
+ return Clipboard.c_str();\r
+ }\r
+\r
+ // check for data\r
+ Atom type;\r
+ int format;\r
+ unsigned long numItems, bytesLeft, dummy;\r
+ unsigned char *data = nullptr;\r
+ XGetWindowProperty (XDisplay, XWindow,\r
+ property_set, // property name\r
+ 0, // offset\r
+ 0, // length (we only check for data, so 0)\r
+ 0, // Delete 0==false\r
+ AnyPropertyType, // AnyPropertyType or property identifier\r
+ &type, // return type\r
+ &format, // return format\r
+ &numItems, // number items\r
+ &bytesLeft, // remaining bytes for partial reads\r
+ &data); // data\r
+ if (data) {\r
+ XFree(data);\r
+ data = nullptr;\r
}\r
\r
+ // for debugging:\r
+ //~ {\r
+ //~ char *type_name = XGetAtomName(XDisplay, type);\r
+ //~ fprintf(stderr, "CIrrDeviceLinux::getTextFromClipboard: actual type: %s (=%ld)\n",\r
+ //~ type_name, type);\r
+ //~ XFree(type_name);\r
+ //~ }\r
+\r
+ if (type != X_ATOM_UTF8_STRING && type != X_ATOM_UTF8_MIME_TYPE) {\r
+ os::Printer::log("CIrrDeviceLinux::getTextFromClipboard: did not get utf-8 string",\r
+ ELL_WARNING);\r
+ return Clipboard.c_str();\r
+ }\r
+\r
+ if (bytesLeft > 0) {\r
+ // there is some data to get\r
+ int result = XGetWindowProperty (XDisplay, XWindow, property_set, 0,\r
+ bytesLeft, 0, AnyPropertyType, &type, &format,\r
+ &numItems, &dummy, &data);\r
+ if (result == Success)\r
+ Clipboard = (irr::c8 *)data;\r
+ XFree (data);\r
+ }\r
+\r
+ // delete the property again, to inform the owner about the successful transfer\r
+ XDeleteProperty(XDisplay, XWindow, property_set);\r
+\r
return Clipboard.c_str();\r
\r
#else\r
- return 0;\r
+ return nullptr;\r
#endif\r
}\r
\r
//! copies text to the clipboard\r
-void CIrrDeviceLinux::copyToClipboard(const c8* text) const\r
+void CIrrDeviceLinux::copyToClipboard(const c8 *text) const\r
{\r
#if defined(_IRR_COMPILE_WITH_X11_)\r
// Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked.\r
Clipboard = text;\r
XSetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD, XWindow, CurrentTime);\r
XFlush (XDisplay);\r
+ Window owner = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD);\r
+ if (owner != XWindow) {\r
+ os::Printer::log("CIrrDeviceLinux::copyToClipboard: failed to set owner", ELL_WARNING);\r
+ }\r
#endif\r
}\r
\r
#ifdef _IRR_COMPILE_WITH_X11_\r
X_ATOM_CLIPBOARD = XInternAtom(XDisplay, "CLIPBOARD", False);\r
X_ATOM_TARGETS = XInternAtom(XDisplay, "TARGETS", False);\r
- X_ATOM_UTF8_STRING = XInternAtom (XDisplay, "UTF8_STRING", False);\r
- X_ATOM_TEXT = XInternAtom (XDisplay, "TEXT", False);\r
+ X_ATOM_UTF8_STRING = XInternAtom(XDisplay, "UTF8_STRING", False);\r
+ X_ATOM_UTF8_MIME_TYPE = XInternAtom(XDisplay, "text/plain;charset=utf-8", False);\r
+ X_ATOM_TEXT = XInternAtom(XDisplay, "TEXT", False);\r
X_ATOM_NETWM_MAXIMIZE_VERT = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", true);\r
X_ATOM_NETWM_MAXIMIZE_HORZ = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", true);\r
X_ATOM_NETWM_STATE = XInternAtom(XDisplay, "_NET_WM_STATE", true);\r