diff options
author | Matthias Clasen <mclasen@redhat.com> | 2015-12-13 18:43:10 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2016-03-25 15:37:20 -0400 |
commit | 6ac7b54378ad1a8468df889744321bd61ab9e565 (patch) | |
tree | fa28a98297d0a80f09a33262c922e9a81e45a4e1 /gtk/gtkdragdest.c | |
parent | db93386f23807b4153a88775d50c7504f623a016 (diff) | |
download | gtk+-6ac7b54378ad1a8468df889744321bd61ab9e565.tar.gz |
dnd: Move GtkDragDest to a separate file
This follows what was done for GtkDragSource in
415030d25f2552d3937ee3c394c50d22c5382982 and shaves another
500 lines off gtkdnd.c.
Diffstat (limited to 'gtk/gtkdragdest.c')
-rw-r--r-- | gtk/gtkdragdest.c | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/gtk/gtkdragdest.c b/gtk/gtkdragdest.c new file mode 100644 index 0000000000..9a679e7801 --- /dev/null +++ b/gtk/gtkdragdest.c @@ -0,0 +1,500 @@ +/* GTK - The GIMP Toolkit + * 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. 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 "config.h" + +#include "gtkdragdest.h" + +#include "gtkdnd.h" +#include "gtkdndprivate.h" +#include "gtkselectionprivate.h" +#include "gtkintl.h" + + +static void +gtk_drag_dest_realized (GtkWidget *widget) +{ + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + + if (gtk_widget_is_toplevel (toplevel)) + gdk_window_register_dnd (gtk_widget_get_window (toplevel)); +} + +static void +gtk_drag_dest_hierarchy_changed (GtkWidget *widget, + GtkWidget *previous_toplevel) +{ + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + + if (gtk_widget_is_toplevel (toplevel) && gtk_widget_get_realized (toplevel)) + gdk_window_register_dnd (gtk_widget_get_window (toplevel)); +} + +static void +gtk_drag_dest_site_destroy (gpointer data) +{ + GtkDragDestSite *site = data; + + if (site->proxy_window) + g_object_unref (site->proxy_window); + + if (site->target_list) + gtk_target_list_unref (site->target_list); + + g_slice_free (GtkDragDestSite, site); +} + +static void +gtk_drag_dest_set_internal (GtkWidget *widget, + GtkDragDestSite *site) +{ + GtkDragDestSite *old_site; + + old_site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest")); + if (old_site) + { + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_dest_realized, + old_site); + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_dest_hierarchy_changed, + old_site); + + site->track_motion = old_site->track_motion; + } + + if (gtk_widget_get_realized (widget)) + gtk_drag_dest_realized (widget); + + g_signal_connect (widget, "realize", + G_CALLBACK (gtk_drag_dest_realized), site); + g_signal_connect (widget, "hierarchy-changed", + G_CALLBACK (gtk_drag_dest_hierarchy_changed), site); + + g_object_set_data_full (G_OBJECT (widget), I_("gtk-drag-dest"), + site, gtk_drag_dest_site_destroy); +} + +/** + * gtk_drag_dest_set: (method) + * @widget: a #GtkWidget + * @flags: which types of default drag behavior to use + * @targets: (allow-none) (array length=n_targets): a pointer to an array of + * #GtkTargetEntrys indicating the drop types that this @widget will + * accept, or %NULL. Later you can access the list with + * gtk_drag_dest_get_target_list() and gtk_drag_dest_find_target(). + * @n_targets: the number of entries in @targets + * @actions: a bitmask of possible actions for a drop onto this @widget. + * + * Sets a widget as a potential drop destination, and adds default behaviors. + * + * The default behaviors listed in @flags have an effect similar + * to installing default handlers for the widget’s drag-and-drop signals + * (#GtkWidget::drag-motion, #GtkWidget::drag-drop, ...). They all exist + * for convenience. When passing #GTK_DEST_DEFAULT_ALL for instance it is + * sufficient to connect to the widget’s #GtkWidget::drag-data-received + * signal to get primitive, but consistent drag-and-drop support. + * + * Things become more complicated when you try to preview the dragged data, + * as described in the documentation for #GtkWidget::drag-motion. The default + * behaviors described by @flags make some assumptions, that can conflict + * with your own signal handlers. For instance #GTK_DEST_DEFAULT_DROP causes + * invokations of gdk_drag_status() in the context of #GtkWidget::drag-motion, + * and invokations of gtk_drag_finish() in #GtkWidget::drag-data-received. + * Especially the later is dramatic, when your own #GtkWidget::drag-motion + * handler calls gtk_drag_get_data() to inspect the dragged data. + * + * There’s no way to set a default action here, you can use the + * #GtkWidget::drag-motion callback for that. Here’s an example which selects + * the action to use depending on whether the control key is pressed or not: + * |[<!-- language="C" --> + * static void + * drag_motion (GtkWidget *widget, + * GdkDragContext *context, + * gint x, + * gint y, + * guint time) + * { +* GdkModifierType mask; + * + * gdk_window_get_pointer (gtk_widget_get_window (widget), + * NULL, NULL, &mask); + * if (mask & GDK_CONTROL_MASK) + * gdk_drag_status (context, GDK_ACTION_COPY, time); + * else + * gdk_drag_status (context, GDK_ACTION_MOVE, time); + * } + * ]| + */ +void +gtk_drag_dest_set (GtkWidget *widget, + GtkDestDefaults flags, + const GtkTargetEntry *targets, + gint n_targets, + GdkDragAction actions) +{ + GtkDragDestSite *site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + site = g_slice_new0 (GtkDragDestSite); + + site->flags = flags; + site->have_drag = FALSE; + if (targets) + site->target_list = gtk_target_list_new (targets, n_targets); + else + site->target_list = NULL; + site->actions = actions; + site->do_proxy = FALSE; + site->proxy_window = NULL; + site->track_motion = FALSE; + + gtk_drag_dest_set_internal (widget, site); +} + +/** + * gtk_drag_dest_set_proxy: (method) + * @widget: a #GtkWidget + * @proxy_window: the window to which to forward drag events + * @protocol: the drag protocol which the @proxy_window accepts + * (You can use gdk_drag_get_protocol() to determine this) + * @use_coordinates: If %TRUE, send the same coordinates to the + * destination, because it is an embedded + * subwindow. + * + * Sets this widget as a proxy for drops to another window. + */ +void +gtk_drag_dest_set_proxy (GtkWidget *widget, + GdkWindow *proxy_window, + GdkDragProtocol protocol, + gboolean use_coordinates) +{ + GtkDragDestSite *site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (!proxy_window || GDK_IS_WINDOW (proxy_window)); + + site = g_slice_new (GtkDragDestSite); + + site->flags = 0; + site->have_drag = FALSE; + site->target_list = NULL; + site->actions = 0; + site->proxy_window = proxy_window; + if (proxy_window) + g_object_ref (proxy_window); + site->do_proxy = TRUE; + site->proxy_protocol = protocol; + site->proxy_coords = use_coordinates; + site->track_motion = FALSE; + + gtk_drag_dest_set_internal (widget, site); +} + +/** + * gtk_drag_dest_unset: (method) + * @widget: a #GtkWidget + * + * Clears information about a drop destination set with + * gtk_drag_dest_set(). The widget will no longer receive + * notification of drags. + */ +void +gtk_drag_dest_unset (GtkWidget *widget) +{ + GtkDragDestSite *old_site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + old_site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest")); + if (old_site) + { + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_dest_realized, + old_site); + g_signal_handlers_disconnect_by_func (widget, + gtk_drag_dest_hierarchy_changed, + old_site); + } + + g_object_set_data (G_OBJECT (widget), I_("gtk-drag-dest"), NULL); +} + +/** + * gtk_drag_dest_get_target_list: (method) + * @widget: a #GtkWidget + * + * Returns the list of targets this widget can accept from + * drag-and-drop. + * + * Returns: (transfer none): the #GtkTargetList, or %NULL if none + */ +GtkTargetList * +gtk_drag_dest_get_target_list (GtkWidget *widget) +{ + GtkDragDestSite *site; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + + site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest")); + + return site ? site->target_list : NULL; +} + +/** + * gtk_drag_dest_set_target_list: (method) + * @widget: a #GtkWidget that’s a drag destination + * @target_list: (allow-none): list of droppable targets, or %NULL for none + * + * Sets the target types that this widget can accept from drag-and-drop. + * The widget must first be made into a drag destination with + * gtk_drag_dest_set(). + */ +void +gtk_drag_dest_set_target_list (GtkWidget *widget, + GtkTargetList *target_list) +{ + GtkDragDestSite *site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest")); + + if (!site) + { + g_warning ("Can't set a target list on a widget until you've called gtk_drag_dest_set() " + "to make the widget into a drag destination"); + return; + } + + if (target_list) + gtk_target_list_ref (target_list); + + if (site->target_list) + gtk_target_list_unref (site->target_list); + + site->target_list = target_list; +} + +/** + * gtk_drag_dest_add_text_targets: (method) + * @widget: a #GtkWidget that’s a drag destination + * + * Add the text targets supported by #GtkSelectionData to + * the target list of the drag destination. The targets + * are added with @info = 0. If you need another value, + * use gtk_target_list_add_text_targets() and + * gtk_drag_dest_set_target_list(). + * + * Since: 2.6 + */ +void +gtk_drag_dest_add_text_targets (GtkWidget *widget) +{ + GtkTargetList *target_list; + + target_list = gtk_drag_dest_get_target_list (widget); + if (target_list) + gtk_target_list_ref (target_list); + else + target_list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_text_targets (target_list, 0); + gtk_drag_dest_set_target_list (widget, target_list); + gtk_target_list_unref (target_list); +} + +/** + * gtk_drag_dest_add_image_targets: (method) + * @widget: a #GtkWidget that’s a drag destination + * + * Add the image targets supported by #GtkSelectionData to + * the target list of the drag destination. The targets + * are added with @info = 0. If you need another value, + * use gtk_target_list_add_image_targets() and + * gtk_drag_dest_set_target_list(). + * + * Since: 2.6 + */ +void +gtk_drag_dest_add_image_targets (GtkWidget *widget) +{ + GtkTargetList *target_list; + + target_list = gtk_drag_dest_get_target_list (widget); + if (target_list) + gtk_target_list_ref (target_list); + else + target_list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_image_targets (target_list, 0, FALSE); + gtk_drag_dest_set_target_list (widget, target_list); + gtk_target_list_unref (target_list); +} + +/** + * gtk_drag_dest_add_uri_targets: (method) + * @widget: a #GtkWidget that’s a drag destination + * + * Add the URI targets supported by #GtkSelectionData to + * the target list of the drag destination. The targets + * are added with @info = 0. If you need another value, + * use gtk_target_list_add_uri_targets() and + * gtk_drag_dest_set_target_list(). + * + * Since: 2.6 + */ +void +gtk_drag_dest_add_uri_targets (GtkWidget *widget) +{ + GtkTargetList *target_list; + + target_list = gtk_drag_dest_get_target_list (widget); + if (target_list) + gtk_target_list_ref (target_list); + else + target_list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_uri_targets (target_list, 0); + gtk_drag_dest_set_target_list (widget, target_list); + gtk_target_list_unref (target_list); +} + +/** + * gtk_drag_dest_set_track_motion: (method) + * @widget: a #GtkWidget that’s a drag destination + * @track_motion: whether to accept all targets + * + * Tells the widget to emit #GtkWidget::drag-motion and + * #GtkWidget::drag-leave events regardless of the targets and the + * %GTK_DEST_DEFAULT_MOTION flag. + * + * This may be used when a widget wants to do generic + * actions regardless of the targets that the source offers. + * + * Since: 2.10 + */ +void +gtk_drag_dest_set_track_motion (GtkWidget *widget, + gboolean track_motion) +{ + GtkDragDestSite *site; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest")); + + g_return_if_fail (site != NULL); + + site->track_motion = track_motion != FALSE; +} + +/** + * gtk_drag_dest_get_track_motion: (method) + * @widget: a #GtkWidget that’s a drag destination + * + * Returns whether the widget has been configured to always + * emit #GtkWidget::drag-motion signals. + * + * Returns: %TRUE if the widget always emits + * #GtkWidget::drag-motion events + * + * Since: 2.10 + */ +gboolean +gtk_drag_dest_get_track_motion (GtkWidget *widget) +{ + GtkDragDestSite *site; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest")); + + if (site) + return site->track_motion; + + return FALSE; +} + +/** + * gtk_drag_dest_find_target: (method) + * @widget: drag destination widget + * @context: drag context + * @target_list: (allow-none): list of droppable targets, or %NULL to use + * gtk_drag_dest_get_target_list (@widget). + * + * Looks for a match between the supported targets of @context and the + * @dest_target_list, returning the first matching target, otherwise + * returning %GDK_NONE. @dest_target_list should usually be the return + * value from gtk_drag_dest_get_target_list(), but some widgets may + * have different valid targets for different parts of the widget; in + * that case, they will have to implement a drag_motion handler that + * passes the correct target list to this function. + * + * Returns: (transfer none): first target that the source offers + * and the dest can accept, or %GDK_NONE + */ +GdkAtom +gtk_drag_dest_find_target (GtkWidget *widget, + GdkDragContext *context, + GtkTargetList *target_list) +{ + GList *tmp_target; + GList *tmp_source = NULL; + GtkWidget *source_widget; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), GDK_NONE); + g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), GDK_NONE); + + source_widget = gtk_drag_get_source_widget (context); + if (target_list == NULL) + target_list = gtk_drag_dest_get_target_list (widget); + + if (target_list == NULL) + return GDK_NONE; + + tmp_target = target_list->list; + while (tmp_target) + { + GtkTargetPair *pair = tmp_target->data; + tmp_source = gdk_drag_context_list_targets (context); + 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)) && + (!(pair->flags & GTK_TARGET_OTHER_APP) || !source_widget) && + (!(pair->flags & GTK_TARGET_OTHER_WIDGET) || (source_widget != widget))) + return pair->target; + else + break; + } + tmp_source = tmp_source->next; + } + tmp_target = tmp_target->next; + } + + return GDK_NONE; +} + |