diff --git a/include/IOSOperator.h b/include/IOSOperator.h index b195aed..6e5768a 100644 --- a/include/IOSOperator.h +++ b/include/IOSOperator.h @@ -26,12 +26,23 @@ public: } //! Copies text to the clipboard + //! \param text: text in utf-8 virtual void copyToClipboard(const c8* text) const = 0; + //! Copies text to the primary selection + //! This is a no-op on some platforms. + //! \param text: text in utf-8 + virtual void copyToPrimarySelection(const c8* text) const = 0; + //! Get text from the clipboard - /** \return Returns 0 if no string is in there. */ + //! \return Returns 0 if no string is in there, otherwise an utf-8 string. virtual const c8* getTextFromClipboard() const = 0; + //! Get text from the primary selection + //! This is a no-op on some platforms. + //! \return Returns 0 if no string is in there, otherwise an utf-8 string. + virtual const c8* getTextFromPrimarySelection() const = 0; + //! Get the total and available system RAM /** \param totalBytes: will contain the total system memory in Kilobytes (1024 B) \param availableBytes: will contain the available memory in Kilobytes (1024 B) diff --git a/source/Irrlicht/CIrrDeviceLinux.cpp b/source/Irrlicht/CIrrDeviceLinux.cpp index 3c19099..0efc8f4 100644 --- a/source/Irrlicht/CIrrDeviceLinux.cpp +++ b/source/Irrlicht/CIrrDeviceLinux.cpp @@ -1000,12 +1000,15 @@ bool CIrrDeviceLinux::run() send_response(req->property); }; - if (req->selection != X_ATOM_CLIPBOARD || + if ((req->selection != X_ATOM_CLIPBOARD && + req->selection != XA_PRIMARY) || req->owner != XWindow) { // we are not the owner, refuse request send_response_refuse(); break; } + const core::stringc &text_buffer = req->selection == X_ATOM_CLIPBOARD ? + Clipboard : PrimarySelection; // for debugging: //~ { @@ -1026,8 +1029,8 @@ bool CIrrDeviceLinux::run() req->target, X_ATOM_UTF8_STRING, 8, // format = 8-bit PropModeReplace, - (unsigned char *)Clipboard.c_str(), - Clipboard.size()); + (unsigned char *)text_buffer.c_str(), + text_buffer.size()); send_response(req->target); break; } @@ -1052,8 +1055,8 @@ bool CIrrDeviceLinux::run() set_property_and_notify( X_ATOM_UTF8_STRING, 8, - Clipboard.c_str(), - Clipboard.size() + text_buffer.c_str(), + text_buffer.size() ); } else { @@ -1676,47 +1679,49 @@ void CIrrDeviceLinux::pollJoysticks() } +#if defined(_IRR_COMPILE_WITH_X11_) //! gets text from the clipboard //! \return Returns 0 if no string is in there, otherwise utf-8 text. -const c8 *CIrrDeviceLinux::getTextFromClipboard() const +const c8 *CIrrDeviceLinux::getTextFromSelection(Atom selection, core::stringc &text_buffer) const { -#if defined(_IRR_COMPILE_WITH_X11_) - Window ownerWindow = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD); + Window ownerWindow = XGetSelectionOwner(XDisplay, selection); if (ownerWindow == XWindow) { - return Clipboard.c_str(); + return text_buffer.c_str(); } - Clipboard = ""; + text_buffer = ""; if (ownerWindow == None) { - return Clipboard.c_str(); + return text_buffer.c_str(); } // delete the property to be set beforehand XDeleteProperty(XDisplay, XWindow, XA_PRIMARY); - XConvertSelection(XDisplay, X_ATOM_CLIPBOARD, X_ATOM_UTF8_STRING, XA_PRIMARY, + XConvertSelection(XDisplay, selection, X_ATOM_UTF8_STRING, XA_PRIMARY, XWindow, CurrentTime); XFlush(XDisplay); // wait for event via a blocking call XEvent event_ret; + std::pair args(XWindow, selection); XIfEvent(XDisplay, &event_ret, [](Display *_display, XEvent *event, XPointer arg) { + auto p = reinterpret_cast *>(arg); return (Bool) (event->type == SelectionNotify && - event->xselection.requestor == *(Window *)arg && - event->xselection.selection == X_ATOM_CLIPBOARD && + event->xselection.requestor == p->first && + event->xselection.selection == p->second && event->xselection.target == X_ATOM_UTF8_STRING); - }, (XPointer)&XWindow); + }, (XPointer)&args); _IRR_DEBUG_BREAK_IF(!(event_ret.type == SelectionNotify && event_ret.xselection.requestor == XWindow && - event_ret.xselection.selection == X_ATOM_CLIPBOARD && + event_ret.xselection.selection == selection && event_ret.xselection.target == X_ATOM_UTF8_STRING)); Atom property_set = event_ret.xselection.property; if (event_ret.xselection.property == None) { // request failed => empty string - return Clipboard.c_str(); + return text_buffer.c_str(); } // check for data @@ -1743,15 +1748,15 @@ const c8 *CIrrDeviceLinux::getTextFromClipboard() const // for debugging: //~ { //~ char *type_name = XGetAtomName(XDisplay, type); - //~ fprintf(stderr, "CIrrDeviceLinux::getTextFromClipboard: actual type: %s (=%ld)\n", + //~ fprintf(stderr, "CIrrDeviceLinux::getTextFromSelection: actual type: %s (=%ld)\n", //~ type_name, type); //~ XFree(type_name); //~ } if (type != X_ATOM_UTF8_STRING && type != X_ATOM_UTF8_MIME_TYPE) { - os::Printer::log("CIrrDeviceLinux::getTextFromClipboard: did not get utf-8 string", + os::Printer::log("CIrrDeviceLinux::getTextFromSelection: did not get utf-8 string", ELL_WARNING); - return Clipboard.c_str(); + return text_buffer.c_str(); } if (bytesLeft > 0) { @@ -1760,20 +1765,49 @@ const c8 *CIrrDeviceLinux::getTextFromClipboard() const bytesLeft, 0, AnyPropertyType, &type, &format, &numItems, &dummy, &data); if (result == Success) - Clipboard = (irr::c8 *)data; + text_buffer = (irr::c8 *)data; XFree (data); } // delete the property again, to inform the owner about the successful transfer XDeleteProperty(XDisplay, XWindow, property_set); - return Clipboard.c_str(); + return text_buffer.c_str(); +} +#endif +//! gets text from the clipboard +//! \return Returns 0 if no string is in there, otherwise utf-8 text. +const c8 *CIrrDeviceLinux::getTextFromClipboard() const +{ +#if defined(_IRR_COMPILE_WITH_X11_) + return getTextFromSelection(X_ATOM_CLIPBOARD, Clipboard); #else return nullptr; #endif } +//! gets text from the primary selection +//! \return Returns 0 if no string is in there, otherwise utf-8 text. +const c8 *CIrrDeviceLinux::getTextFromPrimarySelection() const +{ +#if defined(_IRR_COMPILE_WITH_X11_) + return getTextFromSelection(XA_PRIMARY, PrimarySelection); +#else + return nullptr; +#endif +} + +#if defined(_IRR_COMPILE_WITH_X11_) +bool CIrrDeviceLinux::becomeSelectionOwner(Atom selection) const +{ + XSetSelectionOwner (XDisplay, selection, XWindow, CurrentTime); + XFlush (XDisplay); + Window owner = XGetSelectionOwner(XDisplay, selection); + return owner == XWindow; +} +#endif + //! copies text to the clipboard void CIrrDeviceLinux::copyToClipboard(const c8 *text) const { @@ -1781,15 +1815,23 @@ void CIrrDeviceLinux::copyToClipboard(const c8 *text) const // Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked. // Which btw. also means that on X you lose clipboard content when closing applications. Clipboard = text; - XSetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD, XWindow, CurrentTime); - XFlush (XDisplay); - Window owner = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD); - if (owner != XWindow) { + if (!becomeSelectionOwner(X_ATOM_CLIPBOARD)) { os::Printer::log("CIrrDeviceLinux::copyToClipboard: failed to set owner", ELL_WARNING); } #endif } +//! copies text to the primary selection +void CIrrDeviceLinux::copyToPrimarySelection(const c8 *text) const +{ +#if defined(_IRR_COMPILE_WITH_X11_) + PrimarySelection = text; + if (!becomeSelectionOwner(XA_PRIMARY)) { + os::Printer::log("CIrrDeviceLinux::copyToPrimarySelection: failed to set owner", ELL_WARNING); + } +#endif +} + #ifdef _IRR_COMPILE_WITH_X11_ // return true if the passed event has the type passed in parameter arg Bool PredicateIsEventType(Display *display, XEvent *event, XPointer arg) diff --git a/source/Irrlicht/CIrrDeviceLinux.h b/source/Irrlicht/CIrrDeviceLinux.h index 2d8945c..544a736 100644 --- a/source/Irrlicht/CIrrDeviceLinux.h +++ b/source/Irrlicht/CIrrDeviceLinux.h @@ -97,11 +97,20 @@ namespace irr //! \return Returns 0 if no string is in there, otherwise utf-8 text. virtual const c8 *getTextFromClipboard() const; + //! gets text from the primary selection + //! \return Returns 0 if no string is in there, otherwise utf-8 text. + virtual const c8 *getTextFromPrimarySelection() const; + //! copies text to the clipboard - //! This sets the clipboard selection and _not_ the primary selection which you have on X on the middle mouse button. + //! This sets the clipboard selection and _not_ the primary selection. //! @param text The text in utf-8 virtual void copyToClipboard(const c8 *text) const; + //! copies text to the primary selection + //! This sets the primary selection which you have on X on the middle mouse button. + //! @param text The text in utf-8 + virtual void copyToPrimarySelection(const c8 *text) const; + //! Remove all messages pending in the system message loop void clearSystemMessages() override; @@ -141,6 +150,9 @@ namespace irr bool createInputContext(); void destroyInputContext(); EKEY_CODE getKeyCode(XEvent &event); + + const c8 *getTextFromSelection(Atom selection, core::stringc &text_buffer) const; + bool becomeSelectionOwner(Atom selection) const; #endif //! Implementation of the linux cursor control @@ -413,6 +425,7 @@ namespace irr bool HasNetWM; // text is utf-8 mutable core::stringc Clipboard; + mutable core::stringc PrimarySelection; #endif #if defined(_IRR_LINUX_X11_XINPUT2_) int currentTouchedCount; diff --git a/source/Irrlicht/COSOperator.cpp b/source/Irrlicht/COSOperator.cpp index 25b04ad..906035a 100644 --- a/source/Irrlicht/COSOperator.cpp +++ b/source/Irrlicht/COSOperator.cpp @@ -54,7 +54,6 @@ const core::stringc& COSOperator::getOperatingSystemVersion() const //! copies text to the clipboard -//! \param text: text in utf-8 void COSOperator::copyToClipboard(const c8 *text) const { if (strlen(text)==0) @@ -102,8 +101,20 @@ void COSOperator::copyToClipboard(const c8 *text) const } +//! copies text to the primary selection +void COSOperator::copyToPrimarySelection(const c8 *text) const +{ + if (strlen(text)==0) + return; + +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) + if ( IrrDeviceLinux ) + IrrDeviceLinux->copyToPrimarySelection(text); +#endif +} + + //! gets text from the clipboard -//! \return Returns 0 if no string is in there, otherwise an utf-8 string. const c8* COSOperator::getTextFromClipboard() const { #if defined(_IRR_WINDOWS_API_) @@ -147,6 +158,21 @@ const c8* COSOperator::getTextFromClipboard() const } +//! gets text from the primary selection +const c8* COSOperator::getTextFromPrimarySelection() const +{ +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) + if ( IrrDeviceLinux ) + return IrrDeviceLinux->getTextFromPrimarySelection(); + return 0; + +#else + + return 0; +#endif +} + + bool COSOperator::getSystemMemory(u32* Total, u32* Avail) const { #if defined(_IRR_WINDOWS_API_) diff --git a/source/Irrlicht/COSOperator.h b/source/Irrlicht/COSOperator.h index 6ef0f9b..6510579 100644 --- a/source/Irrlicht/COSOperator.h +++ b/source/Irrlicht/COSOperator.h @@ -27,13 +27,17 @@ public: const core::stringc& getOperatingSystemVersion() const override; //! copies text to the clipboard - //! \param text: text in utf-8 void copyToClipboard(const c8 *text) const override; + //! copies text to the primary selection + void copyToPrimarySelection(const c8 *text) const override; + //! gets text from the clipboard - //! \return Returns 0 if no string is in there, otherwise an utf-8 string. const c8* getTextFromClipboard() const override; + //! gets text from the primary selection + const c8* getTextFromPrimarySelection() const override; + //! gets the total and available system RAM in kB //! \param Total: will contain the total system memory //! \param Avail: will contain the available memory