1
/* sqUnixXdnd.c -- drag-and-drop for the X Window System. -*- C -*-
3
* Copyright (C) 1996-2007 by Ian Piumarta and other authors/contributors
4
* listed elsewhere in this file.
7
* This file is part of Unix Squeak.
9
* Permission is hereby granted, free of charge, to any person obtaining a copy
10
* of this software and associated documentation files (the "Software"), to deal
11
* in the Software without restriction, including without limitation the rights
12
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
* copies of the Software, and to permit persons to whom the Software is
14
* furnished to do so, subject to the following conditions:
16
* The above copyright notice and this permission notice shall be included in
17
* all copies or substantial portions of the Software.
19
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
/* Author: Ian Piumarta <ian.piumarta@inria.fr>
30
* Last edited: 2009-08-19 04:21:30 by piumarta on emilia-2.local
34
* - This only works with version 3 and higher of the XDND protocol.
35
* No attempt whatsoever is made to check for and deal with earlier
36
* versions. Since version 3 is at least six years old now, I doubt
39
* - Some memory could be released between drop operations, but it's
40
* only a few tens of bytes so who cares?
42
* - Only filenames (MIME type text/uri-list) are handled, although
43
* it would be trivial to extend the code to cope with dropping text
44
* selections into the Squeak clipboard. I'm simply too lazy to be
47
* - No attempt is made to verify that XDND protocol messages arrive
48
* in the correct order. (If your WM or file manager is broken, you
49
* get to keep all the shrapnel that will be left behind after
50
* dragging something onto Squeak).
61
#include <X11/Xatom.h>
67
static Atom XdndVersion= (Atom)3;
69
static Atom XdndAware;
70
static Atom XdndSelection;
71
static Atom XdndEnter;
72
static Atom XdndLeave;
73
static Atom XdndPosition;
75
static Atom XdndFinished;
76
static Atom XdndStatus;
77
static Atom XdndActionCopy;
78
static Atom XdndActionMove;
79
static Atom XdndActionLink;
80
static Atom XdndActionAsk;
81
static Atom XdndActionPrivate;
82
static Atom XdndTypeList;
83
static Atom XdndTextUriList;
84
static Atom XdndSelectionAtom;
86
static Window xdndSourceWindow= 0;
87
static int isUrlList= 0;
88
static int xdndWillAccept= 0;
90
/* To keep backword compatibitily, xdndWillAccept is always 1.
91
* isUrlList is 1 only if the dropped type includes "text/uri-list".
93
* case isUrlList == 1: Get url list and send dndFinished immediately. Then record drag event.
94
* case isUrlList == 0: Record drag event anyway (uxDropFileCount= 0). The image will get the data and send dndFinished.
97
static Atom *xdndInTypes= 0; /* all targets in clipboard */
99
static Window xdndOutTarget= None;
100
static Atom *xdndOutTypes= 0; /* Types offered by source window */
102
static XSelectionRequestEvent xdndOutRequestEvent; /* RequestEvent from target */
108
XdndStateOutTracking,
117
#define xdndEnter_sourceWindow(evt) ( (evt)->data.l[0])
118
#define xdndEnter_version(evt) ( (evt)->data.l[1] >> 24)
119
#define xdndEnter_hasThreeTypes(evt) (((evt)->data.l[1] & 0x1UL) == 0)
120
#define xdndEnter_typeAt(evt, idx) ( (evt)->data.l[2 + (idx)])
121
#define xdndEnter_targets(evt) ( (evt)->data.l + 2)
123
#define xdndPosition_sourceWindow(evt) ((Window)((evt)->data.l[0]))
124
#define xdndPosition_rootX(evt) ((evt)->data.l[2] >> 16)
125
#define xdndPosition_rootY(evt) ((evt)->data.l[2] & 0xffffUL)
126
#define xdndPosition_action(evt) ((Atom)((evt)->data.l[4]))
128
#define xdndStatus_targetWindow(evt) ((evt)->data.l[0])
129
#define xdndStatus_setWillAccept(evt, b) ((evt)->data.l[1]= (((evt)->data.l[1] & ~1UL) | ((b) ? 1 : 0)))
130
#define xdndStatus_setWantPosition(evt, b) ((evt)->data.l[1]= (((evt)->data.l[1] & ~2UL) | ((b) ? 2 : 0)))
131
#define xdndStatus_action(evt) ((evt)->data.l[4])
133
#define xdndDrop_sourceWindow(evt) ((Window)((evt)->data.l[0]))
134
#define xdndDrop_time(evt) ((evt)->data.l[2])
136
#define xdndFinished_targetWindow(evt) ((evt)->data.l[0])
140
# define fdebugf(ARGS) do { fprintf ARGS; } while (0)
142
# define fdebugf(ARGS) do { } while (0)
145
static void updateCursor(int state);
147
void getMousePosition(void);
150
static void *xmalloc(size_t size)
152
void *ptr= malloc(size);
155
fprintf(stderr, "out of memory\n");
162
static void *xcalloc(size_t nmemb, size_t size)
164
void *ptr= calloc(nmemb, size);
167
fprintf(stderr, "out of memory\n");
174
static void *xrealloc(void *ptr, size_t size)
176
ptr= realloc(ptr, size);
179
fprintf(stderr, "out of memory\n");
186
static int hexValue(const int c)
188
if (c < '0') return 0;
189
if (c <= '9') return c - '0';
190
if (c < 'A') return 0;
191
if (c <= 'F') return c - 'A' + 10;
192
if (c < 'a') return 0;
193
if (c <= 'f') return c - 'a' + 10;
198
static char *uri2string(const char *uri)
200
size_t len= strlen(uri);
201
char *string= (char *)xmalloc(len + 3);
202
/* whoever wrote the URL stuff in the the image was too damn stupid to understand file URIs */
203
if (!strncmp(uri, "file:", 5))
205
char *in= string, *out= string;
206
strncpy(string, uri + 5, len);
208
if ((in[0] == '%') && isxdigit(in[1]) && isxdigit(in[2]))
210
*out++= hexValue(in[1]) * 16 + hexValue(in[2]);
219
strncpy(string, uri, len);
221
fdebugf((stderr, " uri2string: <%s>\n", string));
226
/*** Handle DnD Output ***/
229
#define DndWindow stParent
231
/* Answer dndAware window under the cursor, or None if not found.
233
static Window dndAwareWindow(Window root, Window child, int *versionReturn)
237
unsigned long nitems, bytesAfter;
239
Window rootReturn, childReturn;
240
int rootX, rootY, winX, winY;
243
if (None == child) return None;
244
XGetWindowProperty(stDisplay, child, XdndAware,
245
0, 0x8000000L, False, XA_ATOM,
246
&actualType, &actualFormat, &nitems,
250
*versionReturn= (int)*data;
254
XQueryPointer(stDisplay, child, &rootReturn, &childReturn, &rootX, &rootY, &winX, &winY, &mask);
256
if (childReturn == None) return None;
258
return dndAwareWindow(root, childReturn, versionReturn);
262
/* Send ClientMessage to drop target.
264
* long data[5] : event specific data
265
* Window source : source window (stParent)
266
* Window target : target window
267
* char * type : event type name
269
static void sendClientMessage(long *data, Window source, Window target, Atom type)
272
XClientMessageEvent *evt= &e.xclient;
273
if (None == target) return;
274
evt->type= ClientMessage;
277
evt->display= stDisplay;
279
evt->message_type= type;
281
evt->data.l[0]= source;
282
evt->data.l[1]= data[1];
283
evt->data.l[2]= data[2];
284
evt->data.l[3]= data[3];
285
evt->data.l[4]= data[4];
286
XSendEvent(stDisplay, target, 0, 0, &e);
287
/*fdebugf((stderr, "Send %s to: 0x%lx\n", type, target));*/
290
static void sendEnter(Window target, Window source)
292
long data[5]= { 0, 0, 0, 0, 0 };
293
data[1] |= 0x0UL; /* just three data types */
294
data[1] |= XdndVersion << 24; /* version num */
296
if (0 != xdndOutTypes)
298
data[2]= xdndOutTypes[0];
299
if (None != xdndOutTypes[1])
301
data[3]= xdndOutTypes[1];
302
if (None != xdndOutTypes[2])
304
data[4]= xdndOutTypes[1];
308
fdebugf((stderr, "Send XdndEnter (output) source: 0x%lx target: 0x%lx\n", source, target));
309
sendClientMessage(data, source, target, XdndEnter);
313
static void sendPosition(Window target, Window source, int rootX, int rootY, Time timestamp)
315
long data[5]= { 0, 0, 0, 0, 0 };
316
data[2]= (rootX << 16) | rootY;
318
data[4]= XdndActionCopy;
319
sendClientMessage(data, source, target, XdndPosition);
323
static void sendDrop(Window target, Window source, Time timestamp)
325
long data[5]= { 0, 0, 0, 0, 0 };
327
fdebugf((stderr, "Send XdndDrop (output) source: 0x%lx target: 0x%lx\n", source, target));
329
sendClientMessage(data, source, target, XdndDrop);
333
static void sendLeave(Window target, Window source)
335
long data[5]= { 0, 0, 0, 0, 0 };
336
fdebugf((stderr, "Send XdndLeave (output) source: 0x%lx target: 0x%lx\n", source, target));
337
sendClientMessage(data, source, target, XdndLeave);
341
static enum XdndState dndOutInitialize(enum XdndState state)
343
fdebugf((stderr, "Internal signal DndOutStart (output)\n"));
344
memset(&xdndOutRequestEvent, 0, sizeof(xdndOutRequestEvent));
345
XSetSelectionOwner(stDisplay, XdndSelection, DndWindow, CurrentTime);
347
return XdndStateOutTracking;
351
/* Track the current mouse position.
353
static enum XdndState dndOutMotion(enum XdndState state, XMotionEvent *evt)
355
Window currentWindow= None;
356
int versionReturn= 0;
358
if ((XdndStateOutTracking != state) && (XdndStateOutAccepted != state)) return state;
360
currentWindow= dndAwareWindow(evt->root, evt->root, &versionReturn);
361
if (DndWindow == currentWindow) /* Cursor is on myself */
364
return XdndStateOutTracking;
367
updateCursor(XdndStateOutAccepted == state);
369
if ((XdndVersion > versionReturn) /* Target's version is too low. */
370
|| (None == currentWindow)) /* I can't find XdndAware window. */
373
return XdndStateOutTracking;
376
fdebugf((stderr, "Receive MotionNotify (output) root: 0x%lx awareWindow: 0x%lx\n", evt->root, currentWindow));
377
if (currentWindow != xdndOutTarget)
379
sendLeave(xdndOutTarget, DndWindow);
380
sendEnter(currentWindow, DndWindow);
383
sendPosition(currentWindow, DndWindow, evt->x_root, evt->y_root, evt->time);
384
xdndOutTarget= currentWindow;
390
/* A status message to know accept or not is received.
392
static enum XdndState dndOutStatus(enum XdndState state, XClientMessageEvent *evt)
394
long *ldata= evt->data.l;
395
fdebugf((stderr, "Receive XdndStatus (output) status: 0x%lx target: 0x%lx\n", ldata[1], ldata[0]));
397
if ((XdndStateOutTracking != state) && (XdndStateOutAccepted != state))
399
/*printf("%i is not expected in XdndStatus\n", state);*/
400
sendLeave(ldata[0], DndWindow);
404
if (xdndOutTarget != ldata[0]) return state;
406
if (ldata[1] && 0x1UL)
407
return XdndStateOutAccepted;
409
return XdndStateOutTracking;
413
/* The mouse button was released.
415
static enum XdndState dndOutRelease(enum XdndState state, XButtonEvent *evt)
417
if (XdndStateIdle == state) return XdndStateIdle;
418
fdebugf((stderr, "Receive ButtonRelease (output) window: 0x%lx\n", evt->window));
420
if (XdndStateOutAccepted == state)
422
sendDrop(xdndOutTarget, DndWindow, evt->time);
423
return XdndStateOutAccepted;
425
sendLeave(xdndOutTarget, DndWindow);
426
return XdndStateIdle;
430
/* Another application is requesting the selection.
432
static enum XdndState dndOutSelectionRequest(enum XdndState state, XSelectionRequestEvent *req)
434
fdebugf((stderr, "Receive SelectionRequest for %s (output) owner: 0x%lx : requestor: 0x%lx\n",
435
XGetAtomName(stDisplay, req->target), req->owner, req->requestor));
436
if (XdndStateOutAccepted != state)
438
/*printf("%i is not expected in SelectionRequest\n", state);*/
441
memcpy(&xdndOutRequestEvent, req, sizeof(xdndOutRequestEvent));
442
recordDragEvent(DragRequest, 1);
447
/* A finished message is received.
449
static enum XdndState dndOutFinished(enum XdndState state, XClientMessageEvent *evt)
451
fdebugf((stderr, "Receive XdndFinished (output) source: 0x%lx target: 0x%lx\n",
452
DndWindow, xdndFinished_targetWindow(evt)));
454
return XdndStateIdle;
459
* TODO: The cursor should be controlled by the image, so it should be removed finally.
461
* state = -1 : Cursor is on Squeak window.
462
* state = 0 : Target window doesn't accept.
463
* state = 1 : Target window accepts.
465
static void updateCursor(int state)
467
static int lastCursor= -1;
469
if (lastCursor == state) return;
470
fdebugf((stderr, "Cursor change (output) previous: %i new: %i\n", lastCursor, state));
474
cursor= XCreateFontCursor(stDisplay, 90);
475
XDefineCursor(stDisplay, stWindow, cursor);
478
XDefineCursor(stDisplay, stWindow, None);
484
static void dndInDestroyTypes(void)
486
if (xdndInTypes == NULL)
493
static void updateInTypes(Atom *newTargets, int targetSize)
497
xdndInTypes= (Atom *)calloc(targetSize + 1, sizeof(Atom));
498
for (i= 0; i < targetSize; ++i)
499
xdndInTypes[i]= newTargets[i];
500
xdndInTypes[targetSize]= None;
504
/* Answer non-zero if dnd input object is available.
506
static int dndAvailable(void)
508
return useXdnd && xdndInTypes;
512
/* Answer types for dropping object.
513
* types - returned types (it should be copied by client), or NULL if unavailable.
514
* count - number of types.
516
static void dndGetTargets(Atom **types, int *count)
521
if (!xdndInTypes) return;
522
for (i= 0; None != xdndInTypes[i]; ++i);
528
static void dndGetTypeList(XClientMessageEvent *evt)
533
if (xdndEnter_hasThreeTypes(evt))
535
fdebugf((stderr, " 3 types\n"));
536
updateInTypes((Atom *) xdndEnter_targets(evt), 3);
542
unsigned long count, remaining;
543
unsigned char *data= 0;
545
XGetWindowProperty(stDisplay, xdndSourceWindow, XdndTypeList, 0, 0x8000000L, False, XA_ATOM,
546
&type, &format, &count, &remaining, &data);
548
if ((type != XA_ATOM) || (format != 32) || (count == 0) || !data)
550
if (data) XFree(data);
551
fprintf(stderr, "XGetWindowProperty failed in xdndGetTypeList\n");
555
updateInTypes((Atom *) data, count);
557
fdebugf((stderr, " %ld types\n", count));
560
/* We only accept filenames (MIME type "text/uri-list"). */
563
for (i= 0; xdndInTypes[i]; ++i)
565
fdebugf((stderr, " type %d == %ld %s\n", i, xdndInTypes[i], XGetAtomName(stDisplay, xdndInTypes[i])));
566
if (XdndTextUriList == xdndInTypes[i])
576
static void dndSendStatus(int willAccept, Atom action)
578
XClientMessageEvent evt;
579
memset(&evt, 0, sizeof(evt));
581
evt.type = ClientMessage;
582
evt.display = stDisplay;
583
evt.window = xdndSourceWindow;
584
evt.message_type = XdndStatus;
587
xdndStatus_targetWindow(&evt)= DndWindow;
588
xdndStatus_setWillAccept(&evt, willAccept);
589
xdndStatus_setWantPosition(&evt, 0);
590
xdndStatus_action(&evt)= action;
592
XSendEvent(stDisplay, xdndSourceWindow, 0, 0, (XEvent *)&evt);
594
/* fdebugf((stderr, " sent status to 0x%lx willAccept=%d data=%ld action=%s(%ld)\n",
595
xdndSourceWindow, willAccept, evt.data.l[1], XGetAtomName(stDisplay, action), action)); */
598
static void dndSendFinished(void)
600
XClientMessageEvent evt;
601
memset(&evt, 0, sizeof(evt));
603
evt.type = ClientMessage;
604
evt.display = stDisplay;
605
evt.window = xdndSourceWindow;
606
evt.message_type = XdndFinished;
609
xdndFinished_targetWindow(&evt)= DndWindow;
610
XSendEvent(stDisplay, xdndSourceWindow, 0, 0, (XEvent *)&evt);
612
fdebugf((stderr, "dndSendFinished target: 0x%lx source: 0x%lx\n", DndWindow, xdndSourceWindow));
616
static enum XdndState dndInEnter(enum XdndState state, XClientMessageEvent *evt)
618
fdebugf((stderr, "Receive XdndEnter (input)\n"));
619
if (xdndEnter_version(evt) < 3)
621
fprintf(stderr, " xdnd: protocol version %ld not supported\n", xdndEnter_version(evt));
624
xdndSourceWindow= xdndEnter_sourceWindow(evt);
627
fdebugf((stderr, " dndEnter target: 0x%lx source: 0x%lx\n", evt->window, xdndSourceWindow));
628
return XdndStateEntered;
632
static enum XdndState dndInLeave(enum XdndState state)
634
fdebugf((stderr, "Receive XdndLeave (input)\n"));
635
recordDragEvent(DragLeave, 1);
636
return XdndStateIdle;
640
static enum XdndState dndInPosition(enum XdndState state, XClientMessageEvent *evt)
642
/*fdebugf((stderr, "Receive XdndPosition (input)\n"));*/
644
if (xdndSourceWindow != xdndPosition_sourceWindow(evt))
646
fdebugf((stderr, "dndInPosition: wrong source window\n"));
647
return XdndStateIdle;
652
if ((state != XdndStateEntered) && (state != XdndStateTracking))
654
fdebugf((stderr, "dndInPosition: wrong state\n"));
655
return XdndStateIdle;
658
if ((state == XdndStateEntered) && xdndWillAccept)
659
recordDragEvent(DragEnter, 1);
663
Atom action= xdndPosition_action(evt);
664
/*fdebugf((stderr, " dndInPosition: action = %ld %s\n", action, XGetAtomName(stDisplay, action)));*/
665
xdndWillAccept= (action == XdndActionMove) | (action == XdndActionCopy)
666
| (action == XdndActionLink) | (action == XdndActionAsk);
671
/*fdebugf((stderr, " dndInPosition: accepting\n"));*/
672
dndSendStatus(1, XdndActionCopy);
673
recordDragEvent(DragMove, 1);
675
else /* won't accept */
677
/*fdebugf((stderr, " dndInPosition: not accepting\n"));*/
678
dndSendStatus(0, XdndActionPrivate);
680
return XdndStateTracking;
684
enum XdndState dndInDrop(enum XdndState state, XClientMessageEvent *evt)
686
fdebugf((stderr, "Receive XdndDrop (input)\n"));
688
/* If there is "text/url-list" in xdndInTypes, the selection is
689
* processed only in DropFilesEvent. But if none (file count == 0),
690
* the selection is handled ClipboardExtendedPlugin.
694
fdebugf((stderr, " dndInDrop: no url list\n"));
695
recordDragEvent(DragDrop, 0);
700
if (xdndSourceWindow != xdndDrop_sourceWindow(evt))
702
fdebugf((stderr, " dndInDrop: wrong source window\n"));
704
else if (xdndWillAccept)
707
fdebugf((stderr, " dndInDrop: converting selection\n"));
708
if (!(owner= XGetSelectionOwner(stDisplay, XdndSelection)))
709
fprintf(stderr, " dndInDrop: XGetSelectionOwner failed\n");
711
XConvertSelection(stDisplay, XdndSelection, XdndTextUriList, XdndSelectionAtom, stWindow, xdndDrop_time(evt));
715
assert(uxDropFileNames);
716
for (i= 0; i < uxDropFileCount; ++i)
717
free(uxDropFileNames[i]);
718
free(uxDropFileNames);
725
fdebugf((stderr, " dndInDrop: refusing selection -- finishing\n"));
729
recordDragEvent(DragLeave, 1);
731
return XdndStateIdle;
735
static void dndGetSelection(Window owner, Atom property)
737
unsigned long remaining;
738
unsigned char *data= 0;
743
if (Success != XGetWindowProperty(stDisplay, owner, property, 0, 65536, 1, AnyPropertyType,
744
&actual, &format, &count, &remaining, &data))
745
fprintf(stderr, "dndGetSelection: XGetWindowProperty failed\n");
747
/* a little violent perhaps */
748
fprintf(stderr, "dndGetSelection: XGetWindowProperty has more than 64K (why?)\n");
751
char *tokens= (char *)data;
753
while ((item= strtok(tokens, "\n\r")))
755
fdebugf((stderr, " got URI <%s>\n", item));
756
if (!strncmp(item, "file:", 5)) /*** xxx BOGUS -- just while image is broken ***/
759
uxDropFileNames= (char **)xrealloc(uxDropFileNames, (uxDropFileCount + 1) * sizeof(char *));
761
uxDropFileNames= (char **)xcalloc(1, sizeof(char *));
762
uxDropFileNames[uxDropFileCount++]= uri2string(item);
767
recordDragEvent(DragDrop, uxDropFileCount);
768
fdebugf((stderr, " uxDropFileCount = %d\n", uxDropFileCount));
774
static enum XdndState dndInSelectionNotify(enum XdndState state, XSelectionEvent *evt)
776
fdebugf((stderr, "Receive SelectionNotify (input)\n"));
777
if (evt->property != XdndSelectionAtom) return state;
779
dndGetSelection(evt->requestor, evt->property);
781
recordDragEvent(DragLeave, 1);
782
return XdndStateIdle;
786
static enum XdndState dndInFinished(enum XdndState state)
788
fdebugf((stderr, "Internal signal DndInFinished (input)\n"));
790
recordDragEvent(DragLeave, 1);
792
return XdndStateIdle;
796
/* DnD client event handler */
798
static enum XdndState dndHandleClientMessage(enum XdndState state, XClientMessageEvent *evt)
800
Atom type= evt->message_type;
801
if (type == XdndStatus) return dndOutStatus(state, evt);
802
else if (type == XdndFinished) return dndOutFinished(state, evt);
803
else if (type == XdndEnter) return dndInEnter(state, evt);
804
else if (type == XdndPosition) return dndInPosition(state, evt);
805
else if (type == XdndDrop) return dndInDrop(state, evt);
806
else if (type == XdndLeave) return dndInLeave(state);
811
/* DnD event handler */
813
static void dndHandleEvent(int type, XEvent *evt)
815
static enum XdndState state= XdndStateIdle;
819
case DndOutStart: state= dndOutInitialize(state); break;
820
case MotionNotify: state= dndOutMotion(state, &evt->xmotion); break;
821
case ButtonRelease: state= dndOutRelease(state, &evt->xbutton); break;
822
case SelectionRequest: state= dndOutSelectionRequest(state, &evt->xselectionrequest); break;
823
case SelectionNotify: state= dndInSelectionNotify(state, &evt->xselection); break;
824
case DndInFinished: state= dndInFinished(state); break;
825
case ClientMessage: state= dndHandleClientMessage(state, &evt->xclient); break;
830
static sqInt display_dndOutStart(char *types, int ntypes)
835
if (xdndOutTypes != 0)
841
for (pos= 0; pos < ntypes; pos += strlen(types + pos) + 1)
844
if (typesSize > 3) return 0; /* Supported types are up to 3 now */
846
xdndOutTypes= xmalloc(sizeof(Atom) * (typesSize + 1));
847
xdndOutTypes[typesSize]= None;
849
for (pos= 0, i= 0; pos < ntypes; pos += strlen(types + pos) + 1, i++)
850
xdndOutTypes[i]= XInternAtom(stDisplay, types + pos, False);
852
for (i= 0; i < typesSize; i++)
853
fdebugf((stderr, "dndOutStart: %s\n", XGetAtomName(stDisplay, xdndOutTypes[i])));
854
dndHandleEvent(DndOutStart, 0);
859
static void display_dndOutSend (char *bytes, int nbytes)
862
XSelectionEvent *res= ¬ify.xselection;
863
Atom targetProperty= ((None == xdndOutRequestEvent.property)
864
? xdndOutRequestEvent.target
865
: xdndOutRequestEvent.property);
867
res->type = SelectionNotify;
868
res->display = xdndOutRequestEvent.display;
869
res->requestor = xdndOutRequestEvent.requestor;
870
res->selection = xdndOutRequestEvent.selection;
871
res->target = xdndOutRequestEvent.target;
872
res->time = xdndOutRequestEvent.time;
873
res->send_event = True;
874
res->property = targetProperty; /* override later if error */
876
XChangeProperty(stDisplay, res->requestor,
877
targetProperty, xdndOutRequestEvent.target,
879
(unsigned char *)bytes,
882
XSendEvent(stDisplay, res->requestor, False, 0, ¬ify);
883
fdebugf((stderr, "Send data for %s (output) requestor: 0x%lx\n",
884
XGetAtomName(stDisplay, res->target), res->requestor));
887
static sqInt display_dndOutAcceptedType(char * buf, int nbuf)
890
if (xdndOutRequestEvent.target == None) return 0;
891
type= XGetAtomName(stDisplay, xdndOutRequestEvent.target);
892
strncpy(buf, type, nbuf);
897
static void dndInitialise(void)
899
XdndAware= XInternAtom(stDisplay, "XdndAware", False);
900
XdndSelection= XInternAtom(stDisplay, "XdndSelection", False);
901
XdndEnter= XInternAtom(stDisplay, "XdndEnter", False);
902
XdndLeave= XInternAtom(stDisplay, "XdndLeave", False);
903
XdndPosition= XInternAtom(stDisplay, "XdndPosition", False);
904
XdndDrop= XInternAtom(stDisplay, "XdndDrop", False);
905
XdndFinished= XInternAtom(stDisplay, "XdndFinished", False);
906
XdndStatus= XInternAtom(stDisplay, "XdndStatus", False);
907
XdndActionCopy= XInternAtom(stDisplay, "XdndActionCopy", False);
908
XdndActionMove= XInternAtom(stDisplay, "XdndActionMove", False);
909
XdndActionLink= XInternAtom(stDisplay, "XdndActionLink", False);
910
XdndActionAsk= XInternAtom(stDisplay, "XdndActionAsk", False);
911
XdndActionPrivate= XInternAtom(stDisplay, "XdndActionPrivate", False);
912
XdndTypeList= XInternAtom(stDisplay, "XdndTypeList", False);
913
XdndTextUriList= XInternAtom(stDisplay, "text/uri-list", False);
914
XdndSelectionAtom= XInternAtom(stDisplay, "XdndSqueakSelection", False);
916
XChangeProperty(stDisplay, DndWindow, XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XdndVersion, 1);
923
#define fail(why) do { fprintf(stderr, "%s\n", why); exit(1); } while (0)
926
static void run(void)
931
XNextEvent(stDisplay, &evt);
934
case MotionNotify: printf("MotionNotify\n"); break;
935
case EnterNotify: printf("EnterNotify\n"); break;
936
case LeaveNotify: printf("LeaveNotify\n"); break;
937
case ButtonPress: printf("ButtonPress\n"); break;
938
case ButtonRelease: printf("ButtonRelease\n"); break;
939
case KeyPress: printf("KeyPress\n"); break;
940
case KeyRelease: printf("KeyRelease\n"); break;
941
case SelectionClear: printf("SelectionClear\n"); break;
942
case SelectionRequest: printf("SelectionRequest\n"); break;
943
case PropertyNotify: printf("PropertyNotify\n"); break;
944
case Expose: printf("Expose\n"); break;
945
case MapNotify: printf("MapNotify\n"); break;
946
case UnmapNotify: printf("UnmapNotify\n"); break;
947
case ConfigureNotify: printf("ConfigureNotify\n"); break;
948
case MappingNotify: printf("MappingNotify\n"); break;
949
case ClientMessage: dndHandleClientMessage(&evt.xclient); break;
950
case SelectionNotify: dndHandleSelectionNotify(&evt.xselection); break;
951
default: printf("unknown event type %d\n", evt.type); break;
957
int main(int argc, char **argv)
959
stDisplay= XOpenDisplay(0);
960
if (!stDisplay) fail("cannot open display");
965
XSetWindowAttributes attributes;
966
unsigned long valuemask= 0;
968
attributes.event_mask= ButtonPressMask | ButtonReleaseMask
969
| KeyPressMask | KeyReleaseMask
971
| EnterWindowMask | LeaveWindowMask | ExposureMask;
972
valuemask |= CWEventMask;
974
win= XCreateWindow(stDisplay, DefaultRootWindow(stDisplay),
975
100, 100, 100, 100, /* geom */
977
CopyFromParent, /* depth */
978
CopyFromParent, /* class */
979
CopyFromParent, /* visual */
983
if (!win) fail("cannot create window");
985
XChangeProperty (stDisplay, win, XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XdndVersion, 3);
986
XMapWindow(stDisplay, stWindow);
988
XCloseDisplay(stDisplay);
994
#endif /* TEST_XDND */