1 /**
2 *
3 * $Id: DragBS.c,v 1.2 2006/02/10 21:30:38 dannybackx Exp $
4 *
5 * Copyright (C) 1995 Free Software Foundation, Inc.
6 * Copyright � 1995-2001, 2006 LessTif Development Team
7 *
8 * This file is part of the GNU LessTif Library.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 **/
25
26 static const char rcsid[] = "$Id: DragBS.c,v 1.2 2006/02/10 21:30:38 dannybackx Exp $";
27
28 #include <LTconfig.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <XmI/XmI.h>
35 #include <Xm/XmP.h>
36 #include <Xm/DisplayP.h>
37 #include <Xm/AtomMgr.h>
38 #include <XmI/AtomMgrI.h>
39 #include <XmI/DragDropI.h>
40 #include <XmI/CutPasteI.h>
41
42 #include <XmI/DebugUtil.h>
43
44 /*
45 * here's a little tidbit to look at. If you've run mwm, or a Motif
46 * application, do an 'xprop' on the root window. You'll see a property
47 * _MOTIF_DRAG_WINDOW; now, do an xprop on _it_. Interesting things running
48 * around there, no? This stuff is crucial to DnD...
49 *
50 * Daniel Dardailler's documentation is invaluable to actually understanding
51 * this mess.
52 *
53 * convention: read/write refers to properties. get/set refers to
54 * XContexts.
55 *
56 * Don't panic when you find all the XGrabServer/XUngrabServer pairs.
57 * Basically, they delineate critical sections where only the grabber should
58 * have access to the X server.
59 */
60
61 /* amai: Hmm, well for now it's just for convenience to help on debugging.
62 * it used to be 100000L
63 */
64 #define PROP_LENGTH 200000L
65
66
67 /*
68 * these are used for protected sections
69 */
70 static Boolean error_flag, bad_window;
71 static int (*oldErrorHandler) (Display *, XErrorEvent *);
72 static int firstProtectRequest;
73 static Window errorWindow = None;
74
75 /*
76 * these targets should always be present on the drag window
77 */
78 static Atom noTarget = 0, stringTarget = XA_STRING;
79
80 /*
81 * some contexts for the drag window, the atoms table, and the targets table.
82 */
83 static XContext displayToDW = None;
84 static XContext displayToAtoms = None;
85 static XContext displayToTargets = None;
86
87
88 /*
89 * basic atoms that must be agreed on
90 */
91 static char *motifAtoms[] =
92 {
93 _XA_MOTIF_DRAG_WINDOW,
94 _XA_MOTIF_DRAG_ATOM_PAIRS,
95 _XA_MOTIF_DRAG_ATOMS,
96 _XA_MOTIF_ATOM_0,
97 _XA_MOTIF_DRAG_TARGETS,
98 _XA_MOTIF_WM_OFFSET,
99 _XA_MOTIF_DRAG_PROXY_WINDOW,
100 _XA_MOTIF_WM_MESSAGES,
101 _XA_MOTIF_WM_HINTS,
102 _XA_MOTIF_WM_MENU,
103 _XA_MOTIF_WM_INFO,
104 _XA_MOTIF_BINDINGS,
105 _XA_ATOM_PAIR,
106 _XA_AVERAGE_WIDTH,
107 _XA_CLIPBOARD,
108 _XA_CLIP_TEMPORARY,
109 _XA_COMPOUND_TEXT,
110 _XA_DELETE,
111 _XA_INCR,
112 _XA_INSERT_SELECTION,
113 _XA_LENGTH,
114 _XA_MOTIF_DESTINATION,
115 _XA_MULTIPLE,
116 _XA_PIXEL_SIZE,
117 _XA_RESOLUTION_Y,
118 _XA_TARGETS,
119 _XA_TEXT,
120 _XA_TIMESTAMP,
121 _XA_WM_DELETE_WINDOW,
122 _XA_WM_PROTOCOLS,
123 _XA_WM_STATE,
124 _XA_XmTRANSFER_SUCCESS,
125 _XA_XmTRANSFER_FAILURE,
126 _XA_MOTIF_CLIP_DATA_DELETE,
127 _XA_MOTIF_CLIP_DATA_REQUEST,
128 _XA_MOTIF_CLIP_HEADER,
129 _XA_MOTIF_CLIP_LOCK_ACCESS_VALID,
130 _XA_MOTIF_CLIP_MESSAGE,
131 _XA_MOTIF_CLIP_NEXT_ID,
132 _XA_MOTIF_CLIP_TIME,
133 _XA_MOTIF_DROP,
134 _XA_MOTIF_DRAG_INITIATOR_INFO,
135 _XA_MOTIF_DRAG_RECEIVER_INFO,
136 _XA_MOTIF_MESSAGE,
137 _XA_XM_TEXT_I_S_PROP
138 };
139
140
141 static int
DWError(Display * display,XErrorEvent * event)142 DWError(Display *display, XErrorEvent *event)
143 {
144 error_flag = True;
145
146 return 0;
147 }
148
149
150 /*
151 * create the drag window
152 */
153 static Window
create_drag_window(Display * display)154 create_drag_window(Display *display)
155 {
156 Window win;
157 XSetWindowAttributes attr;
158
159
160 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:create_drag_window(%d)\n",
161 __FILE__, __LINE__));
162
163 attr.override_redirect = True;
164 attr.event_mask = PropertyChangeMask;
165
166 win = XCreateWindow(display, DefaultRootWindow(display),
167 -100, -100, 10, 10, 0, 0,
168 InputOnly, CopyFromParent,
169 (CWOverrideRedirect | CWEventMask),
170 &attr);
171
172 XMapWindow(display, win);
173
174 return win;
175 }
176
177
178 /*
179 * see if the drag window property can be found on the root window
180 */
181 static Window
read_drag_window(Display * display)182 read_drag_window(Display *display)
183 {
184 int (*old_handler) (Display *, XErrorEvent *);
185 Atom mw, atype;
186 int aformat;
187 unsigned long nitems, bafter;
188 unsigned char *prop = NULL;
189 Window win = None;
190
191
192 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_drag_window(%d)\n",
193 __FILE__, __LINE__));
194
195 old_handler = XSetErrorHandler(DWError);
196
197 error_flag = False;
198
199 mw = XmInternAtom(display, _XA_MOTIF_DRAG_WINDOW, False);
200
201 if (XGetWindowProperty(display, DefaultRootWindow(display),
202 mw, 0L, PROP_LENGTH,
203 False, AnyPropertyType,
204 &atype, &aformat, &nitems, &bafter, &prop)
205 == Success && atype == XA_WINDOW && aformat == 32 && nitems == 1)
206 {
207 win = *((Window *)prop);
208 }
209 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_drag_window(%d) - bafter=%i\n",
210 __FILE__, __LINE__, bafter));
211 if (prop)
212 {
213 XFree((char *)prop);
214 }
215
216 XSetErrorHandler(old_handler);
217
218 if (error_flag)
219 {
220 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_drag_window(%d) - None\n",
221 __FILE__, __LINE__));
222
223 return None;
224 }
225
226 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_drag_window(%d) - %p\n",
227 __FILE__, __LINE__, win));
228
229 return win;
230 }
231
232
233 /*
234 * set the drag window property on the root window
235 */
236 static void
write_drag_window(Display * display,Window * win)237 write_drag_window(Display *display, Window *win)
238 {
239 Atom mw;
240
241 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:write_drag_window(%d)\n",
242 __FILE__, __LINE__));
243
244 mw = XmInternAtom(display, _XA_MOTIF_DRAG_WINDOW, False);
245
246 XChangeProperty(display, DefaultRootWindow(display), mw,
247 XA_WINDOW, 32, PropModeReplace, (unsigned char *)win, 1);
248 }
249
250
251 /*
252 * lookup (program local) the value of the drag window
253 */
254 static Window
get_drag_window(Display * display)255 get_drag_window(Display *display)
256 {
257 Window win;
258
259 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:get_drag_window(%d)\n",
260 __FILE__, __LINE__));
261
262 if (displayToDW == None)
263 {
264 displayToDW = XUniqueContext();
265 }
266
267 if (XFindContext(display, DefaultRootWindow(display),
268 displayToDW, (XPointer *)&win) == XCSUCCESS)
269 {
270 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:get_drag_window(%d) - %p\n",
271 __FILE__, __LINE__, win));
272
273 return win;
274 }
275
276 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:get_drag_window(%d) - None\n",
277 __FILE__, __LINE__));
278
279 return None;
280 }
281
282
283 /*
284 * cache (program local) the value of the drag window
285 */
286 static void
set_drag_window(Display * display,Window win)287 set_drag_window(Display *display, Window win)
288 {
289 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:set_drag_window(%d)\n",
290 __FILE__, __LINE__));
291
292 if (displayToDW == None)
293 {
294 displayToDW = XUniqueContext();
295 }
296
297 if (XFindContext(display, DefaultRootWindow(display),
298 displayToDW, (XPointer *)&win) == XCSUCCESS)
299 {
300 XDeleteContext(display, DefaultRootWindow(display),
301 displayToDW);
302 }
303
304 XSaveContext(display, DefaultRootWindow(display),
305 displayToDW, (XPointer)win);
306 }
307
308
309 /*
310 * catch window errors when fetching or setting the DRAG_WINDOW properties
311 */
312 static int
protect_handler(Display * display,XErrorEvent * event)313 protect_handler(Display *display, XErrorEvent *event)
314 {
315 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:protect_handler(%d)\n",
316 __FILE__, __LINE__));
317
318 if (event->error_code == BadWindow &&
319 event->resourceid == errorWindow &&
320 event->serial >= firstProtectRequest)
321 {
322 bad_window = True;
323
324 return 0;
325 }
326
327 if (oldErrorHandler == NULL)
328 {
329 return 0;
330 }
331
332 return (*oldErrorHandler) (display, event);
333 }
334
335
336 /*
337 * begin catching window errors
338 */
339 static void
begin_protection(Display * display,Window win)340 begin_protection(Display *display, Window win)
341 {
342 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:begin_protection(%d)\n",
343 __FILE__, __LINE__));
344
345 bad_window = False;
346
347 oldErrorHandler = XSetErrorHandler(protect_handler);
348
349 firstProtectRequest = NextRequest(display);
350
351 errorWindow = win;
352 }
353
354
355 /*
356 * end catching window errors
357 */
358 static void
end_protection(Display * display)359 end_protection(Display *display)
360 {
361 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:end_protection(%d)\n",
362 __FILE__, __LINE__));
363
364 XSync(display, False);
365
366 XSetErrorHandler(oldErrorHandler);
367
368 oldErrorHandler = NULL;
369 }
370
371
372 /*
373 * extracts n values (formatted as CARD32) from the drag buffer and
374 * converts them to Atoms
375 */
376 static void
read_atoms_from_drag_buffer(XmDndBufMgr bmgr,int n,Boolean swap,Atom * atoms)377 read_atoms_from_drag_buffer(XmDndBufMgr bmgr, int n, Boolean swap, Atom* atoms)
378 {
379 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atoms_from_drag_buffer(%d) - count %d swap %s\n",
380 __FILE__, __LINE__,
381 n, swap ? "True" : "False"));
382
383 if (sizeof(Atom) == sizeof(CARD32))
384 {
385 _XmReadDragBuffer(bmgr, False, (char*) atoms, sizeof(Atom) * n);
386 if (swap)
387 {
388 int i;
389
390 for (i = 0; i < n; i++)
391 {
392 SWAP4BYTES(atoms[i]);
393 }
394 }
395 }
396 else {
397 CARD32 in;
398 int i;
399
400 if (swap)
401 {
402 for (i = 0; i < n; i++)
403 {
404 _XmReadDragBuffer(bmgr, False, (char*) &in, sizeof(CARD32));
405 SWAP4BYTES(in);
406 atoms[i] = in;
407 }
408 }
409 else {
410 for (i = 0; i < n; i++)
411 {
412 _XmReadDragBuffer(bmgr, False, (char*) &in, sizeof(CARD32));
413 atoms[i] = in;
414 }
415 }
416 }
417 }
418
419
420 /*
421 * writes nent Atoms to the drag buffer
422 */
423 static void
write_atoms_to_drag_buffer(XmDndBufMgr bmgr,int n,Atom * atoms)424 write_atoms_to_drag_buffer(XmDndBufMgr bmgr, int n, Atom* atoms)
425 {
426 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:write_atoms_to_drag_buffer(%d) - count %d\n",
427 __FILE__, __LINE__,
428 n));
429
430 if (sizeof(Atom) == sizeof(CARD32))
431 {
432 _XmWriteDragBuffer(bmgr, False, (char*) atoms, sizeof(Atom) * n);
433 }
434 else {
435 CARD32 out;
436 int i;
437
438 for (i = 0; i < n; i++)
439 {
440 out = atoms[i];
441 _XmWriteDragBuffer(bmgr, False, (char*) &out, sizeof(CARD32));
442 }
443 }
444 }
445
446
447 /*
448 * read from a drag buffer (sort of)
449 * probably for Motif BC (binary compatibility?!)
450 */
451 extern int
_XmReadDragBuffer(XmDndBufMgr bmgr,Boolean read_string,char * retbuf,int bufsize)452 _XmReadDragBuffer(XmDndBufMgr bmgr, Boolean read_string,
453 char *retbuf, int bufsize)
454 {
455 int rsize, eaten;
456 int size;
457
458 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmReadDragBuffer(%d) - read_string %s size %i\n",
459 __FILE__, __LINE__,
460 read_string ? "True" : "False",
461 bufsize));
462
463 if (read_string)
464 {
465 rsize = bmgr->name_size;
466 eaten = bmgr->name_start - bmgr->names;
467
468 if (eaten>rsize) {
469 /* amai: in my understanding this is a major problem and
470 should never happen */
471 _XmWarning(NULL, "%s(%i): eaten=%i > rsize=%i\n",
472 __FILE__, __LINE__, eaten, rsize);
473 /* abort(); */
474 size=0;
475 }
476 else {
477 size = rsize-eaten;
478 if (size > bufsize)
479 size = bufsize;
480 }
481 memcpy(retbuf, bmgr->name_start, size);
482 bmgr->name_start += size;
483 return size;
484 }
485 else
486 {
487 rsize = bmgr->atom_size;
488 eaten = (int)(bmgr->atom_start - bmgr->atoms);
489
490 if (eaten>rsize) {
491 /* amai: in my understanding this is a major problem and
492 should never happen */
493 _XmWarning(NULL, "%s(%i): eaten=%i > rsize=%i\n",
494 __FILE__, __LINE__, eaten, rsize);
495 /* abort(); */
496 size=0;
497 }
498 else {
499 size = rsize-eaten;
500 if (size > bufsize)
501 size = bufsize;
502 }
503 /* fprintf(stderr, "rsize=%i, eaten=%i, bufsize=%i, size=%i\n",
504 rsize, eaten, bufsize, size); */
505 memcpy(retbuf, bmgr->atom_start, size);
506 bmgr->atom_start += size;
507 return size;
508 }
509 }
510
511
512 /*
513 * write to a drag buffer (sort of)
514 * probably for Motif BC (binary compatibility?!)
515 */
516 extern int
_XmWriteDragBuffer(XmDndBufMgr bmgr,Boolean write_string,char * data,int size)517 _XmWriteDragBuffer(XmDndBufMgr bmgr, Boolean write_string,
518 char *data, int size)
519 {
520 int increase_needed;
521
522 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmWriteDragBuffer(%d) write_string %s size %i\n",
523 __FILE__, __LINE__,
524 write_string ? "True" : "False",
525 size));
526
527 if (write_string)
528 {
529 increase_needed = (bmgr->name_size + size) - bmgr->name_avail;
530 if (increase_needed > 0)
531 {
532 increase_needed /= 1000;
533 increase_needed++;
534 increase_needed *= 1000;
535 bmgr->name_avail += increase_needed;
536
537 if (bmgr->names == bmgr->name_ptr)
538 {
539 bmgr->names = XtMalloc(bmgr->name_avail);
540 memcpy(bmgr->names, bmgr->name_ptr, bmgr->name_size);
541 }
542 else
543 {
544 bmgr->names = XtRealloc((char *)bmgr->names, bmgr->name_avail);
545 }
546 }
547
548 memcpy(bmgr->names + bmgr->name_size, data, size);
549 bmgr->name_size += size;
550
551 return size;
552 }
553 else
554 {
555 increase_needed = (bmgr->atom_size + size) - bmgr->atom_avail;
556 if (increase_needed)
557 {
558 increase_needed /= 1000;
559 increase_needed++;
560 increase_needed *= 1000;
561 bmgr->atom_avail += increase_needed;
562 if (bmgr->atoms == bmgr->atom_ptr)
563 {
564 bmgr->atoms = XtMalloc(bmgr->atom_avail);
565 memcpy(bmgr->atoms, bmgr->atom_ptr, bmgr->atom_size);
566 }
567 else
568 {
569 bmgr->atoms = XtRealloc(bmgr->atoms, bmgr->atom_avail);
570 }
571 }
572
573 memcpy(bmgr->atoms + bmgr->atom_size, data, size);
574 bmgr->atom_size += size;
575
576 return size;
577 }
578 }
579
580
581 /*
582 * get the ATOM_PAIRS. They may or may not already exist
583 */
584 static Boolean
read_atom_pairs(Display * display)585 read_atom_pairs(Display *display)
586 {
587 Atom pa, atype;
588 Window win;
589 Boolean gotit = False;
590 XmDndAtomPairs *pairs;
591 XmDndBufMgrRec bmgr;
592 int i;
593 XmDndAtomPair pair;
594 char buf[32];
595 int aformat;
596 unsigned long nitems, bafter;
597 unsigned char *prop = NULL;
598
599 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atom_pairs(%d)\n",
600 __FILE__, __LINE__));
601
602 pa = XmInternAtom(display, _XA_MOTIF_DRAG_ATOM_PAIRS, False);
603
604 win = get_drag_window(display);
605
606 begin_protection(display, win);
607
608 if (XGetWindowProperty(display, win, pa, 0L, PROP_LENGTH,
609 False, pa,
610 &atype, &aformat, &nitems, &bafter,
611 (unsigned char **)&pairs) == Success &&
612 nitems >= 8 && pairs != NULL)
613 {
614 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atom_pairs(%d) - got property, bafter=%i\n",
615 __FILE__, __LINE__, bafter));
616
617 gotit = True;
618 prop = (unsigned char *)pairs;
619 }
620 end_protection(display);
621
622 if (bad_window)
623 {
624 _XmWarning((Widget)XmGetXmDisplay(display),
625 "Bad window ATOM_PAIRS property on DRAG_WINDOW.");
626 }
627
628 if (!gotit)
629 {
630 #if 0
631 _XmWarning((Widget)XmGetXmDisplay(display),
632 "No ATOM_PAIRS property on DRAG_WINDOW.");
633 #endif
634
635 if (prop)
636 {
637 XFree((char *)prop);
638 }
639
640 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atom_pairs(%d) - did not get property\n",
641 __FILE__, __LINE__));
642
643 return False;
644 }
645
646 if (pairs->protocol_version != DND_PROTOCOL_VERSION)
647 {
648 _XmWarning((Widget)XmGetXmDisplay(display),
649 "DND Protocol version mismatch.");
650 }
651
652 if (pairs->byte_order != _XmByteOrder())
653 {
654 SWAP2BYTES(pairs->num_pairs);
655 SWAP4BYTES(pairs->data_size);
656 }
657
658 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atom_pairs(%d) - %i pairs\n",
659 __FILE__, __LINE__,
660 pairs->num_pairs));
661
662 if (pairs->num_pairs > 0)
663 {
664 bmgr.atoms = (char *)pairs;
665 bmgr.atom_start = (char *)(pairs + 1);
666 bmgr.atom_size = pairs->data_size;
667 bmgr.names = (char *)pairs + pairs->data_size;
668 bmgr.name_start = (char *)pairs + pairs->data_size;
669 bmgr.name_size = nitems - pairs->data_size;
670
671 for (i = 0; i < pairs->num_pairs; i++)
672 {
673 _XmReadDragBuffer(&bmgr, False, (char *)&pair,
674 sizeof(XmDndAtomPair));
675
676 if (pairs->byte_order != _XmByteOrder())
677 {
678 SWAP4BYTES(pair.atom);
679 SWAP2BYTES(pair.namelen);
680 }
681
682 _XmReadDragBuffer(&bmgr, True, buf, pair.namelen);
683
684 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atom_pairs(%d) - intern %s\n",
685 __FILE__, __LINE__,
686 buf));
687
688 _XmInternAtomAndName(display, pair.atom, buf);
689 }
690 }
691
692 if (prop)
693 {
694 XFree((char *)prop);
695 }
696
697 return gotit;
698 }
699
700
701 /*
702 * if the ATOM_PAIRS didn't exist, put them on the drag window
703 */
704 static void
write_atom_pairs(Display * display)705 write_atom_pairs(Display *display)
706 {
707 char pairs[1000];
708 char names[1000];
709 XmDndAtomPairs pair_rec;
710 XmDndBufMgrRec bmgr;
711 XmDndAtomPair pair;
712 Atom pa;
713 int i;
714 Window win;
715
716 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:write_atom_pairs(%d)\n",
717 __FILE__, __LINE__));
718
719 pair_rec.byte_order = _XmByteOrder();
720 pair_rec.protocol_version = DND_PROTOCOL_VERSION;
721 pair_rec.num_pairs = XtNumber(motifAtoms);
722
723 bmgr.atoms = pairs;
724 bmgr.atom_ptr = pairs;
725 bmgr.atom_start = NULL;
726 bmgr.atom_size = 0;
727 bmgr.atom_avail = 1000;
728 bmgr.names = names;
729 bmgr.name_ptr = names;
730 bmgr.name_start = NULL;
731 bmgr.name_size = 0;
732 bmgr.name_avail = 1000;
733
734 _XmWriteDragBuffer(&bmgr, False, (char *)&pair_rec, sizeof(XmDndAtomPairs));
735
736 for (i = 0; i < XtNumber(motifAtoms); i++)
737 {
738 pair.atom = XmInternAtom(display, motifAtoms[i], False);
739
740 pair.namelen = strlen(motifAtoms[i]) + 1;
741
742 _XmWriteDragBuffer(&bmgr, True, motifAtoms[i], pair.namelen);
743
744 _XmWriteDragBuffer(&bmgr, False, (char *)&pair, sizeof(XmDndAtomPair));
745
746 }
747
748 ((XmDndAtomPairs *) (bmgr.atoms))->data_size = bmgr.atom_size;
749
750 pa = XmInternAtom(display, _XA_MOTIF_DRAG_ATOM_PAIRS, False);
751
752 win = get_drag_window(display);
753
754 begin_protection(display, win);
755
756 XChangeProperty(display, win, pa, pa, 8, PropModeReplace,
757 (unsigned char *)bmgr.atoms, bmgr.atom_size);
758
759 if (bmgr.atoms != bmgr.atom_ptr)
760 {
761 XtFree(bmgr.atoms);
762 }
763
764 if (bmgr.name_size)
765 {
766 XChangeProperty(display, win, pa, pa, 8, PropModeAppend,
767 (unsigned char *)bmgr.names, bmgr.name_size);
768
769 if (bmgr.names != bmgr.name_ptr)
770 {
771 XtFree(bmgr.names);
772 }
773 }
774
775 end_protection(display);
776
777 if (bad_window)
778 {
779 _XmWarning((Widget)XmGetXmDisplay(display),
780 "Bad window writing ATOM_PAIRS property on DRAG_WINDOW.");
781 }
782 }
783
784
785 /*
786 * fetch the cached atoms table
787 */
788 static XmDndAtomsTable
get_atoms_table(Display * display)789 get_atoms_table(Display *display)
790 {
791 XmDndAtomsTable tbl = NULL;
792
793 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:get_atoms_table(%d)\n",
794 __FILE__, __LINE__));
795
796 if (displayToAtoms == (XContext)0)
797 {
798 displayToAtoms = XUniqueContext();
799 }
800
801 if (XFindContext(display, DefaultRootWindow(display),
802 displayToAtoms, (XPointer *)&tbl) != XCSUCCESS)
803 {
804 return NULL;
805 }
806
807 return tbl;
808 }
809
810
811 /*
812 * cache the atoms table
813 */
814 static void
set_atoms_table(Display * display,XmDndAtomsTable table)815 set_atoms_table(Display *display, XmDndAtomsTable table)
816 {
817 XmDndAtomsTable atoms;
818
819 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:set_atoms_table(%d)\n",
820 __FILE__, __LINE__));
821
822 if (displayToAtoms == (XContext)0)
823 displayToAtoms = XUniqueContext();
824
825 if (XFindContext(display, DefaultRootWindow(display),
826 displayToAtoms, (XPointer *)&atoms) == XCSUCCESS)
827 {
828 if (atoms == table)
829 {
830 return;
831 }
832
833 XDeleteContext(display, DefaultRootWindow(display),
834 displayToAtoms);
835 }
836
837 XSaveContext(display, DefaultRootWindow(display),
838 displayToAtoms, (XPointer)table);
839 }
840
841
842 static XmDndAtomsTable
create_default_atoms_table(Display * display)843 create_default_atoms_table(Display *display)
844 {
845 XmDndAtomsTable tbl;
846
847 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:create_default_atoms_table(%d)\n",
848 __FILE__, __LINE__));
849
850 tbl = (XmDndAtomsTable) XtMalloc(sizeof(XmDndAtomsTableRec));
851 tbl->num_entries = 1;
852
853 tbl->entries =
854 (XmDndAtomsTableEntry) XtMalloc(sizeof(XmDndAtomsTableEntryRec));
855
856 tbl->entries->atom = XmInternAtom(display, _XA_MOTIF_ATOM_0, False);
857 tbl->entries->time = CurrentTime;
858
859 set_atoms_table(display, tbl);
860
861 return tbl;
862 }
863
864
865 static Boolean
read_atoms_table(Display * display,XmDndAtomsTable tbl)866 read_atoms_table(Display *display, XmDndAtomsTable tbl)
867 {
868 Atom da, atype;
869 Window win;
870 int aformat, i;
871 unsigned long nitems, bafter;
872 XmDndAtoms *atoms = NULL;
873 Boolean got_it = False;
874 XmDndAtomsTableEntryRec atom_ent;
875 XmDndBufMgrRec bmgr;
876
877 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atoms_table(%d)\n",
878 __FILE__, __LINE__));
879
880 da = XmInternAtom(display, _XA_MOTIF_DRAG_ATOMS, False);
881
882 win = get_drag_window(display);
883
884 begin_protection(display, win);
885
886 if (XGetWindowProperty(display, win, da, 0L, PROP_LENGTH,
887 False, da,
888 &atype, &aformat, &nitems, &bafter,
889 (unsigned char **)&atoms) == Success &&
890 nitems >= 8)
891 {
892 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_atom_pairs(%d) - got property, bafter=%i\n",
893 __FILE__, __LINE__, bafter));
894 got_it = True;
895 }
896
897 end_protection(display);
898
899 if (bad_window)
900 {
901 _XmWarning((Widget)XmGetXmDisplay(display),
902 "Invalid DRAG WINDOW fetching DRAG_ATOMS.");
903 }
904
905 if (!got_it)
906 {
907 if (atoms)
908 {
909 XFree((XPointer)atoms);
910 }
911
912 return False;
913 }
914
915 if (atoms->protocol_version != DND_PROTOCOL_VERSION)
916 {
917 _XmWarning((Widget)XmGetXmDisplay(display),
918 "DND Protocol version mismatch.");
919 }
920
921 if (atoms->byte_order != _XmByteOrder())
922 {
923 SWAP2BYTES(atoms->num_atoms);
924 SWAP4BYTES(atoms->data_size);
925 }
926
927 if (!tbl)
928 {
929 tbl = (XmDndAtomsTable) XtMalloc(sizeof(XmDndAtomsTableRec));
930
931 tbl->num_entries = 0;
932 tbl->entries = NULL;
933
934 set_atoms_table(display, tbl);
935 }
936
937 if (tbl->num_entries < atoms->num_atoms)
938 {
939 tbl->entries = (XmDndAtomsTableEntry) XtRealloc((char *)tbl->entries,
940 atoms->num_atoms *
941 sizeof(XmDndAtomsTableEntryRec));
942 }
943
944 if (atoms->num_atoms > 0)
945 {
946
947 bmgr.atoms = (char *)atoms;
948 bmgr.atom_start = (char *)(atoms + 1);
949 bmgr.atom_size = atoms->data_size;
950
951 for (i = 0; i < atoms->num_atoms; i++)
952 {
953 _XmReadDragBuffer(&bmgr, False, (char *)&atom_ent,
954 sizeof(XmDndAtomsTableEntryRec));
955
956 if (atoms->byte_order != _XmByteOrder())
957 {
958 SWAP4BYTES(atom_ent.atom);
959 SWAP4BYTES(atom_ent.time);
960 }
961
962 tbl->entries[i].atom = atom_ent.atom;
963 tbl->entries[i].time = atom_ent.time;
964 }
965 }
966
967 return True;
968 }
969
970
971 /*
972 * write the atoms table out to the drag window
973 */
974 static void
write_atoms_table(Display * display,XmDndAtomsTable tbl)975 write_atoms_table(Display *display, XmDndAtomsTable tbl)
976 {
977 char atoms[1000];
978 XmDndAtoms atoms_rec;
979 XmDndBufMgrRec bmgr;
980 Atom pa;
981 int i;
982 Window win;
983
984 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:write_atoms_table(%d)\n",
985 __FILE__, __LINE__));
986
987 if (tbl == NULL)
988 {
989 _XmWarning((Widget)XmGetXmDisplay(display),
990 "No DRAG_ATOMS to write to DRAG_WINDOW.");
991
992 return;
993 }
994
995 atoms_rec.byte_order = _XmByteOrder();
996 atoms_rec.protocol_version = DND_PROTOCOL_VERSION;
997 atoms_rec.num_atoms = tbl->num_entries;
998
999 bmgr.atoms = atoms;
1000 bmgr.atom_ptr = atoms;
1001 bmgr.atom_start = NULL;
1002 bmgr.atom_size = 0;
1003 bmgr.atom_avail = 1000;
1004
1005 _XmWriteDragBuffer(&bmgr, False, (char *)&atoms_rec, sizeof(XmDndAtoms));
1006
1007 for (i = 0; i < tbl->num_entries; i++)
1008 {
1009 _XmWriteDragBuffer(&bmgr, False, (char *)&tbl->entries[i],
1010 sizeof(XmDndAtomsTableEntryRec));
1011
1012 }
1013
1014 ((XmDndAtoms *) (bmgr.atoms))->data_size = bmgr.atom_size;
1015
1016 pa = XmInternAtom(display, _XA_MOTIF_DRAG_ATOMS, False);
1017
1018 win = get_drag_window(display);
1019
1020 begin_protection(display, win);
1021
1022 XChangeProperty(display, win, pa, pa, 8, PropModeReplace,
1023 (unsigned char *)bmgr.atoms, bmgr.atom_size);
1024
1025 if (bmgr.atoms != bmgr.atom_ptr)
1026 {
1027 XtFree(bmgr.atoms);
1028 }
1029
1030 end_protection(display);
1031
1032 if (bad_window)
1033 {
1034 _XmWarning((Widget)XmGetXmDisplay(display),
1035 "Bad window writing DRAG_ATOMS on DRAG_WINDOW.");
1036 }
1037 }
1038
1039
1040 /*
1041 * fetch the cached atoms table
1042 */
1043 static XmDndTargetsTable
get_targets_table(Display * display)1044 get_targets_table(Display *display)
1045 {
1046 XmDndTargetsTable targets = NULL;
1047
1048 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:get_targets_table(%d)\n",
1049 __FILE__, __LINE__));
1050
1051 if (displayToTargets == (XContext)0)
1052 {
1053 displayToTargets = XUniqueContext();
1054 }
1055
1056 if (XFindContext(display, DefaultRootWindow(display),
1057 displayToTargets, (XPointer *)&targets) != XCSUCCESS)
1058 {
1059 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:get_targets_table(%d) - NULL\n",
1060 __FILE__, __LINE__));
1061
1062 return NULL;
1063 }
1064
1065 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:get_targets_table(%d) - %p\n",
1066 __FILE__, __LINE__, targets));
1067
1068 return targets;
1069 }
1070
1071
1072 /*
1073 * cache the atoms table
1074 */
1075 static void
set_targets_table(Display * display,XmDndTargetsTable table)1076 set_targets_table(Display *display, XmDndTargetsTable table)
1077 {
1078 XmDndTargetsTable targets;
1079
1080 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:set_targets_table(%d) - %p\n",
1081 __FILE__, __LINE__, table));
1082
1083 if (displayToTargets == (XContext)0)
1084 {
1085 displayToTargets = XUniqueContext();
1086 }
1087
1088 if (XFindContext(display, DefaultRootWindow(display),
1089 displayToTargets, (XPointer *)&targets) == XCSUCCESS)
1090 {
1091
1092 if (targets == table)
1093 {
1094 return;
1095 }
1096
1097 XDeleteContext(display, DefaultRootWindow(display),
1098 displayToTargets);
1099 }
1100
1101 XSaveContext(display, DefaultRootWindow(display),
1102 displayToTargets, (XPointer)table);
1103 }
1104
1105
1106 /*
1107 * create the default target table
1108 */
1109 static XmDndTargetsTable
create_default_targets_table(Display * display)1110 create_default_targets_table(Display *display)
1111 {
1112 XmDndTargetsTable tbl;
1113
1114 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:create_default_targets_table(%d)\n",
1115 __FILE__, __LINE__));
1116
1117 tbl = (XmDndTargetsTable)XtMalloc(sizeof(XmDndTargetsTableRec));
1118
1119 tbl->num_entries = 2;
1120 tbl->entries =
1121 (XmDndTargetsTableEntry)XtMalloc(sizeof(XmDndTargetsTableEntryRec) *
1122 tbl->num_entries);
1123
1124 tbl->entries[0].num_targets = 1;
1125 tbl->entries[0].targets = &noTarget;
1126
1127 tbl->entries[1].num_targets = 1;
1128 tbl->entries[1].targets = &stringTarget;
1129
1130 set_targets_table(display, tbl);
1131
1132 return tbl;
1133 }
1134
1135
1136 static Boolean
read_targets_table(Display * display,XmDndTargetsTable tbl)1137 read_targets_table(Display *display, XmDndTargetsTable tbl)
1138 {
1139 Atom ta, atype;
1140 Window win;
1141 int aformat, i;
1142 unsigned long nitems, bafter;
1143 XmDndTargets *targets = NULL;
1144 Boolean got_it = False;
1145 XmDndBufMgrRec bmgr;
1146 CARD16 nents;
1147
1148 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_targets_table(%d)\n",
1149 __FILE__, __LINE__));
1150
1151 ta = XmInternAtom(display, _XA_MOTIF_DRAG_TARGETS, False);
1152
1153 win = get_drag_window(display);
1154
1155 begin_protection(display, win);
1156
1157 if (XGetWindowProperty(display, win, ta, 0L, PROP_LENGTH,
1158 False, ta,
1159 &atype, &aformat, &nitems, &bafter,
1160 (unsigned char **)&targets) == Success &&
1161 nitems >= 8)
1162 {
1163 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_targets_table(%d) bafter=%i\n",
1164 __FILE__, __LINE__, bafter));
1165
1166 got_it = True;
1167 }
1168
1169 end_protection(display);
1170
1171 if (bad_window)
1172 {
1173 _XmWarning((Widget)XmGetXmDisplay(display),
1174 "Invalid DRAG WINDOW fetching DRAG_ATOMS.");
1175 }
1176
1177 if (!got_it)
1178 {
1179 if (targets)
1180 {
1181 XFree((XPointer)targets);
1182 }
1183
1184 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_targets_table(%d) - False\n",
1185 __FILE__, __LINE__));
1186
1187 return False;
1188 }
1189
1190 if (targets->protocol_version != DND_PROTOCOL_VERSION)
1191 {
1192 _XmWarning((Widget)XmGetXmDisplay(display),
1193 "DND Protocol version mismatch.");
1194 }
1195
1196 if (targets->byte_order != _XmByteOrder())
1197 {
1198 SWAP2BYTES(targets->num_target_lists);
1199 SWAP4BYTES(targets->data_size);
1200 }
1201
1202 if (!tbl)
1203 {
1204 tbl = (XmDndTargetsTable)XtMalloc(sizeof(XmDndTargetsTableRec));
1205
1206 tbl->num_entries = 0;
1207 tbl->entries = NULL;
1208
1209 set_targets_table(display, tbl);
1210 }
1211
1212 if (tbl->num_entries < targets->num_target_lists)
1213 {
1214 tbl->num_entries = targets->num_target_lists;
1215 tbl->entries =
1216 (XmDndTargetsTableEntry)XtRealloc((char *)tbl->entries,
1217 targets->num_target_lists *
1218 sizeof(XmDndTargetsTableEntryRec));
1219 }
1220
1221 if (targets->num_target_lists > 0)
1222 {
1223
1224 bmgr.atoms = (char *)targets;
1225 bmgr.atom_start = (char *)(targets + 1);
1226 bmgr.atom_size = targets->data_size;
1227
1228 for (i = 0; i < targets->num_target_lists; i++)
1229 {
1230
1231 _XmReadDragBuffer(&bmgr, False, (char *)&nents,
1232 sizeof(CARD16));
1233
1234 if (targets->byte_order != _XmByteOrder())
1235 {
1236 SWAP2BYTES(nents);
1237 }
1238
1239 tbl->entries[i].num_targets = nents;
1240 tbl->entries[i].targets = (Atom *)XtMalloc(nents * sizeof(Atom));
1241
1242 read_atoms_from_drag_buffer(&bmgr, tbl->entries[i].num_targets,
1243 targets->byte_order != _XmByteOrder(),
1244 tbl->entries[i].targets);
1245 }
1246 }
1247
1248 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:read_targets_table(%d) - True %p\n",
1249 __FILE__, __LINE__, tbl));
1250
1251 if (targets)
1252 {
1253 XFree((XPointer)targets);
1254 }
1255 return True;
1256 }
1257
1258
1259 static void
write_targets_table(Display * display,XmDndTargetsTable tbl)1260 write_targets_table(Display *display, XmDndTargetsTable tbl)
1261 {
1262 char targets[1000];
1263 XmDndTargets target_rec;
1264 XmDndBufMgrRec bmgr;
1265 Atom ta;
1266 int i;
1267 Window win;
1268 CARD16 nents;
1269
1270 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:write_targets_table(%d)\n",
1271 __FILE__, __LINE__));
1272
1273 if (tbl == NULL)
1274 {
1275 _XmWarning((Widget)XmGetXmDisplay(display),
1276 "No DRAG_TARGETS to write to DRAG_WINDOW.");
1277
1278 return;
1279 }
1280
1281 target_rec.byte_order = _XmByteOrder();
1282 target_rec.protocol_version = DND_PROTOCOL_VERSION;
1283 target_rec.num_target_lists = tbl->num_entries;
1284
1285 bmgr.atoms = targets;
1286 bmgr.atom_ptr = targets;
1287 bmgr.atom_start = NULL;
1288 bmgr.atom_size = 0;
1289 bmgr.atom_avail = 1000;
1290
1291 _XmWriteDragBuffer(&bmgr, False, (char *)&target_rec, sizeof(XmDndTargets));
1292
1293 for (i = 0; i < tbl->num_entries; i++)
1294 {
1295 nents = tbl->entries[i].num_targets;
1296
1297 _XmWriteDragBuffer(&bmgr, False, (char *)&nents, sizeof(CARD16));
1298
1299 write_atoms_to_drag_buffer(&bmgr, tbl->entries[i].num_targets,
1300 tbl->entries[i].targets);
1301 }
1302
1303 ((XmDndTargets *)(bmgr.atoms))->data_size = bmgr.atom_size;
1304
1305 ta = XmInternAtom(display, _XA_MOTIF_DRAG_TARGETS, False);
1306
1307 win = get_drag_window(display);
1308
1309 begin_protection(display, win);
1310
1311 XChangeProperty(display, win, ta, ta, 8, PropModeReplace,
1312 (unsigned char *)bmgr.atoms, bmgr.atom_size);
1313
1314 if (bmgr.atoms != bmgr.atom_ptr)
1315 {
1316 XtFree(bmgr.atoms);
1317 }
1318
1319 end_protection(display);
1320
1321 if (bad_window)
1322 {
1323 _XmWarning((Widget)XmGetXmDisplay(display),
1324 "Bad window writing DRAG_ATOMS on DRAG_WINDOW.");
1325 }
1326 }
1327
1328
1329 /*
1330 * fetch and/or set the ATOM_PAIRS. This is triggered at least once
1331 * by the first call to XmInternAtom().
1332 */
1333 extern void
_XmInitAtomPairs(Display * display)1334 _XmInitAtomPairs(Display *display)
1335 {
1336 Window win;
1337 char *dstr;
1338 Display *d;
1339
1340 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmInitAtomPairs(%d)\n",
1341 __FILE__, __LINE__));
1342
1343 if ((win = read_drag_window(display)) == None)
1344 {
1345 dstr = XDisplayString(display);
1346
1347 d = XOpenDisplay(dstr);
1348
1349 if (d == NULL)
1350 {
1351 _XmWarning((Widget)XmGetXmDisplay(display),
1352 "Where's your display?");
1353
1354 return;
1355 }
1356
1357 XGrabServer(d);
1358
1359 if ((win = read_drag_window(d)) == None)
1360 {
1361 XSetCloseDownMode(d, RetainPermanent);
1362
1363 win = create_drag_window(d);
1364
1365 write_drag_window(d, &win);
1366 }
1367
1368 XCloseDisplay(d);
1369 }
1370
1371 set_drag_window(display, win);
1372
1373 if (!read_atom_pairs(display))
1374 {
1375 XGrabServer(display);
1376
1377 if (!read_atom_pairs(display))
1378 {
1379 write_atom_pairs(display);
1380 }
1381
1382 XUngrabServer(display);
1383
1384 XFlush(display);
1385 }
1386 }
1387
1388
1389 /*
1390 * intialize the DRAG_TARGETS table, and the DRAG_ATOMS table
1391 */
1392 extern void
_XmInitTargetsTable(Display * display)1393 _XmInitTargetsTable(Display *display)
1394 {
1395 Window win;
1396 char *dstr;
1397 Display *d;
1398 XmDndAtomsTable atoms;
1399 XmDndTargetsTable targets;
1400
1401 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmInitTargetsTable(%d)\n",
1402 __FILE__, __LINE__));
1403
1404 if ((win = read_drag_window(display)) == None)
1405 {
1406
1407 dstr = XDisplayString(display);
1408
1409 d = XOpenDisplay(dstr);
1410
1411 if (d == NULL)
1412 {
1413 _XmWarning((Widget)XmGetXmDisplay(display),
1414 "Where's your display?");
1415
1416 return;
1417 }
1418
1419 XGrabServer(d);
1420
1421 if ((win = read_drag_window(d)) == None)
1422 {
1423
1424 XSetCloseDownMode(d, RetainPermanent);
1425
1426 win = create_drag_window(d);
1427
1428 write_drag_window(d, &win);
1429 }
1430
1431 XCloseDisplay(d);
1432 }
1433
1434 set_drag_window(display, win);
1435
1436 if (!read_atom_pairs(display))
1437 {
1438
1439 XGrabServer(display);
1440
1441 if (!read_atom_pairs(display))
1442 {
1443 write_atom_pairs(display);
1444 }
1445
1446 XUngrabServer(display);
1447
1448 XFlush(display);
1449 }
1450
1451 if (!read_atoms_table(display, get_atoms_table(display)))
1452 {
1453 atoms = create_default_atoms_table(display);
1454
1455 write_atoms_table(display, atoms);
1456 }
1457
1458 if (!read_targets_table(display, get_targets_table(display)))
1459 {
1460 XGrabServer(display);
1461
1462 if (!read_targets_table(display, get_targets_table(display)))
1463 {
1464 targets = create_default_targets_table(display);
1465
1466 write_targets_table(display, targets);
1467 }
1468
1469 XUngrabServer(display);
1470
1471 XFlush(display);
1472 }
1473 }
1474
1475
1476 /*
1477 * called from DropSMgr's CreateInfo method.
1478 */
1479 extern Cardinal
_XmIndexToTargets(Widget shell,Cardinal t_index,Atom ** targetsRtn)1480 _XmIndexToTargets(Widget shell, Cardinal t_index, Atom **targetsRtn)
1481 {
1482 Display *dpy = XtDisplay(shell);
1483 XmDndTargetsTable targets;
1484
1485 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmIndexToTargets(%d)\n",
1486 __FILE__, __LINE__));
1487
1488 if ((targets = get_targets_table(dpy)) == NULL)
1489 {
1490 _XmInitTargetsTable(dpy);
1491
1492 targets = get_targets_table(dpy);
1493 }
1494
1495 if (t_index >= targets->num_entries)
1496 {
1497 if (!read_targets_table(dpy, targets))
1498 {
1499 _XmInitTargetsTable(dpy);
1500 }
1501
1502 targets = get_targets_table(dpy);
1503 }
1504
1505 if (t_index >= targets->num_entries)
1506 {
1507 _XmWarning(shell, "Index out of range to _XmIndexToTargets. %i %i",
1508 t_index, targets->num_entries);
1509
1510 *targetsRtn = NULL;
1511
1512 return 0;
1513 }
1514
1515 *targetsRtn = targets->entries[t_index].targets;
1516
1517 return targets->entries[t_index].num_targets;
1518 }
1519
1520
1521 /*
1522 * minimize duplicates in the targets table by sorting compound entries
1523 */
1524 static int
acompare(XmConst void * a,XmConst void * b)1525 acompare(XmConst void *a, XmConst void *b)
1526 {
1527 Atom *pa = (Atom *)a, *pb = (Atom *)b;
1528
1529 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:acompare(%d)\n",
1530 __FILE__, __LINE__));
1531
1532 return *pa - *pb;
1533 }
1534
1535 /*
1536 * also called from DropSMgr. Creates target list if not already
1537 * there.
1538 */
1539 Cardinal
_XmTargetsToIndex(Widget shell,Atom * tlist,Cardinal numTargets)1540 _XmTargetsToIndex(Widget shell, Atom *tlist, Cardinal numTargets)
1541 {
1542 Display *dpy = XtDisplay(shell);
1543 XmDndTargetsTable targets;
1544 Cardinal i;
1545 Atom *atoms;
1546
1547 DEBUGOUT(_LtDebug(__FILE__, shell,
1548 "%s:_XmTargetsToIndex(%d) - %p 0x%x targets %p\n",
1549 __FILE__, __LINE__,
1550 tlist,
1551 numTargets,
1552 tlist ? tlist[0] : 0
1553 ));
1554 #if 0
1555 /* For Netscape 4.5 PR1 binary compatibility testing.
1556 NS seems to be calling this routine with an invalid (huge) number
1557 of numTargets. I just bail out of the whole routine for testing.
1558 -jac Sept 22, 1998 */
1559 return 0;
1560 #endif
1561
1562 if ((targets = get_targets_table(dpy)) == NULL)
1563 {
1564 _XmInitTargetsTable(dpy);
1565
1566 targets = get_targets_table(dpy);
1567 }
1568 DEBUGOUT(_LtDebug(__FILE__, shell,
1569 "%s:_XmTargetsToIndex(%d) - targets->num_entries %i\n",
1570 __FILE__, __LINE__,
1571 targets->num_entries
1572 ));
1573
1574 #if 1
1575 /* 28 Jul 1999
1576 Navigator is still calling this with a huge value for numTargets.
1577 So for now just do a check for this and bail.....
1578 */
1579 for (i = 0; i < targets->num_entries; i++)
1580 {
1581 if (numTargets == targets->entries[i].num_targets)
1582 {
1583 break;
1584 }
1585 }
1586 if ((int)numTargets > 1000)
1587 {
1588 return(0);
1589 }
1590 #endif
1591
1592 atoms = (Atom *)XtMalloc(numTargets * sizeof(Atom));
1593 for (i = 0; i < numTargets; i++)
1594 {
1595 atoms[i] = tlist[i];
1596 }
1597
1598 qsort(atoms, numTargets, sizeof(Atom), acompare);
1599
1600 /* maybe it's already there ? */
1601 for (i = 0; i < targets->num_entries; i++)
1602 {
1603 if (numTargets == targets->entries[i].num_targets &&
1604 memcmp(atoms, targets->entries[i].targets,
1605 sizeof(Atom) * numTargets) == 0)
1606 {
1607 XtFree((char *)atoms);
1608
1609 return i;
1610 }
1611 }
1612
1613 XGrabServer(dpy);
1614
1615 if (!read_targets_table(dpy, targets))
1616 {
1617 XUngrabServer(dpy);
1618
1619 _XmInitTargetsTable(dpy);
1620
1621 XGrabServer(dpy);
1622
1623 targets = get_targets_table(dpy);
1624 }
1625
1626 /* maybe somebody added while we've been fooling around, but before
1627 * we said nuhuh with the grab */
1628 for (i = 0; i < targets->num_entries; i++)
1629 {
1630 if (numTargets == targets->entries[i].num_targets &&
1631 memcmp(atoms, targets->entries[i].targets,
1632 sizeof(Atom) * numTargets) == 0)
1633 {
1634 XtFree((char *)atoms);
1635
1636 return i;
1637 }
1638 }
1639
1640 /* nope. add them */
1641 i = targets->num_entries;
1642
1643 targets->num_entries++;
1644 targets->entries =
1645 (XmDndTargetsTableEntry)XtRealloc((char *)targets->entries,
1646 sizeof(XmDndTargetsTableEntryRec) *
1647 targets->num_entries);
1648
1649 targets->entries[i].num_targets = numTargets;
1650 targets->entries[i].targets = atoms;
1651
1652 write_targets_table(dpy, targets);
1653
1654 XUngrabServer(dpy);
1655
1656 XFlush(dpy);
1657
1658 return i;
1659 }
1660
1661
1662 /*
1663 * called when a drag starts, to allocate an Atom for the DragContext
1664 */
1665 extern Atom
_XmAllocMotifAtom(Widget shell,Time time)1666 _XmAllocMotifAtom(Widget shell, Time time)
1667 {
1668 XmDndAtomsTable atoms;
1669 Display *dpy = XtDisplay(shell);
1670 Atom alloc = None;
1671 int i;
1672 char buf[32];
1673
1674 DEBUGOUT(_LtDebug(__FILE__, shell, "%s:_XmAllocMotifAtom(%d)\n",
1675 __FILE__, __LINE__));
1676 DEBUGOUT(_LtDebug("DRAGSOURCE", shell, "%s:_XmAllocMotifAtom(%d)\n",
1677 __FILE__, __LINE__));
1678
1679 if ((atoms = get_atoms_table(dpy)) == NULL)
1680 {
1681 _XmInitTargetsTable(dpy);
1682
1683 atoms = get_atoms_table(dpy);
1684 }
1685
1686 XGrabServer(dpy);
1687
1688 if (!read_atoms_table(dpy, atoms))
1689 {
1690 XUngrabServer(dpy);
1691
1692 _XmInitTargetsTable(dpy);
1693
1694 XGrabServer(dpy);
1695
1696 atoms = get_atoms_table(dpy);
1697 }
1698
1699 if (atoms->num_entries != 0)
1700 {
1701 for (i = 0; i < atoms->num_entries; i++)
1702 {
1703 if (atoms->entries[i].time == CurrentTime)
1704 {
1705 alloc = atoms->entries[i].atom;
1706 atoms->entries[i].time = time;
1707
1708 break;
1709 }
1710 }
1711 }
1712
1713 if (alloc == None)
1714 {
1715 i = atoms->num_entries;
1716
1717 atoms->num_entries++;
1718
1719 atoms->entries =
1720 (XmDndAtomsTableEntry) XtRealloc((char *)atoms->entries,
1721 atoms->num_entries * sizeof(XmDndAtomsTableEntryRec));
1722
1723 sprintf(buf, _XA_MOTIF_ATOM_FORMAT, i);
1724 alloc = XmInternAtom(dpy, buf, False);
1725
1726 atoms->entries[i].atom = alloc;
1727 atoms->entries[i].time = time;
1728 }
1729
1730 write_atoms_table(dpy, atoms);
1731
1732 XUngrabServer(dpy);
1733
1734 XFlush(dpy);
1735
1736 if (_LtDebugInDebug("DRAGSOURCE", shell))
1737 {
1738 char *AtomName = XGetAtomName(dpy, alloc);
1739
1740 DEBUGOUT(_LtDebug0("DRAGSOURCE", shell, "\t%s - 0x%x\n", AtomName, time));
1741 XFree(AtomName);
1742 }
1743
1744 return alloc;
1745 }
1746
1747
1748 /*
1749 * Free the atom.
1750 */
1751 extern void
_XmFreeMotifAtom(Widget shell,Atom atom)1752 _XmFreeMotifAtom(Widget shell, Atom atom)
1753 {
1754 XmDndAtomsTable atoms;
1755 Display *dpy = XtDisplay(shell);
1756 int i;
1757
1758 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmFreeMotifAtom(%d)\n",
1759 __FILE__, __LINE__));
1760
1761 if (atom == None)
1762 {
1763 return;
1764 }
1765
1766 if ((atoms = get_atoms_table(dpy)) == NULL)
1767 {
1768 _XmInitTargetsTable(dpy);
1769
1770 atoms = get_atoms_table(dpy);
1771 }
1772
1773 XGrabServer(dpy);
1774
1775 if (!read_atoms_table(dpy, atoms))
1776 {
1777 XUngrabServer(dpy);
1778
1779 _XmInitTargetsTable(dpy);
1780
1781 XGrabServer(dpy);
1782
1783 atoms = get_atoms_table(dpy);
1784 }
1785
1786 if (atoms->num_entries != 0)
1787 {
1788 for (i = 0; i < atoms->num_entries; i++)
1789 {
1790 if (atoms->entries[i].atom == atom)
1791 {
1792 atoms->entries[i].time = CurrentTime;
1793
1794 break;
1795 }
1796 }
1797 }
1798
1799 write_atoms_table(dpy, atoms);
1800
1801 XUngrabServer(dpy);
1802
1803 XFlush(dpy);
1804 }
1805
1806
1807 /*
1808 * I understand what it does, by why would you want to do it?
1809 */
1810 extern void
_XmDestroyMotifWindow(Display * dpy)1811 _XmDestroyMotifWindow(Display *dpy)
1812 {
1813 Atom dw;
1814 Window win;
1815
1816 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmDestroyMotifWindow(%d)\n",
1817 __FILE__, __LINE__));
1818
1819 win = read_drag_window(dpy);
1820 if (win == None)
1821 {
1822 return;
1823 }
1824
1825 dw = XmInternAtom(dpy, _XA_MOTIF_DRAG_WINDOW, False);
1826
1827 XDeleteProperty(dpy, DefaultRootWindow(dpy), dw);
1828
1829 XDestroyWindow(dpy, win);
1830 }
1831
1832
1833 /*
1834 * get the drag proxy window. XmDisplay uses this to initialize
1835 * the proxy instance variable.
1836 */
1837 Window
_XmGetDragProxyWindow(Display * display)1838 _XmGetDragProxyWindow(Display *display)
1839 {
1840 Window win = None;
1841 Atom pw, atype;
1842 int aformat;
1843 unsigned long nitems, bafter;
1844 unsigned char *prop = NULL;
1845
1846 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmGetDragProxyWindow(%d)\n",
1847 __FILE__, __LINE__));
1848
1849 if ((win = read_drag_window(display)) == None)
1850 {
1851 return None;
1852 }
1853
1854 pw = XmInternAtom(display, _XA_MOTIF_DRAG_PROXY_WINDOW, False);
1855
1856 begin_protection(display, win);
1857 if (XGetWindowProperty(display, win, pw, 0L, PROP_LENGTH,
1858 False, AnyPropertyType,
1859 &atype, &aformat, &nitems, &bafter, &prop)
1860 == Success && atype == XA_WINDOW && aformat == 32 && nitems == 1)
1861 {
1862 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmGetDragProxyWindow(%d) - bafter=%i\n",
1863 __FILE__, __LINE__, bafter));
1864 win = *((Window *)prop);
1865 }
1866 end_protection(display);
1867 if (prop)
1868 {
1869 XFree((XPointer)prop);
1870 }
1871
1872 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmGetDragProxyWindow(%d) - %p\n",
1873 __FILE__, __LINE__, win));
1874
1875 return win;
1876 }
1877
1878
1879 /*
1880 * get the drag receiver info property from the target
1881 *
1882 * check out the _XA_MOTIF_DRAG_RECEIVER_INFO property on a Motif
1883 * application's window. There's a lot more there than what Daniel
1884 * talks about. Must be due to PREREGISTER, yes?
1885 */
1886 extern Boolean
_XmGetDragReceiverInfo(Display * display,Window win,XmDragReceiverInfo ri)1887 _XmGetDragReceiverInfo(Display *display, Window win, XmDragReceiverInfo ri)
1888 {
1889 Atom dri;
1890 XmDndReceiverProp *receiver;
1891 Atom type;
1892 int format;
1893 unsigned int border;
1894 unsigned long bafter, length;
1895 Window root;
1896
1897 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmGetDragReceiverInfo(%d)\n",
1898 __FILE__, __LINE__));
1899 DEBUGOUT(_LtDebug0("DRAGSOURCE", NULL, "%s:_XmGetDragReceiverInfo(%d) - %p\n",
1900 __FILE__, __LINE__, win));
1901
1902 dri = XmInternAtom(display, _XA_MOTIF_DRAG_RECEIVER_INFO, False);
1903
1904 if (XGetWindowProperty(display, win, dri, 0L, PROP_LENGTH, False,
1905 dri, &type, &format, &length, &bafter,
1906 (unsigned char **)&receiver) != Success)
1907 {
1908 DEBUGOUT(_LtDebug0("DRAGSOURCE", NULL, "%s:_XmGetDragReceiverInfo(%d) - getting prop failed\n",
1909 __FILE__, __LINE__));
1910 return False;
1911 }
1912
1913 if (length < sizeof(XmDndReceiverProp))
1914 {
1915 ri->dragProtocolStyle = XmDRAG_NONE;
1916 XFree((char *)receiver);
1917 DEBUGOUT(_LtDebug0("DRAGSOURCE", NULL, "%s:_XmGetDragReceiverInfo(%d) - None available\n",
1918 __FILE__, __LINE__));
1919 return False;
1920 }
1921
1922 if (receiver->protocol_version != DND_PROTOCOL_VERSION)
1923 {
1924 _XmWarning(NULL, "Drag protocol version mismatch: %d vs %d\n",
1925 DND_PROTOCOL_VERSION, receiver->protocol_version);
1926 }
1927
1928 if (receiver->byte_order != _XmByteOrder())
1929 {
1930 SWAP4BYTES(receiver->proxy_window);
1931 SWAP2BYTES(receiver->num_drop_sites);
1932 SWAP4BYTES(receiver->total_size);
1933 }
1934
1935 Display_ProxyWindow(XmGetXmDisplay(display)) = receiver->proxy_window;
1936
1937 ri->dragProtocolStyle = receiver->protocol_style;
1938 ri->iccInfo = (XtPointer)XtMalloc(sizeof(XmShellDropSiteInfoRec));
1939
1940 DSI_ByteOrder(ri->iccInfo) = receiver->byte_order;
1941 DSI_NumDropSites(ri->iccInfo) = receiver->num_drop_sites;
1942 DSI_Info(ri->iccInfo).atoms = (char *)receiver;
1943 DSI_Info(ri->iccInfo).atom_size = receiver->total_size;
1944 DSI_Info(ri->iccInfo).atom_start = (char *)(receiver + 1);
1945 DSI_Info(ri->iccInfo).names = (char *)receiver + receiver->total_size;
1946 DSI_Info(ri->iccInfo).name_size = length - receiver->total_size;
1947
1948 XGetGeometry(display, win, &root,
1949 &ri->xOrigin, &ri->yOrigin, &ri->width, &ri->height,
1950 &border, &ri->depth);
1951
1952 XTranslateCoordinates(display, win, root, -border, -border,
1953 &ri->xOrigin, &ri->yOrigin, &root);
1954
1955 return True;
1956 }
1957
1958
1959 extern void
_XmSetDragReceiverInfo(Widget w,Widget widget)1960 _XmSetDragReceiverInfo(Widget w, Widget widget)
1961 {
1962 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmSetDragReceiverInfo(%d)\n",
1963 __FILE__, __LINE__));
1964
1965 }
1966
1967
1968 extern void
_XmClearDragReceiverInfo(Widget shell)1969 _XmClearDragReceiverInfo(Widget shell)
1970 {
1971 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmClearDragReceiverInfo(%d)\n",
1972 __FILE__, __LINE__));
1973
1974 }
1975
1976 /*
1977 * free up the dropsite info
1978 */
1979 extern void
_XmFreeDragReceiverInfo(XmShellDropSiteInfo di)1980 _XmFreeDragReceiverInfo(XmShellDropSiteInfo di)
1981 {
1982 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmFreeDragReceiverInfo(%d)\n",
1983 __FILE__, __LINE__));
1984
1985 if (di)
1986 {
1987 if (di->info.atoms != NULL)
1988 {
1989 XFree(di->info.atoms);
1990 }
1991
1992 XtFree((char *)di);
1993 }
1994 }
1995
1996
1997 extern unsigned char
_XmByteOrder(void)1998 _XmByteOrder(void)
1999 {
2000 static unsigned char byte_order = 0;
2001
2002 /*
2003 DEBUGOUT(_LtDebug0(__FILE__, NULL, "%s:_XmByteOrder(%d)\n",
2004 __FILE__, __LINE__));
2005 */
2006
2007 if (!byte_order)
2008 {
2009 unsigned int endian = 1;
2010
2011 byte_order = (*((char *)&endian)) ? 'l' : 'B';
2012 }
2013
2014 return byte_order;
2015 }
2016