dnd: Move GtkDragDest to a separate file

This follows what was done for GtkDragSource in
415030d25f and shaves another
500 lines off gtkdnd.c.
This commit is contained in:
Matthias Clasen 2015-12-13 18:43:10 -05:00
parent db93386f23
commit 6ac7b54378
15 changed files with 659 additions and 580 deletions

View File

@ -173,6 +173,7 @@ gtk_public_h_sources = \
gtkdebug.h \
gtkdialog.h \
gtkdnd.h \
gtkdragdest.h \
gtkdragsource.h \
gtkdrawingarea.h \
gtkeditable.h \
@ -724,6 +725,7 @@ gtk_base_c_sources = \
gtkcsswidgetnode.c \
gtkcsswin32sizevalue.c \
gtkdialog.c \
gtkdragdest.c \
gtkdragsource.c \
gtkdrawingarea.c \
gtkeditable.c \

View File

@ -41,6 +41,7 @@
#include "gtkcolorutils.h"
#include "gtkdnd.h"
#include "gtkdragsource.h"
#include "gtkdragdest.h"
#include "gtkdrawingarea.h"
#include "gtkframe.h"
#include "gtkgrid.h"

View File

@ -84,6 +84,7 @@
#include <gtk/gtkdebug.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkdnd.h>
#include <gtk/gtkdragdest.h>
#include <gtk/gtkdragsource.h>
#include <gtk/gtkdrawingarea.h>
#include <gtk/gtkeditable.h>

View File

@ -73,6 +73,7 @@
#include "gtkcalendar.h"
#include "gtkdnd.h"
#include "gtkdragdest.h"
#include "gtkintl.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"

View File

@ -37,6 +37,7 @@
#include "gtkcolorchooserdialog.h"
#include "gtkcolorswatchprivate.h"
#include "gtkdnd.h"
#include "gtkdragdest.h"
#include "gtkdragsource.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"

View File

@ -46,6 +46,7 @@
#include <gdk/wayland/gdkwayland.h>
#endif
#include "gtkdragdest.h"
#include "gtkgesturedrag.h"
#include "gtkgesturesingle.h"
#include "gtkicontheme.h"
@ -79,7 +80,6 @@
static GSList *source_widgets = NULL;
typedef struct _GtkDragSourceInfo GtkDragSourceInfo;
typedef struct _GtkDragDestSite GtkDragDestSite;
typedef struct _GtkDragDestInfo GtkDragDestInfo;
@ -121,19 +121,6 @@ struct _GtkDragSourceInfo
guint have_grab : 1; /* Do we still have the pointer grab */
};
struct _GtkDragDestSite
{
GtkDestDefaults flags;
GtkTargetList *target_list;
GdkDragAction actions;
GdkWindow *proxy_window;
GdkDragProtocol proxy_protocol;
guint do_proxy : 1;
guint proxy_coords : 1;
guint have_drag : 1;
guint track_motion : 1;
};
struct _GtkDragDestInfo
{
GtkWidget *widget; /* Widget in which drag is in */
@ -192,10 +179,6 @@ static gboolean gtk_drag_find_widget (GtkWidget *widget,
static void gtk_drag_proxy_begin (GtkWidget *widget,
GtkDragDestInfo *dest_info,
guint32 time);
static void gtk_drag_dest_realized (GtkWidget *widget);
static void gtk_drag_dest_hierarchy_changed (GtkWidget *widget,
GtkWidget *previous_toplevel);
static void gtk_drag_dest_site_destroy (gpointer data);
static void gtk_drag_dest_leave (GtkWidget *widget,
GdkDragContext *context,
guint time);
@ -1025,381 +1008,6 @@ gtk_drag_unhighlight (GtkWidget *widget)
gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_DROP_ACTIVE);
}
static void
gtk_drag_dest_set_internal (GtkWidget *widget,
GtkDragDestSite *site)
{
GtkDragDestSite *old_site;
g_return_if_fail (widget != NULL);
/* HACK, do this in the destroy */
old_site = g_object_get_data (G_OBJECT (widget), "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 widgets 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 widgets #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.
*
* Theres no way to set a default action here, you can use the
* #GtkWidget::drag-motion callback for that. Heres 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),
"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: (nullable) (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), "gtk-drag-dest");
return site ? site->target_list : NULL;
}
/**
* gtk_drag_dest_set_target_list: (method)
* @widget: a #GtkWidget thats 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), "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 thats 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 thats 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 thats 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 thats 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), "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 thats 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), "gtk-drag-dest");
if (site)
return site->track_motion;
return FALSE;
}
/*
* _gtk_drag_dest_handle_event:
* @toplevel: Toplevel widget that received the event
@ -1506,70 +1114,6 @@ _gtk_drag_dest_handle_event (GtkWidget *toplevel,
}
}
/**
* 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;
}
static void
gtk_drag_selection_received (GtkWidget *widget,
GtkSelectionData *selection_data,
@ -1875,39 +1419,6 @@ gtk_drag_clear_source_info (GdkDragContext *context)
g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
}
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);
}
/*
* Default drag handlers
*/
@ -2765,7 +2276,6 @@ gtk_drag_set_icon_surface (GdkDragContext *context,
rgba_visual != NULL &&
gdk_screen_is_composited (screen);
gtk_window_set_screen (GTK_WINDOW (window), screen);
if (has_rgba)
@ -2793,7 +2303,8 @@ gtk_drag_set_icon_surface (GdkDragContext *context,
cairo_region_destroy (region);
/* Need to saturate the colors, so it doesn't look like semi-transparent
* pixels were painted on black. */
* pixels were painted on black.
*/
saturated = gdk_window_create_similar_surface (gtk_widget_get_window (window),
CAIRO_CONTENT_COLOR,
extents.width,

View File

@ -37,56 +37,6 @@
G_BEGIN_DECLS
/**
* GtkDestDefaults:
* @GTK_DEST_DEFAULT_MOTION: If set for a widget, GTK+, during a drag over this
* widget will check if the drag matches this widgets list of possible targets
* and actions.
* GTK+ will then call gdk_drag_status() as appropriate.
* @GTK_DEST_DEFAULT_HIGHLIGHT: If set for a widget, GTK+ will draw a highlight on
* this widget as long as a drag is over this widget and the widget drag format
* and action are acceptable.
* @GTK_DEST_DEFAULT_DROP: If set for a widget, when a drop occurs, GTK+ will
* will check if the drag matches this widgets list of possible targets and
* actions. If so, GTK+ will call gtk_drag_get_data() on behalf of the widget.
* Whether or not the drop is successful, GTK+ will call gtk_drag_finish(). If
* the action was a move, then if the drag was successful, then %TRUE will be
* passed for the @delete parameter to gtk_drag_finish().
* @GTK_DEST_DEFAULT_ALL: If set, specifies that all default actions should
* be taken.
*
* The #GtkDestDefaults enumeration specifies the various
* types of action that will be taken on behalf
* of the user for a drag destination site.
*/
typedef enum {
GTK_DEST_DEFAULT_MOTION = 1 << 0,
GTK_DEST_DEFAULT_HIGHLIGHT = 1 << 1,
GTK_DEST_DEFAULT_DROP = 1 << 2,
GTK_DEST_DEFAULT_ALL = 0x07
} GtkDestDefaults;
/**
* GtkTargetFlags:
* @GTK_TARGET_SAME_APP: If this is set, the target will only be selected
* for drags within a single application.
* @GTK_TARGET_SAME_WIDGET: If this is set, the target will only be selected
* for drags within a single widget.
* @GTK_TARGET_OTHER_APP: If this is set, the target will not be selected
* for drags within a single application.
* @GTK_TARGET_OTHER_WIDGET: If this is set, the target will not be selected
* for drags withing a single widget.
*
* The #GtkTargetFlags enumeration is used to specify
* constraints on a #GtkTargetEntry.
*/
typedef enum {
GTK_TARGET_SAME_APP = 1 << 0, /*< nick=same-app >*/
GTK_TARGET_SAME_WIDGET = 1 << 1, /*< nick=same-widget >*/
GTK_TARGET_OTHER_APP = 1 << 2, /*< nick=other-app >*/
GTK_TARGET_OTHER_WIDGET = 1 << 3 /*< nick=other-widget >*/
} GtkTargetFlags;
/* Destination side */
GDK_AVAILABLE_IN_ALL
@ -108,44 +58,6 @@ void gtk_drag_highlight (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_unhighlight (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set (GtkWidget *widget,
GtkDestDefaults flags,
const GtkTargetEntry *targets,
gint n_targets,
GdkDragAction actions);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set_proxy (GtkWidget *widget,
GdkWindow *proxy_window,
GdkDragProtocol protocol,
gboolean use_coordinates);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_unset (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
GdkDragContext *context,
GtkTargetList *target_list);
GDK_AVAILABLE_IN_ALL
GtkTargetList* gtk_drag_dest_get_target_list (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set_target_list (GtkWidget *widget,
GtkTargetList *target_list);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_add_text_targets (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_add_image_targets (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_add_uri_targets (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set_track_motion (GtkWidget *widget,
gboolean track_motion);
GDK_AVAILABLE_IN_ALL
gboolean gtk_drag_dest_get_track_motion (GtkWidget *widget);
/* Source side */
GDK_AVAILABLE_IN_3_10

View File

@ -22,9 +22,24 @@
#include <gtk/gtkwidget.h>
#include <gtk/gtkselection.h>
#include <gtk/gtkdragdest.h>
#include "gtkimagedefinitionprivate.h"
typedef struct _GtkDragDestSite GtkDragDestSite;
struct _GtkDragDestSite
{
GtkDestDefaults flags;
GtkTargetList *target_list;
GdkDragAction actions;
GdkWindow *proxy_window;
GdkDragProtocol proxy_protocol;
guint do_proxy : 1;
guint proxy_coords : 1;
guint have_drag : 1;
guint track_motion : 1;
};
G_BEGIN_DECLS
GdkDragContext * gtk_drag_begin_internal (GtkWidget *widget,

500
gtk/gtkdragdest.c Normal file
View File

@ -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 widgets 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 widgets #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.
*
* Theres no way to set a default action here, you can use the
* #GtkWidget::drag-motion callback for that. Heres 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 thats 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 thats 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 thats 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 thats 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 thats 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 thats 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;
}

110
gtk/gtkdragdest.h Normal file
View File

@ -0,0 +1,110 @@
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 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/.
*/
#ifndef __GTK_DRAG_DEST_H__
#define __GTK_DRAG_DEST_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkselection.h>
#include <gtk/gtkwidget.h>
G_BEGIN_DECLS
/**
* GtkDestDefaults:
* @GTK_DEST_DEFAULT_MOTION: If set for a widget, GTK+, during a drag over this
* widget will check if the drag matches this widgets list of possible targets
* and actions.
* GTK+ will then call gdk_drag_status() as appropriate.
* @GTK_DEST_DEFAULT_HIGHLIGHT: If set for a widget, GTK+ will draw a highlight on
* this widget as long as a drag is over this widget and the widget drag format
* and action are acceptable.
* @GTK_DEST_DEFAULT_DROP: If set for a widget, when a drop occurs, GTK+ will
* will check if the drag matches this widgets list of possible targets and
* actions. If so, GTK+ will call gtk_drag_get_data() on behalf of the widget.
* Whether or not the drop is successful, GTK+ will call gtk_drag_finish(). If
* the action was a move, then if the drag was successful, then %TRUE will be
* passed for the @delete parameter to gtk_drag_finish().
* @GTK_DEST_DEFAULT_ALL: If set, specifies that all default actions should
* be taken.
*
* The #GtkDestDefaults enumeration specifies the various
* types of action that will be taken on behalf
* of the user for a drag destination site.
*/
typedef enum {
GTK_DEST_DEFAULT_MOTION = 1 << 0,
GTK_DEST_DEFAULT_HIGHLIGHT = 1 << 1,
GTK_DEST_DEFAULT_DROP = 1 << 2,
GTK_DEST_DEFAULT_ALL = 0x07
} GtkDestDefaults;
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set (GtkWidget *widget,
GtkDestDefaults flags,
const GtkTargetEntry *targets,
gint n_targets,
GdkDragAction actions);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set_proxy (GtkWidget *widget,
GdkWindow *proxy_window,
GdkDragProtocol protocol,
gboolean use_coordinates);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_unset (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
GdkAtom gtk_drag_dest_find_target (GtkWidget *widget,
GdkDragContext *context,
GtkTargetList *target_list);
GDK_AVAILABLE_IN_ALL
GtkTargetList* gtk_drag_dest_get_target_list (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set_target_list (GtkWidget *widget,
GtkTargetList *target_list);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_add_text_targets (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_add_image_targets (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_add_uri_targets (GtkWidget *widget);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_set_track_motion (GtkWidget *widget,
gboolean track_motion);
GDK_AVAILABLE_IN_ALL
gboolean gtk_drag_dest_get_track_motion (GtkWidget *widget);
G_END_DECLS
#endif /* __GTK_DRAG_DEST_H__ */

View File

@ -36,6 +36,7 @@
#include "gtkcombobox.h"
#include "gtkcssiconthemevalueprivate.h"
#include "gtkdnd.h"
#include "gtkdragdest.h"
#include "gtkicontheme.h"
#include "deprecated/gtkiconfactory.h"
#include "gtkimage.h"

View File

@ -31,6 +31,7 @@
#include "gtkclipboard.h"
#include "gtkcomboboxtext.h"
#include "gtkdragsource.h"
#include "gtkdragdest.h"
#include "gtkentry.h"
#include "gtkexpander.h"
#include "gtkfilechooserprivate.h"

View File

@ -52,6 +52,7 @@
#include "gtkbutton.h"
#include "gtklistbox.h"
#include "gtkselection.h"
#include "gtkdragdest.h"
#include "gtkdnd.h"
#include "gtkseparator.h"
#include "gtkentry.h"

View File

@ -69,6 +69,27 @@ typedef struct _GtkTargetEntry GtkTargetEntry;
#define GTK_TYPE_SELECTION_DATA (gtk_selection_data_get_type ())
#define GTK_TYPE_TARGET_LIST (gtk_target_list_get_type ())
/**
* GtkTargetFlags:
* @GTK_TARGET_SAME_APP: If this is set, the target will only be selected
* for drags within a single application.
* @GTK_TARGET_SAME_WIDGET: If this is set, the target will only be selected
* for drags within a single widget.
* @GTK_TARGET_OTHER_APP: If this is set, the target will not be selected
* for drags within a single application.
* @GTK_TARGET_OTHER_WIDGET: If this is set, the target will not be selected
* for drags withing a single widget.
*
* The #GtkTargetFlags enumeration is used to specify
* constraints on a #GtkTargetEntry.
*/
typedef enum {
GTK_TARGET_SAME_APP = 1 << 0, /*< nick=same-app >*/
GTK_TARGET_SAME_WIDGET = 1 << 1, /*< nick=same-widget >*/
GTK_TARGET_OTHER_APP = 1 << 2, /*< nick=other-app >*/
GTK_TARGET_OTHER_WIDGET = 1 << 3 /*< nick=other-widget >*/
} GtkTargetFlags;
/**
* GtkTargetEntry:
* @target: a string representation of the target type

View File

@ -36,6 +36,7 @@
#include "gtkprivate.h"
#include "gtkrender.h"
#include "gtkdnd.h"
#include "gtkdragdest.h"
#include "gtkdebug.h"
#include "gtkintl.h"
#include "gtkmain.h"