📄 gdkdnd-x11.c
字号:
/************************************************************* ***************************** XDND ************************** *************************************************************//* Utility functions */static struct { const gchar *name; GdkAtom atom; GdkDragAction action;} xdnd_actions_table[] = { { "XdndActionCopy", None, GDK_ACTION_COPY }, { "XdndActionMove", None, GDK_ACTION_MOVE }, { "XdndActionLink", None, GDK_ACTION_LINK }, { "XdndActionAsk", None, GDK_ACTION_ASK }, { "XdndActionPrivate", None, GDK_ACTION_COPY }, };static const gint xdnd_n_actions = sizeof(xdnd_actions_table) / sizeof(xdnd_actions_table[0]);static gboolean xdnd_actions_initialized = FALSE;static voidxdnd_initialize_actions (void){ gint i; xdnd_actions_initialized = TRUE; for (i=0; i < xdnd_n_actions; i++) xdnd_actions_table[i].atom = gdk_atom_intern (xdnd_actions_table[i].name, FALSE);}static GdkDragActionxdnd_action_from_atom (GdkDisplay *display, Atom xatom){ GdkAtom atom = gdk_x11_xatom_to_atom_for_display (display, xatom); gint i; if (!xdnd_actions_initialized) xdnd_initialize_actions(); for (i=0; i<xdnd_n_actions; i++) if (atom == xdnd_actions_table[i].atom) return xdnd_actions_table[i].action; return 0;}static Atomxdnd_action_to_atom (GdkDisplay *display, GdkDragAction action){ gint i; if (!xdnd_actions_initialized) xdnd_initialize_actions(); for (i=0; i<xdnd_n_actions; i++) if (action == xdnd_actions_table[i].action) return gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom); return None;}/* Source side */static GdkFilterReturn xdnd_status_filter (GdkXEvent *xev, GdkEvent *event, gpointer data){ GdkDisplay *display; XEvent *xevent = (XEvent *)xev; guint32 dest_window = xevent->xclient.data.l[0]; guint32 flags = xevent->xclient.data.l[1]; Atom action = xevent->xclient.data.l[4]; GdkDragContext *context; if (!event->any.window || gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN) return GDK_FILTER_CONTINUE; /* Not for us */ GDK_NOTE (DND, g_message ("XdndStatus: dest_window: %#x action: %ld", dest_window, action)); display = gdk_drawable_get_display (event->any.window); context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window); if (context) { GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); if (private->drag_status == GDK_DRAG_STATUS_MOTION_WAIT) private->drag_status = GDK_DRAG_STATUS_DRAG; event->dnd.send_event = FALSE; event->dnd.type = GDK_DRAG_STATUS; event->dnd.context = context; g_object_ref (context); event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */ if (!(action != 0) != !(flags & 1)) { GDK_NOTE (DND, g_warning ("Received status event with flags not corresponding to action!\n")); action = 0; } context->action = xdnd_action_from_atom (display, action); return GDK_FILTER_TRANSLATE; } return GDK_FILTER_REMOVE;}static GdkFilterReturn xdnd_finished_filter (GdkXEvent *xev, GdkEvent *event, gpointer data){ GdkDisplay *display; XEvent *xevent = (XEvent *)xev; guint32 dest_window = xevent->xclient.data.l[0]; GdkDragContext *context; GdkDragContextPrivateX11 *private; if (!event->any.window || gdk_window_get_window_type (event->any.window) == GDK_WINDOW_FOREIGN) return GDK_FILTER_CONTINUE; /* Not for us */ GDK_NOTE (DND, g_message ("XdndFinished: dest_window: %#x", dest_window)); display = gdk_drawable_get_display (event->any.window); context = gdk_drag_context_find (display, TRUE, xevent->xclient.window, dest_window); if (context) { private = PRIVATE_DATA (context); if (private->version == 5) private->drop_failed = xevent->xclient.data.l[1] == 0; event->dnd.type = GDK_DROP_FINISHED; event->dnd.context = context; g_object_ref (context); event->dnd.time = GDK_CURRENT_TIME; /* FIXME? */ return GDK_FILTER_TRANSLATE; } return GDK_FILTER_REMOVE;}static voidxdnd_set_targets (GdkDragContext *context){ GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); Atom *atomlist; GList *tmp_list = context->targets; gint i; gint n_atoms = g_list_length (context->targets); GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window); atomlist = g_new (Atom, n_atoms); i = 0; while (tmp_list) { atomlist[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data)); tmp_list = tmp_list->next; i++; } XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window), GDK_DRAWABLE_XID (context->source_window), gdk_x11_get_xatom_by_name_for_display (display, "XdndTypeList"), XA_ATOM, 32, PropModeReplace, (guchar *)atomlist, n_atoms); g_free (atomlist); private->xdnd_targets_set = 1;}static voidxdnd_set_actions (GdkDragContext *context){ GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); Atom *atomlist; gint i; gint n_atoms; guint actions; GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window); if (!xdnd_actions_initialized) xdnd_initialize_actions(); actions = context->actions; n_atoms = 0; for (i=0; i<xdnd_n_actions; i++) { if (actions & xdnd_actions_table[i].action) { actions &= ~xdnd_actions_table[i].action; n_atoms++; } } atomlist = g_new (Atom, n_atoms); actions = context->actions; n_atoms = 0; for (i=0; i<xdnd_n_actions; i++) { if (actions & xdnd_actions_table[i].action) { actions &= ~xdnd_actions_table[i].action; atomlist[n_atoms] = gdk_x11_atom_to_xatom_for_display (display, xdnd_actions_table[i].atom); n_atoms++; } } XChangeProperty (GDK_DRAWABLE_XDISPLAY (context->source_window), GDK_DRAWABLE_XID (context->source_window), gdk_x11_get_xatom_by_name_for_display (display, "XdndActionList"), XA_ATOM, 32, PropModeReplace, (guchar *)atomlist, n_atoms); g_free (atomlist); private->xdnd_actions_set = TRUE; private->xdnd_actions = context->actions;}static voidsend_client_message_async_cb (Window window, gboolean success, gpointer data){ GdkDragContext *context = data; GDK_NOTE (DND, g_message ("Got async callback for #%lx, success = %d", window, success)); /* On failure, we immediately continue with the protocol * so we don't end up blocking for a timeout */ if (!success && context->dest_window && window == GDK_WINDOW_XID (context->dest_window)) { GdkEvent temp_event; GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); g_object_unref (context->dest_window); context->dest_window = NULL; context->action = 0; private->drag_status = GDK_DRAG_STATUS_DRAG; temp_event.dnd.type = GDK_DRAG_STATUS; temp_event.dnd.window = context->source_window; temp_event.dnd.send_event = TRUE; temp_event.dnd.context = context; temp_event.dnd.time = GDK_CURRENT_TIME; gdk_event_put (&temp_event); } g_object_unref (context);}static GdkDisplay *gdk_drag_context_get_display (GdkDragContext *context){ if (context->source_window) return GDK_DRAWABLE_DISPLAY (context->source_window); else if (context->dest_window) return GDK_DRAWABLE_DISPLAY (context->dest_window); g_assert_not_reached (); return NULL;}static voidsend_client_message_async (GdkDragContext *context, Window window, gboolean propagate, glong event_mask, XClientMessageEvent *event_send){ GdkDisplay *display = gdk_drag_context_get_display (context); g_object_ref (context); _gdk_x11_send_client_message_async (display, window, propagate, event_mask, event_send, send_client_message_async_cb, context);}static gbooleanxdnd_send_xevent (GdkDragContext *context, GdkWindow *window, gboolean propagate, XEvent *event_send){ GdkDisplay *display = gdk_drag_context_get_display (context); Window xwindow; glong event_mask; g_assert (event_send->xany.type == ClientMessage); /* We short-circuit messages to ourselves */ if (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN) { gint i; for (i = 0; i < G_N_ELEMENTS (xdnd_filters); i++) { if (gdk_x11_get_xatom_by_name_for_display (display, xdnd_filters[i].atom_name) == event_send->xclient.message_type) { GdkEvent temp_event; temp_event.any.window = window; if ((*xdnd_filters[i].func) (event_send, &temp_event, NULL) == GDK_FILTER_TRANSLATE) { gdk_event_put (&temp_event); g_object_unref (temp_event.dnd.context); } return TRUE; } } } xwindow = GDK_WINDOW_XWINDOW (window); if (_gdk_x11_display_is_root_window (display, xwindow)) event_mask = ButtonPressMask; else event_mask = 0; send_client_message_async (context, xwindow, propagate, event_mask, &event_send->xclient); return TRUE;} static voidxdnd_send_enter (GdkDragContext *context){ XEvent xev; GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->dest_window); xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndEnter"); xev.xclient.format = 32; xev.xclient.window = private->drop_xid ? private->drop_xid : GDK_DRAWABLE_XID (context->dest_window); xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window); xev.xclient.data.l[1] = (private->version << 24); /* version */ xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; GDK_NOTE(DND, g_message ("Sending enter source window %#lx XDND protocol version %d\n", GDK_DRAWABLE_XID (context->source_window), private->version)); if (g_list_length (context->targets) > 3) { if (!private->xdnd_targets_set) xdnd_set_targets (context); xev.xclient.data.l[1] |= 1; } else { GList *tmp_list = context->targets; gint i = 2; while (tmp_list) { xev.xclient.data.l[i] = gdk_x11_atom_to_xatom_for_display (display, GDK_POINTER_TO_ATOM (tmp_list->data)); tmp_list = tmp_list->next; i++; } } if (!xdnd_send_xevent (context, context->dest_window, FALSE, &xev)) { GDK_NOTE (DND, g_message ("Send event to %lx failed", GDK_DRAWABLE_XID (context->dest_window))); g_object_unref (context->dest_window); context->dest_window = NULL; }}static voidxdnd_send_leave (GdkDragContext *context){ GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window); XEvent xev; GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndLeave"); xev.xclient.format = 32; xev.xclient.window = private->drop_xid ? private->drop_xid : GDK_DRAWABLE_XID (context->dest_window); xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window); xev.xclient.data.l[1] = 0; xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; if (!xdnd_send_xevent (context, context->dest_window, FALSE, &xev)) { GDK_NOTE (DND, g_message ("Send event to %lx failed", GDK_DRAWABLE_XID (context->dest_window))); g_object_unref (context->dest_window); context->dest_window = NULL; }}static voidxdnd_send_drop (GdkDragContext *context, guint32 time){ GdkDragContextPrivateX11 *private = PRIVATE_DATA (context); GdkDisplay *display = GDK_DRAWABLE_DISPLAY (context->source_window); XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndDrop"); xev.xclient.format = 32; xev.xclient.window = private->drop_xid ? private->drop_xid : GDK_DRAWABLE_XID (context->dest_window); xev.xclient.data.l[0] = GDK_DRAWABLE_XID (context->source_window); xev.xclient.data.l[1] = 0; xev.xclient.data.l[2] = time; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; if (!xdnd_send_xevent (context, context->dest_window, FALSE, &xev)) { GDK_NOTE (DND, g_message ("Send event to %lx failed", GDK_DRAWABLE_XID (context->dest_window))); g_object_unref (context->dest_window); context->dest_window = NULL; }}static voidxdnd_send_motion (GdkDragContext *context, gint x_root, gint y_root,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -