1 /*
2 * This file is part of MPlayer.
3 *
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * based on: WindowMaker implementation,
19 * adopted for MPlayer
20 */
21
22 #include <X11/Xlib.h>
23 #include "wsxdnd.h"
24 #include "gui/app/gui.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <X11/Xatom.h>
31
32 #include "mp_msg.h"
33 #include "help_mp.h"
34
35 #define XDND_VERSION 3L
36
37 Atom XA_XdndAware;
38 Atom XA_XdndEnter;
39 Atom XA_XdndLeave;
40 Atom XA_XdndDrop;
41 Atom XA_XdndPosition;
42 Atom XA_XdndStatus;
43 Atom XA_XdndActionCopy;
44 Atom XA_XdndSelection;
45 Atom XA_XdndFinished;
46 Atom XA_XdndTypeList;
47
48 Atom atom_support;
49
wsXDNDInitialize(void)50 void wsXDNDInitialize(void)
51 {
52
53 XA_XdndAware = XInternAtom(wsDisplay, "XdndAware", False);
54 XA_XdndEnter = XInternAtom(wsDisplay, "XdndEnter", False);
55 XA_XdndLeave = XInternAtom(wsDisplay, "XdndLeave", False);
56 XA_XdndDrop = XInternAtom(wsDisplay, "XdndDrop", False);
57 XA_XdndPosition = XInternAtom(wsDisplay, "XdndPosition", False);
58 XA_XdndStatus = XInternAtom(wsDisplay, "XdndStatus", False);
59 XA_XdndActionCopy = XInternAtom(wsDisplay, "XdndActionCopy", False);
60 XA_XdndSelection = XInternAtom(wsDisplay, "XdndSelection", False);
61 XA_XdndFinished = XInternAtom(wsDisplay, "XdndFinished", False);
62 XA_XdndTypeList = XInternAtom(wsDisplay, "XdndTypeList", False);
63 }
64
wsXDNDMakeAwareness(wsWindow * win)65 void wsXDNDMakeAwareness(wsWindow* win) {
66 long int xdnd_version = XDND_VERSION;
67 XChangeProperty (wsDisplay, win->WindowID, XA_XdndAware, XA_ATOM,
68 32, PropModeAppend, (char *)&xdnd_version, 1);
69 }
70
wsXDNDClearAwareness(wsWindow * win)71 void wsXDNDClearAwareness(wsWindow* win) {
72 XDeleteProperty (wsDisplay, win->WindowID, XA_XdndAware);
73 }
74
75 #define MAX_DND_FILES 64
76 Bool
wsXDNDProcessSelection(wsWindow * win,XEvent * event)77 wsXDNDProcessSelection(wsWindow* win, XEvent *event)
78 {
79 Atom ret_type;
80 int ret_format;
81 unsigned long ret_items;
82 unsigned long remain_byte;
83 char * delme;
84 XEvent xevent;
85
86 Window selowner = XGetSelectionOwner(wsDisplay,XA_XdndSelection);
87
88 XGetWindowProperty(wsDisplay, event->xselection.requestor,
89 event->xselection.property,
90 0, 65536, True, atom_support, &ret_type, &ret_format,
91 &ret_items, &remain_byte, (unsigned char **)&delme);
92
93 /*send finished*/
94 memset (&xevent, 0, sizeof(xevent));
95 xevent.xany.type = ClientMessage;
96 xevent.xany.display = wsDisplay;
97 xevent.xclient.window = selowner;
98 xevent.xclient.message_type = XA_XdndFinished;
99 xevent.xclient.format = 32;
100 XDND_FINISHED_TARGET_WIN(&xevent) = win->WindowID;
101 XSendEvent(wsDisplay, selowner, 0, 0, &xevent);
102
103 if (!delme){
104 mp_msg( MSGT_GPLAYER,MSGL_WARN,_(MSGTR_GUI_MSG_DragAndDropNothing) );
105 return False;
106 }
107
108 {
109 /* Handle dropped files */
110 char * retain = delme;
111 char * files[MAX_DND_FILES];
112 int num = 0;
113
114 while(retain < delme + ret_items) {
115 if (!strncmp(retain,"file:",5)) {
116 /* add more 2 chars while removing 5 is harmless */
117 retain+=5;
118 }
119
120 /* add the "retain" to the list */
121 files[num++]=retain;
122
123
124 /* now check for special characters */
125 {
126 int newone = 0;
127 while(retain < (delme + ret_items)){
128 if(*retain == '\r' || *retain == '\n'){
129 *retain=0;
130 newone = 1;
131 } else {
132 if (newone)
133 break;
134 }
135 retain++;
136 }
137 }
138
139 if (num >= MAX_DND_FILES)
140 break;
141 }
142
143 /* Handle the files */
144 if(win->DNDHandler){
145 win->DNDHandler(num,files);
146 }
147 }
148
149 free(delme);
150 return True;
151 }
152
153 Bool
wsXDNDProcessClientMessage(XClientMessageEvent * event)154 wsXDNDProcessClientMessage(XClientMessageEvent *event)
155 {
156 /* test */
157 /*{
158 char * name = XGetAtomName(wsDisplay, event->message_type);
159 printf("Got %s\n",name);
160 XFree(name);
161 }*/
162
163 if (event->message_type == XA_XdndEnter) {
164 Atom ok = XInternAtom(wsDisplay, "text/uri-list", False);
165 atom_support = None;
166 if ((event->data.l[1] & 1) == 0){
167 int index;
168 for(index = 0; index <= 2 ; index++){
169 if ((Atom) event->data.l[2+index] == ok) {
170 atom_support = ok;
171 }
172 }
173 if (atom_support == None) {
174 mp_msg( MSGT_GPLAYER,MSGL_WARN,_(MSGTR_GUI_MSG_NotAFile0) );
175 }
176 } else {
177 /* need to check the whole list here */
178 unsigned long ret_left = 1;
179 int offset = 0;
180 Atom* ret_buff;
181 Atom ret_type;
182 int ret_format;
183 unsigned long ret_items;
184
185 /* while there is data left...*/
186 while(ret_left && atom_support == None){
187 XGetWindowProperty(wsDisplay,event->data.l[0],XA_XdndTypeList,
188 offset,256,False,XA_ATOM,&ret_type,
189 &ret_format,&ret_items,&ret_left,
190 (unsigned char**)&ret_buff);
191
192 /* sanity checks...*/
193 if(ret_buff == NULL || ret_type != XA_ATOM || ret_format != 8*sizeof(Atom)){
194 XFree(ret_buff);
195 break;
196 }
197 /* now chek what we've got */
198 {
199 unsigned long i;
200 for(i=0; i<ret_items; i++){
201 if(ret_buff[i] == ok){
202 atom_support = ok;
203 break;
204 }
205 }
206 }
207 /* maybe next time ... */
208 XFree(ret_buff);
209 offset += 256;
210 }
211 }
212 return True;
213 }
214
215 if (event->message_type == XA_XdndLeave) {
216 return True;
217 }
218
219 if (event->message_type == XA_XdndDrop) {
220 if ((Window) event->data.l[0] != XGetSelectionOwner(wsDisplay, XA_XdndSelection)){
221 mp_msg( MSGT_GPLAYER,MSGL_WARN,_(MSGTR_GUI_MSG_DragAndDropOwner) );
222 }
223 if (atom_support != None) {
224 XConvertSelection(wsDisplay, XA_XdndSelection, atom_support,
225 XA_XdndSelection, event->window,
226 CurrentTime);
227 }
228 return True;
229 }
230
231 if (event->message_type == XA_XdndPosition) {
232 Window srcwin = event->data.l[0];
233 if (atom_support == None){
234 return True;
235 }
236
237 /* send response */
238 {
239 XEvent xevent;
240 memset (&xevent, 0, sizeof(xevent));
241 xevent.xany.type = ClientMessage;
242 xevent.xany.display = wsDisplay;
243 xevent.xclient.window = srcwin;
244 xevent.xclient.message_type = XA_XdndStatus;
245 xevent.xclient.format = 32;
246
247 XDND_STATUS_TARGET_WIN (&xevent) = event->window;
248 XDND_STATUS_WILL_ACCEPT_SET (&xevent, True);
249 XDND_STATUS_WANT_POSITION_SET(&xevent, True);
250 /* actually need smth real here */
251 XDND_STATUS_RECT_SET(&xevent, 0, 0, 1024,768);
252 XDND_STATUS_ACTION(&xevent) = XA_XdndActionCopy;
253
254 XSendEvent(wsDisplay, srcwin, 0, 0, &xevent);
255 }
256 return True;
257 }
258
259 return False;
260 }
261