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 */
27 #include "WindowMaker.h"
30 #include "workspace.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) {
81 if (sscanf(uri
+1, "%2X", &h
) != 1)
84 memmove(uri
+1, uri
+3, last
- (uri
+2));
91 Bool
wXDNDProcessSelection(XEvent
*event
)
93 WScreen
*scr
= wScreenForWindow(event
->xselection
.requestor
);
97 unsigned long ret_item
;
98 unsigned long remain_byte
;
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
);
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 */
121 WMArrayIterator iter
;
122 int length
, str_size
;
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 */
135 if (retain
[length
] == '\r') { /* useless char, nuke it */
138 if (retain
[length
] == '\n') {
139 str_size
= strlen(&retain
[length
+ 1]);
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)); */
150 WMAddToArray(items
, wstrdup(retain
));
151 total_size
+= strlen(retain
) + 3;
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
, "\"");
169 if (scr
->xdestring
[0])
170 wDockReceiveDNDDrop(scr
, event
);
171 wfree(scr
->xdestring
); /* this xdestring is not from Xlib (no XFree) */
177 static Bool
isAwareXDND(Window window
)
181 unsigned long count
, remaining
;
182 unsigned char *data
= 0;
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
) {
198 static Bool
acceptXDND(Window window
)
200 WScreen
*scr
= wScreenForWindow(window
);
207 for (i
= 0; i
< dock
->max_icons
; i
++) {
208 if (dock
->icon_array
[i
]
209 && dock
->icon_array
[i
]->icon
->core
->window
== window
) {
216 dock
= scr
->workspaces
[scr
->current_workspace
]->clip
;
218 for (i
= 0; i
< dock
->max_icons
; i
++) {
219 if (dock
->icon_array
[i
]
220 && dock
->icon_array
[i
]->icon
->core
->window
== window
) {
230 if (isAwareXDND(dock
->icon_array
[icon_pos
]->icon
->icon_win
))
233 if (dock
->icon_array
[icon_pos
]->dnd_command
!= NULL
)
239 static void wXDNDGetTypeList(Display
*dpy
, Window window
)
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
) {
254 wwarning(_("wXDNDGetTypeList failed = %ld"), _XA_XdndTypeList
);
258 typelist
= malloc((count
+ 1) * sizeof(Atom
));
260 for (i
= 0; i
< count
; i
++) {
262 if (typelist
[i
] == supported_typelist
) {
263 selected_typelist
= typelist
[i
];
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);
279 wXDNDGetTypeList(dpy
, XDND_ENTER_SOURCE_WIN(event
));
281 char *name = XGetAtomName(dpy, selected_typelist);
282 fprintf(stderr, "Get %s\n",name);
287 } else if (event
->message_type
== _XA_XdndLeave
) {
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
);
295 } else if (event
->message_type
== _XA_XdndPosition
) {
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
);