📄 gdkdnd-x11.c
字号:
}static GdkWindowCache *gdk_window_cache_new (GdkScreen *screen){ XWindowAttributes xwa; Display *xdisplay = GDK_SCREEN_XDISPLAY (screen); GdkWindow *root_window = gdk_screen_get_root_window (screen); GdkChildInfoX11 *children; guint nchildren, i; GdkWindowCache *result = g_new (GdkWindowCache, 1); result->children = NULL; result->child_hash = g_hash_table_new (g_direct_hash, NULL); result->screen = screen; XGetWindowAttributes (xdisplay, GDK_WINDOW_XWINDOW (root_window), &xwa); result->old_event_mask = xwa.your_event_mask; XSelectInput (xdisplay, GDK_WINDOW_XWINDOW (root_window), result->old_event_mask | SubstructureNotifyMask); gdk_window_add_filter (root_window, gdk_window_cache_filter, result); if (!_gdk_x11_get_window_child_info (gdk_screen_get_display (screen), GDK_WINDOW_XWINDOW (root_window), FALSE, NULL, &children, &nchildren)) return result; for (i = 0; i < nchildren ; i++) { gdk_window_cache_add (result, children[i].window, children[i].x, children[i].y, children[i].width, children[i].height, children[i].is_mapped); } g_free (children); return result;}static voidgdk_window_cache_destroy (GdkWindowCache *cache){ GdkWindow *root_window = gdk_screen_get_root_window (cache->screen); XSelectInput (GDK_WINDOW_XDISPLAY (root_window), GDK_WINDOW_XWINDOW (root_window), cache->old_event_mask); gdk_window_remove_filter (root_window, gdk_window_cache_filter, cache); g_list_foreach (cache->children, (GFunc)g_free, NULL); g_list_free (cache->children); g_hash_table_destroy (cache->child_hash); g_free (cache);}static Windowget_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_DEBUGstatic voidprint_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 voidinit_byte_order (void){ guint32 myint = 0x01020304; local_byte_order = (*(gchar *)&myint == 1) ? 'B' : 'l';}static guint16card16_to_host (guint16 x, gchar byte_order) { if (byte_order == local_byte_order) return x; else return (x << 8) | (x >> 8);}static guint32card32_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 GdkFilterReturnmotif_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 Windowmotif_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -