Change to the linux kernel coding style
[wmaker-crm.git] / src / xdnd.c
1 /* Many part of code are ripped of an example from JX's site */
2
3 #include "wconfig.h"
4
5 #ifdef XDND
6
7 #include <X11/Xlib.h>
8 #include "WindowMaker.h"
9 #include "window.h"
10 #include "dock.h"
11 #include "xdnd.h"
12 #include "motif.h"
13
14 #include "workspace.h"
15
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include <X11/Xatom.h>
20
21 #define XDND_VERSION 3L
22
23 Atom _XA_XdndAware;
24 Atom _XA_XdndEnter;
25 Atom _XA_XdndLeave;
26 Atom _XA_XdndDrop;
27 Atom _XA_XdndPosition;
28 Atom _XA_XdndStatus;
29 Atom _XA_XdndActionCopy;
30 Atom _XA_XdndSelection;
31 Atom _XA_XdndFinished;
32 Atom _XA_WINDOWMAKER_XDNDEXCHANGE;
33
34 /*
35  Atom _XA_MOTIF_DRAG_RECEIVER_INFO;
36  Atom _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
37  */
38
39 Atom atom_support;
40
41 void wXDNDInitializeAtoms()
42 {
43
44         _XA_XdndAware = XInternAtom(dpy, "XdndAware", False);
45         _XA_XdndEnter = XInternAtom(dpy, "XdndEnter", False);
46         _XA_XdndLeave = XInternAtom(dpy, "XdndLeave", False);
47         _XA_XdndDrop = XInternAtom(dpy, "XdndDrop", False);
48         _XA_XdndPosition = XInternAtom(dpy, "XdndPosition", False);
49         _XA_XdndStatus = XInternAtom(dpy, "XdndStatus", False);
50         _XA_XdndActionCopy = XInternAtom(dpy, "XdndActionCopy", False);
51         _XA_XdndSelection = XInternAtom(dpy, "XdndSelection", False);
52         _XA_XdndFinished = XInternAtom(dpy, "XdndFinished", False);
53
54         _XA_WINDOWMAKER_XDNDEXCHANGE = XInternAtom(dpy, "_WINDOWMAKER_XDNDEXCHANGE", False);
55
56         /*
57            _XA_MOTIF_DRAG_RECEIVER_INFO = XInternAtom(dpy, "_MOTIF_DRAG_RECEIVER_INFO",False);
58            _XA_MOTIF_DRAG_AND_DROP_MESSAGE = XInternAtom(dpy, "_MOTIF_DRAG_AND_DROP_MESSAGE", False);
59          */
60 }
61
62 void wXDNDMakeAwareness(Window window)
63 {
64         long int xdnd_version = 3;
65         /*
66            MotifDragReceiverInfo info;
67          */
68         XChangeProperty(dpy, window, _XA_XdndAware, XA_ATOM, 32, PropModeAppend, (char *)&xdnd_version, 1);
69
70     /*** MOTIF ***
71      info.byte_order = '\0';
72      info.protocol_version = 0;
73      info.protocol_style = XmDRAG_DYNAMIC;
74      info.proxy_window = 0;
75      info.num_drop_sites = 0;
76      info.total_size = sizeof(info);
77
78      XChangeProperty (dpy, window,
79      _XA_MOTIF_DRAG_RECEIVER_INFO,
80      _XA_MOTIF_DRAG_RECEIVER_INFO,
81      8, PropModeReplace,
82      (unsigned char *)&info,
83      sizeof (info));
84      */
85 }
86
87 void wXDNDClearAwareness(Window window)
88 {
89         XDeleteProperty(dpy, window, _XA_XdndAware);
90 }
91
92 Bool wXDNDProcessSelection(XEvent * event)
93 {
94         WScreen *scr = wScreenForWindow(event->xselection.requestor);
95         char *retain;
96         Atom ret_type;
97         int ret_format;
98         unsigned long ret_item;
99         unsigned long remain_byte;
100         char *delme;
101         XEvent xevent;
102         Window selowner = XGetSelectionOwner(dpy, _XA_XdndSelection);
103         WMArray *items;
104
105         XGetWindowProperty(dpy, event->xselection.requestor,
106                            _XA_WINDOWMAKER_XDNDEXCHANGE,
107                            0, 65536, True, atom_support, &ret_type, &ret_format,
108                            &ret_item, &remain_byte, (unsigned char **)&delme);
109         if (delme) {
110                 scr->xdestring = delme;
111         }
112
113         /*send finished */
114         memset(&xevent, 0, sizeof(xevent));
115         xevent.xany.type = ClientMessage;
116         xevent.xany.display = dpy;
117         xevent.xclient.window = selowner;
118         xevent.xclient.message_type = _XA_XdndFinished;
119         xevent.xclient.format = 32;
120         XDND_FINISHED_TARGET_WIN(&xevent) = event->xselection.requestor;
121         XSendEvent(dpy, selowner, 0, 0, &xevent);
122
123         /*process dropping */
124         if (scr->xdestring) {
125                 WMArrayIterator iter;
126                 int length, str_size;
127                 int total_size = 0;
128                 char *tmp;
129
130                 items = WMCreateArray(4);
131                 retain = wstrdup(scr->xdestring);
132                 XFree(scr->xdestring);  /* since xdestring was created by Xlib */
133
134                 length = strlen(retain);
135
136                 /* search in string */
137                 while (length--) {
138                         if (retain[length] == '\r') {   /* useless char, nuke it */
139                                 retain[length] = 0;
140                         }
141                         if (retain[length] == '\n') {
142                                 str_size = strlen(&retain[length + 1]);
143                                 if (str_size) {
144                                         WMAddToArray(items, wstrdup(&retain[length + 1]));
145                                         total_size += str_size + 3;     /* reserve for " \"\"" */
146                                         /* this is nonsense -- if (length)
147                                            WMAppendArray(items, WMCreateArray(1)); */
148                                 }
149                                 retain[length] = 0;
150                         }
151                 }
152                 /* final one */
153                 WMAddToArray(items, wstrdup(retain));
154                 total_size += strlen(retain) + 3;
155                 wfree(retain);
156
157                 /* now pack new string */
158                 scr->xdestring = wmalloc(total_size);
159                 scr->xdestring[0] = 0;  /* empty string */
160                 WM_ETARETI_ARRAY(items, tmp, iter) {
161                         if (!strncmp(tmp, "file:", 5)) {
162                                 /* add more 2 chars while removing 5 is harmless */
163                                 strcat(scr->xdestring, " \"");
164                                 strcat(scr->xdestring, &tmp[5]);
165                                 strcat(scr->xdestring, "\"");
166                         } else {
167                                 /* unsupport object, still need more " ? tell ]d */
168                                 strcat(scr->xdestring, &tmp[5]);
169                         }
170                         wfree(tmp);
171                 }
172                 WMFreeArray(items);
173                 wDockReceiveDNDDrop(scr, event);
174                 /*
175                    printf("free ");
176                    puts(scr->xdestring);
177                  */
178                 wfree(scr->xdestring);  /* this xdestring is not from Xlib (no XFree) */
179         }
180
181         /* why doesn't this function return anything ? -Dan */
182 }
183
184 Bool isAwareXDND(Window window)
185 {
186         Atom actual;
187         int format;
188         unsigned long count, remaining;
189         unsigned char *data = 0;
190
191         if (!window)
192                 return False;
193         XGetWindowProperty(dpy, window, _XA_XdndAware,
194                            0, 0x8000000L, False, XA_ATOM, &actual, &format, &count, &remaining, &data);
195         if (actual != XA_ATOM || format != 32 || count == 0 || !data) {
196                 if (data)
197                         XFree(data);
198                 return False;
199         }
200         if (data)
201                 XFree(data);
202         return True;
203 }
204
205 Bool acceptXDND(Window window)
206 {
207         WScreen *scr = wScreenForWindow(window);
208         WDock *dock;
209         int icon_pos, i;
210
211         icon_pos = -1;
212         if ((dock = scr->dock) != NULL) {
213                 for (i = 0; i < dock->max_icons; i++) {
214                         if (dock->icon_array[i]
215                             && dock->icon_array[i]->icon->core->window == window) {
216                                 icon_pos = i;
217                                 break;
218                         }
219                 }
220         }
221         if (icon_pos < 0 && (dock = scr->workspaces[scr->current_workspace]->clip) != NULL) {
222                 for (i = 0; i < dock->max_icons; i++) {
223                         if (dock->icon_array[i]
224                             && dock->icon_array[i]->icon->core->window == window) {
225                                 icon_pos = i;
226                                 break;
227                         }
228                 }
229         }
230         if (icon_pos < 0)
231                 return False;
232         if (!dock)
233                 return False;
234         if (isAwareXDND(dock->icon_array[icon_pos]->icon->icon_win))
235                 return False;
236
237         if (dock->icon_array[icon_pos]->dnd_command != NULL)
238                 return True;
239
240         return False;
241 }
242
243 Bool wXDNDProcessClientMessage(XClientMessageEvent * event)
244 {
245         /* test */
246         {
247                 char *name = XGetAtomName(dpy, event->message_type);
248                 /*
249                    printf("Get %s\n",name);
250                  */
251                 XFree(name);
252         }
253
254         /*
255            if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
256            printf("motif dnd msg %d\n",event->data.b[0]);
257            if (event->data.b[0] == XmDROP_START){
258            unsigned x_root, y_root, flags;
259            unsigned char reason;
260            unsigned long timestamp;
261            Atom atom;
262            Window source_window;
263            MotifDragInitiatorInfo *initiator_info;
264            Atom ret_type;
265            int ret_format;
266            unsigned long ret_item;
267            unsigned long remain_byte;
268
269            reason = event->data.b[0];
270            flags = event->data.s[1];
271            timestamp = event->data.l[1];
272            x_root = event->data.s[4];
273            y_root = event->data.s[5];
274            atom = event->data.l[3];
275            source_window = event->data.l[4];
276
277            XGetWindowProperty(dpy, source_window, atom,
278            0, sizeof(*initiator_info), True, atom_support,
279            &ret_type, &ret_format,
280            &ret_item, &remain_byte, (unsigned char **)&initiator_info);
281            }
282            }
283            else */
284         if (event->message_type == _XA_XdndEnter) {
285                 if ((event->data.l[1] & 1) == 0) {
286                         atom_support = event->data.l[2];
287                 }
288                 /*
289                    else puts("enter more than 3 types");
290                  */
291                 return True;
292         } else if (event->message_type == _XA_XdndLeave) {
293                 return True;
294         } else if (event->message_type == _XA_XdndDrop) {
295                 if (event->data.l[0] == XGetSelectionOwner(dpy, _XA_XdndSelection)) {
296                         XConvertSelection(dpy, _XA_XdndSelection, atom_support,
297                                           _XA_WINDOWMAKER_XDNDEXCHANGE, event->window, CurrentTime);
298                 } else {
299                         puts("wierd selection owner? QT?");
300                         XConvertSelection(dpy, _XA_XdndSelection, atom_support,
301                                           _XA_WINDOWMAKER_XDNDEXCHANGE, event->window, CurrentTime);
302                 }
303                 return True;
304         } else if (event->message_type == _XA_XdndPosition) {
305                 XEvent xevent;
306                 Window srcwin = event->data.l[0];
307                 if (atom_support != XInternAtom(dpy, "text/uri-list", False)) {
308                         return True;
309                 }
310                 {
311                         memset(&xevent, 0, sizeof(xevent));
312                         xevent.xany.type = ClientMessage;
313                         xevent.xany.display = dpy;
314                         xevent.xclient.window = srcwin;
315                         xevent.xclient.message_type = _XA_XdndStatus;
316                         xevent.xclient.format = 32;
317
318                         XDND_STATUS_TARGET_WIN(&xevent) = event->window;
319                         XDND_STATUS_WILL_ACCEPT_SET(&xevent, acceptXDND(event->window));
320                         XDND_STATUS_WANT_POSITION_SET(&xevent, True);
321                         XDND_STATUS_RECT_SET(&xevent, 0, 0, 1024, 768);
322                         XDND_STATUS_ACTION(&xevent) = _XA_XdndActionCopy;
323
324                         XSendEvent(dpy, srcwin, 0, 0, &xevent);
325                 }
326                 return True;
327         }
328         return False;
329 }
330
331 #endif