📄 gdkdnd.c
字号:
static ginttargets_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 gbooleanmotif_target_table_check (GList *sorted){ GList *tmp_list1, *tmp_list2; gint i; for (i=0; i<motif_n_target_lists; i++) { tmp_list1 = 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 gintmotif_add_to_target_table (GList *targets){ GList *sorted = NULL; gint index = -1; gint i; GList *tmp_list; /* make a sorted copy of the list */ while (targets) { sorted = g_list_insert_sorted (sorted, targets->data, targets_sort_func); targets = targets->next; } /* First check if it is their already */ if (motif_target_lists) index = motif_target_table_check (sorted); /* We need to grab the server while doing this, to ensure * atomiticity. Ugh */ if (index < 0) { /* We need to make sure that it exists _before_ we grab the * server, since we can't open a new connection after we * grab the server. */ motif_find_drag_window (TRUE); XGrabServer(gdk_display); motif_read_target_table(); /* Check again, in case it was added in the meantime */ if (motif_target_lists) index = motif_target_table_check (sorted); if (index < 0) { guint32 total_size = 0; guchar *data; guchar *p; guint16 *p16; MotifTargetTableHeader *header; if (!motif_target_lists) { motif_target_lists = g_new (GList *, 1); motif_n_target_lists = 1; } else { motif_n_target_lists++; motif_target_lists = g_realloc (motif_target_lists, sizeof(GList *) * motif_n_target_lists); } motif_target_lists[motif_n_target_lists - 1] = sorted; sorted = NULL; index = motif_n_target_lists - 1; total_size = sizeof (MotifTargetTableHeader); for (i = 0; i < motif_n_target_lists ; i++) total_size += sizeof(guint16) + sizeof(guint32) * g_list_length (motif_target_lists[i]); data = g_malloc (total_size); header = (MotifTargetTableHeader *)data; p = data + sizeof(MotifTargetTableHeader); header->byte_order = local_byte_order; header->protocol_version = 0; header->n_lists = motif_n_target_lists; header->total_size = total_size; for (i = 0; i < motif_n_target_lists ; i++) { guint16 n_targets = g_list_length (motif_target_lists[i]); guint32 *targets = g_new (guint32, n_targets); guint32 *p32 = targets; tmp_list = motif_target_lists[i]; while (tmp_list) { *p32 = GPOINTER_TO_UINT (tmp_list->data); tmp_list = tmp_list->next; p32++; } p16 = (guint16 *)p; p += sizeof(guint16); memcpy (p, targets, n_targets * sizeof(guint32)); *p16 = n_targets; p += sizeof(guint32) * n_targets; g_free (targets); } XChangeProperty (gdk_display, motif_drag_window, motif_drag_targets_atom, motif_drag_targets_atom, 8, PropModeReplace, data, total_size); } XUngrabServer(gdk_display); } g_list_free (sorted); return index;}/* Translate flags */static voidmotif_dnd_translate_flags (GdkDragContext *context, guint16 flags){ guint recommended_op = flags & 0x000f; guint possible_ops = (flags & 0x0f0) >> 4; switch (recommended_op) { case XmDROP_MOVE: context->suggested_action = GDK_ACTION_MOVE; break; case XmDROP_COPY: context->suggested_action = GDK_ACTION_COPY; break; case XmDROP_LINK: context->suggested_action = GDK_ACTION_LINK; break; default: context->suggested_action = GDK_ACTION_COPY; break; } context->actions = 0; if (possible_ops & XmDROP_MOVE) context->actions |= GDK_ACTION_MOVE; if (possible_ops & XmDROP_COPY) context->actions |= GDK_ACTION_COPY; if (possible_ops & XmDROP_LINK) context->actions |= GDK_ACTION_LINK;}static guint16motif_dnd_get_flags (GdkDragContext *context){ guint16 flags = 0; switch (context->suggested_action) { case GDK_ACTION_MOVE: flags = XmDROP_MOVE; break; case GDK_ACTION_COPY: flags = XmDROP_COPY; break; case GDK_ACTION_LINK: flags = XmDROP_LINK; break; default: flags = XmDROP_NOOP; break; } if (context->actions & GDK_ACTION_MOVE) flags |= XmDROP_MOVE << 8; if (context->actions & GDK_ACTION_COPY) flags |= XmDROP_COPY << 8; if (context->actions & GDK_ACTION_LINK) flags |= XmDROP_LINK << 8; return flags;}/* Source Side */static voidmotif_set_targets (GdkDragContext *context){ GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; MotifDragInitiatorInfo info; gint i; static GdkAtom motif_drag_initiator_info = GDK_NONE; if (!motif_drag_initiator_info) motif_drag_initiator_info = gdk_atom_intern ("_MOTIF_DRAG_INITIATOR_INFO", FALSE); info.byte_order = local_byte_order; info.protocol_version = 0; info.targets_index = motif_add_to_target_table (context->targets); for (i=0; ; i++) { gchar buf[20]; g_snprintf(buf, 20, "_GDK_SELECTION_%d", i); private->motif_selection = gdk_atom_intern (buf, FALSE); if (!XGetSelectionOwner (gdk_display, private->motif_selection)) break; } info.selection_atom = private->motif_selection; XChangeProperty (GDK_WINDOW_XDISPLAY (context->source_window), GDK_WINDOW_XWINDOW (context->source_window), private->motif_selection, motif_drag_initiator_info, 8, PropModeReplace, (guchar *)&info, sizeof (info)); private->motif_targets_set = 1;}guint32motif_check_dest (Window win){ gboolean retval = FALSE; MotifDragReceiverInfo *info; Atom type = None; int format; unsigned long nitems, after; if (!motif_drag_receiver_info_atom) motif_drag_receiver_info_atom = gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE); XGetWindowProperty (gdk_display, win, motif_drag_receiver_info_atom, 0, (sizeof(*info)+3)/4, False, AnyPropertyType, &type, &format, &nitems, &after, (guchar **)&info); if (type != None) { if ((format == 8) && (nitems == sizeof(*info))) { if ((info->protocol_version == 0) && ((info->protocol_style == XmDRAG_PREFER_PREREGISTER) || (info->protocol_style == XmDRAG_PREFER_DYNAMIC) || (info->protocol_style == XmDRAG_DYNAMIC))) retval = TRUE; } else { GDK_NOTE (DND, g_warning ("Invalid Motif drag receiver property on window %ld\n", win)); } XFree (info); } return retval ? win : GDK_NONE; }static voidmotif_send_enter (GdkDragContext *context, guint32 time){ XEvent xev; GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE); xev.xclient.format = 8; xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window); MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_ENTER; MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order; MOTIF_XCLIENT_SHORT (&xev, 1) = 0; MOTIF_XCLIENT_LONG (&xev, 1) = time; MOTIF_XCLIENT_LONG (&xev, 2) = GDK_WINDOW_XWINDOW (context->source_window); if (!private->motif_targets_set) motif_set_targets (context); MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection; if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window), FALSE, 0, &xev)) GDK_NOTE (DND, g_message ("Send event to %lx failed", GDK_WINDOW_XWINDOW (context->dest_window)));}static voidmotif_send_leave (GdkDragContext *context, guint32 time){ XEvent xev; xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE); xev.xclient.format = 8; xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window); MOTIF_XCLIENT_BYTE (&xev, 0) = XmTOP_LEVEL_LEAVE; MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order; MOTIF_XCLIENT_SHORT (&xev, 1) = 0; MOTIF_XCLIENT_LONG (&xev, 1) = time; MOTIF_XCLIENT_LONG (&xev, 2) = GDK_WINDOW_XWINDOW (context->source_window); MOTIF_XCLIENT_LONG (&xev, 3) = 0; if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window), FALSE, 0, &xev)) GDK_NOTE (DND, g_message ("Send event to %lx failed", GDK_WINDOW_XWINDOW (context->dest_window)));}static gbooleanmotif_send_motion (GdkDragContext *context, gint x_root, gint y_root, GdkDragAction action, guint32 time){ gboolean retval; XEvent xev; GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE); xev.xclient.format = 8; xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window); MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order; MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context); MOTIF_XCLIENT_LONG (&xev, 1) = time; if ((context->suggested_action != private->old_action) || (context->actions != private->old_actions)) { MOTIF_XCLIENT_BYTE (&xev, 0) = XmOPERATION_CHANGED; /* private->drag_status = GDK_DRAG_STATUS_ACTION_WAIT; */ retval = TRUE; } else { MOTIF_XCLIENT_BYTE (&xev, 0) = XmDRAG_MOTION; MOTIF_XCLIENT_SHORT (&xev, 4) = x_root; MOTIF_XCLIENT_SHORT (&xev, 5) = y_root; private->drag_status = GDK_DRAG_STATUS_MOTION_WAIT; retval = FALSE; } if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window), FALSE, 0, &xev)) GDK_NOTE (DND, g_message ("Send event to %lx failed", GDK_WINDOW_XWINDOW (context->dest_window))); return retval;}static voidmotif_send_drop (GdkDragContext *context, guint32 time){ XEvent xev; GdkDragContextPrivate *private = (GdkDragContextPrivate *)context; xev.xclient.type = ClientMessage; xev.xclient.message_type = gdk_atom_intern ("_MOTIF_DRAG_AND_DROP_MESSAGE", FALSE); xev.xclient.format = 8; xev.xclient.window = GDK_WINDOW_XWINDOW (context->dest_window); MOTIF_XCLIENT_BYTE (&xev, 0) = XmDROP_START; MOTIF_XCLIENT_BYTE (&xev, 1) = local_byte_order; MOTIF_XCLIENT_SHORT (&xev, 1) = motif_dnd_get_flags (context); MOTIF_XCLIENT_LONG (&xev, 1) = time; MOTIF_XCLIENT_SHORT (&xev, 4) = private->last_x; MOTIF_XCLIENT_SHORT (&xev, 5) = private->last_y; MOTIF_XCLIENT_LONG (&xev, 3) = private->motif_selection; MOTIF_XCLIENT_LONG (&xev, 4) = GDK_WINDOW_XWINDOW (context->source_window); if (!gdk_send_xevent (GDK_WINDOW_XWINDOW (context->dest_window), FALSE, 0, &xev)) GDK_NOTE (DND, g_message ("Send event to %lx failed", GDK_WINDOW_XWINDOW (context->dest_window)));}/* Target Side */static gbooleanmotif_read_initiator_info (Window source_window, Atom atom, GList **targets, GdkAtom *selection){ GList *tmp_list; static GdkAtom motif_drag_initiator_info = GDK_NONE; GdkAtom type; gint format; gulong nitems; gulong bytes_after; MotifDragInitiatorInfo *initiator_info; if (!motif_drag_initiator_info) motif_drag_initiator_info = gdk_atom_intern ("_MOTIF_DRAG_INITIATOR_INFO", FALSE); XGetWindowProperty (gdk_display, source_window, atom, 0, sizeof(*initiator_info), FALSE, motif_drag_initiator_info, &type, &format, &nitems, &bytes_after, (guchar **)&initiator_info); if ((format != 8) || (nitems != sizeof (MotifDragInitiatorInfo)) || (bytes_after != 0)) { g_warning ("Error reading initiator info\n"); return FALSE; } motif_read_target_table (); initiator_info->targets_index = card16_to_host (initiator_info->targets_index, initiator_info->byte_order); initiator_info->selection_atom = card32_to_host (initiator_info->selection_atom, initiator_info->byte_order); if (initiator_info->targets_index >= motif_n_target_lists) { g_warning ("Invalid target index in TOP_LEVEL_ENTER MESSAGE"); XFree (initiator_info); return GDK_FILTER_REMOVE; } tmp_list = g_list_last (motif_target_lists[initiator_info->targets_index]); *targets = NULL; while (tmp_list) { *targets = g_list_prepend (*targets, tmp_list->data); tmp_list = tmp_list->prev; }#ifdef G_ENABLE_DEBUG if (gdk_debug_flags & GDK_DEBUG_DND) print_target_list (*targets);#endif /* G_ENABLE_DEBUG */ *selection = initiator_info->selection_atom; XFree (initiator_info); return TRUE;}static GdkDragContext *motif_drag_context_new (GdkWindow *dest_window, guint32 timestamp, guint32 source_window, guint32 atom){ GdkDragContext *new_context; GdkDragContextPrivate *private; /* FIXME, current_dest_drag really shouldn't be NULL'd * if we error below. */ if (current_dest_drag != NULL) { if (timestamp >= current_dest_drag->start_time) { gdk_drag_context_unref (current_dest_drag); current_dest_drag = NULL; } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -