Mercurial > hg > xemacs-beta
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 } |