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