comparison src/offix.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children b39c14581166
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
1 /*
2 This is a modified DND 1.0 library which does not depend on Xt
3 event handling.
4 Modifications Copyright (c) 1997 Oliver Graf <ograf@fga.de>
5
6 Original DND lib
7 Copyright (C) 1996 César Crusius
8
9 This file is part of the DND Library. This library is free
10 software; you can redistribute it and/or modify it under the terms of
11 the GNU Library General Public License as published by the Free
12 Software Foundation; either version 2 of the License, or (at your
13 option) any later version. This library is distributed in the hope
14 that it will be useful, but WITHOUT ANY WARRANTY; without even the
15 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 PURPOSE. See the GNU Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /* #define DEBUG */
23
24 #include "offix.h"
25 #include <X11/cursorfont.h>
26 #include <X11/Xatom.h>
27 #include <X11/Xmu/WinUtil.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <limits.h>
31
32 /* Local variables */
33 static Display *dpy; /* current display */
34 static int DragPrecision; /* minimum dx,dy to start drag */
35 static int Dragging; /* Drag state flag */
36 static int DataOK; /* Non-zero if data registered */
37 static Atom DndProtocol; /* ClientMessage identifier */
38 static Atom DndSelection; /* For the data transfers */
39 static Atom OldDndProtocol; /* Version 0 atom */
40 static Atom OldDndSelection;/* Version 0 atom */
41 static Atom WM_STATE; /* Needed for icon stuff */
42 static Window Target; /* Drop window */
43 static Widget MainWidget; /* Main widget of application */
44 static int DataType; /* Current drag data type */
45 static int RootFlag; /* Non-zero if dropped on root */
46 static XColor Black,White; /* For the cursors */
47
48 /*=========================================================================
49 * Data for the standard Dnd cursors
50 *=========================================================================*/
51 #include "offix-cursors.h"
52
53 /*=============================================================== CursorData
54 * CursorData contains all the data for the cursors bitmaps
55 *==========================================================================*/
56 typedef struct
57 {
58 int Width,Height;
59 unsigned char *ImageData,*MaskData;
60 int HotSpotX,HotSpotY;
61 Pixmap ImagePixmap,MaskPixmap;
62 Cursor CursorID;
63 } CursorData;
64
65 static CursorData DndCursor[DndEND]={
66 { 0,0,NULL,NULL,0,0,0 },
67 { grey_width, grey_height,grey_bits,grey_mask_bits,
68 grey_x_hot,grey_y_hot},
69 { file_width,file_height,file_bits,file_mask_bits,
70 file_x_hot,file_y_hot},
71 { files_width,files_height,files_bits,files_mask_bits,
72 files_x_hot,files_y_hot},
73 { text_width,text_height,text_bits,text_mask_bits,
74 text_x_hot,text_y_hot },
75 { dir_width,dir_height,dir_bits,dir_mask_bits,
76 dir_x_hot,dir_y_hot },
77 { link_width,link_height,link_bits,link_mask_bits,
78 link_x_hot,link_y_hot},
79 { app_width,app_height,app_bits,app_mask_bits,
80 app_x_hot,app_y_hot },
81 { url_width,url_height,url_bits,url_mask_bits,
82 url_x_hot,url_y_hot },
83 { mime_width,mime_height,mime_bits,mime_mask_bits,
84 mime_x_hot,mime_y_hot }
85 };
86
87 /* Local prototypes */
88 int DndIsDragging(void);
89 void DndStartAction(Widget widget,
90 XtPointer data,
91 XEvent *event,
92 Boolean *p);
93 void DndPropertyHandler(Widget widget,
94 XtPointer data,
95 XEvent *event,
96 Boolean *p);
97
98 /*======================================================== DndHandleDragging
99 * Takes care of the drag and drop process. Wait until the pointer had moved
100 * a little. Then takes control over the pointer until the buttons are
101 * released. After that send a Drag And Drop ClientMessage event. Returns
102 * non-zero if a drop did take place.
103 *===========================================================================*/
104 int
105 DndHandleDragging(Widget widget,XEvent *event)
106 {
107 XEvent Event;
108 Window root = RootWindowOfScreen(XtScreenOfObject(widget));
109 XtAppContext app= XtWidgetToApplicationContext(widget);
110 Window DispatchWindow;
111 int DropX,DropY;
112
113 if(Dragging) return 0;
114
115 XUngrabPointer(dpy,CurrentTime);
116 /* Take control over the pointer */
117 XGrabPointer(dpy,root,False,
118 ButtonMotionMask|ButtonPressMask|ButtonReleaseMask,
119 GrabModeSync,GrabModeAsync,root,
120 DndCursor[DataType].CursorID,
121 CurrentTime);
122
123 /* Wait for button release */
124 Dragging=1; RootFlag=0;
125 while(Dragging)
126 {
127 XAllowEvents(dpy,SyncPointer,CurrentTime);
128 XtAppNextEvent(app,&Event);
129 switch(Event.type)
130 {
131 case ButtonRelease:
132 if(Event.xbutton.subwindow)
133 RootFlag=0;
134 else
135 RootFlag=1;
136 Dragging=0;
137 break;
138 default:
139 XtDispatchEvent(&Event);
140 break;
141 }
142 }
143 DataOK=0;
144 /* Now release the pointer */
145 XUngrabPointer(dpy,CurrentTime);
146 /* Try to guess if the drop occurred in the root window */
147 if(!RootFlag)
148 {
149 Target=XmuClientWindow(dpy,Event.xbutton.subwindow);
150 if (Target==Event.xbutton.subwindow)
151 DispatchWindow=Target;
152 else
153 DispatchWindow=PointerWindow;
154 }
155 else
156 Target=DispatchWindow=XtWindow(MainWidget);
157
158 /* Now build the event structure */
159 DropX=Event.xbutton.x_root;
160 DropY=Event.xbutton.y_root;
161 Event.xclient.type = ClientMessage;
162 Event.xclient.display = dpy;
163 Event.xclient.message_type = DndProtocol;
164 Event.xclient.format = 32;
165 Event.xclient.window = Target;
166 Event.xclient.data.l[0] = DataType;
167 Event.xclient.data.l[1] = (long)event->xbutton.state;
168 Event.xclient.data.l[2] = (long)XtWindow(widget);
169 Event.xclient.data.l[3] = DropX + 65536L*(long)DropY;
170 Event.xclient.data.l[4] = 1;
171
172 /* Send the drop message */
173 XSendEvent(dpy,DispatchWindow,True,NoEventMask,&Event);
174 /* Send an old style version of the message just in case */
175 Event.xclient.message_type = OldDndProtocol;
176 XSendEvent(dpy,DispatchWindow,True,NoEventMask,&Event);
177
178 #ifdef DEBUG
179 fprintf(stderr,"ClientMessage sent to 0x%x(0x%x).\n",
180 DispatchWindow,Target);
181 fprintf(stderr,"The drop coordinates are (%d,%d).\n",DropX,DropY);
182 #endif
183
184 return 1;
185 }
186
187 /*=============================================================== DndIsIcon
188 * Return non-zero if the application is iconic (widget=toplevel)
189 *========================================================================*/
190 int
191 DndIsIcon(Widget widget)
192 {
193 Atom JunkAtom;
194 int JunkInt;
195 unsigned long WinState,JunkLong;
196 unsigned char *Property;
197
198 XGetWindowProperty(dpy,XtWindow(widget),WM_STATE,
199 0L,2L,False,AnyPropertyType,
200 &JunkAtom,&JunkInt,&WinState,&JunkLong,
201 &Property);
202 WinState=(unsigned long)(*((long*)Property));
203 return (WinState==3);
204 }
205
206 /*============================================================ DndInitialize
207 * Must be called anywhere before the top level widget creation and the
208 * main loop. Initialize global variables and bind the DndDispatch function
209 * to the top level widget. Creates the cursors to be used in drag actions.
210 *=========================================================================*/
211 void
212 DndInitialize(Widget shell)
213 {
214 int screen,i;
215 Colormap colormap;
216 Window root;
217
218 dpy = XtDisplayOfObject(shell);
219 screen = DefaultScreen(dpy);
220 colormap= DefaultColormap(dpy,screen);
221 root = DefaultRootWindow(dpy);
222
223
224 Black.pixel=BlackPixel(dpy,screen);
225 White.pixel=WhitePixel(dpy,screen);
226 XQueryColor(dpy,colormap,&Black);
227 XQueryColor(dpy,colormap,&White);
228
229 for(i=1;i!=DndEND;i++)
230 {
231 DndCursor[i].ImagePixmap=
232 XCreateBitmapFromData(dpy,root,
233 (char *) DndCursor[i].ImageData,
234 DndCursor[i].Width,
235 DndCursor[i].Height);
236 DndCursor[i].MaskPixmap=
237 XCreateBitmapFromData(dpy,root,
238 (char *) DndCursor[i].MaskData,
239 DndCursor[i].Width,
240 DndCursor[i].Height);
241 DndCursor[i].CursorID=
242 XCreatePixmapCursor(dpy,DndCursor[i].ImagePixmap,
243 DndCursor[i].MaskPixmap,
244 &Black,&White,
245 DndCursor[i].HotSpotX,
246 DndCursor[i].HotSpotY);
247 }
248
249 DndCursor[0].CursorID=XCreateFontCursor(dpy,XC_question_arrow);
250
251 /* These two are for older versions */
252 OldDndProtocol=XInternAtom(dpy,"DndProtocol",FALSE);
253 OldDndSelection=XInternAtom(dpy,"DndSelection",FALSE);
254 /* Now the correct stuff */
255 DndProtocol=XInternAtom(dpy,"_DND_PROTOCOL",FALSE);
256 DndSelection=XInternAtom(dpy,"_DND_SELECTION",FALSE);
257
258 WM_STATE=XInternAtom(dpy,"WM_STATE",True);
259 Dragging=0;
260 DragPrecision=10;
261 RootFlag=0;
262 MainWidget=shell;
263 }
264
265 int
266 DndIsDragging(void)
267 {
268 return Dragging;
269 }
270
271 /*================================================================= DndSetData
272 * Updates the selection data.
273 *===========================================================================*/
274 void
275 DndSetData(int Type,unsigned char *Data,unsigned long Size)
276 {
277 Window root = DefaultRootWindow(dpy);
278 int AuxSize;
279 unsigned char *AuxData;
280 unsigned long BackSize=Size;
281
282 if (DataOK) return;
283
284 /* Set the data type -- allow any type */
285 DataType = Type;
286
287 /* Set the data */
288 AuxData = Data;
289 AuxSize = ( Size <= INT_MAX ? (int)Size : INT_MAX );
290 XChangeProperty(dpy,root,DndSelection,XA_STRING,8,
291 PropModeReplace,Data,AuxSize);
292 for(Size-=(unsigned long)AuxSize;Size;Size-=(unsigned long)AuxSize)
293 {
294 Data+=AuxSize;
295 AuxSize = ( (Size<=(INT_MAX)) ? (int)Size : (INT_MAX) );
296 XChangeProperty(dpy,root,DndSelection,XA_STRING,8,
297 PropModeAppend,Data,AuxSize);
298 }
299
300 /* Set the data for old DND version */
301 Size = BackSize;
302 AuxData = Data;
303 AuxSize = ( Size <= INT_MAX ? (int)Size : INT_MAX );
304 XChangeProperty(dpy,root,OldDndSelection,XA_STRING,8,
305 PropModeReplace,Data,AuxSize);
306 for(Size-=(unsigned long)AuxSize;Size;Size-=(unsigned long)AuxSize)
307 {
308 Data+=AuxSize;
309 AuxSize = ( (Size<=(INT_MAX)) ? (int)Size : (INT_MAX) );
310 XChangeProperty(dpy,root,OldDndSelection,XA_STRING,8,
311 PropModeAppend,Data,AuxSize);
312 }
313
314 /* Everything is now ok */
315 DataOK=1;
316 }
317
318 /*================================================================== DndGetData
319 * Return a pointer to the current data. See HOWTO for more details.
320 *===========================================================================*/
321 void
322 DndGetData(XEvent *event, unsigned char **Data,unsigned long *Size)
323 {
324 Window root = DefaultRootWindow(dpy);
325
326 Atom ActualType,ActualDndSelection;
327 int ActualFormat;
328 unsigned long RemainingBytes;
329
330 ActualDndSelection=(DndProtocolVersion(event) == 0L ?
331 OldDndSelection :
332 DndSelection );
333
334 XGetWindowProperty(dpy,root,ActualDndSelection,
335 0L,1000000L,
336 FALSE,AnyPropertyType,
337 &ActualType,&ActualFormat,
338 Size,&RemainingBytes,
339 Data);
340 }
341
342 /*================================== DndDataType DndDragButtons DndSourceWidget
343 *
344 * Return information about the Dnd event received. If a non-dnd event is
345 * passed, the function DndDataType returns DndNotDnd, and the others
346 * return zero.
347 *===========================================================================*/
348 int
349 DndDataType(XEvent *event)
350 {
351 int Type;
352
353 if(!DndIsDropMessage(event)) return DndNotDnd;
354 Type=(int)(event->xclient.data.l[0]);
355 if(Type>=DndEND) Type=DndUnknown;
356 return Type;
357 }
358
359 unsigned int
360 DndDragButtons(XEvent *event)
361 {
362 if(!DndIsDropMessage(event)) return 0;
363 return (unsigned int)(event->xclient.data.l[1]);
364 }
365
366 Window
367 DndSourceWindow(XEvent *event)
368 {
369 if(!DndIsDropMessage(event)) return 0;
370 if(DndProtocolVersion(event)<__DragAndDropH__)
371 /* We will try to do something about it, but nothing is certain */
372 return XtWindow((Widget)(event->xclient.data.l[2]));
373 return (Window)(event->xclient.data.l[2]);
374 }
375
376 void
377 DndDropRootCoordinates(XEvent *event,int *x,int *y)
378 {
379 if(!DndIsDropMessage(event))
380 {
381 *x=0; *y=0;
382 return;
383 }
384
385 /* If it is an old protocol version we try to get the coordinates
386 using the current pointer position. Of course, the pointer may have
387 moved since the drop, but there's nothing we can do about it.
388 */
389 if(DndProtocolVersion(event)<1L)
390 {
391 Window root_return,child_return;
392 int win_x_return,win_y_return;
393 unsigned int mask_return;
394
395 XQueryPointer(dpy,DefaultRootWindow(dpy),
396 &root_return,&child_return,x,y,
397 &win_x_return,&win_y_return,&mask_return);
398 return;
399 }
400 /* Thanks god you are using a decent protocol version */
401 *x=(int)((long)(event->xclient.data.l[3]) & 0xffff);
402 *y=(int)((long)(event->xclient.data.l[3])/65536);
403 }
404
405 void
406 DndDropCoordinates(Widget widget,XEvent *event,int *x,int *y)
407 {
408 int root_x,root_y;
409 Window child_return;
410
411 DndDropRootCoordinates(event,&root_x,&root_y);
412 XTranslateCoordinates(dpy,DefaultRootWindow(dpy),
413 XtWindow(widget),
414 root_x,root_y,
415 x,y,
416 &child_return);
417 }
418
419 long
420 DndProtocolVersion(XEvent *event)
421 {
422 if(!DndIsDropMessage(event)) return -1L;
423 return event->xclient.data.l[4];
424 }
425
426 int
427 DndIsDropMessage(XEvent *event)
428 {
429 if(event->xclient.type != ClientMessage) return 0;
430 if(event->xclient.message_type == OldDndProtocol &&
431 event->xclient.data.l[4]==0) return 1;
432 if(event->xclient.message_type == DndProtocol) return 1;
433 return 0;
434 }
435
436 void
437 DndChangeCursor(int Type,int width,int height,char *image,char *mask,
438 int hot_x,int hot_y)
439 {
440 DndCursor[Type].ImagePixmap=
441 XCreateBitmapFromData(dpy,DefaultRootWindow(dpy),
442 image,width,height);
443 DndCursor[Type].MaskPixmap=
444 XCreateBitmapFromData(dpy,DefaultRootWindow(dpy),
445 mask,width,height);
446 DndCursor[Type].CursorID=
447 XCreatePixmapCursor(dpy,DndCursor[Type].ImagePixmap,
448 DndCursor[Type].MaskPixmap,
449 &Black,&White,
450 hot_x,hot_y);
451 }