2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: proxy.c /main/6 1998/08/03 09:33:32 mgreess $ */
24 /* Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc. */
25 /* Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 AT&T */
26 /* All Rights Reserved */
28 /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
29 /* UNIX System Laboratories, Inc. */
30 /* The copyright notice above does not evidence any */
31 /* actual or intended publication of such source code. */
34 * The Proxy Agent is used to translate Drag And Drop (dnd)
35 * messages between Motif and OLIT clients.
38 * Any Motif or OLIT client running before the proxy was started will have to
39 * be restarted to participate in drag and drop.
45 #include <X11/Xproto.h>
47 #include <X11/Xutil.h>
48 #include <X11/Xatom.h>
51 #define DPRINTF(args) (void) printf args
52 #define a2s(atom) (atom ? XGetAtomName(dpy, atom) : "0")
57 #define OLIT_DROP_SELECTION 0
58 #define OLIT_DROP_TIME 1
59 #define OLIT_DROP_COORDINATE 2
60 #define OLIT_DROP_SITE_ID 3
61 #define OLIT_DROP_OPERATION 4
63 #define GET_PROPERTY_MAX 1000000
64 #define MOTIF_DRAG_PROTOCOL_VERSION 0
65 #define DROP_TABLE_MAX 10
66 #define MOTIF_MESSAGE_TYPE_MASK 0x7f
67 #define MOTIF_RECEIVER_BIT 0x80
68 #define MOTIF_DROP_SITE_STATUS_MASK ((CARD16) 0xFF0F)
69 #define MOTIF_DROP_SITE_STATUS_VALID ((CARD16) 0x0030)
72 MOTIF_TOP_LEVEL_ENTER,
73 MOTIF_TOP_LEVEL_LEAVE,
75 MOTIF_DROP_SITE_ENTER,
76 MOTIF_DROP_SITE_LEAVE,
79 MOTIF_DRAG_DROP_FINISH,
80 MOTIF_OPERATION_CHANGED
86 XmDRAG_PREFER_PREREGISTER,
88 XmDRAG_PREFER_DYNAMIC,
90 XmDRAG_PREFER_RECEIVER
96 Time time_stamp; /* time of drop_start or trigger */
98 Window proxy_sel_req_win; /* needed for concurrent drops */
99 Window receiver_win; /* was motif_receiver_win!!!
100 * This field was only for the olit
101 * source and was initialized in
102 * HandleOlitTrigger().
104 * Now this field is also served as
105 * the olit destination for the
106 * SUN_DRAGDROP_DONE situation and
107 * this field is initialized in
108 * ProxyMain:SelectionRequest... */
109 CARD32 motif_action; /* for olit source only */
110 INT16 trigger_x; /* for olit source only */
111 INT16 trigger_y; /* for olit source only */
112 Atom status; /* for olit source only!
113 * ATOM_MOTIF_SUCESS or
114 * ATOM_MOTIF_FAILURE.
115 * This field will set in
116 * ProxyMain:SelectionRequest... */
126 BYTE protocol_version;
127 CARD16 num_target_lists B16;
140 } motif_drop_start_t;
144 BYTE protocol_version;
145 CARD16 targets_index B16;
146 CARD32 icc_handle B32;
151 BYTE protocol_version;
152 BYTE drag_protocol_style;
154 CARD32 proxy_window B32;
155 CARD16 num_drop_sites B16;
157 CARD32 heap_offset B32;
160 typedef struct _box {
161 short x1, x2, y1, y2;
171 typedef struct _site {
173 unsigned long site_id;
180 extern char *ProgramName;
181 extern drop_site_t *MasterSiteList;
182 extern Window proxy_win;
183 extern Atom ATOM_DRAGDROP_INTEREST;
184 extern Atom ATOM_WM_STATE;
186 unsigned char *GetInterestProperty();
188 static ForwardConversion();
190 static drop_info_t drop_table[DROP_TABLE_MAX];
191 Atom ATOM_SUN_DND_TRIGGER;
192 Atom ATOM_SUN_DND_DONE;
193 Atom ATOM_SUN_SELECTION_END;
194 Atom ATOM_SUN_SELECTION_ERROR;
195 Atom ATOM_SUN_DND_ACK;
196 Atom ATOM_MOTIF_DRAG_WIN;
197 Atom ATOM_MOTIF_PROXY_WIN;
198 Atom ATOM_MOTIF_DND_MESS;
199 Atom ATOM_MOTIF_INITIATOR_INFO;
200 Atom ATOM_MOTIF_RECEIVER_INFO;
201 Atom ATOM_MOTIF_SUCCESS;
202 Atom ATOM_MOTIF_FAILURE;
203 Atom ATOM_MOTIF_TARGETS;
206 Window motif_drag_win;
207 char motif_byte_order;
210 InitializeByteOrder()
212 unsigned int endian = 1;
214 /* if LSByte is set, then hardware uses little endian addressing */
215 if (*((char *)&endian))
216 motif_byte_order = 'l';
218 motif_byte_order = 'B';
221 /* swap 2 bytes of data if the byte order is different */
222 Swap2Bytes(byte_order, data)
226 static CARD16 ret_data;
227 char *old_p = (char *) &data;
228 char *new_p = (char *) &ret_data;
230 if (byte_order == motif_byte_order)
238 /* swap 4 bytes of data if the byte order is different */
239 Swap4Bytes(byte_order, data)
243 static CARD32 ret_data;
244 char *old_p = (char *) &data;
245 char *new_p = (char *) &ret_data;
247 if (byte_order == motif_byte_order)
258 /* Get a new drop record */
259 /* use source_handle to indicate whether record is free or in use */
263 int i, oldest_index=0;
265 for(i=0; i<DROP_TABLE_MAX; i++)
266 if (drop_table[i].source_handle == 0) {
270 /* if there are no more free records then use the oldest record */
271 for(i=1; i<DROP_TABLE_MAX; i++)
272 if (drop_table[i].time_stamp < drop_table[oldest_index].time_stamp)
275 return drop_table+oldest_index;
278 /* Search for a drop record */
279 /* use source_handle as the key to the drop_info record */
281 GetDropInfo(proxy_sel_req_win)
282 Window proxy_sel_req_win;
286 for(i=0; i<DROP_TABLE_MAX; i++)
287 if (drop_table[i].proxy_sel_req_win == proxy_sel_req_win) {
293 /* Search for a drop record using the proxy_handle as the key */
295 GetDropInfoUsingProxyHandle(proxy_handle)
300 for(i=0; i<DROP_TABLE_MAX; i++)
301 if (drop_table[i].proxy_handle == proxy_handle
302 && drop_table[i].source_handle)
307 /* Delete a drop record */
309 ClearDropInfo(proxy_handle)
313 for(i=0; i<DROP_TABLE_MAX; i++)
314 if (drop_table[i].proxy_handle == proxy_handle) {
315 drop_table[i].source_handle = 0; /* reset flag */
320 /* get the window that has the atom associated with it */
322 GetAtomWindow(dpy, win, atom)
329 unsigned int nchildren;
333 unsigned long nitems, after;
337 XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
338 &type, &format, &nitems, &after, &data);
342 if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren) ||
345 for (i = nchildren - 1; i >= 0; i--) {
346 if (inf = GetAtomWindow(dpy, children[i], atom))
353 /* get the window that is a property of the inputed window */
355 GetPropertyWindow(dpy, in_win, atom)
362 unsigned long lengthRtn;
363 unsigned long bytesafter;
364 Window *property = NULL;
367 if ((XGetWindowProperty (dpy,
377 (unsigned char **) &property) == Success) &&
378 (type == XA_WINDOW) &&
384 XFree ((char *)property);
390 /* startup initialization */
391 ProxyInit(dpy, dsdm_win)
395 enum { XA_MOTIF_DRAG_WINDOW, XA_MOTIF_DRAG_PROXY_WINDOW,
396 XA_MOTIF_DRAG_AND_DROP_MESSAGE,
397 XA_MOTIF_DRAG_INITIATOR_INFO, XA_MOTIF_DRAG_RECEIVER_INFO,
398 XAXmTRANSFER_SUCCESS, XAXmTRANSFER_FAILURE,
399 XA_MOTIF_DRAG_TARGETS, XA_SUN_DRAGDROP_TRIGGER,
400 XA_SUN_DRAGDROP_DONE, XA_SUN_SELECTION_END, XA_SUN_SELECTION_ERROR,
401 XA_SUN_DRAGDROP_ACK, XATARGETS, XAMULTIPLE, NUM_ATOMS };
402 static char* atom_names[] = {
403 "_MOTIF_DRAG_WINDOW", "_MOTIF_DRAG_PROXY_WINDOW",
404 "_MOTIF_DRAG_AND_DROP_MESSAGE",
405 "_MOTIF_DRAG_INITIATOR_INFO", "_MOTIF_DRAG_RECEIVER_INFO",
406 "XmTRANSFER_SUCCESS", "XmTRANSFER_FAILURE",
407 "_MOTIF_DRAG_TARGETS", "_SUN_DRAGDROP_TRIGGER",
408 "_SUN_DRAGDROP_DONE", "_SUN_SELECTION_END", "_SUN_SELECTION_ERROR",
409 "_SUN_DRAGDROP_ACK", "TARGETS", "MULTIPLE" };
412 enum { ATOM_BUF_LEN = 25 };
413 char buf[ATOM_BUF_LEN * DROP_TABLE_MAX];
414 char *buf_names[DROP_TABLE_MAX];
415 Atom buf_atoms[DROP_TABLE_MAX];
416 XSetWindowAttributes attr;
417 Atom atoms[NUM_ATOMS];
419 InitializeByteOrder();
421 /* make motif_drag_win and proxy_win persistant */
422 XSetCloseDownMode(dpy, RetainPermanent);
423 XInternAtoms(dpy, atom_names, NUM_ATOMS, False, atoms);
425 ATOM_MOTIF_DRAG_WIN = atoms[XA_MOTIF_DRAG_WINDOW];
426 ATOM_MOTIF_PROXY_WIN = atoms[XA_MOTIF_DRAG_PROXY_WINDOW];
427 ATOM_MOTIF_DND_MESS = atoms[XA_MOTIF_DRAG_AND_DROP_MESSAGE];
428 ATOM_MOTIF_INITIATOR_INFO = atoms[XA_MOTIF_DRAG_INITIATOR_INFO];
429 ATOM_MOTIF_RECEIVER_INFO = atoms[XA_MOTIF_DRAG_RECEIVER_INFO];
430 ATOM_MOTIF_SUCCESS = atoms[XAXmTRANSFER_SUCCESS];
431 ATOM_MOTIF_FAILURE = atoms[XAXmTRANSFER_FAILURE];
432 ATOM_MOTIF_TARGETS = atoms[XA_MOTIF_DRAG_TARGETS];
434 ATOM_SUN_DND_TRIGGER = atoms[XA_SUN_DRAGDROP_TRIGGER];
435 ATOM_SUN_DND_DONE = atoms[XA_SUN_DRAGDROP_DONE];
436 ATOM_SUN_SELECTION_ERROR = atoms[XA_SUN_SELECTION_ERROR];
437 ATOM_SUN_SELECTION_END = atoms[XA_SUN_SELECTION_END];
438 ATOM_SUN_DND_ACK = atoms[XA_SUN_DRAGDROP_ACK];
440 ATOM_TARGETS = atoms[XATARGETS];
441 ATOM_MULTIPLE = atoms[XAMULTIPLE];
443 for (i=0; i<DROP_TABLE_MAX; i++) {
444 buf_names[i] = buf + (ATOM_BUF_LEN * i);
445 sprintf(buf_names[i], "DND_PROXY_HANDLE_%d", i);
447 XInternAtoms(dpy, buf_names, DROP_TABLE_MAX, False, buf_atoms);
449 for (i=0; i<DROP_TABLE_MAX; i++) {
450 drop_table[i].proxy_handle = buf_atoms[i];
451 drop_table[i].proxy_sel_req_win =
453 DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0,
454 InputOnly, CopyFromParent, 0, &attr);
456 motif_drag_win = GetPropertyWindow(dpy, DefaultRootWindow(dpy),
457 ATOM_MOTIF_DRAG_WIN);
459 /* if motif_drag_win doesn't exist then define and declare it */
460 if (motif_drag_win == None) {
461 motif_drag_win = dsdm_win;
462 XChangeProperty (dpy,
463 DefaultRootWindow(dpy),
468 (unsigned char *) &motif_drag_win,
473 /* define and declare the proxy_window */
474 proxy_win = dsdm_win;
475 XChangeProperty(dpy, motif_drag_win,
476 ATOM_MOTIF_PROXY_WIN, /* property */
477 XA_WINDOW, /* type */
479 PropModeReplace, /* mode */
480 (unsigned char *) &proxy_win, /* data */
485 printf("drag_win=0x%lx, proxy_win=0x%lx\n", motif_drag_win, proxy_win);
487 /* Watch for mapping of top level windows */
488 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureNotifyMask);
490 /* Watch for someone taking away proxy_win ownership */
491 XSelectInput(dpy, proxy_win, PropertyChangeMask);
493 for(i=0; i<DROP_TABLE_MAX; i++)
494 XSetSelectionOwner(dpy, drop_table[i].proxy_handle,
495 proxy_win, CurrentTime);
498 /* Place the motif receiver property on the Openlook receiver's top
500 AdvertiseMotifDropSite(dpy, win)
504 motif_receiver_t receiver_info;
505 unsigned long nitems;
507 int motif_receiver = False;
509 #define OL_PREVIEW_INDEX 4
510 #define MOTIF_RECEIVER_FLAG 0x80000000
511 /* make sure receiver is not a Motif application */
512 data = (CARD32 *) GetInterestProperty(dpy, win, &nitems);
514 if (nitems > OL_PREVIEW_INDEX &&
515 (data[OL_PREVIEW_INDEX] & MOTIF_RECEIVER_FLAG))
516 motif_receiver = True;
523 printf("AdvertiseMotifDropSite\n");
526 receiver_info.byte_order = motif_byte_order;
527 receiver_info.protocol_version = MOTIF_DRAG_PROTOCOL_VERSION;
528 receiver_info.drag_protocol_style = XmDRAG_DROP_ONLY;
529 receiver_info.proxy_window = proxy_win;
530 receiver_info.num_drop_sites = 0; /* not used in drag_drop_only mode */
531 receiver_info.heap_offset = 0; /* not used in drag_drop_only mode */
535 ATOM_MOTIF_RECEIVER_INFO, /* property */
536 ATOM_MOTIF_RECEIVER_INFO, /* type */
538 PropModeReplace, /* mode */
539 (unsigned char *) &receiver_info, /* data */
540 sizeof(motif_receiver_t) /* size of data in bytes */
544 /* Determine if the drop coordinate is within a rectangle */
546 InRect(drop_x, drop_y, x, y, width, height)
547 int drop_x, drop_y, x, y;
548 unsigned int width, height;
550 if ((drop_x >= x) && (drop_x <= (x+width)) &&
551 (drop_y >= y) && (drop_y <= (y+height)))
557 #define DRAGDROP_VERSION 0 /* OLIT dnd version */
558 #define INTEREST_RECT 0
559 #define INTEREST_WINDOW 1
560 #define NEXTWORD(result) if (index >= nitems) { \
564 (result) = data[index++]
566 /* get the drop site given the window and coordinate */
568 GetOlitDropSite(dpy, top_level_win, drop_x, drop_y, ret_site_id, ret_event_win)
570 Window top_level_win;
571 INT16 drop_x, drop_y;
572 unsigned long *ret_site_id;
573 Window *ret_event_win;
575 unsigned long *data, nitems, version, nsites, event_win, site_id, flags;
576 unsigned long areatype, nrects, areawin;
582 unsigned int width, height, border, ujunk;
585 *ret_event_win = *ret_site_id = 0;
586 data = (unsigned long *) GetInterestProperty(dpy, top_level_win, &nitems);
587 if (data == NULL) return;
589 /* get root window */
590 if (XGetGeometry(dpy, top_level_win, &root_win, &junk, &junk,
591 &ujunk, &ujunk, &ujunk, &ujunk) == 0)
595 if (version != DRAGDROP_VERSION) return;
597 for (i=0; i<nsites && !done; ++i) {
598 NEXTWORD(event_win); NEXTWORD(site_id); NEXTWORD(flags);
603 for (j=0; j<nrects && !done; ++j) {
608 if (XTranslateCoordinates(dpy, top_level_win, root_win, x, y,
610 done = InRect((int)drop_x,(int)drop_y, x, y, width,height);
613 case INTEREST_WINDOW:
615 for (j=0; j<nrects && !done; ++j) {
617 if (0 == XGetGeometry(dpy, areawin, &wjunk, &junk, &junk,
618 &width, &height, &border, &ujunk)) {
620 "%s: XGetGeometry failed on window 0x%lx\n",
621 ProgramName, areawin);
624 if (XTranslateCoordinates(dpy, areawin, root_win, 0, 0,
628 width = width + border;
629 height = height + border;
630 done = InRect((int)drop_x, (int)drop_y, x, y,width,height);
636 "%s: unknown site area type on window 0x%lx\n",
637 ProgramName, top_level_win);
642 *ret_site_id = site_id;
643 *ret_event_win = event_win;
647 #define MOTIF_DROP_MOVE_ACTION (1 << 0)
648 #define MOTIF_DROP_COPY_ACTION (1 << 1)
649 #define MOTIF_DROP_LINK_ACTION (1 << 2)
650 #define MOTIF_DROP_ALLOWED_ACTIONS 0x0F00
651 #define OLIT_DROP_ACKNOWLEDGE_ACTION (1 << 1)
652 #define OLIT_DROP_TRANSIENT_ACTION (1 << 2)
653 #define OLIT_DROP_MOVE_ACTION (1 << 0)
654 #define OLIT_DROP_COPY_ACTION 0
655 #define OLIT_DROP_LINK_ACTION (1 << 10)
657 /* translate an OLIT operation to a Motif operation */
659 ConvertOlitAction(olit_action)
664 motif_action = MOTIF_DROP_COPY_ACTION | (MOTIF_DROP_COPY_ACTION << 8);
666 if (olit_action & OLIT_DROP_MOVE_ACTION)
667 motif_action |= MOTIF_DROP_MOVE_ACTION | (MOTIF_DROP_MOVE_ACTION << 8);
668 else if (olit_action & OLIT_DROP_LINK_ACTION)
669 motif_action |= MOTIF_DROP_LINK_ACTION | (MOTIF_DROP_LINK_ACTION << 8);
674 /* translate a Motif operation to an OLIT operation */
676 ConvertMotifAction(motif_action)
681 olit_action = OLIT_DROP_TRANSIENT_ACTION;
682 if (motif_action & MOTIF_DROP_MOVE_ACTION)
683 olit_action |= OLIT_DROP_MOVE_ACTION;
684 else if (motif_action & MOTIF_DROP_COPY_ACTION)
685 olit_action |= OLIT_DROP_COPY_ACTION;
686 else if (motif_action & MOTIF_DROP_LINK_ACTION)
687 olit_action |= OLIT_DROP_LINK_ACTION;
693 /* Process Motif ClientMessage */
694 HandleMotifMessage(dpy, event)
696 XClientMessageEvent *event;
698 motif_drop_start_t info;
699 drop_info_t *drop_info;
702 dest_win = event->window;
703 info.message_type = event->data.b[0];
704 info.byte_order = event->data.b[1];
706 if (info.message_type & MOTIF_RECEIVER_BIT) {
708 If initiator is Motif then forward it this message. */
709 if (event->window != proxy_win)
710 XSendEvent(dpy, event->window, False,
711 NoEventMask, (XEvent *) event);
714 /* initiator message */
715 if ((info.message_type & MOTIF_MESSAGE_TYPE_MASK)== MOTIF_DROP_START) {
716 unsigned long site_id;
718 XClientMessageEvent out_event;
721 /* receiver will never be MOTIF because MOTIF receivers
722 don't set the proxy field of RECEIVER_INFO atom
725 info.flags = Swap2Bytes(info.byte_order, event->data.s[1]);
727 /* since dropSiteStatus can't be determined in a short amount
728 of time, always return a valid drop site */
729 info.flags &= MOTIF_DROP_SITE_STATUS_MASK;
730 info.flags |= MOTIF_DROP_SITE_STATUS_VALID;
732 info.time = Swap4Bytes(info.byte_order, event->data.l[1]);
733 info.x = Swap2Bytes(info.byte_order, event->data.s[4]);
734 info.y = Swap2Bytes(info.byte_order, event->data.s[5]);
735 info.icc_handle = Swap4Bytes(info.byte_order, event->data.l[3]);
736 info.src_window = Swap4Bytes(info.byte_order, event->data.l[4]);
738 /* send a drop start ack here
739 to give ourselves more time to process the drop
740 because GetOlitDropSite or
741 selection processing might take a long time
743 info.message_type = event->data.b[0] |= MOTIF_RECEIVER_BIT;
744 event->data.s[1] = Swap2Bytes(info.byte_order, info.flags);
745 event->window = info.src_window;
746 XSendEvent(dpy, event->window, False,
747 NoEventMask, (XEvent *) event);
749 /* get olit drop site */
751 dest_win, info.x, info.y, &site_id, &event_win);
752 drop_info = NewDropInfo();
753 olit_action = ConvertMotifAction(info.flags);
754 if (event_win && olit_action) {
755 drop_info->source_handle = info.icc_handle;
756 drop_info->time_stamp = info.time;
758 out_event.type = ClientMessage;
759 out_event.send_event = True;
760 out_event.display = dpy;
761 out_event.window = event_win;
762 out_event.message_type = ATOM_SUN_DND_TRIGGER;
763 out_event.format = 32;
765 out_event.data.l[OLIT_DROP_SELECTION]= drop_info->proxy_handle;
766 out_event.data.l[OLIT_DROP_TIME] = info.time;
767 out_event.data.l[OLIT_DROP_COORDINATE] =
768 (info.x << 16) | info.y;
769 out_event.data.l[OLIT_DROP_SITE_ID] = site_id;
770 out_event.data.l[OLIT_DROP_OPERATION] = olit_action;
771 XSendEvent(dpy, out_event.window, False,
772 NoEventMask, (XEvent *) &out_event);
775 /* tell motif initiator that the drop failed */
776 XConvertSelection(dpy,
788 /* Process OLIT ClientMessage */
790 HandleOlitTrigger(dpy, event)
792 XClientMessageEvent *event;
795 char success = False;
796 Atom source_handle = event->data.l[OLIT_DROP_SELECTION];
797 Time time_stamp = event->data.l[OLIT_DROP_TIME];
799 /* proxy agent only gets ATOM_SUN_DND_TRIGGER if
802 /* map site_id to site_window */
803 for (site = MasterSiteList; site != NULL; site = site->next) {
804 if (site->site_id == event->data.l[OLIT_DROP_SITE_ID]) {
805 drop_info_t *drop_info = NewDropInfo();
807 drop_info->motif_action =
808 ConvertOlitAction(event->data.l[OLIT_DROP_OPERATION]);
809 drop_info->receiver_win = site->window_id;
810 drop_info->source_handle = source_handle;
811 drop_info->trigger_x = (event->data.l[OLIT_DROP_COORDINATE]) >> 16;
812 drop_info->trigger_y =
813 (event->data.l[OLIT_DROP_COORDINATE]) & 0x0000ffff;
814 drop_info->time_stamp = time_stamp;
816 if ((event->data.l[OLIT_DROP_OPERATION])
817 & OLIT_DROP_ACKNOWLEDGE_ACTION) {
818 XConvertSelection(dpy,
819 drop_info->source_handle, /* selection */
821 ATOM_SUN_DND_ACK, /* property */
822 drop_info->proxy_sel_req_win,
823 drop_info->time_stamp /* time */
827 /* get olit initiator targets */
828 XConvertSelection(dpy,
829 drop_info->source_handle, /* selection */
831 drop_info->proxy_handle, /* property */
832 drop_info->proxy_sel_req_win,
833 drop_info->time_stamp /* time */
840 /* tell olit initiator we are done */
841 XConvertSelection(dpy, source_handle,
843 ATOM_SUN_DND_DONE, /* property */
849 /* Place the Motif initiator property on the initiator's top level window */
851 UpdateInitiatorAtom(dpy, win, channel, targets_index)
855 CARD16 targets_index;
857 motif_initiator_t initiator_info;
859 initiator_info.byte_order = motif_byte_order;
860 initiator_info.protocol_version = MOTIF_DRAG_PROTOCOL_VERSION;
861 initiator_info.targets_index = targets_index;
862 initiator_info.icc_handle = channel;
864 XChangeProperty(dpy, win,
865 channel, /* property */
866 ATOM_MOTIF_INITIATOR_INFO, /* type */
868 PropModeReplace, /* mode */
869 (unsigned char *) &initiator_info, /* data */
870 sizeof(motif_initiator_t) /* size of data in bytes */
874 /* Send Motif DROP_START ClientMessage to receiver */
875 SendStartDrop(dpy, src_win, drop_info)
878 drop_info_t *drop_info;
880 motif_drop_start_t info;
881 XClientMessageEvent event;
883 info.message_type = MOTIF_DROP_START;
884 info.byte_order = motif_byte_order;
885 info.flags = drop_info->motif_action;
886 info.time = drop_info->time_stamp;
887 info.x = drop_info->trigger_x;
888 info.y = drop_info->trigger_y;
889 info.icc_handle = drop_info->proxy_handle;
890 info.src_window = src_win;
892 event.type = ClientMessage;
893 event.send_event = True;
895 event.window = drop_info->receiver_win;
896 event.message_type = ATOM_MOTIF_DND_MESS;
898 memcpy(&event.data, &info, sizeof(info));
899 XSendEvent(dpy, event.window, False, NoEventMask, (XEvent *) &event);
902 /* Compare data of type Atom */
904 AtomCompare(atom1, atom2)
907 return(*atom1 - *atom2);
910 /* Get the Motif TARGETS */
912 GetTargetsList(dpy, targets_list_p)
914 motif_targets_t **targets_list_p;
916 motif_targets_t *targets_list;
919 unsigned long length, bytes_after;
921 status = XGetWindowProperty(dpy,
924 0L, GET_PROPERTY_MAX,
931 (unsigned char **) &targets_list);
932 if ((status != Success) || (type != ATOM_MOTIF_TARGETS) || (length == 0)) {
933 /* allocate targets_list of zero targets */
934 targets_list = (motif_targets_t *) malloc(sizeof(motif_targets_t));
935 targets_list->byte_order = motif_byte_order;
936 targets_list->protocol_version = MOTIF_DRAG_PROTOCOL_VERSION;
937 targets_list->num_target_lists = 0;
938 targets_list->size = sizeof(motif_targets_t);
940 *targets_list_p = targets_list;
944 MatchTargets(targets_list, atoms, atom_cnt, targets_index_p)
945 motif_targets_t *targets_list;
947 unsigned long atom_cnt;
948 CARD16 *targets_index_p;
952 int num_sub_list_items, sub_list_index;
954 char byte_order = targets_list->byte_order;
955 int num_target_lists;
956 CARD32 target, tmp_data;
958 num_target_lists = Swap2Bytes(byte_order, targets_list->num_target_lists);
959 data = (CARD32 *) (targets_list+1);
960 for (target_index=0; target_index < num_target_lists; target_index++) {
961 num_sub_p = (CARD16 *) data;
962 num_sub_list_items = (int) Swap2Bytes(byte_order, *num_sub_p);
963 data = (CARD32 *) (num_sub_p+1);
965 if (num_sub_list_items == atom_cnt) {
966 for (sub_list_index=0; sub_list_index < num_sub_list_items;
968 /* address isn't long word aligned so copy one byte at a time */
969 memcpy(&tmp_data, data+sub_list_index, 4);
970 target = Swap4Bytes(byte_order, tmp_data);
971 if (target != atoms[sub_list_index])
974 /* if all the atoms match then we got a match */
975 if (sub_list_index >= num_sub_list_items) {
979 data += num_sub_list_items;
982 *targets_index_p = target_index;
985 /* Put OLIT targets on the Motif TARGETS targets list */
987 GetTargetsIndex(dpy, in_data, atom_cnt, targets_index_p)
989 unsigned char *in_data;
990 unsigned long atom_cnt;
991 CARD16 *targets_index_p; /* RETURN */
993 Atom *atoms = (Atom *) in_data;
994 motif_targets_t *new_list, *targets_list;
995 int i, old_size, new_size;
997 CARD32 *target_data, tmp_data;
999 motif_initiator_t initiator_info;
1001 CARD16 num_target_lists;
1004 for (i=0; i<atom_cnt; i++) {
1005 printf("GetTargetsIndex: target[%d]=%s\n", i, a2s(atoms[i]));
1009 /* search existing targets list for a match, otherwise add our
1010 targets to the list */
1011 qsort((void *)atoms, (size_t)atom_cnt, (size_t)sizeof(Atom), AtomCompare);
1012 GetTargetsList(dpy, &targets_list);
1013 MatchTargets(targets_list, atoms, atom_cnt, targets_index_p);
1014 byte_order = targets_list->byte_order;
1015 num_target_lists = Swap2Bytes(byte_order,targets_list->num_target_lists);
1016 if (*targets_index_p < num_target_lists)
1019 /* no match, add our targets to the list */
1020 old_size = Swap4Bytes(byte_order, targets_list->size);
1021 /* new size = old_list_size + target_cnt(CARD16) + targets(CARD32) */
1022 new_size = old_size + sizeof(CARD16) + (sizeof(CARD32) * atom_cnt);
1023 new_list = (motif_targets_t *)
1024 realloc(targets_list, new_size);
1026 /* change the new data's byte order to the existing data's byte order */
1027 /* put data in motif target list format */
1029 new_list->num_target_lists = Swap2Bytes(byte_order, num_target_lists);
1030 new_list->size = Swap4Bytes(byte_order, new_size);
1032 target_cnt = (CARD16 *) (((BYTE *) new_list) + old_size);
1033 *target_cnt = Swap2Bytes(byte_order, atom_cnt); /* target_cnt */
1034 target_data = (CARD32 *) (target_cnt + 1);
1035 for (i=0; i<atom_cnt; i++) {
1036 /* address isn't long word aligned so copy one byte at a time */
1037 tmp_data = Swap4Bytes(byte_order, atoms[i]);
1038 memcpy(target_data+i, &tmp_data, 4);
1041 /* overwrite existing targets_list */
1042 XChangeProperty(dpy, motif_drag_win, ATOM_MOTIF_TARGETS,
1043 ATOM_MOTIF_TARGETS, 8,
1045 (unsigned char *) new_list, new_size);
1049 * update target list property
1050 * advertise psuedo motif initiator info property
1051 * send DROP_START message to motif receiver
1054 ContinueHandleOlitTrigger(dpy, data, length, drop_info)
1056 unsigned char *data;
1057 unsigned long length;
1058 drop_info_t *drop_info;
1060 CARD16 targets_index;
1061 Window psuedo_motif_initiator_win;
1063 GetTargetsIndex(dpy, data, length, &targets_index);
1064 psuedo_motif_initiator_win = proxy_win;
1065 UpdateInitiatorAtom(dpy, psuedo_motif_initiator_win,
1066 drop_info->proxy_handle, targets_index);
1067 SendStartDrop(dpy, psuedo_motif_initiator_win, drop_info);
1070 /* Get OLIT initiator's TARGETS */
1071 ProcessOlitInitiatorConversion(event, drop_info)
1072 XSelectionEvent *event;
1073 drop_info_t *drop_info;
1077 unsigned long length, bytes_after;
1078 unsigned char *data;
1081 /* XView needs this */
1082 if (event->target == ATOM_SUN_DND_ACK)
1083 XChangeProperty(event->display, event->requestor, event->property,
1084 event->target, 32, PropModeReplace, NULL, 0);
1087 sometimes type is TARGETS and sometimes type is ATOM so don't bother
1089 if ((event->target == ATOM_TARGETS) &&
1090 event->property && (XGetWindowProperty (event->display,
1093 0L, GET_PROPERTY_MAX,
1100 (unsigned char **) &data) == Success)
1103 ContinueHandleOlitTrigger(event->display, data, length, drop_info);
1108 /* copy a property and the associated data from one window to another.
1109 Returns True if successful else returns False */
1111 CopyProperty(dpy, property, old_win, new_win)
1114 Window old_win, new_win;
1118 unsigned long length, bytes_after;
1119 unsigned char *data;
1121 if (property && (XGetWindowProperty (dpy, old_win, property,
1122 0L, GET_PROPERTY_MAX,
1129 (unsigned char **) &data) == Success)
1131 XChangeProperty(dpy, new_win, property,
1132 type, format, PropModeReplace, data, (int) length);
1140 /* copy the targets property and the associated data
1141 from one window to another.
1142 Returns True if we get ATOM_SUN_DND_DONE or ATOM_SUN_SELECTION_END */
1144 CopyTargets(dpy, prop, old_win, new_win)
1147 Window old_win, new_win;
1151 unsigned long length, bytes_after;
1152 unsigned char *data;
1153 target_prop_t *target_info;
1155 int ol_done = False;
1157 if ((XGetWindowProperty (dpy, old_win, prop,
1158 0L, GET_PROPERTY_MAX,
1167 target_info = (target_prop_t *) data;
1168 for(i=0; i < (length / 2); i++, target_info++) {
1169 DPRINTF(("CopyTargets: targets[%d]=%s\n", i, a2s(target_info->target)));
1170 CopyProperty(dpy, target_info->property, old_win, new_win);
1171 if (target_info->target == ATOM_SUN_DND_DONE ||
1172 (target_info->target == ATOM_SUN_SELECTION_END))
1180 /* Forward the SelectionNotify to the receiver.
1181 Returns True if we get ATOM_SUN_DND_DONE or ATOM_SUN_SELECTION_END */
1183 ForwardConversion(event, drop_info)
1184 XSelectionEvent *event;
1185 drop_info_t *drop_info;
1187 int ol_done = False;
1189 if (CopyProperty(event->display, event->property,
1190 event->requestor, drop_info->source_win)) {
1192 if (event->target == ATOM_MULTIPLE) {
1193 /* get target name and property pair
1194 copy all these properties */
1195 ol_done = CopyTargets(event->display, event->property,
1196 event->requestor, drop_info->source_win);
1200 /* initiator couldn't convert property, tell receiver this */
1201 event->property = 0;
1204 event->requestor = drop_info->source_win;
1205 event->selection = drop_info->proxy_handle;
1206 XSendEvent(event->display, event->requestor, False, 0, (XEvent*)event);
1210 /* This routine handles the selectionrequest for the target MULTIPLE.
1211 XtGetSelectionValues generates a selection request with the target
1212 MULTIPLE. This is how multiple targets selection
1213 (a selection request that asks for multiple targets) work:
1214 Window A calls XtGetSelectionValues
1215 Xt places a property on window A which contains all the targets.
1216 Xt asks selection owner of selection 1 to convert.
1217 Window B which is the selection owner of selection 1
1218 gets a selectionrequest.
1219 Window B reads the property on window A to get the targets
1220 and then converts them.
1221 Window B places the converted targets data in properties on window A.
1222 Window B places the target names and the properties holding
1223 the target data (target/property pair) in a property on window A.
1225 With single target selection (XtGetSelectionValue), window B would
1226 get the target from the selectionrequest event structure and convert it.
1228 The following is how the proxy agent behaves when there is a multiple
1230 Window A calls XtGetSelectionValues
1231 Xt places a property on window A which contains all the targets.
1232 Xt asks selection owner of selection 1 to convert.
1233 Proxy agent which is the selection owner of selection 1
1234 gets a selectionrequest.
1235 Proxy agent reads the property on window A to get the targets.
1236 Proxy agent places a property on itself which contains all the targets.
1237 Proxy agent asks selection owner of selection 2 to convert.
1238 Window B which is the selection owner of selection 2
1239 gets a selectionrequest.
1240 Window B reads the property on proxy agent to get the targets
1241 and then converts them.
1242 Window B places the converted targets data in properties on proxy agent.
1243 Window B places the target names and the properties holding
1244 the target data in a property proxy agent.
1245 Proxy agent reads the targets data and places the targets data
1246 in a property on window A.
1247 Proxy agent reads the target names and the properties holding
1248 the target data and places this info in a property on window A.
1250 ForwardMultpleSelectionRequest(event, drop_info)
1251 XSelectionRequestEvent *event;
1252 drop_info_t *drop_info;
1255 unsigned long length, bytes_after;
1256 unsigned char *data;
1258 drop_info->source_win = event->requestor;
1260 if (CopyProperty(event->display, event->property,
1261 event->requestor, drop_info->proxy_sel_req_win)) {
1263 /* change requestor and selection */
1264 event->requestor = drop_info->proxy_sel_req_win;
1265 event->selection = drop_info->source_handle;
1267 /* forward selection request to initiator */
1268 XConvertSelection(event->display,
1279 /* tell the initiator to clean up and do internal cleanup */
1280 DndDone(dpy, status, drop_info)
1283 drop_info_t *drop_info;
1285 XConvertSelection(dpy,
1286 drop_info->source_handle,
1288 drop_info->proxy_handle,
1289 drop_info->proxy_sel_req_win,
1290 drop_info->time_stamp);
1292 /* XView needs this */
1293 if (status == ATOM_SUN_DND_DONE)
1294 XConvertSelection(dpy,
1295 drop_info->source_handle,
1296 ATOM_SUN_SELECTION_END,
1297 drop_info->proxy_handle,
1298 drop_info->proxy_sel_req_win,
1299 drop_info->time_stamp);
1303 ProxyMain(dpy, event)
1307 switch(event->type) {
1310 printf("ClientMessage\n");
1312 if (event->xclient.message_type == ATOM_SUN_DND_TRIGGER)
1313 HandleOlitTrigger(dpy, &event->xclient);
1314 else if (event->xclient.message_type == ATOM_MOTIF_DND_MESS)
1315 HandleMotifMessage(dpy, &event->xclient);
1321 client_win = GetAtomWindow(dpy, event->xcreatewindow.window,
1324 /* if client has olit dnd interest then attach motif dnd
1325 interest to client */
1326 if (GetAtomWindow(dpy, client_win, ATOM_DRAGDROP_INTEREST)) {
1327 AdvertiseMotifDropSite(dpy, client_win);
1329 /* look for PropertyChange because olit receivers
1330 don't always declare ATOM_DRAGDROP_INTEREST at MapNotify time
1332 XSelectInput(dpy, client_win, PropertyChangeMask);
1337 case PropertyNotify:
1338 /* printf("PropertyNotify, win=0x%lx\n", event->xproperty.window);*/
1339 /* if a OLIT drop site is advertised
1340 then advertise MOTIF drop site also */
1341 if (event->xproperty.atom == ATOM_DRAGDROP_INTEREST) {
1342 AdvertiseMotifDropSite(dpy, event->xproperty.window);
1344 else if (event->xproperty.atom == ATOM_MOTIF_PROXY_WIN) {
1345 if ((motif_drag_win == event->xproperty.window) &&
1346 (proxy_win != GetPropertyWindow(dpy, motif_drag_win,
1347 ATOM_MOTIF_PROXY_WIN)))
1348 /* proxy_win has been stolen by another client,
1351 /* maybe the following should be a X message */
1352 fprintf(stderr, "%s: lost proxy control\n", ProgramName);
1355 /* In the future, we might want to handle the case where
1356 * a client removes the ATOM_DRAGDROP_INTEREST or the
1357 * ATOM_MOTIF_RECEIVER_INFO atom
1361 case SelectionRequest: {
1362 drop_info_t *drop_info;
1364 printf("SelectionRequest, selection=%s, target=%s, prop=%s, win=0x%lx, time=%ld\n",
1365 a2s(event->xselectionrequest.selection),
1366 a2s(event->xselectionrequest.target),
1367 a2s(event->xselectionrequest.property),
1368 event->xselectionrequest.requestor,
1369 event->xselectionrequest.time
1372 drop_info = GetDropInfoUsingProxyHandle
1373 (event->xselectionrequest.selection);
1374 if (drop_info == NULL)
1375 /* unknown selection, ignore the SelectionRequest */
1377 if (event->xselectionrequest.target == ATOM_SUN_DND_DONE ||
1378 (event->xselectionrequest.target == ATOM_SUN_SELECTION_END)) {
1379 /* tell motif initiator we are done OLIT does not have a
1380 * Failure; so all dnd exit status map to SUCCESS.
1382 * Also record `requestor' id, so that we know who to
1383 * forward when receiving SelectionNotify. */
1384 drop_info->receiver_win = event->xselectionrequest.requestor;
1385 DndDone(dpy, ATOM_MOTIF_SUCCESS, drop_info);
1387 else if (event->xselectionrequest.target == ATOM_MOTIF_SUCCESS
1388 || (event->xselectionrequest.target == ATOM_MOTIF_FAILURE)) {
1389 /* tell olit initiator we are done.
1391 * We will have to remember this target value so that
1392 * we know what to forward when receiving SelectionNotify.
1394 * Note that olit protocol doesn't have a XmTRANSFER_FAILURE
1395 * equivalence, the closest is _SUN_DRAGDROP_ERROR. We
1396 * may want to consider it otherwise olit app will
1397 * think the drop was successful...
1399 drop_info->status = event->xselectionrequest.target;
1400 DndDone(dpy, ATOM_SUN_DND_DONE, drop_info);
1402 else if (event->xselectionrequest.target == ATOM_SUN_SELECTION_ERROR)
1404 /* tell motif initiator OLIT can not handle this drop.
1405 * we have a failure.
1407 DndDone(dpy, ATOM_MOTIF_FAILURE, drop_info);
1409 else if (event->xselectionrequest.target == ATOM_MULTIPLE)
1410 ForwardMultpleSelectionRequest(
1411 &(event->xselectionrequest), drop_info);
1413 /* forward selection request to initiator */
1414 drop_info->source_win = event->xselectionrequest.requestor;
1415 XConvertSelection(event->xselectionrequest.display,
1416 drop_info->source_handle,
1417 event->xselectionrequest.target,
1418 event->xselectionrequest.property,
1419 drop_info->proxy_sel_req_win,
1420 event->xselectionrequest.time
1424 } /* end of case SelectionRequest */
1426 case SelectionNotify:
1428 printf("SelectionNotify, sel=%s, target=%s, prop=%s, w=0x%lx, time=%ld\n",
1429 a2s(event->xselection.selection),
1430 a2s(event->xselection.target),
1431 a2s(event->xselection.property), event->xselection.requestor,
1432 event->xselection.time);
1435 drop_info_t *drop_info = GetDropInfo(event->xselection.requestor);
1437 if (drop_info == NULL ||
1438 (event->xselection.time < drop_info->time_stamp))
1439 /* got SelectionNotify of unknown selection (source) */
1442 /* Trap these two targets, so that the destination side
1443 * will not see selection-time-out */
1444 if (event->xselection.target == ATOM_SUN_DND_DONE || /* olit->motif */
1445 event->xselection.target == ATOM_MOTIF_SUCCESS) { /* motif->olit */
1447 XSelectionEvent * xe = &event->xselection;
1449 /* Currently, in both olit dnd protocol and
1450 * motif dnd protocol, the destination side
1451 * DONT check the value from the source side!
1453 * We will have to copy xe->property to
1454 * drop_info->receiver_win if this is no longer
1455 * TRUE in the future... */
1456 xe->requestor = drop_info->receiver_win;
1457 xe->selection = drop_info->proxy_handle;
1458 xe->target = xe->target == ATOM_SUN_DND_DONE ?
1459 drop_info->status : ATOM_SUN_DND_DONE;
1460 XSendEvent(xe->display, xe->requestor, False,
1461 NoEventMask, event);
1463 ClearDropInfo(drop_info->proxy_handle);
1466 /* if event->property is proxy_handle then the convert request
1467 was from the proxy agent
1468 else the convert request was from the receiver */
1469 if (event->xselection.property == drop_info->proxy_handle ||
1470 (event->xselection.property == ATOM_SUN_DND_ACK)) {
1471 ProcessOlitInitiatorConversion(&event->xselection, drop_info);
1473 if (ForwardConversion(event, drop_info)) {
1475 /* We are here ONLY if the target is ATOM_MULTIPLE and
1476 * the target list contains either _SUN_DRAGDROP_DONE or
1477 * _SUN_SELECTION_END. Probably for XView support?! */
1478 DndDone(dpy, ATOM_MOTIF_SUCCESS, drop_info);
1482 } /* end of case SelectionNotify */
1483 } /* end of switch */