doc: explain how to help translating the Window Maker project
[wmaker-crm.git] / src / xdnd.c
blobafbbd44c83b283dbe11e0cfe1d6090e965244c1b
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
5 * Copyright (c) 2014 Window Maker Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation
21 /* Many part of code are ripped of an example from JX's site */
23 #include "wconfig.h"
25 #ifdef XDND
27 #include "WindowMaker.h"
28 #include "dock.h"
29 #include "xdnd.h"
30 #include "workspace.h"
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <X11/Xatom.h>
37 static Atom _XA_XdndAware;
38 static Atom _XA_XdndEnter;
39 static Atom _XA_XdndLeave;
40 static Atom _XA_XdndDrop;
41 static Atom _XA_XdndPosition;
42 static Atom _XA_XdndStatus;
43 static Atom _XA_XdndActionCopy;
44 static Atom _XA_XdndSelection;
45 static Atom _XA_XdndFinished;
46 static Atom _XA_XdndTypeList;
47 static Atom _XA_WINDOWMAKER_XDNDEXCHANGE;
48 static Atom supported_typelist;
49 static Atom selected_typelist;
51 void wXDNDInitializeAtoms(void)
53 _XA_XdndAware = XInternAtom(dpy, "XdndAware", False);
54 _XA_XdndEnter = XInternAtom(dpy, "XdndEnter", False);
55 _XA_XdndLeave = XInternAtom(dpy, "XdndLeave", False);
56 _XA_XdndDrop = XInternAtom(dpy, "XdndDrop", False);
57 _XA_XdndPosition = XInternAtom(dpy, "XdndPosition", False);
58 _XA_XdndStatus = XInternAtom(dpy, "XdndStatus", False);
59 _XA_XdndActionCopy = XInternAtom(dpy, "XdndActionCopy", False);
60 _XA_XdndSelection = XInternAtom(dpy, "XdndSelection", False);
61 _XA_XdndFinished = XInternAtom(dpy, "XdndFinished", False);
62 _XA_XdndTypeList = XInternAtom(dpy, "XdndTypeList", False);
63 _XA_WINDOWMAKER_XDNDEXCHANGE = XInternAtom(dpy, "_WINDOWMAKER_XDNDEXCHANGE", False);
65 supported_typelist = XInternAtom(dpy, "text/uri-list", False);
68 void wXDNDMakeAwareness(Window window)
70 long int xdnd_version = XDND_VERSION;
71 XChangeProperty(dpy, window, _XA_XdndAware, XA_ATOM, 32,
72 PropModeAppend, (unsigned char *)&xdnd_version, 1);
75 static void wXDNDDecodeURI(char *uri)
77 char *last = uri + strlen(uri);
78 while (uri < last-2) {
79 if (*uri == '%') {
80 int h;
81 if (sscanf(uri+1, "%2X", &h) != 1)
82 break;
83 *uri = h;
84 memmove(uri+1, uri+3, last - (uri+2));
85 last -= 2;
87 uri++;
91 Bool wXDNDProcessSelection(XEvent *event)
93 WScreen *scr = wScreenForWindow(event->xselection.requestor);
94 char *retain;
95 Atom ret_type;
96 int ret_format;
97 unsigned long ret_item;
98 unsigned long remain_byte;
99 char *delme;
100 XEvent xevent;
101 Window selowner = XGetSelectionOwner(dpy, _XA_XdndSelection);
103 XGetWindowProperty(dpy, event->xselection.requestor,
104 _XA_WINDOWMAKER_XDNDEXCHANGE,
105 0, 65536, True, selected_typelist, &ret_type, &ret_format,
106 &ret_item, &remain_byte, (unsigned char **)&delme);
108 /*send finished */
109 memset(&xevent, 0, sizeof(xevent));
110 xevent.xany.type = ClientMessage;
111 xevent.xany.display = dpy;
112 xevent.xclient.window = selowner;
113 xevent.xclient.message_type = _XA_XdndFinished;
114 xevent.xclient.format = 32;
115 XDND_FINISHED_TARGET_WIN(&xevent) = event->xselection.requestor;
116 XSendEvent(dpy, selowner, 0, 0, &xevent);
118 /*process dropping */
119 if (delme) {
120 WMArray *items;
121 WMArrayIterator iter;
122 int length, str_size;
123 int total_size = 0;
124 char *tmp;
126 scr->xdestring = delme;
127 items = WMCreateArray(4);
128 retain = wstrdup(scr->xdestring);
129 XFree(scr->xdestring); /* since xdestring was created by Xlib */
131 length = strlen(retain);
133 /* search in string */
134 while (length--) {
135 if (retain[length] == '\r') { /* useless char, nuke it */
136 retain[length] = 0;
138 if (retain[length] == '\n') {
139 str_size = strlen(&retain[length + 1]);
140 if (str_size) {
141 WMAddToArray(items, wstrdup(&retain[length + 1]));
142 total_size += str_size + 3; /* reserve for " \"\"" */
143 /* this is nonsense -- if (length)
144 WMAppendArray(items, WMCreateArray(1)); */
146 retain[length] = 0;
149 /* final one */
150 WMAddToArray(items, wstrdup(retain));
151 total_size += strlen(retain) + 3;
152 wfree(retain);
154 /* now pack new string */
155 scr->xdestring = wmalloc(total_size);
156 scr->xdestring[0] = 0; /* empty string */
157 WM_ETARETI_ARRAY(items, tmp, iter) {
158 /* only supporting file: URI objects */
159 if (!strncmp(tmp, "file://", 7)) {
160 /* drag-and-drop file name format as per the spec is encoded as an URI */
161 wXDNDDecodeURI(&tmp[7]);
162 strcat(scr->xdestring, " \"");
163 strcat(scr->xdestring, &tmp[7]);
164 strcat(scr->xdestring, "\"");
166 wfree(tmp);
168 WMFreeArray(items);
169 if (scr->xdestring[0])
170 wDockReceiveDNDDrop(scr, event);
171 wfree(scr->xdestring); /* this xdestring is not from Xlib (no XFree) */
174 return True;
177 static Bool isAwareXDND(Window window)
179 Atom actual;
180 int format;
181 unsigned long count, remaining;
182 unsigned char *data = 0;
184 if (!window)
185 return False;
186 XGetWindowProperty(dpy, window, _XA_XdndAware,
187 0, 0x8000000L, False, XA_ATOM, &actual, &format, &count, &remaining, &data);
188 if (actual != XA_ATOM || format != 32 || count == 0 || !data) {
189 if (data)
190 XFree(data);
191 return False;
193 if (data)
194 XFree(data);
195 return True;
198 static Bool acceptXDND(Window window)
200 WScreen *scr = wScreenForWindow(window);
201 WDock *dock;
202 int icon_pos, i;
204 icon_pos = -1;
205 dock = scr->dock;
206 if (dock) {
207 for (i = 0; i < dock->max_icons; i++) {
208 if (dock->icon_array[i]
209 && dock->icon_array[i]->icon->core->window == window) {
210 icon_pos = i;
211 break;
215 if (icon_pos < 0) {
216 dock = scr->workspaces[scr->current_workspace]->clip;
217 if (dock) {
218 for (i = 0; i < dock->max_icons; i++) {
219 if (dock->icon_array[i]
220 && dock->icon_array[i]->icon->core->window == window) {
221 icon_pos = i;
222 break;
227 if (icon_pos < 0)
228 return False;
230 if (isAwareXDND(dock->icon_array[icon_pos]->icon->icon_win))
231 return False;
233 if (dock->icon_array[icon_pos]->dnd_command != NULL)
234 return True;
236 return False;
239 static void wXDNDGetTypeList(Display *dpy, Window window)
241 Atom type, *a;
242 Atom *typelist;
243 int format, i;
244 unsigned long count, remaining;
245 unsigned char *data = NULL;
247 XGetWindowProperty(dpy, window, _XA_XdndTypeList,
248 0, 0x8000000L, False, XA_ATOM,
249 &type, &format, &count, &remaining, &data);
251 if (type != XA_ATOM || format != 32 || count == 0 || !data) {
252 if (data)
253 XFree(data);
254 wwarning(_("wXDNDGetTypeList failed = %ld"), _XA_XdndTypeList);
255 return;
258 typelist = malloc((count + 1) * sizeof(Atom));
259 a = (Atom *) data;
260 for (i = 0; i < count; i++) {
261 typelist[i] = a[i];
262 if (typelist[i] == supported_typelist) {
263 selected_typelist = typelist[i];
264 break;
267 typelist[count] = 0;
268 XFree(data);
269 free(typelist);
272 Bool wXDNDProcessClientMessage(XClientMessageEvent *event)
274 if (event->message_type == _XA_XdndEnter) {
276 if (XDND_ENTER_THREE_TYPES(event)) {
277 selected_typelist = XDND_ENTER_TYPE(event, 0);
278 } else {
279 wXDNDGetTypeList(dpy, XDND_ENTER_SOURCE_WIN(event));
281 char *name = XGetAtomName(dpy, selected_typelist);
282 fprintf(stderr, "Get %s\n",name);
283 XFree(name);
286 return True;
287 } else if (event->message_type == _XA_XdndLeave) {
288 return True;
289 } else if (event->message_type == _XA_XdndDrop) {
290 if (XDND_DROP_SOURCE_WIN(event) == XGetSelectionOwner(dpy, _XA_XdndSelection)) {
291 XConvertSelection(dpy, _XA_XdndSelection, selected_typelist,
292 _XA_WINDOWMAKER_XDNDEXCHANGE, event->window, CurrentTime);
294 return True;
295 } else if (event->message_type == _XA_XdndPosition) {
296 XEvent xevent;
297 Window srcwin = XDND_POSITION_SOURCE_WIN(event);
298 if (selected_typelist == supported_typelist) {
299 memset(&xevent, 0, sizeof(xevent));
300 xevent.xany.type = ClientMessage;
301 xevent.xany.display = dpy;
302 xevent.xclient.window = srcwin;
303 xevent.xclient.message_type = _XA_XdndStatus;
304 xevent.xclient.format = 32;
306 XDND_STATUS_TARGET_WIN(&xevent) = event->window;
307 XDND_STATUS_WILL_ACCEPT_SET(&xevent, acceptXDND(event->window));
308 XDND_STATUS_WANT_POSITION_SET(&xevent, True);
309 XDND_STATUS_RECT_SET(&xevent, 0, 0, 0, 0);
310 XDND_STATUS_ACTION(&xevent) = _XA_XdndActionCopy;
312 XSendEvent(dpy, srcwin, 0, 0, &xevent);
314 return True;
316 return False;
318 #endif