-static Window
-get_client_window_at_coords_recurse (GdkDisplay *display,
- Window win,
- gboolean is_toplevel,
- gint x,
- gint y)
-{
- GdkChildInfoX11 *children;
- unsigned int nchildren;
- int i;
- gboolean found_child = FALSE;
- GdkChildInfoX11 child;
- gboolean has_wm_state = FALSE;
-
- if (!_gdk_x11_get_window_child_info (display, win, TRUE,
- is_toplevel? &has_wm_state : NULL,
- &children, &nchildren))
- return None;
-
- if (has_wm_state)
- return win;
-
- for (i = nchildren - 1; (i >= 0) && !found_child; i--)
- {
- GdkChildInfoX11 *cur_child = &children[i];
-
- if ((cur_child->is_mapped) && (cur_child->window_class == InputOutput) &&
- (x >= cur_child->x) && (x < cur_child->x + cur_child->width) &&
- (y >= cur_child->y) && (y < cur_child->y + cur_child->height))
- {
- x -= cur_child->x;
- y -= cur_child->y;
- child = *cur_child;
- found_child = TRUE;
- }
- }
-
- g_free (children);
-
- if (found_child)
- {
- if (child.has_wm_state)
- return child.window;
- else
- return get_client_window_at_coords_recurse (display, child.window, FALSE, x, y);
- }
- else
- return None;
-}
-
-static Window
-get_client_window_at_coords (GdkWindowCache *cache,
- Window ignore,
- gint x_root,
- gint y_root)
-{
- GList *tmp_list;
- Window retval = None;
-
- gdk_error_trap_push ();
-
- tmp_list = cache->children;
-
- while (tmp_list && !retval)
- {
- GdkCacheChild *child = tmp_list->data;
-
- if ((child->xid != ignore) && (child->mapped))
- {
- if ((x_root >= child->x) && (x_root < child->x + child->width) &&
- (y_root >= child->y) && (y_root < child->y + child->height))
- {
- retval = get_client_window_at_coords_recurse (gdk_screen_get_display (cache->screen),
- child->xid, TRUE,
- x_root - child->x,
- y_root - child->y);
- if (!retval)
- retval = child->xid;
- }
-
- }
- tmp_list = tmp_list->next;
- }
-
- gdk_error_trap_pop ();
-
- if (retval)
- return retval;
- else
- return GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (cache->screen));
-}
-
-/*************************************************************
- ***************************** MOTIF *************************
- *************************************************************/
-
-/* values used in the message type for Motif DND */
-enum {
- XmTOP_LEVEL_ENTER,
- XmTOP_LEVEL_LEAVE,
- XmDRAG_MOTION,
- XmDROP_SITE_ENTER,
- XmDROP_SITE_LEAVE,
- XmDROP_START,
- XmDROP_FINISH,
- XmDRAG_DROP_FINISH,
- XmOPERATION_CHANGED
-};
-
-/* Values used to specify type of protocol to use */
-enum {
- XmDRAG_NONE,
- XmDRAG_DROP_ONLY,
- XmDRAG_PREFER_PREREGISTER,
- XmDRAG_PREREGISTER,
- XmDRAG_PREFER_DYNAMIC,
- XmDRAG_DYNAMIC,
- XmDRAG_PREFER_RECEIVER
-};
-
-/* Operation codes */
-enum {
- XmDROP_NOOP,
- XmDROP_MOVE = 0x01,
- XmDROP_COPY = 0x02,
- XmDROP_LINK = 0x04
-};
-
-/* Drop site status */
-enum {
- XmNO_DROP_SITE = 0x01,
- XmDROP_SITE_INVALID = 0x02,
- XmDROP_SITE_VALID = 0x03
-};
-
-/* completion status */
-enum {
- XmDROP,
- XmDROP_HELP,
- XmDROP_CANCEL,
- XmDROP_INTERRUPT
-};
-
-/* Byte swapping routines. The motif specification leaves it
- * up to us to save a few bytes in the client messages
- */
-static gchar local_byte_order = '\0';
-
-#ifdef G_ENABLE_DEBUG
-static void
-print_target_list (GList *targets)
-{
- while (targets)
- {
- gchar *name = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
- g_message ("\t%s", name);
- g_free (name);
- targets = targets->next;
- }
-}
-#endif /* G_ENABLE_DEBUG */
-
-static void
-init_byte_order (void)
-{
- guint32 myint = 0x01020304;
- local_byte_order = (*(gchar *)&myint == 1) ? 'B' : 'l';
-}
-
-static guint16
-card16_to_host (guint16 x, gchar byte_order) {
- if (byte_order == local_byte_order)
- return x;
- else
- return (x << 8) | (x >> 8);
-}
-
-static guint32
-card32_to_host (guint32 x, gchar byte_order) {
- if (byte_order == local_byte_order)
- return x;
- else
- return (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
-}
-
-/* Motif packs together fields of varying length into the
- * client message. We can't rely on accessing these
- * through data.s[], data.l[], etc, because on some architectures
- * (i.e., Alpha) these won't be valid for format == 8.
- */
-
-#define MOTIF_XCLIENT_BYTE(xevent,i) \
- (xevent)->xclient.data.b[i]
-#define MOTIF_XCLIENT_SHORT(xevent,i) \
- ((gint16 *)&((xevent)->xclient.data.b[0]))[i]
-#define MOTIF_XCLIENT_LONG(xevent,i) \
- ((gint32 *)&((xevent)->xclient.data.b[0]))[i]
-
-#define MOTIF_UNPACK_BYTE(xevent,i) MOTIF_XCLIENT_BYTE(xevent,i)
-#define MOTIF_UNPACK_SHORT(xevent,i) \
- card16_to_host (MOTIF_XCLIENT_SHORT(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
-#define MOTIF_UNPACK_LONG(xevent,i) \
- card32_to_host (MOTIF_XCLIENT_LONG(xevent,i), MOTIF_XCLIENT_BYTE(xevent, 1))
-
-/***** Dest side ***********/
-
-/* Property placed on source windows */
-typedef struct _MotifDragInitiatorInfo {
- guint8 byte_order;
- guint8 protocol_version;
- guint16 targets_index;
- guint32 selection_atom;
-} MotifDragInitiatorInfo;
-
-/* Header for target table on the drag window */
-typedef struct _MotifTargetTableHeader {
- guchar byte_order;
- guchar protocol_version;
- guint16 n_lists;
- guint32 total_size;
-} MotifTargetTableHeader;
-
-/* Property placed on target windows */
-typedef struct _MotifDragReceiverInfo {
- guint8 byte_order;
- guint8 protocol_version;
- guint8 protocol_style;
- guint8 pad;
- guint32 proxy_window;
- guint16 num_drop_sites;
- guint16 padding;
- guint32 total_size;
-} MotifDragReceiverInfo;
-
-/* Target table handling */
-
-static GdkFilterReturn
-motif_drag_window_filter (GdkXEvent *xevent,
- GdkEvent *event,
- gpointer data)
-{
- XEvent *xev = (XEvent *)xevent;
- GdkDisplay *display = GDK_WINDOW_DISPLAY (event->any.window);
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
-
- switch (xev->xany.type)
- {
- case DestroyNotify:
- display_x11->motif_drag_window = None;
- display_x11->motif_drag_gdk_window = NULL;
- break;
- case PropertyNotify:
- if (display_x11->motif_target_lists &&
- (xev->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS")))
- motif_read_target_table (display);
- break;
- }
- return GDK_FILTER_REMOVE;
-}
-
-static Window
-motif_lookup_drag_window (GdkDisplay *display,
- Display *lookup_xdisplay)
-{
- Window retval = None;
- gulong bytes_after, nitems;
- Atom type;
- gint format;
- guchar *data;
-
- XGetWindowProperty (lookup_xdisplay, RootWindow (lookup_xdisplay, 0),
- gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW"),
- 0, 1, FALSE,
- XA_WINDOW, &type, &format, &nitems, &bytes_after,
- &data);
-
- if ((format == 32) && (nitems == 1) && (bytes_after == 0))
- {
- retval = *(Window *)data;
- GDK_NOTE (DND,
- g_message ("Found drag window %#lx\n", GDK_DISPLAY_X11 (display)->motif_drag_window));
- }
-
- if (type != None)
- XFree (data);
-
- return retval;
-}
-
-/* Finds the window where global Motif drag information is stored.
- * If it doesn't exist and 'create' is TRUE, create one.
- */
-static Window
-motif_find_drag_window (GdkDisplay *display,
- gboolean create)
-{
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
-
- if (!display_x11->motif_drag_window)
- {
- Atom motif_drag_window_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_WINDOW");
- display_x11->motif_drag_window = motif_lookup_drag_window (display, display_x11->xdisplay);
-
- if (!display_x11->motif_drag_window && create)
- {
- /* Create a persistant window. (Copied from LessTif) */
-
- Display *persistant_xdisplay;
- XSetWindowAttributes attr;
- persistant_xdisplay = XOpenDisplay (gdk_display_get_name (display));
- XSetCloseDownMode (persistant_xdisplay, RetainPermanent);
-
- XGrabServer (persistant_xdisplay);
-
- display_x11->motif_drag_window = motif_lookup_drag_window (display, persistant_xdisplay);
-
- if (!display_x11->motif_drag_window)
- {
- attr.override_redirect = True;
- attr.event_mask = PropertyChangeMask;
-
- display_x11->motif_drag_window =
- XCreateWindow (persistant_xdisplay,
- RootWindow (persistant_xdisplay, 0),
- -100, -100, 10, 10, 0, 0,
- InputOnly, (Visual *)CopyFromParent,
- (CWOverrideRedirect | CWEventMask), &attr);
-
- GDK_NOTE (DND,
- g_message ("Created drag window %#lx\n", display_x11->motif_drag_window));
-
- XChangeProperty (persistant_xdisplay,
- RootWindow (persistant_xdisplay, 0),
- motif_drag_window_atom, XA_WINDOW,
- 32, PropModeReplace,
- (guchar *)&motif_drag_window_atom, 1);
-
- }
- XUngrabServer (persistant_xdisplay);
- XCloseDisplay (persistant_xdisplay);
- }
-
- /* There is a miniscule race condition here if the drag window
- * gets destroyed exactly now.
- */
- if (display_x11->motif_drag_window)
- {
- display_x11->motif_drag_gdk_window =
- gdk_window_foreign_new_for_display (display, display_x11->motif_drag_window);
- gdk_window_add_filter (display_x11->motif_drag_gdk_window,
- motif_drag_window_filter,
- NULL);
- }
- }
-
- return display_x11->motif_drag_window;
-}
-
-static void
-motif_read_target_table (GdkDisplay *display)
-{
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
- gulong bytes_after, nitems;
- Atom type;
- gint format;
- gint i, j;
-
- Atom motif_drag_targets_atom = gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_TARGETS");
-
- if (display_x11->motif_target_lists)
- {
- for (i=0; i<display_x11->motif_n_target_lists; i++)
- g_list_free (display_x11->motif_target_lists[i]);
-
- g_free (display_x11->motif_target_lists);
- display_x11->motif_target_lists = NULL;
- display_x11->motif_n_target_lists = 0;
- }
-
- if (motif_find_drag_window (display, FALSE))
- {
- guchar *data;
- MotifTargetTableHeader *header = NULL;
- guchar *target_bytes = NULL;
- guchar *p;
- gboolean success = FALSE;
-
- gdk_error_trap_push ();
- XGetWindowProperty (display_x11->xdisplay,
- display_x11->motif_drag_window,
- motif_drag_targets_atom,
- 0, (sizeof(MotifTargetTableHeader)+3)/4, FALSE,
- motif_drag_targets_atom,
- &type, &format, &nitems, &bytes_after,
- &data);
-
- if (gdk_error_trap_pop () || (format != 8) || (nitems < sizeof (MotifTargetTableHeader)))
- goto error;
-
- header = (MotifTargetTableHeader *)data;
-
- header->n_lists = card16_to_host (header->n_lists, header->byte_order);
- header->total_size = card32_to_host (header->total_size, header->byte_order);
-
- gdk_error_trap_push ();
- XGetWindowProperty (display_x11->xdisplay,
- display_x11->motif_drag_window,
- motif_drag_targets_atom,
- (sizeof(MotifTargetTableHeader)+3)/4,
- (header->total_size + 3)/4 - (sizeof(MotifTargetTableHeader) + 3)/4,
- FALSE,
- motif_drag_targets_atom, &type, &format, &nitems,
- &bytes_after, &target_bytes);
-
- if (gdk_error_trap_pop () || (format != 8) || (bytes_after != 0) ||
- (nitems != header->total_size - sizeof(MotifTargetTableHeader)))
- goto error;
-
- display_x11->motif_n_target_lists = header->n_lists;
- display_x11->motif_target_lists = g_new0 (GList *, display_x11->motif_n_target_lists);
-
- p = target_bytes;
- for (i=0; i<header->n_lists; i++)
- {
- gint n_targets;
- guint32 *targets;
-
- if (p + sizeof(guint16) - target_bytes > nitems)
- goto error;
-
- n_targets = card16_to_host (*(gushort *)p, header->byte_order);
-
- /* We need to make a copy of the targets, since it may
- * be unaligned
- */
- targets = g_new (guint32, n_targets);
- memcpy (targets, p + sizeof(guint16), sizeof(guint32) * n_targets);
-
- p += sizeof(guint16) + n_targets * sizeof(guint32);
- if (p - target_bytes > nitems)
- goto error;
-
- for (j=0; j<n_targets; j++)
- display_x11->motif_target_lists[i] =
- g_list_prepend (display_x11->motif_target_lists[i],
- GUINT_TO_POINTER (card32_to_host (targets[j],
- header->byte_order)));
- g_free (targets);
- display_x11->motif_target_lists[i] = g_list_reverse (display_x11->motif_target_lists[i]);
- }
-
- success = TRUE;
-
- error:
- if (header)
- XFree (header);
-
- if (target_bytes)
- XFree (target_bytes);
-
- if (!success)
- {
- if (display_x11->motif_target_lists)
- {
- g_free (display_x11->motif_target_lists);
- display_x11->motif_target_lists = NULL;
- display_x11->motif_n_target_lists = 0;
- }
- g_warning ("Error reading Motif target table\n");
- }
- }
-}
-
-static gint
-targets_sort_func (gconstpointer a, gconstpointer b)
-{
- return (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) ?
- -1 : ((GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) ? 1 : 0);
-}
-
-/* Check if given (sorted) list is in the targets table */
-static gint
-motif_target_table_check (GdkDisplay *display,
- GList *sorted)
-{
- GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
- GList *tmp_list1, *tmp_list2;
- gint i;
-
- for (i=0; i<display_x11->motif_n_target_lists; i++)
- {
- tmp_list1 = display_x11->motif_target_lists[i];
- tmp_list2 = sorted;
-
- while (tmp_list1 && tmp_list2)
- {
- if (tmp_list1->data != tmp_list2->data)
- break;
-
- tmp_list1 = tmp_list1->next;
- tmp_list2 = tmp_list2->next;
- }
- if (!tmp_list1 && !tmp_list2) /* Found it */
- return i;
- }
-
- return -1;
-}
-
-static gint
-motif_add_to_target_table (GdkDisplay *display,
- GList *targets) /* targets is list of GdkAtom */