Browse Source

Linux/X11: Prefer CLIPBOARD selection to PRIMARY

As specified in https://specifications.freedesktop.org/clipboards-spec/clipboards-latest.txt, CLIPBOARD should be used for explicit cut/copy/paste operations over PRIMARY
v6.1.6
ed 4 years ago
parent
commit
faf5ed4023
3 changed files with 86 additions and 55 deletions
  1. +52
    -29
      modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp
  2. +30
    -21
      modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp
  3. +4
    -5
      modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h

+ 52
- 29
modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp View File

@@ -60,17 +60,19 @@ public:
s.xselection.property = None;
s.xselection.time = evt.xselectionrequest.time;
auto* display = getDisplay();
if (allowedTypes.contains (targetType))
{
s.xselection.property = evt.xselectionrequest.property;
X11Symbols::getInstance()->xChangeProperty (getDisplay(), evt.xselectionrequest.requestor, evt.xselectionrequest.property,
X11Symbols::getInstance()->xChangeProperty (display, evt.xselectionrequest.requestor, evt.xselectionrequest.property,
targetType, 8, PropModeReplace,
reinterpret_cast<const unsigned char*> (textOrFiles.toRawUTF8()),
(int) textOrFiles.getNumBytesAsUTF8());
}
X11Symbols::getInstance()->xSendEvent (getDisplay(), evt.xselectionrequest.requestor, True, 0, &s);
X11Symbols::getInstance()->xSendEvent (display, evt.xselectionrequest.requestor, True, 0, &s);
}
void handleExternalDragAndDropStatus (const XClientMessageEvent& clientMsg)
@@ -81,9 +83,11 @@ public:
canDrop = false;
silentRect = {};
const auto& atoms = getAtoms();
if ((clientMsg.data.l[1] & 1) != 0
&& ((Atom) clientMsg.data.l[4] == getAtoms().XdndActionCopy
|| (Atom) clientMsg.data.l[4] == getAtoms().XdndActionPrivate))
&& ((Atom) clientMsg.data.l[4] == atoms.XdndActionCopy
|| (Atom) clientMsg.data.l[4] == atoms.XdndActionPrivate))
{
if ((clientMsg.data.l[1] & 2) == 0) // target requests silent rectangle
silentRect.setBounds ((int) clientMsg.data.l[2] >> 16, (int) clientMsg.data.l[2] & 0xffff,
@@ -112,8 +116,11 @@ public:
void handleExternalDragMotionNotify()
{
auto newTargetWindow = externalFindDragTargetWindow (X11Symbols::getInstance()->xRootWindow (getDisplay(),
X11Symbols::getInstance()->xDefaultScreen (getDisplay())));
auto* display = getDisplay();
auto newTargetWindow = externalFindDragTargetWindow (X11Symbols::getInstance()
->xRootWindow (display,
X11Symbols::getInstance()->xDefaultScreen (display)));
if (targetWindow != newTargetWindow)
{
@@ -153,13 +160,15 @@ public:
(int) clientMsg.data.l[2] & 0xffff));
dropPos -= peer->getBounds().getPosition();
auto targetAction = getAtoms().XdndActionCopy;
const auto& atoms = getAtoms();
for (int i = numElementsInArray (getAtoms().allowedActions); --i >= 0;)
auto targetAction = atoms.XdndActionCopy;
for (int i = numElementsInArray (atoms.allowedActions); --i >= 0;)
{
if ((Atom) clientMsg.data.l[4] == getAtoms().allowedActions[i])
if ((Atom) clientMsg.data.l[4] == atoms.allowedActions[i])
{
targetAction = getAtoms().allowedActions[i];
targetAction = atoms.allowedActions[i];
break;
}
}
@@ -206,12 +215,14 @@ public:
return;
}
const auto& atoms = getAtoms();
dragAndDropSourceWindow = (::Window) clientMsg.data.l[0];
if ((clientMsg.data.l[1] & 1) != 0)
{
XWindowSystemUtilities::ScopedXLock xLock;
XWindowSystemUtilities::GetXProperty prop (dragAndDropSourceWindow, getAtoms().XdndTypeList, 0, 0x8000000L, false, XA_ATOM);
XWindowSystemUtilities::GetXProperty prop (dragAndDropSourceWindow, atoms.XdndTypeList, 0, 0x8000000L, false, XA_ATOM);
if (prop.success && prop.actualType == XA_ATOM && prop.actualFormat == 32 && prop.numItems != 0)
{
@@ -244,9 +255,9 @@ public:
}
for (int i = 0; i < srcMimeTypeAtomList.size() && dragAndDropCurrentMimeType == 0; ++i)
for (int j = 0; j < numElementsInArray (getAtoms().allowedMimeTypes); ++j)
if (srcMimeTypeAtomList[i] == getAtoms().allowedMimeTypes[j])
dragAndDropCurrentMimeType = getAtoms().allowedMimeTypes[j];
for (int j = 0; j < numElementsInArray (atoms.allowedMimeTypes); ++j)
if (srcMimeTypeAtomList[i] == atoms.allowedMimeTypes[j])
dragAndDropCurrentMimeType = atoms.allowedMimeTypes[j];
handleDragAndDropPosition (clientMsg, peer);
}
@@ -326,22 +337,26 @@ public:
targetWindow = windowH;
completionCallback = std::move (cb);
allowedTypes.add (XWindowSystemUtilities::Atoms::getCreating (getDisplay(), isText ? "text/plain" : "text/uri-list"));
auto* display = getDisplay();
allowedTypes.add (XWindowSystemUtilities::Atoms::getCreating (display, isText ? "text/plain" : "text/uri-list"));
auto pointerGrabMask = (unsigned int) (Button1MotionMask | ButtonReleaseMask);
XWindowSystemUtilities::ScopedXLock xLock;
if (X11Symbols::getInstance()->xGrabPointer (getDisplay(), windowH, True, pointerGrabMask,
if (X11Symbols::getInstance()->xGrabPointer (display, windowH, True, pointerGrabMask,
GrabModeAsync, GrabModeAsync, None, None, CurrentTime) == GrabSuccess)
{
const auto& atoms = getAtoms();
// No other method of changing the pointer seems to work, this call is needed from this very context
X11Symbols::getInstance()->xChangeActivePointerGrab (getDisplay(), pointerGrabMask, (Cursor) createDraggingHandCursor(), CurrentTime);
X11Symbols::getInstance()->xChangeActivePointerGrab (display, pointerGrabMask, (Cursor) createDraggingHandCursor(), CurrentTime);
X11Symbols::getInstance()->xSetSelectionOwner (getDisplay(), getAtoms().XdndSelection, windowH, CurrentTime);
X11Symbols::getInstance()->xSetSelectionOwner (display, atoms.XdndSelection, windowH, CurrentTime);
// save the available types to XdndTypeList
X11Symbols::getInstance()->xChangeProperty (getDisplay(), windowH, getAtoms().XdndTypeList, XA_ATOM, 32, PropModeReplace,
X11Symbols::getInstance()->xChangeProperty (display, windowH, atoms.XdndTypeList, XA_ATOM, 32, PropModeReplace,
reinterpret_cast<const unsigned char*> (allowedTypes.getRawDataPointer()), allowedTypes.size());
dragging = true;
@@ -358,32 +373,36 @@ public:
private:
//==============================================================================
XWindowSystemUtilities::Atoms& getAtoms() const { return XWindowSystem::getInstance()->getAtoms(); }
::Display* getDisplay() const { return XWindowSystem::getInstance()->getDisplay(); }
const XWindowSystemUtilities::Atoms& getAtoms() const noexcept { return XWindowSystem::getInstance()->getAtoms(); }
::Display* getDisplay() const noexcept { return XWindowSystem::getInstance()->getDisplay(); }
//==============================================================================
void sendDragAndDropMessage (XClientMessageEvent& msg)
{
auto* display = getDisplay();
msg.type = ClientMessage;
msg.display = getDisplay();
msg.display = display;
msg.window = dragAndDropSourceWindow;
msg.format = 32;
msg.data.l[0] = (long) windowH;
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xSendEvent (getDisplay(), dragAndDropSourceWindow, False, 0, (XEvent*) &msg);
X11Symbols::getInstance()->xSendEvent (display, dragAndDropSourceWindow, False, 0, (XEvent*) &msg);
}
bool sendExternalDragAndDropMessage (XClientMessageEvent& msg)
{
auto* display = getDisplay();
msg.type = ClientMessage;
msg.display = getDisplay();
msg.display = display;
msg.window = targetWindow;
msg.format = 32;
msg.data.l[0] = (long) windowH;
XWindowSystemUtilities::ScopedXLock xLock;
return X11Symbols::getInstance()->xSendEvent (getDisplay(), targetWindow, False, 0, (XEvent*) &msg) != 0;
return X11Symbols::getInstance()->xSendEvent (display, targetWindow, False, 0, (XEvent*) &msg) != 0;
}
void sendExternalDragAndDropDrop()
@@ -416,7 +435,9 @@ private:
XClientMessageEvent msg;
zerostruct (msg);
msg.message_type = getAtoms().XdndPosition;
const auto& atoms = getAtoms();
msg.message_type = atoms.XdndPosition;
auto mousePos = Desktop::getInstance().getMousePosition();
@@ -428,7 +449,7 @@ private:
msg.data.l[1] = 0;
msg.data.l[2] = (mousePos.x << 16) | mousePos.y;
msg.data.l[3] = CurrentTime;
msg.data.l[4] = (long) getAtoms().XdndActionCopy; // this is all JUCE currently supports
msg.data.l[4] = (long) atoms.XdndActionCopy; // this is all JUCE currently supports
expectingStatus = sendExternalDragAndDropMessage (msg);
}
@@ -469,9 +490,11 @@ private:
if (dragAndDropSourceWindow != None && dragAndDropCurrentMimeType != None)
{
auto* display = getDisplay();
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xConvertSelection (getDisplay(), getAtoms().XdndSelection, dragAndDropCurrentMimeType,
XWindowSystemUtilities::Atoms::getCreating (getDisplay(), "JXSelectionWindowProperty"),
X11Symbols::getInstance()->xConvertSelection (display, getAtoms().XdndSelection, dragAndDropCurrentMimeType,
XWindowSystemUtilities::Atoms::getCreating (display, "JXSelectionWindowProperty"),
requestor, (::Time) clientMsg.data.l[2]);
}
}


+ 30
- 21
modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp View File

@@ -1328,9 +1328,11 @@ namespace ClipboardHelpers
int propertyFormat = 0;
size_t numDataItems = 0;
if (evt.selection == XA_PRIMARY || evt.selection == XWindowSystem::getInstance()->getAtoms().clipboard)
const auto& atoms = XWindowSystem::getInstance()->getAtoms();
if (evt.selection == XA_PRIMARY || evt.selection == atoms.clipboard)
{
if (evt.target == XA_STRING || evt.target == XWindowSystem::getInstance()->getAtoms().utf8String)
if (evt.target == XA_STRING || evt.target == atoms.utf8String)
{
auto localContent = XWindowSystem::getInstance()->getLocalClipboardContent();
@@ -1340,15 +1342,17 @@ namespace ClipboardHelpers
localContent.copyToUTF8 (data, numDataItems);
propertyFormat = 8; // bits/item
}
else if (evt.target == XWindowSystem::getInstance()->getAtoms().targets)
else if (evt.target == atoms.targets)
{
// another application wants to know what we are able to send
numDataItems = 2;
propertyFormat = 32; // atoms are 32-bit
data.calloc (numDataItems * 4);
Atom* atoms = unalignedPointerCast<Atom*> (data.getData());
atoms[0] = XWindowSystem::getInstance()->getAtoms().utf8String;
atoms[1] = XA_STRING;
auto* dataAtoms = unalignedPointerCast<Atom*> (data.getData());
dataAtoms[0] = atoms.utf8String;
dataAtoms[1] = XA_STRING;
evt.target = XA_ATOM;
}
@@ -2588,14 +2592,12 @@ void XWindowSystem::copyTextToClipboard (const String& clipText)
{
localClipboardContent = clipText;
X11Symbols::getInstance()->xSetSelectionOwner (display, XA_PRIMARY, juce_messageWindowHandle, CurrentTime);
X11Symbols::getInstance()->xSetSelectionOwner (display, XA_PRIMARY, juce_messageWindowHandle, CurrentTime);
X11Symbols::getInstance()->xSetSelectionOwner (display, atoms.clipboard, juce_messageWindowHandle, CurrentTime);
}
String XWindowSystem::getTextFromClipboard() const
{
String content;
/* 1) try to read from the "CLIPBOARD" selection first (the "high
level" clipboard that is supposed to be filled by ctrl-C
etc). When a clipboard manager is running, the content of this
@@ -2605,22 +2607,29 @@ String XWindowSystem::getTextFromClipboard() const
2) and then try to read from "PRIMARY" selection (the "legacy" selection
filled by good old x11 apps such as xterm)
*/
auto selection = XA_PRIMARY;
Window selectionOwner = None;
if ((selectionOwner = X11Symbols::getInstance()->xGetSelectionOwner (display, selection)) == None)
auto getContentForSelection = [this] (Atom selectionAtom) -> String
{
selection = atoms.clipboard;
selectionOwner = X11Symbols::getInstance()->xGetSelectionOwner (display, selection);
}
auto selectionOwner = X11Symbols::getInstance()->xGetSelectionOwner (display, selectionAtom);
if (selectionOwner == None)
return {};
if (selectionOwner != None)
{
if (selectionOwner == juce_messageWindowHandle)
content = localClipboardContent;
else if (! ClipboardHelpers::requestSelectionContent (display, content, selection, atoms.utf8String))
ClipboardHelpers::requestSelectionContent (display, content, selection, XA_STRING);
}
return localClipboardContent;
String content;
if (! ClipboardHelpers::requestSelectionContent (display, content, selectionAtom, atoms.utf8String))
ClipboardHelpers::requestSelectionContent (display, content, selectionAtom, XA_STRING);
return content;
};
auto content = getContentForSelection (atoms.clipboard);
if (content.isEmpty())
content = getContentForSelection (XA_PRIMARY);
return content;
}


+ 4
- 5
modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h View File

@@ -158,13 +158,12 @@ public:
void copyTextToClipboard (const String&);
String getTextFromClipboard() const;
String getLocalClipboardContent() const noexcept { return localClipboardContent; }
String getLocalClipboardContent() const { return localClipboardContent; }
::Display* getDisplay() noexcept { return display; }
const XWindowSystemUtilities::Atoms& getAtoms() const noexcept { return atoms; }
::Display* getDisplay() { return display; }
XWindowSystemUtilities::Atoms& getAtoms() { return atoms; }
bool isX11Available() const noexcept { return xIsAvailable; }
bool isX11Available() const noexcept { return xIsAvailable; }
//==============================================================================
void handleWindowMessage (LinuxComponentPeer*, XEvent&) const;


Loading…
Cancel
Save