comparison src/offix.c @ 197:acd284d43ca1 r20-3b25

Import from CVS: tag r20-3b25
author cvs
date Mon, 13 Aug 2007 10:00:02 +0200
parents
children 78478c60bfcd
comparison
equal deleted inserted replaced
196:58e0786448ca 197:acd284d43ca1
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 <values.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 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 DndHandleDragging(Widget widget,XEvent *event)
105 {
106 XEvent Event;
107 Window root = RootWindowOfScreen(XtScreenOfObject(widget));
108 XtAppContext app= XtWidgetToApplicationContext(widget);
109 Window DispatchWindow;
110 int DropX,DropY;
111
112 if(Dragging) return 0;
113
114 XUngrabPointer(dpy,CurrentTime);
115 /* Take control over the pointer */
116 XGrabPointer(dpy,root,False,
117 ButtonMotionMask|ButtonPressMask|ButtonReleaseMask,
118 GrabModeSync,GrabModeAsync,root,
119 DndCursor[DataType].CursorID,
120 CurrentTime);
121
122 /* Wait for button release */
123 Dragging=1; RootFlag=0;
124 while(Dragging)
125 {
126 XAllowEvents(dpy,SyncPointer,CurrentTime);
127 XtAppNextEvent(app,&Event);
128 switch(Event.type)
129 {
130 case ButtonRelease:
131 if(Event.xbutton.subwindow)
132 RootFlag=0;
133 else
134 RootFlag=1;
135 Dragging=0;
136 break;
137 default:
138 XtDispatchEvent(&Event);
139 break;
140 }
141 }
142 DataOK=0;
143 /* Now release the pointer */
144 XUngrabPointer(dpy,CurrentTime);
145 /* Try to guess if the drop occurred in the root window */
146 if(!RootFlag)
147 {
148 Target=XmuClientWindow(dpy,Event.xbutton.subwindow);
149 if (Target==Event.xbutton.subwindow)
150 DispatchWindow=Target;
151 else
152 DispatchWindow=PointerWindow;
153 }
154 else
155 Target=DispatchWindow=XtWindow(MainWidget);
156
157 /* Now build the event structure */
158 DropX=Event.xbutton.x_root;
159 DropY=Event.xbutton.y_root;
160 Event.xclient.type = ClientMessage;
161 Event.xclient.display = dpy;
162 Event.xclient.message_type = DndProtocol;
163 Event.xclient.format = 32;
164 Event.xclient.window = Target;
165 Event.xclient.data.l[0] = DataType;
166 Event.xclient.data.l[1] = (long)event->xbutton.state;
167 Event.xclient.data.l[2] = (long)XtWindow(widget);
168 Event.xclient.data.l[3] = DropX + 65536L*(long)DropY;
169 Event.xclient.data.l[4] = 1;
170
171 /* Send the drop message */
172 XSendEvent(dpy,DispatchWindow,True,NoEventMask,&Event);
173 /* Send an old style version of the message just in case */
174 Event.xclient.message_type = OldDndProtocol;
175 XSendEvent(dpy,DispatchWindow,True,NoEventMask,&Event);
176
177 #ifdef DEBUG
178 fprintf(stderr,"ClientMessage sent to 0x%x(0x%x).\n",
179 DispatchWindow,Target);
180 fprintf(stderr,"The drop coordinates are (%d,%d).\n",DropX,DropY);
181 #endif
182
183 return 1;
184 }
185
186 /*=============================================================== DndIsIcon
187 * Return non-zero if the application is iconic (widget=toplevel)
188 *========================================================================*/
189 int
190 DndIsIcon(Widget widget)
191 {
192 Atom JunkAtom;
193 int JunkInt;
194 unsigned long WinState,JunkLong;
195 unsigned char *Property;
196
197 XGetWindowProperty(dpy,XtWindow(widget),WM_STATE,
198 0L,2L,False,AnyPropertyType,
199 &JunkAtom,&JunkInt,&WinState,&JunkLong,
200 &Property);
201 WinState=(unsigned long)(*((long*)Property));
202 return (WinState==3);
203 }
204
205 /*============================================================ DndInitialize
206 * Must be called anywhere before the top level widget creation and the
207 * main loop. Initialize global variables and bind the DndDispatch function
208 * to the top level widget. Creates the cursors to be used in drag actions.
209 *=========================================================================*/
210 void
211 DndInitialize(Widget shell)
212 {
213 int screen,i;
214 Colormap colormap;
215 Window root;
216
217 dpy = XtDisplayOfObject(shell);
218 screen = DefaultScreen(dpy);
219 colormap= DefaultColormap(dpy,screen);
220 root = DefaultRootWindow(dpy);
221
222
223 Black.pixel=BlackPixel(dpy,screen);
224 White.pixel=WhitePixel(dpy,screen);
225 XQueryColor(dpy,colormap,&Black);
226 XQueryColor(dpy,colormap,&White);
227
228 for(i=1;i!=DndEND;i++)
229 {
230 DndCursor[i].ImagePixmap=
231 XCreateBitmapFromData(dpy,root,
232 DndCursor[i].ImageData,
233 DndCursor[i].Width,
234 DndCursor[i].Height);
235 DndCursor[i].MaskPixmap=
236 XCreateBitmapFromData(dpy,root,
237 DndCursor[i].MaskData,
238 DndCursor[i].Width,
239 DndCursor[i].Height);
240 DndCursor[i].CursorID=
241 XCreatePixmapCursor(dpy,DndCursor[i].ImagePixmap,
242 DndCursor[i].MaskPixmap,
243 &Black,&White,
244 DndCursor[i].HotSpotX,
245 DndCursor[i].HotSpotY);
246 }
247
248 DndCursor[0].CursorID=XCreateFontCursor(dpy,XC_question_arrow);
249
250 /* These two are for older versions */
251 OldDndProtocol=XInternAtom(dpy,"DndProtocol",FALSE);
252 OldDndSelection=XInternAtom(dpy,"DndSelection",FALSE);
253 /* Now the correct stuff */
254 DndProtocol=XInternAtom(dpy,"_DND_PROTOCOL",FALSE);
255 DndSelection=XInternAtom(dpy,"_DND_SELECTION",FALSE);
256
257 WM_STATE=XInternAtom(dpy,"WM_STATE",True);
258 Dragging=0;
259 DragPrecision=10;
260 RootFlag=0;
261 MainWidget=shell;
262 }
263
264 int DndIsDragging(void) { return Dragging; }
265
266 /*================================================================= DndSetData
267 * Updates the selection data.
268 *===========================================================================*/
269 void DndSetData(int Type,unsigned char *Data,unsigned long Size)
270 {
271 Window root = DefaultRootWindow(dpy);
272 int AuxSize;
273 unsigned char *AuxData;
274 unsigned long BackSize=Size;
275
276 if (DataOK) return;
277
278 /* Set the data type -- allow any type */
279 DataType = Type;
280
281 /* Set the data */
282 AuxData = Data;
283 AuxSize = ( Size <= MAXINT ? (int)Size : MAXINT );
284 XChangeProperty(dpy,root,DndSelection,XA_STRING,8,
285 PropModeReplace,Data,AuxSize);
286 for(Size-=(unsigned long)AuxSize;Size;Size-=(unsigned long)AuxSize)
287 {
288 Data+=AuxSize;
289 AuxSize = ( (Size<=(MAXINT)) ? (int)Size : (MAXINT) );
290 XChangeProperty(dpy,root,DndSelection,XA_STRING,8,
291 PropModeAppend,Data,AuxSize);
292 }
293
294 /* Set the data for old DND version */
295 Size = BackSize;
296 AuxData = Data;
297 AuxSize = ( Size <= MAXINT ? (int)Size : MAXINT );
298 XChangeProperty(dpy,root,OldDndSelection,XA_STRING,8,
299 PropModeReplace,Data,AuxSize);
300 for(Size-=(unsigned long)AuxSize;Size;Size-=(unsigned long)AuxSize)
301 {
302 Data+=AuxSize;
303 AuxSize = ( (Size<=(MAXINT)) ? (int)Size : (MAXINT) );
304 XChangeProperty(dpy,root,OldDndSelection,XA_STRING,8,
305 PropModeAppend,Data,AuxSize);
306 }
307
308 /* Everything is now ok */
309 DataOK=1;
310 }
311
312 /*================================================================== DndGetData
313 * Return a pointer to the current data. Se HOWTO for more details.
314 *===========================================================================*/
315 void DndGetData(XEvent *event, unsigned char **Data,unsigned long *Size)
316 {
317 Window root = DefaultRootWindow(dpy);
318
319 Atom ActualType,ActualDndSelection;
320 int ActualFormat;
321 unsigned long RemainingBytes;
322
323 ActualDndSelection=(DndProtocolVersion(event) == 0L ?
324 OldDndSelection :
325 DndSelection );
326
327 XGetWindowProperty(dpy,root,ActualDndSelection,
328 0L,1000000L,
329 FALSE,AnyPropertyType,
330 &ActualType,&ActualFormat,
331 Size,&RemainingBytes,
332 Data);
333 }
334
335 /*================================== DndDataType DndDragButtons DndSourceWidget
336 *
337 * Return information about the Dnd event received. If a non-dnd event is
338 * passed, the function DndDataType returns DndNotDnd, and the others
339 * return zero.
340 *===========================================================================*/
341 int DndDataType(XEvent *event)
342 {
343 int Type;
344
345 if(!DndIsDropMessage(event)) return DndNotDnd;
346 Type=(int)(event->xclient.data.l[0]);
347 if(Type>=DndEND) Type=DndUnknown;
348 return Type;
349 }
350
351 unsigned int DndDragButtons(XEvent *event)
352 {
353 if(!DndIsDropMessage(event)) return 0;
354 return (unsigned int)(event->xclient.data.l[1]);
355 }
356
357 Window DndSourceWindow(XEvent *event)
358 {
359 if(!DndIsDropMessage(event)) return 0;
360 if(DndProtocolVersion(event)<__DragAndDropH__)
361 /* We will try to do something about it, but nothing is certain */
362 return XtWindow((Widget)(event->xclient.data.l[2]));
363 return (Window)(event->xclient.data.l[2]);
364 }
365
366 void DndDropRootCoordinates(XEvent *event,int *x,int *y)
367 {
368 if(!DndIsDropMessage(event))
369 {
370 *x=0; *y=0;
371 return;
372 }
373
374 /* If it is an old protocol version we try to get the coordinates
375 using the current pointer position. Of course, the pointer may have
376 moved since the drop, but there's nothing we can do about it.
377 */
378 if(DndProtocolVersion(event)<1L)
379 {
380 Window root_return,child_return;
381 int win_x_return,win_y_return;
382 unsigned int mask_return;
383
384 XQueryPointer(dpy,DefaultRootWindow(dpy),
385 &root_return,&child_return,x,y,
386 &win_x_return,&win_y_return,&mask_return);
387 return;
388 }
389 /* Thanks god you are using a decent protocol version */
390 *x=(int)((long)(event->xclient.data.l[3]) & 0xffff);
391 *y=(int)((long)(event->xclient.data.l[3])/65536);
392 }
393
394 void DndDropCoordinates(Widget widget,XEvent *event,int *x,int *y)
395 {
396 int root_x,root_y;
397 Window child_return;
398
399 DndDropRootCoordinates(event,&root_x,&root_y);
400 XTranslateCoordinates(dpy,DefaultRootWindow(dpy),
401 XtWindow(widget),
402 root_x,root_y,
403 x,y,
404 &child_return);
405 }
406
407 long DndProtocolVersion(XEvent *event)
408 {
409 if(!DndIsDropMessage(event)) return -1L;
410 return event->xclient.data.l[4];
411 }
412
413 int DndIsDropMessage(XEvent *event)
414 {
415 if(event->xclient.type != ClientMessage) return 0;
416 if(event->xclient.message_type == OldDndProtocol &&
417 event->xclient.data.l[4]==0) return 1;
418 if(event->xclient.message_type == DndProtocol) return 1;
419 return 0;
420 }
421
422 void DndChangeCursor(int Type,int width,int height,char *image,char *mask,
423 int hot_x,int hot_y)
424 {
425 DndCursor[Type].ImagePixmap=
426 XCreateBitmapFromData(dpy,DefaultRootWindow(dpy),
427 image,width,height);
428 DndCursor[Type].MaskPixmap=
429 XCreateBitmapFromData(dpy,DefaultRootWindow(dpy),
430 mask,width,height);
431 DndCursor[Type].CursorID=
432 XCreatePixmapCursor(dpy,DndCursor[Type].ImagePixmap,
433 DndCursor[Type].MaskPixmap,
434 &Black,&White,
435 hot_x,hot_y);
436 }