From 9545320f9ce4b6792257fada3f849f32e445f799 Mon Sep 17 00:00:00 2001 From: Window Maker Date: Sun, 24 May 2026 10:58:22 +0200 Subject: [PATCH] =?UTF-8?q?wings:=20phase=20=CE=B3=20(dragcommon)=20?= =?UTF-8?q?=E2=80=94=20split=20X11=20XDND=20wire=20code=20into=20=5Fx11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dragcommon.c now contains only backend-neutral helpers (WMCreateDragOperationArray/Item, accessors, W_FreeViewXdndPart). dragcommon_x11.c is new and owns: - W_OperationToAction/W_ActionToOperation atom translation - windowExists / handleNoWindowXError probe - W_SendDnDClientMessage XSendEvent path - W_HandleDNDClientMessage XDND wire dispatch - handleLeaveMessage These touch scr->xdnd*Atom fields and call XSendEvent / XGetAtomName / XSetErrorHandler etc. — strictly X11. Wayland DnD will be added later through wl_data_device. dragsource.c and dragdestination.c still contain Xlib calls; those splits come next. --- WINGs/Makefile.am | 1 + WINGs/dragcommon.c | 220 ++-------------------------------------- WINGs/dragcommon_x11.c | 221 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 212 deletions(-) create mode 100644 WINGs/dragcommon_x11.c diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 1021508..d3c9a13 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -28,6 +28,7 @@ EXTRA_DIST = BUGS make-rgb Examples Extras Tests libWINGs_la_SOURCES = \ configuration.c \ dragcommon.c \ + dragcommon_x11.c \ dragdestination.c \ dragsource.c \ rgb.h \ diff --git a/WINGs/dragcommon.c b/WINGs/dragcommon.c index 146e4f3..fe712b6 100644 --- a/WINGs/dragcommon.c +++ b/WINGs/dragcommon.c @@ -1,69 +1,14 @@ +/* + * dragcommon.c — backend-neutral DnD helpers. + * + * X11-specific XDND code has moved to dragcommon_x11.c. This file + * holds only the parts that don't touch a windowing system: array + * accessors and free-on-view-destroy bookkeeping. + */ + #include "wconfig.h" - #include "WINGsP.h" -#define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion -#define XDND_DEST_INFO(dragInfo) dragInfo->destInfo -#define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView - -static Bool _WindowExists; - -WMNativeAtom W_OperationToAction(WMScreen * scr, WMDragOperationType operation) -{ - switch (operation) { - case WDOperationNone: - return WM_NATIVE_NONE; - - case WDOperationCopy: - return scr->xdndActionCopy; - - case WDOperationMove: - return scr->xdndActionMove; - - case WDOperationLink: - return scr->xdndActionLink; - - case WDOperationAsk: - return scr->xdndActionAsk; - - case WDOperationPrivate: - return scr->xdndActionPrivate; - - default: - return WM_NATIVE_NONE; - } -} - -WMDragOperationType W_ActionToOperation(WMScreen * scr, WMNativeAtom action) -{ - if (action == scr->xdndActionCopy) { - return WDOperationCopy; - - } else if (action == scr->xdndActionMove) { - return WDOperationMove; - - } else if (action == scr->xdndActionLink) { - return WDOperationLink; - - } else if (action == scr->xdndActionAsk) { - return WDOperationAsk; - - } else if (action == scr->xdndActionPrivate) { - return WDOperationPrivate; - - } else if (action == WM_NATIVE_NONE) { - - return WDOperationNone; - } else { - char *tmp = XGetAtomName(scr->display, action); - - wwarning(_("unknown XDND action %s"), tmp); - XFree(tmp); - - return WDOperationCopy; - } -} - static void freeDragOperationItem(void *item) { wfree(item); @@ -94,155 +39,6 @@ char *WMGetDragOperationItemText(WMDragOperationItem * item) return ((W_DragOperationItem *) item)->text; } -static int handleNoWindowXError(Display * dpy, XErrorEvent * errEvt) -{ - /* Parameter not used, but tell the compiler that it is ok */ - (void) dpy; - - if (errEvt->error_code == BadWindow || errEvt->error_code == BadDrawable) { - _WindowExists = False; - return Success; - } - - return errEvt->error_code; -} - -static Bool windowExists(Display * dpy, WNativeWindow win) -{ - void *previousErrorHandler; - XWindowAttributes attr; - - XSynchronize(dpy, True); - previousErrorHandler = XSetErrorHandler(handleNoWindowXError); - _WindowExists = True; - - /* can generate BadDrawable or BadWindow */ - XGetWindowAttributes(dpy, win, &attr); - - XSetErrorHandler(previousErrorHandler); - XSynchronize(dpy, False); - return _WindowExists; -} - -Bool -W_SendDnDClientMessage(Display * dpy, WNativeWindow win, WMNativeAtom message, - unsigned long data0, - unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4) -{ - XEvent ev; - -#ifdef XDND_DEBUG - char *msgName = XGetAtomName(dpy, message); - - printf("sending message %s ... ", msgName); - XFree(msgName); -#endif - - if (!windowExists(dpy, win)) { - wwarning(_("target %lu for XDND message no longer exists"), win); - return False; /* message not sent */ - } - - ev.type = ClientMessage; - ev.xclient.message_type = message; - ev.xclient.format = 32; - ev.xclient.window = win; - ev.xclient.data.l[0] = data0; - ev.xclient.data.l[1] = data1; - ev.xclient.data.l[2] = data2; - ev.xclient.data.l[3] = data3; - ev.xclient.data.l[4] = data4; - - XSendEvent(dpy, win, False, 0, &ev); - XFlush(dpy); - -#ifdef XDND_DEBUG - printf("sent\n"); -#endif - return True; /* message sent */ -} - -static void handleLeaveMessage(WMDraggingInfo * info) -{ - if (XDND_DEST_INFO(info) != NULL) { - /* XDND_DEST_VIEW is never NULL (it's the xdnd aware view) */ - wassertr(XDND_DEST_VIEW(info) != NULL); - if (XDND_DEST_VIEW(info)->dragDestinationProcs != NULL) { - XDND_DEST_VIEW(info)->dragDestinationProcs->concludeDragOperation(XDND_DEST_VIEW(info)); - } - W_DragDestinationInfoClear(info); - } -} - -void W_HandleDNDClientMessage(WMView * toplevel, XClientMessageEvent * event) -{ - WMScreen *scr = W_VIEW_SCREEN(toplevel); - WMDraggingInfo *info = &scr->dragInfo; - WMNativeAtom messageType = event->message_type; - -#ifdef XDND_DEBUG - { - char *msgTypeName = XGetAtomName(scr->display, messageType); - - if (msgTypeName != NULL) - printf("event type = %s\n", msgTypeName); - else - printf("pb with event type !\n"); - } -#endif - - /* Messages from destination to source */ - if (messageType == scr->xdndStatusAtom || messageType == scr->xdndFinishedAtom) { - W_DragSourceStopTimer(); - W_DragSourceStateHandler(info, event); - return; - } - - /* Messages from source to destination */ - if (messageType == scr->xdndEnterAtom) { - Bool positionSent = (XDND_DEST_INFO(info) != NULL); - - W_DragDestinationStopTimer(); - W_DragDestinationStoreEnterMsgInfo(info, toplevel, event); - - /* Xdnd version 3 and up are not compatible with version 1 or 2 */ - if (XDND_SOURCE_VERSION(info) > 2) { - - if (positionSent) { - /* xdndPosition previously received on xdnd aware view */ - W_DragDestinationStateHandler(info, event); - return; - } else { - W_DragDestinationStartTimer(info); - return; - } - } else { - wwarning(_("unsupported version %i for XDND enter message"), XDND_SOURCE_VERSION(info)); - W_DragDestinationCancelDropOnEnter(toplevel, info); - return; - } - } - - if (messageType == scr->xdndPositionAtom) { - W_DragDestinationStopTimer(); - W_DragDestinationStorePositionMsgInfo(info, toplevel, event); - W_DragDestinationStateHandler(info, event); - return; - } - - if (messageType == scr->xdndSelectionAtom || messageType == scr->xdndDropAtom) { - W_DragDestinationStopTimer(); - W_DragDestinationStateHandler(info, event); - return; - } - - if (messageType == scr->xdndLeaveAtom) { - /* conclude drop operation, and clear dragging info */ - W_DragDestinationStopTimer(); - handleLeaveMessage(info); - } -} - /* called in destroyView (wview.c) */ void W_FreeViewXdndPart(WMView * view) { diff --git a/WINGs/dragcommon_x11.c b/WINGs/dragcommon_x11.c new file mode 100644 index 0000000..f2de058 --- /dev/null +++ b/WINGs/dragcommon_x11.c @@ -0,0 +1,221 @@ +/* + * dragcommon_x11.c — X11 XDND-specific helpers. + * + * Operation↔atom translation, ClientMessage send/recv, error-handler + * window-exists probe — all things that talk Xlib/XDND wire protocol. + */ + +#include "wconfig.h" +#include "WINGsP.h" + +#include + +#define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion +#define XDND_DEST_INFO(dragInfo) dragInfo->destInfo +#define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView + +static Bool _WindowExists; + +WMNativeAtom W_OperationToAction(WMScreen * scr, WMDragOperationType operation) +{ + switch (operation) { + case WDOperationNone: + return WM_NATIVE_NONE; + + case WDOperationCopy: + return scr->xdndActionCopy; + + case WDOperationMove: + return scr->xdndActionMove; + + case WDOperationLink: + return scr->xdndActionLink; + + case WDOperationAsk: + return scr->xdndActionAsk; + + case WDOperationPrivate: + return scr->xdndActionPrivate; + + default: + return WM_NATIVE_NONE; + } +} + +WMDragOperationType W_ActionToOperation(WMScreen * scr, WMNativeAtom action) +{ + if (action == scr->xdndActionCopy) { + return WDOperationCopy; + + } else if (action == scr->xdndActionMove) { + return WDOperationMove; + + } else if (action == scr->xdndActionLink) { + return WDOperationLink; + + } else if (action == scr->xdndActionAsk) { + return WDOperationAsk; + + } else if (action == scr->xdndActionPrivate) { + return WDOperationPrivate; + + } else if (action == WM_NATIVE_NONE) { + + return WDOperationNone; + } else { + char *tmp = XGetAtomName(scr->display, action); + + wwarning(_("unknown XDND action %s"), tmp); + XFree(tmp); + + return WDOperationCopy; + } +} + +static int handleNoWindowXError(Display * dpy, XErrorEvent * errEvt) +{ + (void) dpy; + + if (errEvt->error_code == BadWindow || errEvt->error_code == BadDrawable) { + _WindowExists = False; + return Success; + } + + return errEvt->error_code; +} + +static Bool windowExists(Display * dpy, WNativeWindow win) +{ + void *previousErrorHandler; + XWindowAttributes attr; + + XSynchronize(dpy, True); + previousErrorHandler = XSetErrorHandler(handleNoWindowXError); + _WindowExists = True; + + /* can generate BadDrawable or BadWindow */ + XGetWindowAttributes(dpy, win, &attr); + + XSetErrorHandler(previousErrorHandler); + XSynchronize(dpy, False); + return _WindowExists; +} + +Bool +W_SendDnDClientMessage(Display * dpy, WNativeWindow win, WMNativeAtom message, + unsigned long data0, + unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4) +{ + XEvent ev; + +#ifdef XDND_DEBUG + char *msgName = XGetAtomName(dpy, message); + + printf("sending message %s ... ", msgName); + XFree(msgName); +#endif + + if (!windowExists(dpy, win)) { + wwarning(_("target %lu for XDND message no longer exists"), win); + return False; /* message not sent */ + } + + ev.type = ClientMessage; + ev.xclient.message_type = message; + ev.xclient.format = 32; + ev.xclient.window = win; + ev.xclient.data.l[0] = data0; + ev.xclient.data.l[1] = data1; + ev.xclient.data.l[2] = data2; + ev.xclient.data.l[3] = data3; + ev.xclient.data.l[4] = data4; + + XSendEvent(dpy, win, False, 0, &ev); + XFlush(dpy); + +#ifdef XDND_DEBUG + printf("sent\n"); +#endif + return True; /* message sent */ +} + +static void handleLeaveMessage(WMDraggingInfo * info) +{ + if (XDND_DEST_INFO(info) != NULL) { + /* XDND_DEST_VIEW is never NULL (it's the xdnd aware view) */ + wassertr(XDND_DEST_VIEW(info) != NULL); + if (XDND_DEST_VIEW(info)->dragDestinationProcs != NULL) { + XDND_DEST_VIEW(info)->dragDestinationProcs->concludeDragOperation(XDND_DEST_VIEW(info)); + } + W_DragDestinationInfoClear(info); + } +} + +void W_HandleDNDClientMessage(WMView * toplevel, XClientMessageEvent * event) +{ + WMScreen *scr = W_VIEW_SCREEN(toplevel); + WMDraggingInfo *info = &scr->dragInfo; + WMNativeAtom messageType = event->message_type; + +#ifdef XDND_DEBUG + { + char *msgTypeName = XGetAtomName(scr->display, messageType); + + if (msgTypeName != NULL) + printf("event type = %s\n", msgTypeName); + else + printf("pb with event type !\n"); + } +#endif + + /* Messages from destination to source */ + if (messageType == scr->xdndStatusAtom || messageType == scr->xdndFinishedAtom) { + W_DragSourceStopTimer(); + W_DragSourceStateHandler(info, event); + return; + } + + /* Messages from source to destination */ + if (messageType == scr->xdndEnterAtom) { + Bool positionSent = (XDND_DEST_INFO(info) != NULL); + + W_DragDestinationStopTimer(); + W_DragDestinationStoreEnterMsgInfo(info, toplevel, event); + + /* Xdnd version 3 and up are not compatible with version 1 or 2 */ + if (XDND_SOURCE_VERSION(info) > 2) { + + if (positionSent) { + /* xdndPosition previously received on xdnd aware view */ + W_DragDestinationStateHandler(info, event); + return; + } else { + W_DragDestinationStartTimer(info); + return; + } + } else { + wwarning(_("unsupported version %i for XDND enter message"), XDND_SOURCE_VERSION(info)); + W_DragDestinationCancelDropOnEnter(toplevel, info); + return; + } + } + + if (messageType == scr->xdndPositionAtom) { + W_DragDestinationStopTimer(); + W_DragDestinationStorePositionMsgInfo(info, toplevel, event); + W_DragDestinationStateHandler(info, event); + return; + } + + if (messageType == scr->xdndSelectionAtom || messageType == scr->xdndDropAtom) { + W_DragDestinationStopTimer(); + W_DragDestinationStateHandler(info, event); + return; + } + + if (messageType == scr->xdndLeaveAtom) { + /* conclude drop operation, and clear dragging info */ + W_DragDestinationStopTimer(); + handleLeaveMessage(info); + } +}