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 */
30 #include <X11/Xatom.h>
32 #include "WindowMaker.h"
35 #include "workspace.h"
38 static Atom _XA_XdndAware
;
39 static Atom _XA_XdndEnter
;
40 static Atom _XA_XdndLeave
;
41 static Atom _XA_XdndDrop
;
42 static Atom _XA_XdndPosition
;
43 static Atom _XA_XdndStatus
;
44 static Atom _XA_XdndActionCopy
;
45 static Atom _XA_XdndSelection
;
46 static Atom _XA_XdndFinished
;
47 static Atom _XA_XdndTypeList
;
48 static Atom _XA_WINDOWMAKER_XDNDEXCHANGE
;
49 static Atom supported_typelist
;
50 static Atom selected_typelist
;
52 void wXDNDInitializeAtoms(void)
54 _XA_XdndAware
= XInternAtom(dpy
, "XdndAware", False
);
55 _XA_XdndEnter
= XInternAtom(dpy
, "XdndEnter", False
);
56 _XA_XdndLeave
= XInternAtom(dpy
, "XdndLeave", False
);
57 _XA_XdndDrop
= XInternAtom(dpy
, "XdndDrop", False
);
58 _XA_XdndPosition
= XInternAtom(dpy
, "XdndPosition", False
);
59 _XA_XdndStatus
= XInternAtom(dpy
, "XdndStatus", False
);
60 _XA_XdndActionCopy
= XInternAtom(dpy
, "XdndActionCopy", False
);
61 _XA_XdndSelection
= XInternAtom(dpy
, "XdndSelection", False
);
62 _XA_XdndFinished
= XInternAtom(dpy
, "XdndFinished", False
);
63 _XA_XdndTypeList
= XInternAtom(dpy
, "XdndTypeList", False
);
64 _XA_WINDOWMAKER_XDNDEXCHANGE
= XInternAtom(dpy
, "_WINDOWMAKER_XDNDEXCHANGE", False
);
66 supported_typelist
= XInternAtom(dpy
, "text/uri-list", False
);
69 void wXDNDMakeAwareness(Window window
)
71 long int xdnd_version
= XDND_VERSION
;
72 XChangeProperty(dpy
, window
, _XA_XdndAware
, XA_ATOM
, 32,
73 PropModeAppend
, (unsigned char *)&xdnd_version
, 1);
76 static void wXDNDDecodeURI(char *uri
)
78 char *last
= uri
+ strlen(uri
);
79 while (uri
< last
-2) {
82 if (sscanf(uri
+1, "%2X", &h
) != 1)
85 memmove(uri
+1, uri
+3, last
- (uri
+2));
92 Bool
wXDNDProcessSelection(XEvent
*event
)
94 WScreen
*scr
= wScreenForWindow(event
->xselection
.requestor
);
98 unsigned long ret_item
;
99 unsigned long remain_byte
;
102 Window selowner
= XGetSelectionOwner(dpy
, _XA_XdndSelection
);
104 XGetWindowProperty(dpy
, event
->xselection
.requestor
,
105 _XA_WINDOWMAKER_XDNDEXCHANGE
,
106 0, 65536, True
, selected_typelist
, &ret_type
, &ret_format
,
107 &ret_item
, &remain_byte
, (unsigned char **)&delme
);
110 memset(&xevent
, 0, sizeof(xevent
));
111 xevent
.xany
.type
= ClientMessage
;
112 xevent
.xany
.display
= dpy
;
113 xevent
.xclient
.window
= selowner
;
114 xevent
.xclient
.message_type
= _XA_XdndFinished
;
115 xevent
.xclient
.format
= 32;
116 XDND_FINISHED_TARGET_WIN(&xevent
) = event
->xselection
.requestor
;
117 XSendEvent(dpy
, selowner
, 0, 0, &xevent
);
119 /*process dropping */
122 WMArrayIterator iter
;
123 int length
, str_size
;
127 scr
->xdestring
= delme
;
128 items
= WMCreateArray(4);
129 retain
= wstrdup(scr
->xdestring
);
130 XFree(scr
->xdestring
); /* since xdestring was created by Xlib */
132 length
= strlen(retain
);
134 /* search in string */
136 if (retain
[length
] == '\r') { /* useless char, nuke it */
139 if (retain
[length
] == '\n') {
140 str_size
= strlen(&retain
[length
+ 1]);
142 WMAddToArray(items
, wstrdup(&retain
[length
+ 1]));
143 total_size
+= str_size
+ 3; /* reserve for " \"\"" */
144 /* this is nonsense -- if (length)
145 WMAppendArray(items, WMCreateArray(1)); */
151 WMAddToArray(items
, wstrdup(retain
));
152 total_size
+= strlen(retain
) + 3;
155 /* now pack new string */
156 scr
->xdestring
= wmalloc(total_size
);
157 scr
->xdestring
[0] = 0; /* empty string */
158 WM_ETARETI_ARRAY(items
, tmp
, iter
) {
159 /* only supporting file: URI objects */
160 if (!strncmp(tmp
, "file://", 7)) {
161 /* drag-and-drop file name format as per the spec is encoded as an URI */
162 wXDNDDecodeURI(&tmp
[7]);
163 strcat(scr
->xdestring
, " \"");
164 strcat(scr
->xdestring
, &tmp
[7]);
165 strcat(scr
->xdestring
, "\"");
170 if (scr
->xdestring
[0])
171 wDockReceiveDNDDrop(scr
, event
);
172 wfree(scr
->xdestring
); /* this xdestring is not from Xlib (no XFree) */
178 static Bool
isAwareXDND(Window window
)
182 unsigned long count
, remaining
;
183 unsigned char *data
= 0;
187 XGetWindowProperty(dpy
, window
, _XA_XdndAware
,
188 0, 0x8000000L
, False
, XA_ATOM
, &actual
, &format
, &count
, &remaining
, &data
);
189 if (actual
!= XA_ATOM
|| format
!= 32 || count
== 0 || !data
) {
199 static Bool
acceptXDND(Window window
)
201 WScreen
*scr
= wScreenForWindow(window
);
208 for (i
= 0; i
< dock
->max_icons
; i
++) {
209 if (dock
->icon_array
[i
]
210 && dock
->icon_array
[i
]->icon
->core
->window
== window
) {
217 dock
= scr
->workspaces
[scr
->current_workspace
]->clip
;
219 for (i
= 0; i
< dock
->max_icons
; i
++) {
220 if (dock
->icon_array
[i
]
221 && dock
->icon_array
[i
]->icon
->core
->window
== window
) {
231 if (isAwareXDND(dock
->icon_array
[icon_pos
]->icon
->icon_win
))
234 if (dock
->icon_array
[icon_pos
]->dnd_command
!= NULL
)
240 static void wXDNDGetTypeList(Display
*dpy
, Window window
)
245 unsigned long count
, remaining
;
246 unsigned char *data
= NULL
;
248 XGetWindowProperty(dpy
, window
, _XA_XdndTypeList
,
249 0, 0x8000000L
, False
, XA_ATOM
,
250 &type
, &format
, &count
, &remaining
, &data
);
252 if (type
!= XA_ATOM
|| format
!= 32 || count
== 0 || !data
) {
255 wwarning(_("wXDNDGetTypeList failed = %ld"), _XA_XdndTypeList
);
259 typelist
= malloc((count
+ 1) * sizeof(Atom
));
261 for (i
= 0; i
< count
; i
++) {
263 if (typelist
[i
] == supported_typelist
) {
264 selected_typelist
= typelist
[i
];
273 Bool
wXDNDProcessClientMessage(XClientMessageEvent
*event
)
275 if (event
->message_type
== _XA_XdndEnter
) {
277 if (XDND_ENTER_THREE_TYPES(event
)) {
278 selected_typelist
= XDND_ENTER_TYPE(event
, 0);
280 wXDNDGetTypeList(dpy
, XDND_ENTER_SOURCE_WIN(event
));
282 char *name = XGetAtomName(dpy, selected_typelist);
283 fprintf(stderr, "Get %s\n",name);
288 } else if (event
->message_type
== _XA_XdndLeave
) {
290 } else if (event
->message_type
== _XA_XdndDrop
) {
291 if (XDND_DROP_SOURCE_WIN(event
) == XGetSelectionOwner(dpy
, _XA_XdndSelection
)) {
292 XConvertSelection(dpy
, _XA_XdndSelection
, selected_typelist
,
293 _XA_WINDOWMAKER_XDNDEXCHANGE
, event
->window
, CurrentTime
);
296 } else if (event
->message_type
== _XA_XdndPosition
) {
298 Window srcwin
= XDND_POSITION_SOURCE_WIN(event
);
299 if (selected_typelist
== supported_typelist
) {
300 memset(&xevent
, 0, sizeof(xevent
));
301 xevent
.xany
.type
= ClientMessage
;
302 xevent
.xany
.display
= dpy
;
303 xevent
.xclient
.window
= srcwin
;
304 xevent
.xclient
.message_type
= _XA_XdndStatus
;
305 xevent
.xclient
.format
= 32;
307 XDND_STATUS_TARGET_WIN(&xevent
) = event
->window
;
308 XDND_STATUS_WILL_ACCEPT_SET(&xevent
, acceptXDND(event
->window
));
309 XDND_STATUS_WANT_POSITION_SET(&xevent
, True
);
310 XDND_STATUS_RECT_SET(&xevent
, 0, 0, 0, 0);
311 XDND_STATUS_ACTION(&xevent
) = _XA_XdndActionCopy
;
313 XSendEvent(dpy
, srcwin
, 0, 0, &xevent
);