39 bool isDragging()
const noexcept
45 void handleExternalSelectionClear()
48 externalResetDragAndDrop();
51 void handleExternalSelectionRequest (
const XEvent&
evt)
57 s.xselection.requestor =
evt.xselectionrequest.requestor;
58 s.xselection.selection =
evt.xselectionrequest.selection;
60 s.xselection.property = None;
61 s.xselection.time =
evt.xselectionrequest.time;
63 auto* display = getDisplay();
67 s.xselection.property =
evt.xselectionrequest.property;
69 X11Symbols::getInstance()->xChangeProperty (display,
evt.xselectionrequest.requestor,
evt.xselectionrequest.property,
71 reinterpret_cast<const unsigned char*
> (textOrFiles.
toRawUTF8()),
75 X11Symbols::getInstance()->xSendEvent (display,
evt.xselectionrequest.requestor, True, 0, &s);
82 expectingStatus =
false;
86 const auto& atoms = getAtoms();
89 && ((Atom)
clientMsg.data.l[4] == atoms.XdndActionCopy
90 || (Atom)
clientMsg.data.l[4] == atoms.XdndActionPrivate))
101 void handleExternalDragButtonReleaseEvent()
104 X11Symbols::getInstance()->xUngrabPointer (getDisplay(),
CurrentTime);
108 sendExternalDragAndDropDrop();
112 sendExternalDragAndDropLeave();
113 externalResetDragAndDrop();
117 void handleExternalDragMotionNotify()
119 auto* display = getDisplay();
121 auto newTargetWindow = externalFindDragTargetWindow (X11Symbols::getInstance()
122 ->xRootWindow (display,
123 X11Symbols::getInstance()->xDefaultScreen (display)));
127 if (targetWindow != None)
128 sendExternalDragAndDropLeave();
138 if (xdndVersion == -1)
142 sendExternalDragAndDropEnter();
145 if (! expectingStatus)
146 sendExternalDragAndDropPosition();
151 if (dragAndDropSourceWindow == 0)
154 dragAndDropSourceWindow = (::Window)
clientMsg.data.l[0];
164 const auto& atoms = getAtoms();
170 if ((Atom)
clientMsg.data.l[4] == atoms.allowedActions[i])
179 if (dragInfo.position !=
dropPos)
183 if (dragInfo.isEmpty())
186 if (! dragInfo.isEmpty())
187 peer->handleDragMove (dragInfo);
193 if (dragInfo.isEmpty())
196 finishAfterDropDataReceived =
true;
201 handleDragAndDropDataReceived();
208 srcMimeTypeAtomList.
clear();
210 dragAndDropCurrentMimeType = 0;
215 dragAndDropSourceWindow = 0;
219 const auto& atoms = getAtoms();
221 dragAndDropSourceWindow = (::Window)
clientMsg.data.l[0];
228 dragAndDropSourceWindow,
237 auto* types =
prop.data;
239 for (
unsigned long i = 0; i <
prop.numItems; ++i)
242 memcpy (&type, types,
sizeof (
unsigned long));
245 srcMimeTypeAtomList.
add (type);
247 types +=
sizeof (
unsigned long);
252 if (srcMimeTypeAtomList.
isEmpty())
254 for (
int i = 2; i < 5; ++i)
256 srcMimeTypeAtomList.
add ((
unsigned long)
clientMsg.data.l[i]);
258 if (srcMimeTypeAtomList.
isEmpty())
260 dragAndDropSourceWindow = 0;
265 for (
int i = 0; i < srcMimeTypeAtomList.
size() && dragAndDropCurrentMimeType == 0; ++i)
267 if (srcMimeTypeAtomList[i] == atoms.allowedMimeTypes[
j])
268 dragAndDropCurrentMimeType = atoms.allowedMimeTypes[
j];
270 handleDragAndDropPosition (
clientMsg, peer);
273 void handleDragAndDropExit()
275 if (
auto* peer = getPeerFor (windowH))
276 peer->handleDragExit (dragInfo);
281 void handleDragAndDropSelection (
const XEvent&
evt)
285 if (
evt.xselection.property != None)
296 evt.xselection.property,
307 if (
prop.bytesLeft <= 0)
314 if (XWindowSystemUtilities::Atoms::isMimeTypeFile (getDisplay(), dragAndDropCurrentMimeType))
316 for (
const auto& line : lines)
318 const auto escaped = line.replace (
"+",
"%2B").replace (
"file://",
String(),
true);
322 dragInfo.files.
trim();
330 if (finishAfterDropDataReceived)
331 handleDragAndDropDataReceived();
335 void externalResetDragAndDrop()
340 X11Symbols::getInstance()->xUngrabPointer (getDisplay(),
CurrentTime);
343 NullCheckedInvocation::invoke (completionCallback);
353 targetWindow = windowH;
354 completionCallback = std::move (
cb);
356 auto* display = getDisplay();
358 allowedTypes.
add (XWindowSystemUtilities::Atoms::getCreating (display, isText ?
"text/plain" :
"text/uri-list"));
364 if (X11Symbols::getInstance()->xGrabPointer (display, windowH, True,
pointerGrabMask,
367 const auto& atoms = getAtoms();
370 X11Symbols::getInstance()->xChangeActivePointerGrab (display,
pointerGrabMask, (Cursor) createDraggingHandCursor(),
CurrentTime);
372 X11Symbols::getInstance()->xSetSelectionOwner (display, atoms.XdndSelection, windowH,
CurrentTime);
375 X11Symbols::getInstance()->xChangeProperty (display, windowH, atoms.XdndTypeList,
XA_ATOM, 32,
PropModeReplace,
379 xdndVersion = getDnDVersionForWindow (targetWindow);
381 sendExternalDragAndDropEnter();
382 handleExternalDragMotionNotify();
393 ::Display* getDisplay()
const noexcept {
return XWindowSystem::getInstance()->getDisplay(); }
398 auto* display = getDisplay();
401 msg.display = display;
402 msg.window = dragAndDropSourceWindow;
404 msg.data.l[0] = (
long) windowH;
407 X11Symbols::getInstance()->xSendEvent (display, dragAndDropSourceWindow, False, 0, (
XEvent*) &msg);
412 auto* display = getDisplay();
415 msg.display = display;
416 msg.window = targetWindow;
418 msg.data.l[0] = (
long) windowH;
421 return X11Symbols::getInstance()->xSendEvent (display, targetWindow, False, 0, (
XEvent*) &msg) != 0;
424 void sendExternalDragAndDropDrop()
429 msg.message_type = getAtoms().XdndDrop;
432 sendExternalDragAndDropMessage (msg);
435 void sendExternalDragAndDropEnter()
440 msg.message_type = getAtoms().XdndEnter;
441 msg.data.l[1] = (xdndVersion << 24);
443 for (
int i = 0; i < 3; ++i)
444 msg.data.l[i + 2] = (
long) allowedTypes[i];
446 sendExternalDragAndDropMessage (msg);
449 void sendExternalDragAndDropPosition()
454 const auto& atoms = getAtoms();
456 msg.message_type = atoms.XdndPosition;
468 msg.data.l[4] = (
long) atoms.XdndActionCopy;
470 expectingStatus = sendExternalDragAndDropMessage (msg);
478 msg.message_type = getAtoms().XdndStatus;
482 sendDragAndDropMessage (msg);
485 void sendExternalDragAndDropLeave()
490 msg.message_type = getAtoms().XdndLeave;
491 sendExternalDragAndDropMessage (msg);
494 void sendDragAndDropFinish()
499 msg.message_type = getAtoms().XdndFinished;
500 sendDragAndDropMessage (msg);
507 if (dragAndDropSourceWindow != None && dragAndDropCurrentMimeType != None)
509 auto* display = getDisplay();
512 X11Symbols::getInstance()->xConvertSelection (display, getAtoms().XdndSelection, dragAndDropCurrentMimeType,
513 XWindowSystemUtilities::Atoms::getCreating (display,
"JXSelectionWindowProperty"),
518 bool isWindowDnDAware (::Window w)
const
521 auto* properties = X11Symbols::getInstance()->xListProperties (getDisplay(), w, &
numProperties);
526 if (properties[i] == getAtoms().XdndAware)
529 if (properties !=
nullptr)
530 X11Symbols::getInstance()->xFree (properties);
535 int getDnDVersionForWindow (::Window target)
539 getAtoms().XdndAware,
545 if (
prop.success &&
prop.data !=
nullptr &&
prop.actualFormat == 32 &&
prop.numItems == 1)
546 return jmin ((
int)
prop.data[0], (
int) XWindowSystemUtilities::Atoms::DndVersion);
551 ::Window externalFindDragTargetWindow (::Window target)
556 if (isWindowDnDAware (target))
565 return externalFindDragTargetWindow (child);
568 void handleDragAndDropDataReceived()
572 sendDragAndDropFinish();
576 if (
auto* peer = getPeerFor (windowH))
580 void resetDragAndDrop()
584 dragAndDropCurrentMimeType = 0;
585 dragAndDropSourceWindow = 0;
586 srcMimeTypeAtomList.
clear();
587 finishAfterDropDataReceived =
false;
591 ::Window windowH = 0, targetWindow = 0, dragAndDropSourceWindow = 0;
593 int xdndVersion = -1;
594 bool isText =
false, dragging =
false, expectingStatus =
false, canDrop =
false, finishAfterDropDataReceived =
false;
596 Atom dragAndDropCurrentMimeType;