I wrote a demo to capture XDND type messages for dragging files between folders in UBUNTU22.04. But I found that even though I set the mask for all message types, I still couldn't catch messages from the Client Message type when I was dragging files from one directory to another.
Here is my code, which can be compiled directly from Downloads folder(It`s Important as I implied based on the folder , see it in my code :D ) to others on uruntu22-64bits
#include <limits.h>#include <stdarg.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <pthread.h>#include <X11/Xlib.h>#include <X11/Xresource.h>#include <X11/Xutil.h>#include <X11/Xatom.h>#include <X11/X.h>//-----------------------------------------------------------------------------typedef unsigned int ATOM;#define Bool int#define Status int#define True 1#define False 0#define TRUE 1#define FALE 0static Atom XdndVersion= (Atom)3;static Atom XdndAware;static Atom XdndSelection;static Atom XdndEnter;static Atom XdndLeave;static Atom XdndPosition;static Atom XdndDrop;static Atom XdndFinished;static Atom XdndStatus;static Atom XdndActionCopy;static Atom XdndActionMove;static Atom XdndActionLink;static Atom XdndActionAsk;static Atom XdndActionPrivate;static Atom XdndTypeList;static Atom XdndTextUriList;static Atom XdndSelectionAtom;static Window xdndSourceWindow= 0;static Atom *xdndTypeList= 0;static int xdndWillAccept= 0;#define xdndEnter_sourceWindow(evt) ( (evt)->data.l[0])#define xdndEnter_version(evt) ( (evt)->data.l[1] >> 24)#define xdndEnter_hasThreeTypes(evt) (((evt)->data.l[1] & 0x1UL) == 0)#define xdndEnter_typeAt(evt, idx) ( (evt)->data.l[2 + (idx)])#define xdndPosition_sourceWindow(evt) ((Window)((evt)->data.l[0]))#define xdndPosition_rootX(evt) ((evt)->data.l[2] >> 16)#define xdndPosition_rootY(evt) ((evt)->data.l[2] & 0xffffUL)#define xdndPosition_action(evt) ((Atom)((evt)->data.l[4]))#define xdndStatus_targetWindow(evt) ((evt)->data.l[0])#define xdndStatus_setWillAccept(evt, b) ((evt)->data.l[1]= (((evt)->data.l[1] & ~1UL) | ((b) ? 1 : 0)))#define xdndStatus_setWantPosition(evt, b) ((evt)->data.l[1]= (((evt)->data.l[1] & ~2UL) | ((b) ? 2 : 0)))#define xdndStatus_action(evt) ((evt)->data.l[4])#define xdndDrop_sourceWindow(evt) ((Window)((evt)->data.l[0]))#define xdndDrop_time(evt) ((evt)->data.l[2])#define xdndFinished_targetWindow(evt) ((evt)->data.l[0])enum XdndState { XdndStateIdle, XdndStateEntered, XdndStateTracking};static enum XdndState xdndState= XdndStateIdle;struct xdndatom { Atom atom; char *name;}; struct FullLinuxWindowAttributes{ unsigned int sizeof_FullLinuxWindowAttributes; char windowName[512]; int root_x_return; int root_y_return; int win_x_return; int win_y_return; char typeof_currentX11Window[32]; char* currentX11Window; unsigned int sizeof_CurrentX11Window; char typeof_xWindowAttributes[32]; char* xWindowAttributes; unsigned int sizeof_xWindowAttributes; char attributes[2048][32]; char reservedData[512]; };static struct xdndatom xdndatoms[] = { { 0, "XdndAware" }, { 0, "XdndSelection" }, { 0, "XdndEnter" }, { 0, "XdndLeave" }, { 0, "XdndPosition" }, { 0, "XdndDrop" }, { 0, "XdndFinished" }, { 0, "XdndStatus" }, { 0, "XdndActionCopy" }, { 0, "XdndActionMove" }, { 0, "XdndActionLink" }, { 0, "XdndActionAsk" }, { 0, "XdndActionPrivate" }, { 0, "XdndTypeList" }, { 0, "XdndActionList" }, { 0, "XdndActionDescription" }, { 0, "text/uri-list" }, { 0, "UTF8_STRING" }, { 0, "COMPOUND_TEXT" }, { 0, "TEXT" }, { 0, "STRING" }, { 0, "text/plain;charset=utf-8" }, { 0, "text/plain" }};char** uxDropFileNames;static Atom XdndTypeList;static Atom XdndTextUriList; Display* stDisplay ; Window stParent;void dndInitialise(void){ XdndAware= XInternAtom(stDisplay, "XdndAware", False); XdndSelection= XInternAtom(stDisplay, "XdndSelection", False); XdndEnter= XInternAtom(stDisplay, "XdndEnter", False); XdndLeave= XInternAtom(stDisplay, "XdndLeave", False); XdndPosition= XInternAtom(stDisplay, "XdndPosition", False); XdndDrop= XInternAtom(stDisplay, "XdndDrop", False); XdndFinished= XInternAtom(stDisplay, "XdndFinished", False); XdndStatus= XInternAtom(stDisplay, "XdndStatus", False); XdndActionCopy= XInternAtom(stDisplay, "XdndActionCopy", False); XdndActionMove= XInternAtom(stDisplay, "XdndActionMove", False); XdndActionLink= XInternAtom(stDisplay, "XdndActionLink", False); XdndActionAsk= XInternAtom(stDisplay, "XdndActionAsk", False); XdndActionPrivate= XInternAtom(stDisplay, "XdndActionPrivate", False); XdndTypeList= XInternAtom(stDisplay, "XdndTypeList", False); XdndTextUriList= XInternAtom(stDisplay, "text/uri-list", False); XdndSelectionAtom= XInternAtom(stDisplay, "XdndSqueakSelection", False); XChangeProperty(stDisplay, stParent, XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XdndVersion, 1);}static const char *xdnd_get_atom_name(Atom atom){ int i; char *name = "Unregistered Xdnd Atom"; for(i = 0; i < sizeof(xdndatoms) / sizeof(struct xdndatom); i++) { if(xdndatoms[i].atom == atom) { name = xdndatoms[i].name; break; } } return name;}static void *xcalloc(size_t nmemb, size_t size){ void *ptr= calloc(nmemb, size); if (!ptr) { fprintf(stderr, "out of memory\n"); exit(1); } return ptr;}static void dndGetTypeList(XClientMessageEvent *evt){ if(!stDisplay) return ; if (xdndTypeList) { free(xdndTypeList); xdndTypeList= 0; } xdndWillAccept= 0; if (xdndEnter_hasThreeTypes(evt)) { int i; printf(" 3 types\n"); xdndTypeList= (Atom *)xcalloc(3 + 1, sizeof(Atom)); for (i= 0; i < 3; ++i) xdndTypeList[i]= xdndEnter_typeAt(evt, i); xdndTypeList[3]= 0; } else { Atom type, *atoms; int format; unsigned long i, count, remaining; unsigned char *data= 0; XGetWindowProperty(stDisplay, xdndSourceWindow, XdndTypeList, 0, 0x8000000L, False, XA_ATOM,&type, &format, &count, &remaining, &data); if ((type != XA_ATOM) || (format != 32) || (count == 0) || !data) { if (data) XFree(data); fprintf(stderr, "XGetWindowProperty failed in xdndGetTypeList\n"); return; } xdndTypeList= (Atom *)xcalloc(count + 1, sizeof(Atom)); atoms= (Atom *)data; for (i= 0; i < count; ++i) xdndTypeList[i]= atoms[i]; xdndTypeList[count]= 0; XFree(data); printf(" %ld types\n", count); } /* We only accept filenames (MIME type "text/uri-list"). */ { int i; for (i= 0; xdndTypeList[i]; ++i) { printf(" type %d == %ld %s\n", i, xdndTypeList[i], XGetAtomName(stDisplay, xdndTypeList[i])); if (XdndTextUriList == xdndTypeList[i]) xdndWillAccept= 1; } }}static void dndEnter(XClientMessageEvent *evt){ printf( "dndEnter\n"); if (xdndEnter_version(evt) < 3) { fprintf(stderr, "xdnd: protocol version %ld not supported\n", xdndEnter_version(evt)); return; } Window xdndSourceWindow= xdndEnter_sourceWindow(evt); dndGetTypeList(evt); xdndState= XdndStateEntered;}static void dndSendFinished(Window target){ XClientMessageEvent evt; memset (&evt, 0, sizeof(evt)); evt.type = ClientMessage; evt.display = stDisplay; evt.window = xdndSourceWindow; evt.message_type = XdndFinished; evt.format = 32; xdndFinished_targetWindow(&evt)= target; XSendEvent(stDisplay, xdndSourceWindow, 0, 0, (XEvent *)&evt); printf( "sent finished to %ld\n", xdndSourceWindow);}static void dndLeave(XClientMessageEvent *evt){ printf("dndLeave\n"); //recordDragEvent(DragLeave, 1); xdndState= XdndStateIdle;}static void dndGetSelection(Window owner, Atom property){ unsigned long remaining; unsigned char *data= 0; Atom actual; int format; unsigned long count; if (Success != XGetWindowProperty(stDisplay, owner, property, 0, 65536, 1, AnyPropertyType,&actual, &format, &count, &remaining, &data)) fprintf(stderr, "dndGetSelection: XGetWindowProperty failed\n"); else if (remaining) /* a little violent perhaps */ fprintf(stderr, "dndGetSelection: XGetWindowProperty has more than 64K (why?)\n"); else { char *tokens= data; char *item= 0; while ((item= strtok(tokens, "\n\r"))) { printf("got URI <%s>\n", item); if (!strncmp(item, "file:", 5)) /*** xxx BOGUS -- just while image is broken ***/ { /* if (uxDropFileCount) uxDropFileNames= (char **)xrealloc(uxDropFileNames, (uxDropFileCount + 1) * sizeof(char *)); else uxDropFileNames= (char **)xcalloc(1, sizeof(char *)); uxDropFileNames[uxDropFileCount++]= uri2string(item);*/ } tokens= 0; } //if (uxDropFileCount) //recordDragEvent(DragDrop, uxDropFileCount); //printf("+++ DROP %d\n", uxDropFileCount); } XFree(data);}int dndHandleSelectionNotify(XSelectionEvent *evt){ if (evt->property == XdndSelectionAtom) { dndGetSelection(evt->requestor, evt->property); dndSendFinished(evt->requestor); dndLeave((XClientMessageEvent *)evt); return 1; } return 0;}int dndHandleClientMessage(XClientMessageEvent *evt){ int handled= 1; Atom type= evt->message_type; printf("dndHandleClientMessage\n"); if(type == XdndEnter) dndEnter(evt); /*else if (type == XdndPosition) dndPosition(evt); else if (type == XdndDrop) dndDrop(evt); else if (type == XdndLeave) dndLeave(evt);*/ else handled= 0; return handled;}static void run(Window checkWindow){ while (1) { XEvent evt; long event_mask= ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask | ExposureMask; event_mask = 0x00ffffff; XSelectInput(stDisplay,checkWindow,event_mask); XWindowEvent (stDisplay,checkWindow, event_mask,&evt); printf ("evt.type: %d\n",evt.type); switch (evt.type) { case MotionNotify: printf("MotionNotify\n"); break; case EnterNotify: printf("EnterNotify\n"); break; case LeaveNotify: printf("LeaveNotify\n"); break; case ButtonPress: printf("ButtonPress\n"); break; case ButtonRelease: printf("ButtonRelease\n"); break; case KeyPress: printf("KeyPress\n"); break; case KeyRelease: printf("KeyRelease\n"); break; case SelectionClear: printf("SelectionClear\n"); break; case SelectionRequest: printf("SelectionRequest\n"); break; case PropertyNotify: printf("PropertyNotify\n"); break; case Expose: printf("Expose\n"); break; case MapNotify: printf("MapNotify\n"); break; case UnmapNotify: printf("UnmapNotify\n"); break; case ConfigureNotify: printf("ConfigureNotify\n"); break; case MappingNotify: printf("MappingNotify\n"); break; case ClientMessage: { printf("ClientMessage\n"); dndHandleClientMessage(&evt.xclient); break; } case SelectionNotify: { printf("SelectionNotify\n"); dndHandleSelectionNotify(&evt.xselection); break; } default: printf("unknown event type %d\n", evt.type); break; } }}int get_linux_window_info(struct FullLinuxWindowAttributes* outPutAttributes){ int root_x_return; int root_y_return; int win_x_return; int win_y_return; int returnValue= 0; //Display* stDisplay = XOpenDisplay(NULL); if(!stDisplay) return -1; XWindowAttributes xWindowAttributes; Window w; Window root_window = DefaultRootWindow(stDisplay); Window root_return; Window parent_return; Window child_window; Window* child_window_spec = NULL; ATOM XdndPositionAtom ; ATOM XdndDropAtom ; ATOM XdndActionCopyAtom ; ATOM XdndStatusAtom ; ATOM XdndFinishedAtom; ATOM XdndAware; XEvent event; unsigned long type, len, remain =0; int form = 0; unsigned char *listAttribute; unsigned int windowNum = 0; unsigned int mask; if(outPutAttributes) outPutAttributes = malloc(sizeof(XWindowAttributes)); if(!outPutAttributes) return -1; returnValue = XQueryPointer(stDisplay, root_window, &root_window, &child_window, \&root_x_return, &root_y_return, \&win_x_return, &win_y_return, &mask); returnValue = XQueryTree(stDisplay, root_window, &root_window, &parent_return, &child_window_spec, &windowNum); if(windowNum>0) { for(unsigned int i = 0; i < windowNum; ++i) { XGetWindowAttributes(stDisplay, child_window_spec[i], &xWindowAttributes); if (xWindowAttributes.map_state == 2) { // IsViewable char* buffer = NULL; // XFetchName(stDisplay, child_window_spec[i], &buffer); // printf("# %d :(attrs.x %d : attrs.y %d attrs.width %d , attrs.height %d ) name %s \n", \ i , xWindowAttributes.x , xWindowAttributes.y , \ xWindowAttributes.width , xWindowAttributes.height , buffer) ; // outPutAttributes->sizeof_FullLinuxWindowAttributes = sizeof(struct FullLinuxWindowAttributes); if(buffer) memcpy(outPutAttributes->windowName,buffer,strlen(buffer)); outPutAttributes->root_x_return = root_x_return; outPutAttributes->root_y_return = root_y_return; outPutAttributes->win_x_return = win_x_return; outPutAttributes->win_y_return = win_y_return; strcpy(outPutAttributes->typeof_currentX11Window,"Window"); memcpy(&(outPutAttributes->currentX11Window),&child_window_spec[i],sizeof(Window) ); outPutAttributes->sizeof_CurrentX11Window = sizeof(Window); strcpy(outPutAttributes->typeof_xWindowAttributes,"XWindowAttributes"); memcpy(&(outPutAttributes->xWindowAttributes),&xWindowAttributes,sizeof(XWindowAttributes) ); outPutAttributes->sizeof_xWindowAttributes = sizeof(XWindowAttributes); XdndAware = XInternAtom(stDisplay, "XdndAware", True); /*XdndPositionAtom = XInternAtom(stDisplay, "XdndPosition", True); XdndDropAtom = XInternAtom(stDisplay, "XdndDrop", True); XdndActionCopyAtom = XInternAtom(stDisplay, "XdndActionCopy", True); XdndStatusAtom = XInternAtom(stDisplay, "XdndStatus", True); XdndFinishedAtom = XInternAtom(stDisplay, "XdndFinished", True);*/ /*xclipboard*/ if(buffer==NULL) continue; if(strcmp(buffer,"Downloads")==0) { int result = XGetWindowProperty( stDisplay, child_window_spec[i], XdndAware, 0, 65535, False, AnyPropertyType, &type, &form, &len, &remain,&listAttribute ); if(type != None && result== Success) { result = XGetWindowProperty( stDisplay, child_window_spec[i], XdndAware, 0, remain, False, AnyPropertyType, &type, &form, &len, &remain,&listAttribute ); if(type != None && result== Success) { printf("type %ld, form %d, len %ld, remain %ld \n",type, form, len, remain); ATOM tempAtom ; memcpy (&tempAtom,listAttribute,4); tempAtom = tempAtom & 0xFF; printf("tempAtom %lu\n",(unsigned long)tempAtom); /*char* tempAtomName = XGetAtomName(stDisplay,tempAtom); if(tempAtomName) printf("tempAtomName %s \n",tempAtomName); */ run(child_window_spec[i]); } } } XFree(buffer); } } } return 0;}int select_file(){ struct FullLinuxWindowAttributes outPutAttributes; get_linux_window_info(&outPutAttributes);}void main(){ stDisplay = XOpenDisplay(NULL); stParent = DefaultRootWindow(stDisplay); dndInitialise(); { //run(stParent); struct FullLinuxWindowAttributes outPutAttributes; get_linux_window_info(&outPutAttributes); } //select_file();}