📄 gtkdnd.c
字号:
* results: *************************************************************/voidgtk_drag_dest_handle_event (GtkWidget *toplevel, GdkEvent *event){ GtkDragDestInfo *info; GdkDragContext *context; g_return_if_fail (toplevel != NULL); g_return_if_fail (event != NULL); context = event->dnd.context; info = g_dataset_get_data (context, "gtk-info"); if (!info) { info = g_new (GtkDragDestInfo, 1); info->widget = NULL; info->context = event->dnd.context; info->proxy_source = NULL; info->proxy_data = NULL; info->dropped = FALSE; info->proxy_drop_wait = FALSE; g_dataset_set_data_full (context, "gtk-info", info, gtk_drag_dest_info_destroy); } /* Find the widget for the event */ switch (event->type) { case GDK_DRAG_ENTER: break; case GDK_DRAG_LEAVE: if (info->widget) { gtk_drag_dest_leave (info->widget, context, event->dnd.time); info->widget = NULL; } break; case GDK_DRAG_MOTION: case GDK_DROP_START: { GtkDragFindData data; gint tx, ty; if (event->type == GDK_DROP_START) { info->dropped = TRUE; /* We send a leave here so that the widget unhighlights * properly. */ if (info->widget) { gtk_drag_dest_leave (info->widget, context, event->dnd.time); info->widget = NULL; } } gdk_window_get_origin (toplevel->window, &tx, &ty); data.x = event->dnd.x_root - tx; data.y = event->dnd.y_root - ty; data.context = context; data.info = info; data.found = FALSE; data.toplevel = TRUE; data.callback = (event->type == GDK_DRAG_MOTION) ? gtk_drag_dest_motion : gtk_drag_dest_drop; data.time = event->dnd.time; gtk_drag_find_widget (toplevel, &data); if (info->widget && !data.found) { gtk_drag_dest_leave (info->widget, context, event->dnd.time); info->widget = NULL; } /* Send a reply. */ if (event->type == GDK_DRAG_MOTION) { if (!data.found) gdk_drag_status (context, 0, event->dnd.time); } else if (event->type == GDK_DROP_START && !info->proxy_source) { gdk_drop_reply (context, data.found, event->dnd.time); if ((context->protocol == GDK_DRAG_PROTO_MOTIF) && !data.found) gtk_drag_finish (context, FALSE, FALSE, event->dnd.time); } } break; default: g_assert_not_reached (); }}/************************************************************* * gtk_drag_dest_find_target: * Decide on a target for the drag. * arguments: * site: * context: * results: *************************************************************/static GdkAtomgtk_drag_dest_find_target (GtkWidget *widget, GtkDragDestSite *site, GdkDragContext *context){ GList *tmp_target; GList *tmp_source = NULL; GtkWidget *source_widget = gtk_drag_get_source_widget (context); tmp_target = site->target_list->list; while (tmp_target) { GtkTargetPair *pair = tmp_target->data; tmp_source = context->targets; while (tmp_source) { if (tmp_source->data == GUINT_TO_POINTER (pair->target)) { if ((!(pair->flags & GTK_TARGET_SAME_APP) || source_widget) && (!(pair->flags & GTK_TARGET_SAME_WIDGET) || (source_widget == widget))) return pair->target; else break; } tmp_source = tmp_source->next; } tmp_target = tmp_target->next; } return GDK_NONE;}static voidgtk_drag_selection_received (GtkWidget *widget, GtkSelectionData *selection_data, guint32 time, gpointer data){ GdkDragContext *context; GtkDragDestInfo *info; GtkWidget *drop_widget; drop_widget = data; context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context"); info = g_dataset_get_data (context, "gtk-info"); if (info->proxy_data && info->proxy_data->target == selection_data->target) { gtk_selection_data_set (info->proxy_data, selection_data->type, selection_data->format, selection_data->data, selection_data->length); gtk_main_quit (); return; } if (selection_data->target == gdk_atom_intern ("DELETE", FALSE)) { gtk_drag_finish (context, TRUE, FALSE, time); } else if ((selection_data->target == gdk_atom_intern ("XmTRANSFER_SUCCESS", FALSE)) || (selection_data->target == gdk_atom_intern ("XmTRANSFER_FAILURE", FALSE))) { /* Do nothing */ } else { GtkDragDestSite *site; site = gtk_object_get_data (GTK_OBJECT (drop_widget), "gtk-drag-dest"); if (site->target_list) { guint target_info; if (gtk_target_list_find (site->target_list, selection_data->target, &target_info)) { if (!(site->flags & GTK_DEST_DEFAULT_DROP) || selection_data->length >= 0) gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), "drag_data_received", context, info->drop_x, info->drop_y, selection_data, target_info, time); } } else { gtk_signal_emit_by_name (GTK_OBJECT (drop_widget), "drag_data_received", context, info->drop_x, info->drop_y, selection_data, 0, time); } if (site->flags & GTK_DEST_DEFAULT_DROP) { gtk_drag_finish (context, (selection_data->length >= 0), (context->action == GDK_ACTION_MOVE), time); } gtk_widget_unref (drop_widget); } gtk_signal_disconnect_by_func (GTK_OBJECT (widget), GTK_SIGNAL_FUNC (gtk_drag_selection_received), data); gtk_object_set_data (GTK_OBJECT (widget), "drag-context", NULL); gdk_drag_context_unref (context); gtk_drag_release_ipc_widget (widget);}/************************************************************* * gtk_drag_find_widget: * Recursive callback used to locate widgets for * DRAG_MOTION and DROP_START events. * arguments: * * results: *************************************************************/static voidgtk_drag_find_widget (GtkWidget *widget, GtkDragFindData *data){ GtkAllocation new_allocation; gint x_offset = 0; gint y_offset = 0; new_allocation = widget->allocation; if (data->found || !GTK_WIDGET_MAPPED (widget)) return; /* Note that in the following code, we only count the * position as being inside a WINDOW widget if it is inside * widget->window; points that are outside of widget->window * but within the allocation are not counted. This is consistent * with the way we highlight drag targets. */ if (!GTK_WIDGET_NO_WINDOW (widget)) { new_allocation.x = 0; new_allocation.y = 0; } if (widget->parent) { GdkWindow *window = widget->window; while (window != widget->parent->window) { gint tx, ty, twidth, theight; gdk_window_get_size (window, &twidth, &theight); if (new_allocation.x < 0) { new_allocation.width += new_allocation.x; new_allocation.x = 0; } if (new_allocation.y < 0) { new_allocation.height += new_allocation.y; new_allocation.y = 0; } if (new_allocation.x + new_allocation.width > twidth) new_allocation.width = twidth - new_allocation.x; if (new_allocation.y + new_allocation.height > theight) new_allocation.height = theight - new_allocation.y; gdk_window_get_position (window, &tx, &ty); new_allocation.x += tx; x_offset += tx; new_allocation.y += ty; y_offset += ty; window = gdk_window_get_parent (window); } } if (data->toplevel || ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) && (data->x < new_allocation.x + new_allocation.width) && (data->y < new_allocation.y + new_allocation.height))) { /* First, check if the drag is in a valid drop site in * one of our children */ if (GTK_IS_CONTAINER (widget)) { GtkDragFindData new_data = *data; new_data.x -= x_offset; new_data.y -= y_offset; new_data.found = FALSE; new_data.toplevel = FALSE; gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback)gtk_drag_find_widget, &new_data); data->found = new_data.found; } /* If not, and this widget is registered as a drop site, check to * emit "drag_motion" to check if we are actually in * a drop site. */ if (!data->found && gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest")) { data->found = data->callback (widget, data->context, data->x - new_allocation.x, data->y - new_allocation.y, data->time); /* If so, send a "drag_leave" to the last widget */ if (data->found) { if (data->info->widget && data->info->widget != widget) { gtk_drag_dest_leave (data->info->widget, data->context, data->time); } data->info->widget = widget; } } }}static voidgtk_drag_proxy_begin (GtkWidget *widget, GtkDragDestInfo *dest_info){ GtkDragSourceInfo *source_info; GList *tmp_list; source_info = g_new0 (GtkDragSourceInfo, 1); source_info->ipc_widget = gtk_drag_get_ipc_widget (); source_info->widget = widget; gtk_widget_ref (source_info->widget); source_info->context = gdk_drag_begin (source_info->ipc_widget->window, dest_info->context->targets); source_info->target_list = gtk_target_list_new (NULL, 0); tmp_list = dest_info->context->targets; while (tmp_list) { gtk_target_list_add (source_info->target_list, GPOINTER_TO_UINT (tmp_list->data), 0, 0); tmp_list = tmp_list->next; } source_info->proxy_dest = dest_info; g_dataset_set_data (source_info->context, "gtk-info", source_info); gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget), "selection_get", GTK_SIGNAL_FUNC (gtk_drag_selection_get), source_info); dest_info->proxy_source = source_info;}static voidgtk_drag_dest_info_destroy (gpointer data){ GtkDragDestInfo *info = data; g_free (info);}static voidgtk_drag_dest_realized (GtkWidget *widget){ GtkWidget *toplevel = gtk_widget_get_toplevel (widget); gdk_window_register_dnd (toplevel->window);}static voidgtk_drag_dest_site_destroy (gpointer data){ GtkDragDestSite *site = data; if (site->target_list) gtk_target_list_unref (site->target_list); g_free (site);}/* * Default drag handlers */static void gtk_drag_dest_leave (GtkWidget *widget, GdkDragContext *context, guint time){ GtkDragDestSite *site; site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); g_return_if_fail (site != NULL); if (site->do_proxy) { GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info"); if (info->proxy_source && !info->dropped) gdk_drag_abort (info->proxy_source->context, time); return; } else { if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag) gtk_drag_unhighlight (widget); if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag) gtk_signal_emit_by_name (GTK_OBJECT (widget), "drag_leave", context, time); site->have_drag = FALSE; }}static gbooleangtk_drag_dest_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time){ GtkDragDestSite *site; GdkDragAction action = 0; gboolean retval; site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); g_return_val_if_fail (site != NULL, FALSE); if (site->do_proxy) { GdkAtom selection; GdkEvent *current_event; GdkWindow *dest_window; GdkDragProtocol proto; GtkDragDestInfo *info = g_dataset_get_data (context, "gtk-info"); if (!info->proxy_source) gtk_drag_proxy_begin (widget, info);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -