blob: 1b5c9d49ce42841e8da7b76d08578c2043f13209 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#ifdef HEADLESS
27 #error This file should not be included in headless library
28#endif
29
30#include "awt_dnd.h"
31
32#include "awt_p.h"
33
34#include "java_awt_dnd_DnDConstants.h"
35
36/* Shared atoms */
37
38Atom XA_WM_STATE;
39Atom XA_DELETE;
40
41/* XDnD atoms */
42
43Atom XA_XdndAware;
44Atom XA_XdndProxy;
45
46Atom XA_XdndEnter;
47Atom XA_XdndPosition;
48Atom XA_XdndLeave;
49Atom XA_XdndDrop;
50Atom XA_XdndStatus;
51Atom XA_XdndFinished;
52
53Atom XA_XdndTypeList;
54Atom XA_XdndSelection;
55
56Atom XA_XdndActionCopy;
57Atom XA_XdndActionMove;
58Atom XA_XdndActionLink;
59Atom XA_XdndActionAsk;
60Atom XA_XdndActionPrivate;
61Atom XA_XdndActionList;
62
63/* Motif DnD atoms */
64
65Atom _XA_MOTIF_DRAG_WINDOW;
66Atom _XA_MOTIF_DRAG_TARGETS;
67Atom _XA_MOTIF_DRAG_INITIATOR_INFO;
68Atom _XA_MOTIF_DRAG_RECEIVER_INFO;
69Atom _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
70Atom _XA_MOTIF_ATOM_0;
71Atom XA_XmTRANSFER_SUCCESS;
72Atom XA_XmTRANSFER_FAILURE;
73
74unsigned char MOTIF_BYTE_ORDER = 0;
75
76static Window awt_root_window = None;
77
78static Boolean
79init_atoms(Display* display) {
80 struct atominit {
81 Atom *atomptr;
82 const char *name;
83 };
84
85 /* Add new atoms to this list */
86 static struct atominit atom_list[] = {
87 /* Shared atoms */
88 { &XA_WM_STATE, "WM_STATE" },
89 { &XA_DELETE, "DELETE" },
90
91 /* XDnD atoms */
92 { &XA_XdndAware, "XdndAware" },
93 { &XA_XdndProxy, "XdndProxy" },
94 { &XA_XdndEnter, "XdndEnter" },
95 { &XA_XdndPosition, "XdndPosition" },
96 { &XA_XdndLeave, "XdndLeave" },
97 { &XA_XdndDrop, "XdndDrop" },
98 { &XA_XdndStatus, "XdndStatus" },
99 { &XA_XdndFinished, "XdndFinished" },
100 { &XA_XdndTypeList, "XdndTypeList" },
101 { &XA_XdndSelection, "XdndSelection" },
102 { &XA_XdndActionCopy, "XdndActionCopy" },
103 { &XA_XdndActionMove, "XdndActionMove" },
104 { &XA_XdndActionLink, "XdndActionLink" },
105 { &XA_XdndActionAsk, "XdndActionAsk" },
106 { &XA_XdndActionPrivate, "XdndActionPrivate" },
107 { &XA_XdndActionList, "XdndActionList" },
108
109 /* Motif DnD atoms */
110 { &_XA_MOTIF_DRAG_WINDOW, "_MOTIF_DRAG_WINDOW" },
111 { &_XA_MOTIF_DRAG_TARGETS, "_MOTIF_DRAG_TARGETS" },
112 { &_XA_MOTIF_DRAG_INITIATOR_INFO, "_MOTIF_DRAG_INITIATOR_INFO" },
113 { &_XA_MOTIF_DRAG_RECEIVER_INFO, "_MOTIF_DRAG_RECEIVER_INFO" },
114 { &_XA_MOTIF_DRAG_AND_DROP_MESSAGE, "_MOTIF_DRAG_AND_DROP_MESSAGE" },
115 { &_XA_MOTIF_ATOM_0, "_MOTIF_ATOM_0" },
116 { &XA_XmTRANSFER_SUCCESS, "XmTRANSFER_SUCCESS" },
117 { &XA_XmTRANSFER_FAILURE, "XmTRANSFER_FAILURE" }
118 };
119
120#define ATOM_LIST_LENGTH (sizeof(atom_list)/sizeof(atom_list[0]))
121
122 const char *names[ATOM_LIST_LENGTH];
123 Atom atoms[ATOM_LIST_LENGTH];
124 Status status;
125 size_t i;
126
127 /* Fill the array of atom names */
128 for (i = 0; i < ATOM_LIST_LENGTH; ++i) {
129 names[i] = atom_list[i].name;
130 }
131
132 DTRACE_PRINT2("%s:%d initializing atoms ... ", __FILE__, __LINE__);
133
134 status = XInternAtoms(awt_display, (char**)names, ATOM_LIST_LENGTH,
135 False, atoms);
136 if (status == 0) {
137 DTRACE_PRINTLN("failed");
138 return False;
139 }
140
141 /* Store returned atoms into corresponding global variables */
142 DTRACE_PRINTLN("ok");
143 for (i = 0; i < ATOM_LIST_LENGTH; ++i) {
144 *atom_list[i].atomptr = atoms[i];
145 }
146
147 return True;
148#undef ATOM_LIST_LENGTH
149}
150
151/*
152 * NOTE: must be called after awt_root_shell is created and realized.
153 */
154Boolean
155awt_dnd_init(Display* display) {
156 static Boolean inited = False;
157
158 if (!inited) {
159 Boolean atoms_inited = False;
160 Boolean ds_inited = False;
161 unsigned int value = 1;
162 MOTIF_BYTE_ORDER = (*((char*)&value) != 0) ? 'l' : 'B';
163
164 /* NOTE: init_atoms() should be called before the rest of initialization
165 so that atoms can be used. */
166 inited = init_atoms(display);
167
168 if (inited) {
169 if (XtIsRealized(awt_root_shell)) {
170 awt_root_window = XtWindow(awt_root_shell);
171 } else {
172 inited = False;
173 }
174 }
175
176 inited = inited && awt_dnd_ds_init(display);
177 }
178
179 return inited;
180}
181
182/*
183 * Returns a window of awt_root_shell.
184 */
185Window
186get_awt_root_window() {
187 return awt_root_window;
188}
189
190static unsigned char local_xerror_code = Success;
191
192static int
193xerror_handler(Display *dpy, XErrorEvent *err) {
194 local_xerror_code = err->error_code;
195 return 0;
196}
197
198/**************** checked_X* wrappers *****************************************/
199#undef NO_SYNC
200#undef SYNC_TRACE
201
202unsigned char
203checked_XChangeProperty(Display* display, Window w, Atom property, Atom type,
204 int format, int mode, unsigned char* data,
205 int nelements) {
206 XErrorHandler xerror_saved_handler;
207
208#ifndef NO_SYNC
209 XSync(display, False);
210#ifdef SYNC_TRACE
211 fprintf(stderr,"XSync 1\n");
212#endif
213#endif
214 local_xerror_code = Success;
215 xerror_saved_handler = XSetErrorHandler(xerror_handler);
216
217 XChangeProperty(display, w, property, type, format, mode, data, nelements);
218
219#ifndef NO_SYNC
220 XSync(display, False);
221#ifdef SYNC_TRACE
222 fprintf(stderr,"XSync 2\n");
223#endif
224#endif
225 XSetErrorHandler(xerror_saved_handler);
226
227 return local_xerror_code;
228}
229
230unsigned char
231checked_XGetWindowProperty(Display* display, Window w, Atom property, long long_offset,
232 long long_length, Bool delete, Atom req_type,
233 Atom* actual_type_return, int* actual_format_return,
234 unsigned long* nitems_return, unsigned long* bytes_after_return,
235 unsigned char** prop_return) {
236
237 XErrorHandler xerror_saved_handler;
238 int ret_val = Success;
239
240#ifndef NO_SYNC
241 XSync(display, False);
242#ifdef SYNC_TRACE
243 fprintf(stderr,"XSync 3\n");
244#endif
245#endif
246 local_xerror_code = Success;
247 xerror_saved_handler = XSetErrorHandler(xerror_handler);
248
249 ret_val = XGetWindowProperty(display, w, property, long_offset, long_length,
250 delete, req_type, actual_type_return,
251 actual_format_return, nitems_return,
252 bytes_after_return, prop_return);
253
254#ifndef NO_SYNC
255 XSync(display, False);
256#ifdef SYNC_TRACE
257 fprintf(stderr,"XSync 4\n");
258#endif
259#endif
260 XSetErrorHandler(xerror_saved_handler);
261
262 return ret_val != Success ? local_xerror_code : Success;
263}
264
265unsigned char
266checked_XSendEvent(Display* display, Window w, Bool propagate, long event_mask,
267 XEvent* event_send) {
268
269 XErrorHandler xerror_saved_handler;
270 Status ret_val = 0;
271
272#ifndef NO_SYNC
273 XSync(display, False);
274#ifdef SYNC_TRACE
275 fprintf(stderr,"XSync 5\n");
276#endif
277#endif
278 local_xerror_code = Success;
279 xerror_saved_handler = XSetErrorHandler(xerror_handler);
280
281 ret_val = XSendEvent(display, w, propagate, event_mask, event_send);
282
283#ifndef NO_SYNC
284 XSync(display, False);
285#ifdef SYNC_TRACE
286 fprintf(stderr,"XSync 6\n");
287#endif
288#endif
289 XSetErrorHandler(xerror_saved_handler);
290
291 return ret_val == 0 ? local_xerror_code : Success;
292}
293
294/*
295 * NOTE: returns Success even if the two windows aren't on the same screen.
296 */
297unsigned char
298checked_XTranslateCoordinates(Display* display, Window src_w, Window dest_w,
299 int src_x, int src_y, int* dest_x_return,
300 int* dest_y_return, Window* child_return) {
301
302 XErrorHandler xerror_saved_handler;
303 Bool ret_val = True;
304
305#ifndef NO_SYNC
306 XSync(display, False);
307#ifdef SYNC_TRACE
308 fprintf(stderr,"XSync 7\n");
309#endif
310#endif
311 local_xerror_code = Success;
312 xerror_saved_handler = XSetErrorHandler(xerror_handler);
313
314 ret_val = XTranslateCoordinates(display, src_w, dest_w, src_x, src_y,
315 dest_x_return, dest_y_return, child_return);
316
317#ifndef NO_SYNC
318 XSync(display, False);
319#ifdef SYNC_TRACE
320 fprintf(stderr,"XSync 8\n");
321#endif
322#endif
323 XSetErrorHandler(xerror_saved_handler);
324
325 return local_xerror_code;
326}
327
328unsigned char
329checked_XSelectInput(Display* display, Window w, long event_mask) {
330 XErrorHandler xerror_saved_handler;
331 Bool ret_val = True;
332
333#ifndef NO_SYNC
334 XSync(display, False);
335#ifdef SYNC_TRACE
336 fprintf(stderr,"XSync 7\n");
337#endif
338#endif
339 local_xerror_code = Success;
340 xerror_saved_handler = XSetErrorHandler(xerror_handler);
341
342 XSelectInput(display, w, event_mask);
343
344#ifndef NO_SYNC
345 XSync(display, False);
346#ifdef SYNC_TRACE
347 fprintf(stderr,"XSync 8\n");
348#endif
349#endif
350 XSetErrorHandler(xerror_saved_handler);
351
352 return local_xerror_code;
353}
354/******************************************************************************/
355
356jint
357xdnd_to_java_action(Atom action) {
358 if (action == XA_XdndActionCopy) {
359 return java_awt_dnd_DnDConstants_ACTION_COPY;
360 } else if (action == XA_XdndActionMove) {
361 return java_awt_dnd_DnDConstants_ACTION_MOVE;
362 } else if (action == XA_XdndActionLink) {
363 return java_awt_dnd_DnDConstants_ACTION_LINK;
364 } else if (action == None) {
365 return java_awt_dnd_DnDConstants_ACTION_NONE;
366 } else {
367 /* XdndActionCopy is the default. */
368 return java_awt_dnd_DnDConstants_ACTION_COPY;
369 }
370}
371
372Atom
373java_to_xdnd_action(jint action) {
374 switch (action) {
375 case java_awt_dnd_DnDConstants_ACTION_COPY: return XA_XdndActionCopy;
376 case java_awt_dnd_DnDConstants_ACTION_MOVE: return XA_XdndActionMove;
377 case java_awt_dnd_DnDConstants_ACTION_LINK: return XA_XdndActionLink;
378 default: return None;
379 }
380}
381
382void
383write_card8(void** p, CARD8 value) {
384 CARD8** card8_pp = (CARD8**)p;
385 **card8_pp = value;
386 (*card8_pp)++;
387}
388
389void
390write_card16(void** p, CARD16 value) {
391 CARD16** card16_pp = (CARD16**)p;
392 **card16_pp = value;
393 (*card16_pp)++;
394}
395
396void
397write_card32(void** p, CARD32 value) {
398 CARD32** card32_pp = (CARD32**)p;
399 **card32_pp = value;
400 (*card32_pp)++;
401}
402
403CARD8
404read_card8(char* data, size_t offset) {
405 return *((CARD8*)(data + offset));
406}
407
408CARD16
409read_card16(char* data, size_t offset, char byte_order) {
410 CARD16 card16 = *((CARD16*)(data + offset));
411
412 if (byte_order != MOTIF_BYTE_ORDER) {
413 SWAP2BYTES(card16);
414 }
415
416 return card16;
417}
418
419CARD32
420read_card32(char* data, size_t offset, char byte_order) {
421 CARD32 card32 = *((CARD32*)(data + offset));
422
423 if (byte_order != MOTIF_BYTE_ORDER) {
424 SWAP4BYTES(card32);
425 }
426
427 return card32;
428}
429
430static Window
431read_motif_window(Display* dpy) {
432 Window root_window = DefaultRootWindow(dpy);
433 Window motif_window = None;
434
435 unsigned char ret;
436 Atom type;
437 int format;
438 unsigned long nitems;
439 unsigned long after;
440 unsigned char *data;
441
442 ret = checked_XGetWindowProperty(dpy, root_window, _XA_MOTIF_DRAG_WINDOW,
443 0, 0xFFFF, False, AnyPropertyType, &type,
444 &format, &nitems, &after, &data);
445
446 if (ret != Success) {
447 DTRACE_PRINTLN2("%s:%d Failed to read _MOTIF_DRAG_WINDOW.",
448 __FILE__, __LINE__);
449 return None;
450 }
451
452
453 if (type == XA_WINDOW && format == 32 && nitems == 1) {
454 motif_window = *((Window*)data);
455 }
456
457 XFree ((char *)data);
458
459 return motif_window;
460}
461
462static Window
463create_motif_window(Display* dpy) {
464 Window root_window = DefaultRootWindow(dpy);
465 Window motif_window = None;
466 Display* display = NULL;
467 XSetWindowAttributes swa;
468
469 display = XOpenDisplay(XDisplayString(dpy));
470 if (display == NULL) {
471 return None;
472 }
473
474 XGrabServer(display);
475
476 XSetCloseDownMode(display, RetainPermanent);
477
478 swa.override_redirect = True;
479 swa.event_mask = PropertyChangeMask;
480 motif_window = XCreateWindow(display, root_window,
481 -10, -10, 1, 1, 0, 0,
482 InputOnly, CopyFromParent,
483 (CWOverrideRedirect|CWEventMask),
484 &swa);
485 XMapWindow(display, motif_window);
486
487 XChangeProperty(display, root_window, _XA_MOTIF_DRAG_WINDOW, XA_WINDOW, 32,
488 PropModeReplace, (unsigned char *)&motif_window, 1);
489
490 XUngrabServer(display);
491
492 XCloseDisplay(display);
493
494 return motif_window;
495}
496
497Window
498get_motif_window(Display* dpy) {
499 /*
500 * Note: it is unsafe to cache the motif drag window handle, as another
501 * client can change the _MOTIF_DRAG_WINDOW property on the root, the handle
502 * becomes out-of-sync and all subsequent drag operations will fail.
503 */
504 Window motif_window = read_motif_window(dpy);
505 if (motif_window == None) {
506 motif_window = create_motif_window(dpy);
507 }
508
509 return motif_window;
510}
511
512typedef struct {
513 CARD16 num_targets;
514 Atom* targets;
515} TargetsTableEntry;
516
517typedef struct {
518 CARD16 num_entries;
519 TargetsTableEntry* entries;
520} TargetsTable;
521
522typedef struct {
523 CARD8 byte_order;
524 CARD8 protocol_version;
525 CARD16 num_entries B16;
526 CARD32 heap_offset B32;
527} TargetsPropertyRec;
528
529static TargetsTable*
530get_target_list_table(Display* dpy) {
531 Window motif_window = get_motif_window(dpy);
532 TargetsTable* targets_table = NULL;
533 TargetsPropertyRec* targets_property_rec_ptr;
534 char* bufptr;
535
536 unsigned char ret;
537 Atom type;
538 int format;
539 unsigned long nitems;
540 unsigned long after;
541 unsigned char *data;
542 unsigned int i, j;
543
544 ret = checked_XGetWindowProperty(dpy, motif_window, _XA_MOTIF_DRAG_TARGETS,
545 0L, 100000L, False, _XA_MOTIF_DRAG_TARGETS,
546 &type, &format, &nitems, &after,
547 (unsigned char**)&targets_property_rec_ptr);
548
549 if (ret != Success || type != _XA_MOTIF_DRAG_TARGETS ||
550 targets_property_rec_ptr == NULL) {
551
552 DTRACE_PRINT2("%s:%d Cannot read _XA_MOTIF_DRAG_TARGETS", __FILE__, __LINE__);
553 return NULL;
554 }
555
556 if (targets_property_rec_ptr->protocol_version !=
557 MOTIF_DND_PROTOCOL_VERSION) {
558 DTRACE_PRINT2("%s:%d incorrect protocol version", __FILE__, __LINE__);
559 return NULL;
560 }
561
562 if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) {
563 SWAP2BYTES(targets_property_rec_ptr->num_entries);
564 SWAP4BYTES(targets_property_rec_ptr->heap_offset);
565 }
566
567 targets_table = (TargetsTable*)malloc(sizeof(TargetsTable));
568 if (targets_table == NULL) {
569 DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
570 return NULL;
571 }
572 targets_table->num_entries = targets_property_rec_ptr->num_entries;
573 targets_table->entries =
574 (TargetsTableEntry*)malloc(sizeof(TargetsTableEntry) *
575 targets_property_rec_ptr->num_entries);
576 if (targets_table->entries == NULL) {
577 DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
578 free(targets_table);
579 return NULL;
580 }
581
582 bufptr = (char *)targets_property_rec_ptr + sizeof(TargetsPropertyRec);
583 for (i = 0; i < targets_table->num_entries; i++) {
584 CARD16 num_targets;
585 Atom* targets;
586 memcpy(&num_targets, bufptr, 2 );
587 bufptr += 2;
588 if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) {
589 SWAP2BYTES(num_targets);
590 }
591
592 targets = (Atom*)malloc(sizeof(Atom) * num_targets);
593 if (targets == NULL) {
594 DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
595 free(targets_table->entries);
596 free(targets_table);
597 return NULL;
598 }
599 for (j = 0; j < num_targets; j++) {
600 CARD32 target;
601 memcpy(&target, bufptr, 4 );
602 bufptr += 4;
603 if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) {
604 SWAP4BYTES(target);
605 }
606 targets[j] = (Atom)target;
607 }
608
609 targets_table->entries[i].num_targets = num_targets;
610 targets_table->entries[i].targets = targets;
611 }
612
613 free(targets_property_rec_ptr);
614
615 return targets_table;
616}
617
618static void
619put_target_list_table(Display* dpy, TargetsTable* table) {
620 Window motif_window = get_motif_window(dpy);
621 TargetsPropertyRec* targets_property_rec_ptr;
622 size_t table_size = sizeof(TargetsPropertyRec);
623 unsigned char ret;
624 int i, j;
625 char* buf;
626
627 for (i = 0; i < table->num_entries; i++) {
628 table_size += table->entries[i].num_targets * sizeof(Atom) + 2;
629 }
630
631 targets_property_rec_ptr = (TargetsPropertyRec*)malloc(table_size);
632 if (targets_property_rec_ptr == NULL) {
633 DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
634 return;
635 }
636 targets_property_rec_ptr->byte_order = MOTIF_BYTE_ORDER;
637 targets_property_rec_ptr->protocol_version = MOTIF_DND_PROTOCOL_VERSION;
638 targets_property_rec_ptr->num_entries = table->num_entries;
639 targets_property_rec_ptr->heap_offset = table_size;
640
641 buf = (char*)targets_property_rec_ptr + sizeof(TargetsPropertyRec);
642
643 for (i = 0; i < table->num_entries; i++) {
644 CARD16 num_targets = table->entries[i].num_targets;
645 memcpy(buf, &num_targets, 2);
646 buf += 2;
647
648 for (j = 0; j < num_targets; j++) {
649 CARD32 target = table->entries[i].targets[j];
650 memcpy(buf, &target, 4);
651 buf += 4;
652 }
653 }
654
655 ret = checked_XChangeProperty(dpy, motif_window, _XA_MOTIF_DRAG_TARGETS,
656 _XA_MOTIF_DRAG_TARGETS, 8, PropModeReplace,
657 (unsigned char*)targets_property_rec_ptr,
658 (int)table_size);
659
660 if (ret != Success) {
661 DTRACE_PRINT2("%s:%d XChangeProperty failed", __FILE__, __LINE__);
662 }
663
664 XtFree((char*)targets_property_rec_ptr);
665}
666
667static int
668_compare(const void* p1, const void* p2) {
669 long diff = *(Atom*)p1 - *(Atom*)p2;
670
671 if (diff > 0) {
672 return 1;
673 } else if (diff < 0) {
674 return -1;
675 } else {
676 return 0;
677 }
678}
679
680/*
681 * Returns the index for the specified target list or -1 on failure.
682 */
683int
684get_index_for_target_list(Display* dpy, Atom* targets, unsigned int num_targets) {
685 TargetsTable* targets_table = NULL;
686 Atom* sorted_targets = NULL;
687 int i, j;
688 int ret = -1;
689
690 if (targets == NULL && num_targets > 0) {
691 DTRACE_PRINT4("%s:%d targets=%X num_targets=%d",
692 __FILE__, __LINE__, targets, num_targets);
693 return -1;
694 }
695
696 if (num_targets > 0) {
697 sorted_targets = (Atom*)malloc(sizeof(Atom) * num_targets);
698 if (sorted_targets == NULL) {
699 DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__);
700 return -1;
701 }
702
703 memcpy(sorted_targets, targets, sizeof(Atom) * num_targets);
704 qsort ((void *)sorted_targets, (size_t)num_targets, (size_t)sizeof(Atom),
705 _compare);
706 }
707
708 XGrabServer(dpy);
709 targets_table = get_target_list_table(dpy);
710
711 if (targets_table != NULL) {
712 for (i = 0; i < targets_table->num_entries; i++) {
713 TargetsTableEntry* entry_ptr = &targets_table->entries[i];
714 Boolean equals = True;
715 if (num_targets == entry_ptr->num_targets) {
716 for (j = 0; j < entry_ptr->num_targets; j++) {
717 if (sorted_targets[j] != entry_ptr->targets[j]) {
718 equals = False;
719 break;
720 }
721 }
722 } else {
723 equals = False;
724 }
725
726 if (equals) {
727 XUngrabServer(dpy);
728 /* Workaround for bug 5039226 */
729 XSync(dpy, False);
730 free((char*)sorted_targets);
731 return i;
732 }
733 }
734 } else {
735 targets_table = (TargetsTable*)malloc(sizeof(TargetsTable));
736 targets_table->num_entries = 0;
737 targets_table->entries = NULL;
738 }
739
740 /* Index not found - expand the table. */
741 targets_table->entries =
742 (TargetsTableEntry*)realloc((char*)targets_table->entries,
743 sizeof(TargetsTableEntry) *
744 (targets_table->num_entries + 1));
745 if (targets_table->entries == NULL) {
746 DTRACE_PRINT2("%s:%d realloc failed.", __FILE__, __LINE__);
747 XUngrabServer(dpy);
748 /* Workaround for bug 5039226 */
749 XSync(dpy, False);
750 free((char*)sorted_targets);
751 return -1;
752 }
753
754 /* Fill in the new entry */
755 {
756 TargetsTableEntry* new_entry =
757 &targets_table->entries[targets_table->num_entries];
758
759 new_entry->num_targets = num_targets;
760 if (num_targets > 0) {
761 new_entry->targets = (Atom*)malloc(sizeof(Atom) * num_targets);
762 if (new_entry->targets == NULL) {
763 DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__);
764 XUngrabServer(dpy);
765 /* Workaround for bug 5039226 */
766 XSync(dpy, False);
767 free((char*)sorted_targets);
768 return -1;
769 }
770 memcpy(new_entry->targets, sorted_targets,
771 sizeof(Atom) * num_targets);
772 } else {
773 new_entry->targets = NULL;
774 }
775 }
776
777 targets_table->num_entries++;
778
779 put_target_list_table(dpy, targets_table);
780
781 XUngrabServer(dpy);
782 /* Workaround for bug 5039226 */
783 XSync(dpy, False);
784
785 ret = targets_table->num_entries - 1;
786
787 free((char*)sorted_targets);
788
789 for (i = 0; i < targets_table->num_entries; i++) {
790 free((char*)targets_table->entries[i].targets);
791 }
792
793 free((char*)targets_table->entries);
794 free((char*)targets_table);
795 return ret;
796}
797
798/*
799 * Retrieves the target list for the specified index.
800 * Stores the number of targets in the list to 'num_targets' and the targets
801 * to 'targets'. On failure stores 0 and NULL respectively.
802 * The caller should free the allocated array when done with it.
803 */
804void
805get_target_list_for_index(Display* dpy, int index, Atom** targets, unsigned int* num_targets) {
806 TargetsTable* table = get_target_list_table(dpy);
807 TargetsTableEntry* entry = NULL;
808
809 if (table == NULL) {
810 DTRACE_PRINT2("%s:%d No target table.", __FILE__, __LINE__);
811 *targets = NULL;
812 *num_targets = 0;
813 return;
814 }
815
816 if (table->num_entries <= index) {
817 DTRACE_PRINT4("%s:%d index out of bounds idx=%d entries=%d",
818 __FILE__, __LINE__, index, table->num_entries);
819 *targets = NULL;
820 *num_targets = 0;
821 return;
822 }
823
824 entry = &table->entries[index];
825
826 *targets = (Atom*)malloc(entry->num_targets * sizeof(Atom));
827
828 if (*targets == NULL) {
829 DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__);
830 *num_targets = 0;
831 return;
832 }
833
834 memcpy(*targets, entry->targets, entry->num_targets * sizeof(Atom));
835 *num_targets = entry->num_targets;
836}
837
838jint
839motif_to_java_actions(unsigned char motif_action) {
840 jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE;
841
842 if (motif_action & MOTIF_DND_COPY) {
843 java_action |= java_awt_dnd_DnDConstants_ACTION_COPY;
844 }
845
846 if (motif_action & MOTIF_DND_MOVE) {
847 java_action |= java_awt_dnd_DnDConstants_ACTION_MOVE;
848 }
849
850 if (motif_action & MOTIF_DND_LINK) {
851 java_action |= java_awt_dnd_DnDConstants_ACTION_LINK;
852 }
853
854 return java_action;
855}
856
857unsigned char
858java_to_motif_actions(jint java_action) {
859 unsigned char motif_action = MOTIF_DND_NOOP;
860
861 if (java_action & java_awt_dnd_DnDConstants_ACTION_COPY) {
862 motif_action |= MOTIF_DND_COPY;
863 }
864
865 if (java_action & java_awt_dnd_DnDConstants_ACTION_MOVE) {
866 motif_action |= MOTIF_DND_MOVE;
867 }
868
869 if (java_action & java_awt_dnd_DnDConstants_ACTION_LINK) {
870 motif_action |= MOTIF_DND_LINK;
871 }
872
873 return motif_action;
874}
875
876Boolean
877awt_dnd_process_event(XEvent* event) {
878 Boolean ret = awt_dnd_ds_process_event(event) ||
879 awt_dnd_dt_process_event(event);
880
881 /* Extract the event from the queue if it is processed. */
882 if (ret) {
883 XNextEvent(event->xany.display, event);
884 }
885
886 return ret;
887}