📄 gdkdnd.c
字号:
/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//* * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */#include <X11/Xlib.h>#include <X11/Xatom.h>#include <string.h>#include "gdkx.h"#include "gdk/gdkprivate.h"#include "gdk.h"typedef struct _GdkDragContextPrivate GdkDragContextPrivate;typedef enum { GDK_DRAG_STATUS_DRAG, GDK_DRAG_STATUS_MOTION_WAIT, GDK_DRAG_STATUS_ACTION_WAIT, GDK_DRAG_STATUS_DROP} GtkDragStatus;typedef struct { guint32 xid; gint x, y, width, height; gboolean mapped;} GdkCacheChild;typedef struct { GList *children; GHashTable *child_hash; guint old_event_mask;} GdkWindowCache;/* Structure that holds information about a drag in progress. * this is used on both source and destination sides. */struct _GdkDragContextPrivate { GdkDragContext context; GdkAtom motif_selection; GdkAtom xdnd_selection; guint ref_count; guint16 last_x; /* Coordinates from last event */ guint16 last_y; GdkDragAction old_action; /* The last action we sent to the source */ GdkDragAction old_actions; /* The last actions we sent to the source */ GdkDragAction xdnd_actions; /* What is currently set in XdndActionList */ Window dest_xid; /* The last window we looked up */ Window drop_xid; /* The (non-proxied) window that is receiving drops */ guint xdnd_targets_set : 1; /* Whether we've already set XdndTypeList */ guint xdnd_actions_set : 1; /* Whether we've already set XdndActionList */ guint xdnd_have_actions : 1; /* Whether an XdndActionList was provided */ guint motif_targets_set : 1; /* Whether we've already set motif initiator info */ guint drag_status : 4; /* current status of drag */ GdkWindowCache *window_cache;};GdkDragContext *current_dest_drag = NULL;/* Forward declarations */static void gdk_window_cache_destroy (GdkWindowCache *cache);static void motif_read_target_table (void);static GdkFilterReturn motif_dnd_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);static GdkFilterReturn xdnd_enter_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);static GdkFilterReturn xdnd_leave_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);static GdkFilterReturn xdnd_position_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);static GdkFilterReturn xdnd_status_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);static GdkFilterReturn xdnd_drop_filter (GdkXEvent *xev, GdkEvent *event, gpointer data);static void xdnd_manage_source_filter (GdkDragContext *context, GdkWindow *window, gboolean add_filter);/* Drag Contexts */static GList *contexts;GdkDragContext *gdk_drag_context_new (void){ GdkDragContextPrivate *result; result = g_new0 (GdkDragContextPrivate, 1); result->ref_count = 1; contexts = g_list_prepend (contexts, result); return (GdkDragContext *)result;}void gdk_drag_context_ref (GdkDragContext *context){ g_return_if_fail (context != NULL); ((GdkDragContextPrivate *)context)->ref_count++;}void gdk_drag_context_unref (GdkDragContext *context){ GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; g_return_if_fail (context != NULL); g_return_if_fail (private->ref_count > 0); private->ref_count--; if (private->ref_count == 0) { g_dataset_destroy (private); g_list_free (context->targets); if (context->source_window) { if ((context->protocol == GDK_DRAG_PROTO_XDND) && !context->is_source) xdnd_manage_source_filter (context, context->source_window, FALSE); gdk_window_unref (context->source_window); } if (context->dest_window) gdk_window_unref (context->dest_window); if (private->window_cache) gdk_window_cache_destroy (private->window_cache); contexts = g_list_remove (contexts, private); g_free (private); }}static GdkDragContext *gdk_drag_context_find (gboolean is_source, Window source_xid, Window dest_xid){ GList *tmp_list = contexts; GdkDragContext *context; GdkDragContextPrivate *private; Window context_dest_xid; while (tmp_list) { context = (GdkDragContext *)tmp_list->data; private = (GdkDragContextPrivate *)context; context_dest_xid = context->dest_window ? (private->drop_xid ? private->drop_xid : GDK_WINDOW_XWINDOW (context->dest_window)) : None; if ((!context->is_source == !is_source) && ((source_xid == None) || (context->source_window && (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) && ((dest_xid == None) || (context_dest_xid == dest_xid))) return context; tmp_list = tmp_list->next; } return NULL;}/* Utility functions */static voidgdk_window_cache_add (GdkWindowCache *cache, guint32 xid, gint x, gint y, gint width, gint height, gboolean mapped){ GdkCacheChild *child = g_new (GdkCacheChild, 1); child->xid = xid; child->x = x; child->y = y; child->width = width; child->height = height; child->mapped = mapped; cache->children = g_list_prepend (cache->children, child); g_hash_table_insert (cache->child_hash, GUINT_TO_POINTER (xid), cache->children);}static GdkFilterReturngdk_window_cache_filter (GdkXEvent *xev, GdkEvent *event, gpointer data){ XEvent *xevent = (XEvent *)xev; GdkWindowCache *cache = data; switch (xevent->type) { case CirculateNotify: break; case ConfigureNotify: { XConfigureEvent *xce = &xevent->xconfigure; GList *node; node = g_hash_table_lookup (cache->child_hash, GUINT_TO_POINTER (xce->window)); if (node) { GdkCacheChild *child = node->data; child->x = xce->x; child->y = xce->y; child->width = xce->width; child->height = xce->height; if (xce->above == None && (node->next)) { GList *last = g_list_last (cache->children); cache->children = g_list_remove_link (cache->children, node); last->next = node; node->next = NULL; node->prev = last; } else { GList *above_node = g_hash_table_lookup (cache->child_hash, GUINT_TO_POINTER (xce->above)); if (above_node && node->prev != above_node) { cache->children = g_list_remove_link (cache->children, node); node->next = above_node->next; if (node->next) node->next->prev = node; node->prev = above_node; above_node->next = node; } } } break; } case CreateNotify: { XCreateWindowEvent *xcwe = &xevent->xcreatewindow; if (!g_hash_table_lookup (cache->child_hash, GUINT_TO_POINTER (xcwe->window))) gdk_window_cache_add (cache, xcwe->window, xcwe->x, xcwe->y, xcwe->width, xcwe->height, FALSE); break; } case DestroyNotify: { XDestroyWindowEvent *xdwe = &xevent->xdestroywindow; GList *node; node = g_hash_table_lookup (cache->child_hash, GUINT_TO_POINTER (xdwe->window)); if (node) { g_hash_table_remove (cache->child_hash, GUINT_TO_POINTER (xdwe->window)); cache->children = g_list_remove_link (cache->children, node); g_free (node->data); g_list_free_1 (node); } break; } case MapNotify: { XMapEvent *xme = &xevent->xmap; GList *node; node = g_hash_table_lookup (cache->child_hash, GUINT_TO_POINTER (xme->window)); if (node) { GdkCacheChild *child = node->data; child->mapped = TRUE; } break; } case ReparentNotify: break; case UnmapNotify: { XMapEvent *xume = &xevent->xmap; GList *node; node = g_hash_table_lookup (cache->child_hash, GUINT_TO_POINTER (xume->window)); if (node) { GdkCacheChild *child = node->data; child->mapped = FALSE; } break; } default: return GDK_FILTER_CONTINUE; } return GDK_FILTER_REMOVE;}static GdkWindowCache *gdk_window_cache_new (void){ XWindowAttributes xwa; Window root, parent, *children; unsigned int nchildren; int i; gint old_warnings = gdk_error_warnings; GdkWindowCache *result = g_new (GdkWindowCache, 1); result->children = NULL; result->child_hash = g_hash_table_new (g_direct_hash, NULL); XGetWindowAttributes (gdk_display, gdk_root_window, &xwa); result->old_event_mask = xwa.your_event_mask; XSelectInput (gdk_display, gdk_root_window, result->old_event_mask | SubstructureNotifyMask); gdk_window_add_filter ((GdkWindow *)&gdk_root_parent, gdk_window_cache_filter, result); gdk_error_code = 0; gdk_error_warnings = 0; if (XQueryTree(gdk_display, gdk_root_window, &root, &parent, &children, &nchildren) == 0) return result; for (i = 0; i < nchildren ; i++) { XGetWindowAttributes (gdk_display, children[i], &xwa); gdk_window_cache_add (result, children[i], xwa.x, xwa.y, xwa.width, xwa.height, xwa.map_state != IsUnmapped); if (gdk_error_code) gdk_error_code = 0; else { gdk_window_cache_add (result, children[i], xwa.x, xwa.y, xwa.width, xwa.height, (xwa.map_state != IsUnmapped)); } } XFree (children); gdk_error_warnings = old_warnings; return result;}static voidgdk_window_cache_destroy (GdkWindowCache *cache){ XSelectInput (gdk_display, gdk_root_window, cache->old_event_mask); gdk_window_remove_filter ((GdkWindow *)&gdk_root_parent, 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 (Window win, gint x, gint y){ Window root, tmp_parent, *children; unsigned int nchildren; int i; Window child = None; Atom type = None; int format; unsigned long nitems, after; unsigned char *data; static Atom wm_state_atom = None; if (!wm_state_atom) wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE); XGetWindowProperty (gdk_display, win, wm_state_atom, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &data); if (gdk_error_code) { gdk_error_code = 0; return None; } if (type != None) { XFree (data); return win; }#if 0 /* This is beautiful! Damn Enlightenment and click-to-focus */ XTranslateCoordinates (gdk_display, gdk_root_window, win, x_root, y_root, &dest_x, &dest_y, &child); if (gdk_error_code) { gdk_error_code = 0; return None; } #else if (XQueryTree(gdk_display, win, &root, &tmp_parent, &children, &nchildren) == 0) return 0; if (!gdk_error_code) { for (i = nchildren - 1; (i >= 0) && (child == None); i--) { XWindowAttributes xwa; XGetWindowAttributes (gdk_display, children[i], &xwa); if (gdk_error_code) gdk_error_code = 0; else if ((xwa.map_state == IsViewable) && (xwa.class == InputOutput) && (x >= xwa.x) && (x < xwa.x + (gint)xwa.width) && (y >= xwa.y) && (y < xwa.y + (gint)xwa.height)) { x -= xwa.x; y -= xwa.y; child = children[i]; } } XFree (children); } else gdk_error_code = 0;#endif if (child) return get_client_window_at_coords_recurse (child, 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -