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