forked from AuroraMiddleware/gtk
Merge branch 'dnd-gestures-2' into 'master'
Add new dnd api See merge request GNOME/gtk!1278
This commit is contained in:
commit
f5daecf353
@ -119,48 +119,76 @@ get_image_paintable (GtkImage *image)
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
|
||||
paintable = get_image_paintable (GTK_IMAGE (widget));
|
||||
if (paintable)
|
||||
{
|
||||
gtk_drag_set_icon_paintable (drag, paintable, -2, -2);
|
||||
gtk_drag_source_set_icon (source, paintable, -2, -2);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
gpointer data)
|
||||
static void
|
||||
get_texture (GValue *value,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data));
|
||||
|
||||
paintable = get_image_paintable (GTK_IMAGE (widget));
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
gtk_selection_data_set_texture (selection_data, GDK_TEXTURE (paintable));
|
||||
g_value_set_object (value, paintable);
|
||||
}
|
||||
|
||||
static GdkContentProvider *
|
||||
prepare_drag (GtkDragSource *source,
|
||||
double x,
|
||||
double y,
|
||||
GtkWidget *image)
|
||||
{
|
||||
return gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
got_texture (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
if (gtk_selection_data_get_length (selection_data) > 0)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GtkWidget *image = data;
|
||||
const GValue *value;
|
||||
GError *error = NULL;
|
||||
|
||||
texture = gtk_selection_data_get_texture (selection_data);
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
|
||||
g_object_unref (texture);
|
||||
value = gdk_drop_read_value_finish (drop, result, &error);
|
||||
if (value)
|
||||
{
|
||||
GdkTexture *texture = g_value_get_object (value);
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("Failed to get data: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
if (gdk_drop_has_value (drop, GDK_TYPE_TEXTURE))
|
||||
{
|
||||
gdk_drop_read_value_async (drop, GDK_TYPE_TEXTURE, G_PRIORITY_DEFAULT, NULL, got_texture, widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -171,12 +199,8 @@ copy_image (GSimpleAction *action,
|
||||
GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
|
||||
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data));
|
||||
|
||||
g_print ("copy image\n");
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
{
|
||||
g_print ("set clipboard\n");
|
||||
gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable));
|
||||
}
|
||||
gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable));
|
||||
|
||||
if (paintable)
|
||||
g_object_unref (paintable);
|
||||
@ -247,6 +271,9 @@ do_clipboard (GtkWidget *do_widget)
|
||||
{ "paste", paste_image, NULL, NULL, NULL },
|
||||
};
|
||||
GActionGroup *actions;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
GdkContentFormats *formats;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
@ -305,22 +332,21 @@ do_clipboard (GtkWidget *do_widget)
|
||||
|
||||
/* Create the first image */
|
||||
image = gtk_image_new_from_icon_name ("dialog-warning");
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), 48);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), image);
|
||||
|
||||
/* make image a drag source */
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-begin",
|
||||
G_CALLBACK (drag_begin), image);
|
||||
g_signal_connect (image, "drag-data-get",
|
||||
G_CALLBACK (drag_data_get), image);
|
||||
source = gtk_drag_source_new ();
|
||||
g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
/* accept drops on image */
|
||||
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
|
||||
NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_dest_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-data-received",
|
||||
G_CALLBACK (drag_data_received), image);
|
||||
formats = gdk_content_formats_new_for_gtype (GDK_TYPE_TEXTURE);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
|
||||
gdk_content_formats_unref (formats);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
/* context menu on image */
|
||||
gesture = gtk_gesture_click_new ();
|
||||
@ -337,22 +363,21 @@ do_clipboard (GtkWidget *do_widget)
|
||||
|
||||
/* Create the second image */
|
||||
image = gtk_image_new_from_icon_name ("process-stop");
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), 48);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), image);
|
||||
|
||||
/* make image a drag source */
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-begin",
|
||||
G_CALLBACK (drag_begin), image);
|
||||
g_signal_connect (image, "drag-data-get",
|
||||
G_CALLBACK (drag_data_get), image);
|
||||
source = gtk_drag_source_new ();
|
||||
g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
/* accept drops on image */
|
||||
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
|
||||
NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_dest_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-data-received",
|
||||
G_CALLBACK (drag_data_received), image);
|
||||
formats = gdk_content_formats_new_for_gtype (GDK_TYPE_TEXTURE);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
|
||||
gdk_content_formats_unref (formats);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
/* context menu on image */
|
||||
gesture = gtk_gesture_click_new ();
|
||||
|
@ -5,9 +5,6 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* Drag 'n Drop */
|
||||
static const char *target_table[] = {
|
||||
"text/uri-list"
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -76,30 +73,11 @@ search_text_changed (GtkEntry *entry, IconBrowserWindow *win)
|
||||
gtk_tree_model_filter_refilter (win->filter_model);
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
get_icon (GtkWidget *image, const gchar *name, gint size)
|
||||
{
|
||||
GtkIconInfo *info;
|
||||
GtkStyleContext *context;
|
||||
GdkTexture *texture;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
context = gtk_widget_get_style_context (image);
|
||||
info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (), name, size, 0);
|
||||
texture = GDK_TEXTURE (gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL));
|
||||
pixbuf = gdk_pixbuf_get_from_texture (texture);
|
||||
g_object_unref (texture);
|
||||
g_object_unref (info);
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
set_image (GtkWidget *image, const gchar *name, gint size)
|
||||
{
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (image), name);
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), size);
|
||||
gtk_drag_source_set_icon_name (image, name);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -365,78 +343,107 @@ search_mode_toggled (GObject *searchbar, GParamSpec *pspec, IconBrowserWindow *w
|
||||
gtk_list_box_unselect_all (GTK_LIST_BOX (win->context_list));
|
||||
}
|
||||
|
||||
static void
|
||||
get_image_data (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection,
|
||||
guint target_info,
|
||||
gpointer data)
|
||||
static GdkPaintable *
|
||||
get_image_paintable (GtkImage *image)
|
||||
{
|
||||
GtkWidget *image;
|
||||
const gchar *name;
|
||||
gint size;
|
||||
GdkPixbuf *pixbuf;
|
||||
const gchar *icon_name;
|
||||
GtkIconTheme *icon_theme;
|
||||
GtkIconInfo *icon_info;
|
||||
int size;
|
||||
|
||||
image = gtk_bin_get_child (GTK_BIN (widget));
|
||||
|
||||
name = gtk_image_get_icon_name (GTK_IMAGE (image));
|
||||
size = gtk_image_get_pixel_size (GTK_IMAGE (image));
|
||||
|
||||
pixbuf = get_icon (image, name, size);
|
||||
gtk_selection_data_set_pixbuf (selection, pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
switch (gtk_image_get_storage_type (image))
|
||||
{
|
||||
case GTK_IMAGE_PAINTABLE:
|
||||
return g_object_ref (gtk_image_get_paintable (image));
|
||||
case GTK_IMAGE_ICON_NAME:
|
||||
icon_name = gtk_image_get_icon_name (image);
|
||||
size = gtk_image_get_pixel_size (image);
|
||||
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
|
||||
icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size,
|
||||
GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_GENERIC_FALLBACK);
|
||||
if (icon_info == NULL)
|
||||
return NULL;
|
||||
return gtk_icon_info_load_icon (icon_info, NULL);
|
||||
default:
|
||||
g_warning ("Image storage type %d not handled",
|
||||
gtk_image_get_storage_type (image));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_scalable_image_data (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection,
|
||||
guint target_info,
|
||||
gpointer data)
|
||||
drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
gchar *uris[2];
|
||||
GtkIconInfo *info;
|
||||
GtkWidget *image;
|
||||
GFile *file;
|
||||
const gchar *name;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
image = gtk_bin_get_child (GTK_BIN (widget));
|
||||
name = gtk_image_get_icon_name (GTK_IMAGE (image));
|
||||
paintable = get_image_paintable (GTK_IMAGE (widget));
|
||||
if (paintable)
|
||||
{
|
||||
int w, h;
|
||||
|
||||
w = gdk_paintable_get_intrinsic_width (paintable);
|
||||
h = gdk_paintable_get_intrinsic_height (paintable);
|
||||
gtk_drag_source_set_icon (source, paintable, w, h);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_texture (GValue *value,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data));
|
||||
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
g_value_set_object (value, paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
get_file (GValue *value,
|
||||
gpointer data)
|
||||
{
|
||||
const char *name;
|
||||
GtkIconInfo *info;
|
||||
GFile *file;
|
||||
|
||||
name = gtk_image_get_icon_name (GTK_IMAGE (data));
|
||||
|
||||
info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (), name, -1, 0);
|
||||
file = g_file_new_for_path (gtk_icon_info_get_filename (info));
|
||||
uris[0] = g_file_get_uri (file);
|
||||
uris[1] = NULL;
|
||||
|
||||
gtk_selection_data_set_uris (selection, uris);
|
||||
|
||||
g_free (uris[0]);
|
||||
g_object_unref (info);
|
||||
g_value_set_object (value, file);
|
||||
g_object_unref (file);
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_image_dnd (GtkWidget *image)
|
||||
{
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-data-get", G_CALLBACK (get_image_data), NULL);
|
||||
GdkContentProvider *content;
|
||||
GtkDragSource *source;
|
||||
|
||||
source = gtk_drag_source_new ();
|
||||
content = gdk_content_provider_new_with_callback (GDK_TYPE_TEXTURE, get_texture, image);
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_object_unref (content);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
|
||||
}
|
||||
|
||||
static void
|
||||
setup_scalable_image_dnd (GtkWidget *image)
|
||||
{
|
||||
GtkWidget *parent;
|
||||
GdkContentFormats *targets;
|
||||
GdkContentProvider *content;
|
||||
GtkDragSource *source;
|
||||
|
||||
parent = gtk_widget_get_parent (image);
|
||||
targets = gdk_content_formats_new (target_table, G_N_ELEMENTS (target_table));
|
||||
gtk_drag_source_set (parent, GDK_BUTTON1_MASK,
|
||||
targets,
|
||||
GDK_ACTION_COPY);
|
||||
gdk_content_formats_unref (targets);
|
||||
source = gtk_drag_source_new ();
|
||||
content = gdk_content_provider_new_with_callback (G_TYPE_FILE, get_file, image);
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_object_unref (content);
|
||||
|
||||
g_signal_connect (parent, "drag-data-get", G_CALLBACK (get_scalable_image_data), NULL);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -446,8 +453,7 @@ icon_browser_window_init (IconBrowserWindow *win)
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (win));
|
||||
|
||||
list = gdk_content_formats_new (NULL, 0);
|
||||
list = gtk_content_formats_add_text_targets (list);
|
||||
list = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
|
||||
gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (win->list),
|
||||
GDK_BUTTON1_MASK,
|
||||
list,
|
||||
@ -459,7 +465,6 @@ icon_browser_window_init (IconBrowserWindow *win)
|
||||
setup_image_dnd (win->image3);
|
||||
setup_image_dnd (win->image4);
|
||||
setup_image_dnd (win->image5);
|
||||
setup_image_dnd (win->image6);
|
||||
setup_scalable_image_dnd (win->image6);
|
||||
|
||||
win->contexts = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, context_free);
|
||||
|
@ -344,6 +344,13 @@
|
||||
<xi:include href="xml/gtkpadcontroller.xml" />
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<title>Data exchange, clipboards and Drag-and-Drop</title>
|
||||
<xi:include href="xml/gtkdragsource.xml"/>
|
||||
<xi:include href="xml/gtkdragicon.xml"/>
|
||||
<xi:include href="xml/gtkdroptarget.xml"/>
|
||||
</chapter>
|
||||
|
||||
</part>
|
||||
|
||||
<part id="gtkbase">
|
||||
@ -352,7 +359,6 @@
|
||||
<xi:include href="xml/gtkfeatures.xml" />
|
||||
<xi:include href="xml/gtkaccelgroup.xml" />
|
||||
<xi:include href="xml/gtkaccelmap.xml" />
|
||||
<xi:include href="xml/gtkdnd.xml" />
|
||||
<xi:include href="xml/gtksettings.xml" />
|
||||
<xi:include href="xml/gtkbindings.xml" />
|
||||
<xi:include href="xml/gtkenums.xml" />
|
||||
|
@ -5001,49 +5001,6 @@ GTK_TYPE_SELECTION_DATA
|
||||
gtk_selection_data_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkdnd</FILE>
|
||||
<TITLE>Drag and Drop</TITLE>
|
||||
GtkDestDefaults
|
||||
GtkDragResult
|
||||
|
||||
<SUBSECTION Destination Side>
|
||||
gtk_drag_dest_set
|
||||
gtk_drag_dest_unset
|
||||
gtk_drag_dest_find_target
|
||||
gtk_drag_dest_get_target_list
|
||||
gtk_drag_dest_set_target_list
|
||||
gtk_drag_dest_add_text_targets
|
||||
gtk_drag_dest_add_image_targets
|
||||
gtk_drag_dest_add_uri_targets
|
||||
gtk_drag_dest_set_track_motion
|
||||
gtk_drag_dest_get_track_motion
|
||||
gtk_drag_get_data
|
||||
gtk_drag_get_source_widget
|
||||
gtk_drag_highlight
|
||||
gtk_drag_unhighlight
|
||||
|
||||
<SUBSECTION Source Side>
|
||||
gtk_drag_begin
|
||||
gtk_drag_cancel
|
||||
gtk_drag_set_icon_widget
|
||||
gtk_drag_set_icon_paintable
|
||||
gtk_drag_set_icon_name
|
||||
gtk_drag_set_icon_gicon
|
||||
gtk_drag_set_icon_default
|
||||
gtk_drag_check_threshold
|
||||
gtk_drag_source_set
|
||||
gtk_drag_source_set_icon_name
|
||||
gtk_drag_source_set_icon_gicon
|
||||
gtk_drag_source_set_icon_paintable
|
||||
gtk_drag_source_unset
|
||||
gtk_drag_source_set_target_list
|
||||
gtk_drag_source_get_target_list
|
||||
gtk_drag_source_add_text_targets
|
||||
gtk_drag_source_add_image_targets
|
||||
gtk_drag_source_add_uri_targets
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkbindings</FILE>
|
||||
<TITLE>Bindings</TITLE>
|
||||
@ -7191,3 +7148,69 @@ gtk_constraint_guide_get_max_size
|
||||
GTK_TYPE_CONSTRAINT_GUIDE
|
||||
gtk_constraint_guide_get_tyoe
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkdragsource</FILE>
|
||||
GtkDragSource
|
||||
gtk_drag_source_new
|
||||
gtk_drag_source_set_content
|
||||
gtk_drag_source_get_content
|
||||
gtk_drag_source_set_actions
|
||||
gtk_drag_source_get_actions
|
||||
gtk_drag_source_set_icon
|
||||
gtk_drag_source_drag_cancel
|
||||
gtk_drag_source_get_drag
|
||||
gtk_drag_check_threshold
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_DRAG_SOURCE
|
||||
GTK_DRAG_SOURCE
|
||||
GTK_DRAG_SOURCE_CLASS
|
||||
GTK_IS_DRAG_SOURCE
|
||||
GTK_IS_DRAG_SOURCE_CLASS
|
||||
GTK_DRAG_SOURCE_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_drag_source_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkdroptarget</FILE>
|
||||
GtkDropTarget
|
||||
gtk_drop_target_new
|
||||
gtk_drop_target_set_formats
|
||||
gtk_drop_target_get_formats
|
||||
gtk_drop_target_set_actions
|
||||
gtk_drop_target_get_actions
|
||||
gtk_drop_target_get_drop
|
||||
gtk_drop_target_find_mimetype
|
||||
gtk_drop_target_read_selection
|
||||
gtk_drop_target_read_selection_finish
|
||||
gtk_drag_highlight
|
||||
gtk_drag_unhighlight
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_DROP_TARGET
|
||||
GTK_DROP_TARGET
|
||||
GTK_DROP_TARGET_CLASS
|
||||
GTK_IS_DROP_TARGET
|
||||
GTK_IS_DROP_TARGET_CLASS
|
||||
GTK_DROP_TARGET_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_drop_target_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkdragicon</FILE>
|
||||
GtkDragIcon
|
||||
gtk_drag_icon_new_for_drag
|
||||
gtk_drag_icon_set_from_paintable
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_DRAG_ICON
|
||||
GTK_DRAG_ICON
|
||||
GTK_DRAG_ICON_CLASS
|
||||
GTK_IS_DRAG_ICON
|
||||
GTK_IS_DRAG_ICON_CLASS
|
||||
GTK_DRAG_ICON_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_drag_icon_get_type
|
||||
</SECTION>
|
||||
|
@ -57,7 +57,10 @@ gtk_constraint_target_get_type
|
||||
gtk_container_get_type
|
||||
gtk_css_provider_get_type
|
||||
gtk_dialog_get_type
|
||||
gtk_drag_icon_get_type
|
||||
gtk_drag_source_get_type
|
||||
gtk_drawing_area_get_type
|
||||
gtk_drop_target_get_type
|
||||
gtk_editable_get_type
|
||||
gtk_entry_buffer_get_type
|
||||
gtk_entry_completion_get_type
|
||||
|
@ -96,7 +96,6 @@ private_headers = [
|
||||
'gtkcsswidgetnodeprivate.h',
|
||||
'gtkcsswin32sizevalueprivate.h',
|
||||
'gtkdialogprivate.h',
|
||||
'gtkdndprivate.h',
|
||||
'gtkentryprivate.h',
|
||||
'gtkeventcontrollerlegacyprivate.h',
|
||||
'gtkeventcontrollerprivate.h',
|
||||
|
@ -903,6 +903,37 @@
|
||||
gtk_tooltip_set_custom().
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Switch to the new DND api</title>
|
||||
<para>
|
||||
The source-side DND apis in GTK 4 have been changed to use an event controller, #GtkDragSource.
|
||||
</para>
|
||||
<para>
|
||||
Instead of calling gtk_drag_source_set() and connecting to #GtkWidget signals, you create
|
||||
a #GtkDragSource object, attach it to the widget with gtk_widget_add_controller(), and connect
|
||||
to #GtkDragSource signals. Instead of calling gtk_drag_begin() on a widget to start a drag
|
||||
manually, call gdk_drag_begin().
|
||||
</para>
|
||||
<para>
|
||||
The ::drag-data-get signal has been replaced by the #GtkDragSource::prepare signal, which
|
||||
returns a #GdkContentProvider for the drag operation.
|
||||
</para>
|
||||
<para>
|
||||
The destination-side DND apis in GTK 4 have also been changed to use and event controller,
|
||||
#GTkDropTarget.
|
||||
</para>
|
||||
<para>
|
||||
Instead of calling gtk_drag_dest_set() and connecting to #GtkWidget signals, you create
|
||||
a #GtkDropTarget object, attach it to the widget with gtk_widget_add_controller(), and
|
||||
connect to #GtkDropTarget signals.
|
||||
</para>
|
||||
<para>
|
||||
The ::drag-motion signal has been renamed to #GtkDragSource::accept, and instead of
|
||||
::drag-data-received, you need to use async read methods on the #GdkDrop object, such
|
||||
as gdk_drop_read_value_async() or gdk_drop_read_text_async().
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "gdkcontentformats.h"
|
||||
#include "filetransferportalprivate.h"
|
||||
#include "gdktexture.h"
|
||||
#include "gdkrgbaprivate.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
@ -848,6 +849,63 @@ file_uri_deserializer (GdkContentDeserializer *deserializer)
|
||||
g_object_unref (output);
|
||||
}
|
||||
|
||||
static void
|
||||
color_deserializer_finish (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer deserializer)
|
||||
{
|
||||
GOutputStream *stream = G_OUTPUT_STREAM (source);
|
||||
GError *error = NULL;
|
||||
gssize written;
|
||||
|
||||
written = g_output_stream_splice_finish (stream, result, &error);
|
||||
if (written < 0)
|
||||
{
|
||||
gdk_content_deserializer_return_error (deserializer, error);
|
||||
return;
|
||||
}
|
||||
else if (written == 0)
|
||||
{
|
||||
GdkRGBA black = GDK_RGBA ("000");
|
||||
|
||||
/* Never return NULL, we only return that on error */
|
||||
g_value_set_boxed (gdk_content_deserializer_get_value (deserializer), &black);
|
||||
}
|
||||
else
|
||||
{
|
||||
guint16 *data;
|
||||
GdkRGBA rgba;
|
||||
|
||||
data = (guint16 *)g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (stream));
|
||||
rgba.red = data[0] / 65535.0;
|
||||
rgba.green = data[1] / 65535.0;
|
||||
rgba.blue = data[2] / 65535.0;
|
||||
rgba.alpha = data[3] / 65535.0;
|
||||
|
||||
g_value_set_boxed (gdk_content_deserializer_get_value (deserializer), &rgba);
|
||||
}
|
||||
gdk_content_deserializer_return_success (deserializer);
|
||||
}
|
||||
|
||||
static void
|
||||
color_deserializer (GdkContentDeserializer *deserializer)
|
||||
{
|
||||
GOutputStream *output;
|
||||
guint16 *data;
|
||||
|
||||
data = g_new0 (guint16, 4);
|
||||
output = g_memory_output_stream_new (data, 4 * sizeof (guint16), NULL, g_free);
|
||||
|
||||
g_output_stream_splice_async (output,
|
||||
gdk_content_deserializer_get_input_stream (deserializer),
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
|
||||
gdk_content_deserializer_get_priority (deserializer),
|
||||
gdk_content_deserializer_get_cancellable (deserializer),
|
||||
color_deserializer_finish,
|
||||
deserializer);
|
||||
g_object_unref (output);
|
||||
}
|
||||
|
||||
static void
|
||||
init (void)
|
||||
{
|
||||
@ -956,5 +1014,11 @@ init (void)
|
||||
string_deserializer,
|
||||
(gpointer) "ASCII",
|
||||
NULL);
|
||||
|
||||
gdk_content_register_deserializer ("application/x-color",
|
||||
GDK_TYPE_RGBA,
|
||||
color_deserializer,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "gdkcontentprovider.h"
|
||||
|
||||
#include "gdkcontentformats.h"
|
||||
#include "gdkcontentserializer.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkcontentproviderimpl.h"
|
||||
|
||||
@ -280,3 +281,232 @@ gdk_content_provider_new_for_bytes (const char *mime_type,
|
||||
|
||||
return GDK_CONTENT_PROVIDER (content);
|
||||
}
|
||||
|
||||
#define GDK_TYPE_CONTENT_PROVIDER_CALLBACK (gdk_content_provider_callback_get_type ())
|
||||
#define GDK_CONTENT_PROVIDER_CALLBACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_CALLBACK, GdkContentProviderCallback))
|
||||
|
||||
typedef struct _GdkContentProviderCallback GdkContentProviderCallback;
|
||||
typedef struct _GdkContentProviderCallbackClass GdkContentProviderCallbackClass;
|
||||
|
||||
struct _GdkContentProviderCallback
|
||||
{
|
||||
GdkContentProvider parent;
|
||||
|
||||
GType type;
|
||||
GdkContentProviderGetValueFunc func;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct _GdkContentProviderCallbackClass
|
||||
{
|
||||
GdkContentProviderClass parent_class;
|
||||
};
|
||||
|
||||
GType gdk_content_provider_callback_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_TYPE (GdkContentProviderCallback, gdk_content_provider_callback, GDK_TYPE_CONTENT_PROVIDER)
|
||||
|
||||
static GdkContentFormats *
|
||||
gdk_content_provider_callback_ref_formats (GdkContentProvider *provider)
|
||||
{
|
||||
GdkContentProviderCallback *callback = GDK_CONTENT_PROVIDER_CALLBACK (provider);
|
||||
|
||||
return gdk_content_formats_new_for_gtype (callback->type);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_content_provider_callback_get_value (GdkContentProvider *provider,
|
||||
GValue *value,
|
||||
GError **error)
|
||||
{
|
||||
GdkContentProviderCallback *callback = GDK_CONTENT_PROVIDER_CALLBACK (provider);
|
||||
|
||||
if (G_VALUE_HOLDS (value, callback->type) && callback->func != NULL)
|
||||
{
|
||||
callback->func (value, callback->data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return GDK_CONTENT_PROVIDER_CLASS (gdk_content_provider_callback_parent_class)->get_value (provider, value, error);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_content_provider_callback_class_init (GdkContentProviderCallbackClass *class)
|
||||
{
|
||||
GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
|
||||
|
||||
provider_class->ref_formats = gdk_content_provider_callback_ref_formats;
|
||||
provider_class->get_value = gdk_content_provider_callback_get_value;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_content_provider_callback_init (GdkContentProviderCallback *content)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_content_provider_new_for_callback:
|
||||
* @type: the type that the callback provides
|
||||
* @func: callback to populate a #GValue
|
||||
* @data: data that gets passed to @func
|
||||
*
|
||||
* Create a content provider that provides data that is provided via a callback.
|
||||
*
|
||||
* Returns: a new #GdkContentProvider
|
||||
**/
|
||||
GdkContentProvider *
|
||||
gdk_content_provider_new_with_callback (GType type,
|
||||
GdkContentProviderGetValueFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
GdkContentProviderCallback *content;
|
||||
|
||||
content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_CALLBACK, NULL);
|
||||
content->type = type;
|
||||
content->func = func;
|
||||
content->data = data;
|
||||
|
||||
return GDK_CONTENT_PROVIDER (content);
|
||||
}
|
||||
|
||||
#define GDK_TYPE_CONTENT_PROVIDER_CALLBACK2 (gdk_content_provider_callback2_get_type ())
|
||||
#define GDK_CONTENT_PROVIDER_CALLBACK2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CONTENT_PROVIDER_CALLBACK2, GdkContentProviderCallback2))
|
||||
|
||||
typedef struct _GdkContentProviderCallback2 GdkContentProviderCallback2;
|
||||
typedef struct _GdkContentProviderCallback2Class GdkContentProviderCallback2Class;
|
||||
|
||||
struct _GdkContentProviderCallback2
|
||||
{
|
||||
GdkContentProvider parent;
|
||||
|
||||
GdkContentFormats *formats;
|
||||
GdkContentProviderGetBytesFunc func;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct _GdkContentProviderCallback2Class
|
||||
{
|
||||
GdkContentProviderClass parent_class;
|
||||
};
|
||||
|
||||
GType gdk_content_provider_callback2_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_TYPE (GdkContentProviderCallback2, gdk_content_provider_callback2, GDK_TYPE_CONTENT_PROVIDER)
|
||||
|
||||
static GdkContentFormats *
|
||||
gdk_content_provider_callback2_ref_formats (GdkContentProvider *provider)
|
||||
{
|
||||
GdkContentProviderCallback2 *callback = GDK_CONTENT_PROVIDER_CALLBACK2 (provider);
|
||||
|
||||
return gdk_content_formats_ref (callback->formats);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_content_provider_callback2_write_mime_type_done (GObject *stream,
|
||||
GAsyncResult *result,
|
||||
gpointer task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_output_stream_write_all_finish (G_OUTPUT_STREAM (stream), result, NULL, &error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_content_provider_callback2_write_mime_type_async (GdkContentProvider *provider,
|
||||
const char *mime_type,
|
||||
GOutputStream *stream,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GdkContentProviderCallback2 *content = GDK_CONTENT_PROVIDER_CALLBACK2 (provider);
|
||||
GTask *task;
|
||||
GBytes *bytes;
|
||||
|
||||
task = g_task_new (content, cancellable, callback, user_data);
|
||||
g_task_set_priority (task, io_priority);
|
||||
g_task_set_source_tag (task, gdk_content_provider_callback2_write_mime_type_async);
|
||||
|
||||
if (!gdk_content_formats_contain_mime_type (content->formats, mime_type))
|
||||
{
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Cannot provide contents as “%s”"), mime_type);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
bytes = content->func (mime_type, content->data);
|
||||
if (!bytes)
|
||||
{
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Failed to get contents as “%s”"), mime_type);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_set_data_full (G_OBJECT (task), "bytes", bytes, (GDestroyNotify)g_bytes_unref);
|
||||
|
||||
g_output_stream_write_all_async (stream,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes),
|
||||
io_priority,
|
||||
cancellable,
|
||||
gdk_content_provider_callback2_write_mime_type_done,
|
||||
task);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_content_provider_callback2_write_mime_type_finish (GdkContentProvider *provider,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (g_task_is_valid (result, provider), FALSE);
|
||||
g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_content_provider_callback2_write_mime_type_async, FALSE);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_content_provider_callback2_class_init (GdkContentProviderCallback2Class *class)
|
||||
{
|
||||
GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
|
||||
|
||||
provider_class->ref_formats = gdk_content_provider_callback2_ref_formats;
|
||||
provider_class->write_mime_type_async = gdk_content_provider_callback2_write_mime_type_async;
|
||||
provider_class->write_mime_type_finish = gdk_content_provider_callback2_write_mime_type_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_content_provider_callback2_init (GdkContentProviderCallback2 *content)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_content_provider_new_with_formats:
|
||||
* @formats: formats to advertise
|
||||
* @func: callback to populate a #GValue
|
||||
* @data: data that gets passed to @func
|
||||
*
|
||||
* Create a content provider that provides data that is provided via a callback.
|
||||
*
|
||||
* Returns: a new #GdkContentProvider
|
||||
**/
|
||||
GdkContentProvider *
|
||||
gdk_content_provider_new_with_formats (GdkContentFormats *formats,
|
||||
GdkContentProviderGetBytesFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
GdkContentProviderCallback2 *content;
|
||||
content = g_object_new (GDK_TYPE_CONTENT_PROVIDER_CALLBACK2, NULL);
|
||||
content->formats = gdk_content_formats_union_serialize_mime_types (gdk_content_formats_ref (formats));
|
||||
content->func = func;
|
||||
content->data = data;
|
||||
|
||||
return GDK_CONTENT_PROVIDER (content);
|
||||
}
|
||||
|
@ -35,6 +35,21 @@ GDK_AVAILABLE_IN_ALL
|
||||
GdkContentProvider * gdk_content_provider_new_for_bytes (const char *mime_type,
|
||||
GBytes *bytes);
|
||||
|
||||
typedef void (*GdkContentProviderGetValueFunc) (GValue *value,
|
||||
gpointer data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentProvider * gdk_content_provider_new_with_callback (GType type,
|
||||
GdkContentProviderGetValueFunc func,
|
||||
gpointer data);
|
||||
|
||||
typedef GBytes * (*GdkContentProviderGetBytesFunc) (const char *mime_type,
|
||||
gpointer data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentProvider * gdk_content_provider_new_with_formats (GdkContentFormats *formats,
|
||||
GdkContentProviderGetBytesFunc func,
|
||||
gpointer data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "gdkpixbuf.h"
|
||||
#include "filetransferportalprivate.h"
|
||||
#include "gdktextureprivate.h"
|
||||
#include "gdkrgba.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <string.h>
|
||||
@ -862,6 +863,48 @@ file_text_serializer (GdkContentSerializer *serializer)
|
||||
gdk_content_serializer_set_task_data (serializer, path, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
color_serializer_finish (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer serializer)
|
||||
{
|
||||
GOutputStream *stream = G_OUTPUT_STREAM (source);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_output_stream_write_all_finish (stream, result, NULL, &error))
|
||||
gdk_content_serializer_return_error (serializer, error);
|
||||
else
|
||||
gdk_content_serializer_return_success (serializer);
|
||||
}
|
||||
|
||||
static void
|
||||
color_serializer (GdkContentSerializer *serializer)
|
||||
{
|
||||
const GValue *value;
|
||||
GdkRGBA *rgba;
|
||||
guint16 *data;
|
||||
|
||||
value = gdk_content_serializer_get_value (serializer);
|
||||
rgba = g_value_get_boxed (value);
|
||||
data = g_new0 (guint16, 4);
|
||||
if (rgba)
|
||||
{
|
||||
data[0] = (guint16) (rgba->red * 65535);
|
||||
data[1] = (guint16) (rgba->green * 65535);
|
||||
data[2] = (guint16) (rgba->blue * 65535);
|
||||
data[3] = (guint16) (rgba->alpha * 65535);
|
||||
}
|
||||
|
||||
g_output_stream_write_all_async (gdk_content_serializer_get_output_stream (serializer),
|
||||
data,
|
||||
4 * sizeof (guint16),
|
||||
gdk_content_serializer_get_priority (serializer),
|
||||
gdk_content_serializer_get_cancellable (serializer),
|
||||
color_serializer_finish,
|
||||
serializer);
|
||||
gdk_content_serializer_set_task_data (serializer, data, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
init (void)
|
||||
{
|
||||
@ -984,5 +1027,11 @@ init (void)
|
||||
string_serializer,
|
||||
(gpointer) "ASCII",
|
||||
NULL);
|
||||
|
||||
gdk_content_register_serializer (GDK_TYPE_RGBA,
|
||||
"application/x-color",
|
||||
color_serializer,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
@ -90,20 +90,30 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkDrag, gdk_drag, G_TYPE_OBJECT)
|
||||
|
||||
/**
|
||||
* SECTION:dnd
|
||||
* @title: Drag And Drop
|
||||
* @short_description: Functions for controlling drag and drop handling
|
||||
* @Title: Drag And Drop
|
||||
* @Short_description: Functions for controlling drag and drop handling
|
||||
*
|
||||
* These functions provide a low level interface for drag and drop.
|
||||
* These functions provide a low-level interface for drag and drop.
|
||||
*
|
||||
* The GdkDrag object represents the source side of an ongoing DND operation.
|
||||
* It is created when a drag is started, and stays alive for duration of
|
||||
* the DND operation.
|
||||
* the DND operation. After a drag has been started with gdk_drag_begin(),
|
||||
* the caller gets informed about the status of the ongoing drag operation
|
||||
* with signals on the #GtkDrag object.
|
||||
*
|
||||
* The GdkDrop object represents the target side of an ongoing DND operation.
|
||||
* Possible drop sites get informed about the status of the ongoing drag operation
|
||||
* with events of type %GDK_DRAG_ENTER, %GDK_DRAG_LEAVE, %GDK_DRAG_MOTION and
|
||||
* %GDK_DROP_START. The #GdkDrop object can be obtained from these #GdkEvents
|
||||
* using gdk_event_get_drop().
|
||||
*
|
||||
* The actual data transfer is initiated from the target side via an async
|
||||
* read, using one of the GdkDrop functions for this purpose: gdk_drop_read_async(),
|
||||
* gdk_drop_read_value_async() or gdk_drop_read_text_async().
|
||||
*
|
||||
* GTK+ provides a higher level abstraction based on top of these functions,
|
||||
* and so they are not normally needed in GTK+ applications. See the
|
||||
* [Drag and Drop][gtk4-Drag-and-Drop] section of the GTK+ documentation
|
||||
* GTK provides a higher level abstraction based on top of these functions,
|
||||
* and so they are not normally needed in GTK applications. See the
|
||||
* [Drag and Drop][gtk4-Drag-and-Drop] section of the GTK documentation
|
||||
* for more information.
|
||||
*/
|
||||
|
||||
|
@ -1001,3 +1001,30 @@ gdk_drop_emit_drop_event (GdkDrop *self,
|
||||
gdk_drop_do_emit_event (event, dont_queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_drop_has_value:
|
||||
* @drop: a #GdkDrop
|
||||
* @type: the type to check
|
||||
*
|
||||
* Returns whether calling gdk_drop_read_value_async() for @type
|
||||
* can succeed.
|
||||
*
|
||||
* Returns: %TRUE if the data can be deserialized to the given type
|
||||
*/
|
||||
gboolean
|
||||
gdk_drop_has_value (GdkDrop *drop,
|
||||
GType type)
|
||||
{
|
||||
GdkContentFormats *formats;
|
||||
gboolean ret;
|
||||
|
||||
formats = gdk_content_formats_ref (gdk_drop_get_formats (drop));
|
||||
formats = gdk_content_formats_union_deserialize_gtypes (formats);
|
||||
|
||||
ret = gdk_content_formats_contain_gtype (formats, type);
|
||||
|
||||
gdk_content_formats_unref (formats);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,9 @@ char * gdk_drop_read_text_finish (GdkDrop
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_drop_has_value (GdkDrop *self,
|
||||
GType type);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -1013,6 +1013,13 @@ gdk_event_set_coords (GdkEvent *event,
|
||||
event->touchpad_pinch.x = x;
|
||||
event->touchpad_pinch.y = y;
|
||||
break;
|
||||
case GDK_DRAG_ENTER:
|
||||
case GDK_DRAG_LEAVE:
|
||||
case GDK_DRAG_MOTION:
|
||||
case GDK_DROP_START:
|
||||
event->dnd.x = x;
|
||||
event->dnd.y = y;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3583,7 +3583,13 @@ gdk_surface_register_dnd (GdkSurface *surface)
|
||||
*
|
||||
* Starts a drag and creates a new drag context for it.
|
||||
*
|
||||
* This function is called by the drag source.
|
||||
* This function is called by the drag source. After this call, you
|
||||
* probably want to set up the drag icon using the surface returned
|
||||
* by gdk_drag_get_drag_surface().
|
||||
*
|
||||
* Note: if @actions include %GDK_ACTION_MOVE, you need to listen for
|
||||
* the #GdkDrag::dnd-finished signal and delete the data at the source
|
||||
* if gdk_drag_get_selected_action() returns %GDK_ACTION_MOVE.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a newly created #GdkDrag or
|
||||
* %NULL on error.
|
||||
|
@ -747,7 +747,7 @@ gdk_x11_drop_status (GdkDrop *drop,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
GdkX11Drop *drop_x11 = GDK_X11_DROP (drop);
|
||||
GdkDragAction possible_actions;
|
||||
GdkDragAction possible_actions, suggested_action;
|
||||
XEvent xev;
|
||||
GdkDisplay *display;
|
||||
|
||||
@ -755,6 +755,17 @@ gdk_x11_drop_status (GdkDrop *drop,
|
||||
|
||||
possible_actions = actions & gdk_drop_get_actions (drop);
|
||||
|
||||
if (drop_x11->suggested_action != 0)
|
||||
suggested_action = drop_x11->suggested_action;
|
||||
else if (possible_actions & GDK_ACTION_COPY)
|
||||
suggested_action = GDK_ACTION_COPY;
|
||||
else if (possible_actions & GDK_ACTION_MOVE)
|
||||
suggested_action = GDK_ACTION_MOVE;
|
||||
else if (possible_actions & GDK_ACTION_ASK)
|
||||
suggested_action = GDK_ACTION_ASK;
|
||||
else
|
||||
suggested_action = 0;
|
||||
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "XdndStatus");
|
||||
xev.xclient.format = 32;
|
||||
@ -764,7 +775,7 @@ gdk_x11_drop_status (GdkDrop *drop,
|
||||
xev.xclient.data.l[1] = (possible_actions != 0) ? (2 | 1) : 0;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
xev.xclient.data.l[3] = 0;
|
||||
xev.xclient.data.l[4] = xdnd_action_to_atom (display, possible_actions);
|
||||
xev.xclient.data.l[4] = xdnd_action_to_atom (display, suggested_action);
|
||||
|
||||
if (gdk_drop_get_drag (drop))
|
||||
{
|
||||
|
@ -90,8 +90,8 @@
|
||||
#include <gtk/gtkcustomlayout.h>
|
||||
#include <gtk/gtkdebug.h>
|
||||
#include <gtk/gtkdialog.h>
|
||||
#include <gtk/gtkdnd.h>
|
||||
#include <gtk/gtkdragdest.h>
|
||||
#include <gtk/gtkdragicon.h>
|
||||
#include <gtk/gtkdragsource.h>
|
||||
#include <gtk/gtkdrawingarea.h>
|
||||
#include <gtk/gtkeditable.h>
|
||||
|
@ -72,7 +72,6 @@
|
||||
#endif
|
||||
|
||||
#include "gtkcalendar.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
@ -87,6 +86,10 @@
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkeventcontrollerscroll.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkicontheme.h"
|
||||
#include "gtkdragicon.h"
|
||||
|
||||
#define TIMEOUT_INITIAL 500
|
||||
#define TIMEOUT_REPEAT 50
|
||||
@ -248,7 +251,6 @@ struct _GtkCalendarPrivate
|
||||
guint need_timer : 1;
|
||||
|
||||
guint in_drag : 1;
|
||||
guint drag_highlight : 1;
|
||||
|
||||
guint32 timer;
|
||||
gint click_child;
|
||||
@ -329,22 +331,17 @@ static gboolean gtk_calendar_query_tooltip (GtkWidget *widget,
|
||||
gboolean keyboard_mode,
|
||||
GtkTooltip *tooltip);
|
||||
|
||||
static void gtk_calendar_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data);
|
||||
static void gtk_calendar_drag_data_received (GtkWidget *widget,
|
||||
static gboolean gtk_calendar_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data);
|
||||
static gboolean gtk_calendar_drag_motion (GtkWidget *widget,
|
||||
GtkCalendar *calendar);
|
||||
static void gtk_calendar_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gtk_calendar_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
static gboolean gtk_calendar_drag_drop (GtkWidget *widget,
|
||||
GtkCalendar *calendar);
|
||||
static gboolean gtk_calendar_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
int x,
|
||||
int y,
|
||||
GtkCalendar *calendar);
|
||||
|
||||
|
||||
static void calendar_start_spinning (GtkCalendar *calendar,
|
||||
@ -392,12 +389,6 @@ gtk_calendar_class_init (GtkCalendarClass *class)
|
||||
widget_class->grab_notify = gtk_calendar_grab_notify;
|
||||
widget_class->query_tooltip = gtk_calendar_query_tooltip;
|
||||
|
||||
widget_class->drag_data_get = gtk_calendar_drag_data_get;
|
||||
widget_class->drag_motion = gtk_calendar_drag_motion;
|
||||
widget_class->drag_leave = gtk_calendar_drag_leave;
|
||||
widget_class->drag_drop = gtk_calendar_drag_drop;
|
||||
widget_class->drag_data_received = gtk_calendar_drag_data_received;
|
||||
|
||||
/**
|
||||
* GtkCalendar:year:
|
||||
*
|
||||
@ -675,6 +666,8 @@ gtk_calendar_init (GtkCalendar *calendar)
|
||||
#else
|
||||
gchar *week_start;
|
||||
#endif
|
||||
GdkContentFormats *formats;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
gtk_widget_set_can_focus (widget, TRUE);
|
||||
|
||||
@ -792,11 +785,17 @@ gtk_calendar_init (GtkCalendar *calendar)
|
||||
priv->click_child = -1;
|
||||
|
||||
priv->in_drag = 0;
|
||||
priv->drag_highlight = 0;
|
||||
|
||||
gtk_drag_dest_set (widget, 0, NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_dest_add_text_targets (widget);
|
||||
formats = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
|
||||
gdk_content_formats_unref (formats);
|
||||
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (gtk_calendar_drag_accept), calendar);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_calendar_drag_leave), calendar);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_calendar_drag_drop), calendar);
|
||||
|
||||
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
priv->year_before = 0;
|
||||
|
||||
/* Translate to calendar:YM if you want years to be displayed
|
||||
@ -2661,6 +2660,27 @@ gtk_calendar_drag_begin (GtkGestureDrag *gesture,
|
||||
priv->in_drag = TRUE;
|
||||
}
|
||||
|
||||
static GdkContentProvider *
|
||||
get_calendar_content (GtkCalendar *calendar)
|
||||
{
|
||||
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
|
||||
GDate *date;
|
||||
gchar str[128];
|
||||
GValue value = G_VALUE_INIT;
|
||||
GdkContentProvider *content;
|
||||
|
||||
date = g_date_new_dmy (priv->selected_day, priv->month + 1, priv->year);
|
||||
g_date_strftime (str, 127, "%x", date);
|
||||
g_free (date);
|
||||
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
g_value_set_string (&value, str);
|
||||
content = gdk_content_provider_new_for_value (&value);
|
||||
g_value_unset (&value);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_calendar_drag_update (GtkGestureDrag *gesture,
|
||||
double x,
|
||||
@ -2671,8 +2691,12 @@ gtk_calendar_drag_update (GtkGestureDrag *gesture,
|
||||
GtkCalendar *calendar = GTK_CALENDAR (widget);
|
||||
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
|
||||
gdouble start_x, start_y;
|
||||
GdkContentProvider *content;
|
||||
GdkDevice *device;
|
||||
GdkDrag *drag;
|
||||
GdkContentFormats *targets;
|
||||
GtkIconTheme *theme;
|
||||
GdkPaintable *paintable;
|
||||
GdkSurface *surface;
|
||||
|
||||
if (!priv->in_drag)
|
||||
return;
|
||||
@ -2682,19 +2706,22 @@ gtk_calendar_drag_update (GtkGestureDrag *gesture,
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
|
||||
|
||||
gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (widget));
|
||||
device = gtk_gesture_get_device (GTK_GESTURE (gesture));
|
||||
|
||||
targets = gdk_content_formats_new (NULL, 0);
|
||||
targets = gtk_content_formats_add_text_targets (targets);
|
||||
drag = gtk_drag_begin (widget,
|
||||
gtk_gesture_get_device (GTK_GESTURE (gesture)),
|
||||
targets, GDK_ACTION_COPY,
|
||||
start_x, start_y);
|
||||
content = get_calendar_content (calendar);
|
||||
|
||||
drag = gdk_drag_begin (surface, device, content, GDK_ACTION_COPY, start_x, start_y);
|
||||
|
||||
theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (widget));
|
||||
paintable = gtk_icon_theme_load_icon (theme, "text-x-generic", 32, 0, NULL);
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, 0, 0);
|
||||
g_clear_object (&paintable);
|
||||
|
||||
g_object_unref (content);
|
||||
g_object_unref (drag);
|
||||
|
||||
priv->in_drag = 0;
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
gtk_drag_set_icon_default (drag);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -2914,24 +2941,6 @@ gtk_calendar_grab_notify (GtkWidget *widget,
|
||||
* Drag and Drop *
|
||||
****************************************/
|
||||
|
||||
static void
|
||||
gtk_calendar_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
GtkCalendar *calendar = GTK_CALENDAR (widget);
|
||||
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
|
||||
GDate *date;
|
||||
gchar str[128];
|
||||
gsize len;
|
||||
|
||||
date = g_date_new_dmy (priv->selected_day, priv->month + 1, priv->year);
|
||||
len = g_date_strftime (str, 127, "%x", date);
|
||||
gtk_selection_data_set_text (selection_data, str, len);
|
||||
|
||||
g_free (date);
|
||||
}
|
||||
|
||||
/* Get/set whether drag_motion requested the drag data and
|
||||
* drag_data_received should thus not actually insert the data,
|
||||
* since the data doesn’t result from a drop.
|
||||
@ -2953,87 +2962,33 @@ get_status_pending (GdkDrop *drop)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_calendar_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
gtk_calendar_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkCalendar *calendar)
|
||||
{
|
||||
GtkCalendar *calendar = GTK_CALENDAR (widget);
|
||||
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
|
||||
|
||||
priv->drag_highlight = 0;
|
||||
gtk_drag_unhighlight (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_calendar_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkCalendar *calendar = GTK_CALENDAR (widget);
|
||||
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
|
||||
GdkAtom target;
|
||||
|
||||
if (!priv->drag_highlight)
|
||||
{
|
||||
priv->drag_highlight = 1;
|
||||
gtk_drag_highlight (widget);
|
||||
}
|
||||
|
||||
target = gtk_drag_dest_find_target (widget, drop, NULL);
|
||||
if (target == NULL || gdk_drop_get_actions (drop) == 0)
|
||||
gdk_drop_status (drop, 0);
|
||||
else if (get_status_pending (drop) == 0)
|
||||
{
|
||||
set_status_pending (drop, gdk_drop_get_actions (drop));
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_calendar_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GdkAtom target;
|
||||
|
||||
target = gtk_drag_dest_find_target (widget, drop, NULL);
|
||||
if (target != NULL)
|
||||
{
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_calendar_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
got_text (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkCalendar *calendar = GTK_CALENDAR (widget);
|
||||
GtkDropTarget *dest = GTK_DROP_TARGET (data);
|
||||
GtkCalendar *calendar = GTK_CALENDAR (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)));
|
||||
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
guint day, month, year;
|
||||
gchar *str;
|
||||
GDate *date;
|
||||
GdkDragAction suggested_action;
|
||||
|
||||
suggested_action = get_status_pending (drop);
|
||||
set_status_pending (drop, 0);
|
||||
|
||||
str = gdk_drop_read_text_finish (drop, result, NULL);
|
||||
|
||||
if (suggested_action)
|
||||
{
|
||||
set_status_pending (drop, 0);
|
||||
|
||||
/* We are getting this data due to a request in drag_motion,
|
||||
* rather than due to a request in drag_drop, so we are just
|
||||
* supposed to call drag_status, not actually paste in the
|
||||
* data.
|
||||
*/
|
||||
str = (gchar*) gtk_selection_data_get_text (selection_data);
|
||||
|
||||
if (str)
|
||||
{
|
||||
date = g_date_new ();
|
||||
@ -3045,14 +3000,13 @@ gtk_calendar_drag_data_received (GtkWidget *widget,
|
||||
}
|
||||
else
|
||||
suggested_action = 0;
|
||||
|
||||
gdk_drop_status (drop, suggested_action);
|
||||
|
||||
if (suggested_action == 0)
|
||||
gtk_drop_target_deny_drop (dest, drop);
|
||||
return;
|
||||
}
|
||||
|
||||
date = g_date_new ();
|
||||
str = (gchar*) gtk_selection_data_get_text (selection_data);
|
||||
if (str)
|
||||
{
|
||||
g_date_set_parse (date, str);
|
||||
@ -3064,6 +3018,7 @@ gtk_calendar_drag_data_received (GtkWidget *widget,
|
||||
g_warning ("Received invalid date data");
|
||||
g_date_free (date);
|
||||
gdk_drop_finish (drop, 0);
|
||||
gtk_drop_target_deny_drop (dest, drop);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3074,7 +3029,6 @@ gtk_calendar_drag_data_received (GtkWidget *widget,
|
||||
|
||||
gdk_drop_finish (drop, suggested_action);
|
||||
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (calendar));
|
||||
if (!(priv->display_flags & GTK_CALENDAR_NO_MONTH_CHANGE)
|
||||
&& (priv->display_flags & GTK_CALENDAR_SHOW_HEADING))
|
||||
@ -3083,6 +3037,47 @@ gtk_calendar_drag_data_received (GtkWidget *widget,
|
||||
g_object_thaw_notify (G_OBJECT (calendar));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_calendar_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkCalendar *calendar)
|
||||
{
|
||||
GdkAtom target;
|
||||
|
||||
target = gtk_drop_target_find_mimetype (dest);
|
||||
if (!target || gdk_drop_get_actions (drop) == 0)
|
||||
{
|
||||
gdk_drop_status (drop, 0);
|
||||
return FALSE;
|
||||
}
|
||||
else if (get_status_pending (drop) == 0)
|
||||
{
|
||||
set_status_pending (drop, gdk_drop_get_actions (drop));
|
||||
gdk_drop_read_text_async (drop, NULL, got_text, dest);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_calendar_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkCalendar *calendar)
|
||||
{
|
||||
GdkAtom target;
|
||||
|
||||
target = gtk_drop_target_find_mimetype (dest);
|
||||
if (target != NULL)
|
||||
{
|
||||
set_status_pending (drop, 0);
|
||||
gdk_drop_read_text_async (drop, NULL, got_text, dest);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/****************************************
|
||||
* Public API *
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkcolorchooserdialog.h"
|
||||
#include "gtkcolorswatchprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkintl.h"
|
||||
@ -45,6 +44,9 @@
|
||||
#include "gtkprivate.h"
|
||||
#include "gtksnapshot.h"
|
||||
#include "gtkstylecontext.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkeventcontroller.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -121,21 +123,6 @@ static void gtk_color_button_get_property (GObject *object,
|
||||
static void gtk_color_button_clicked (GtkButton *button,
|
||||
gpointer user_data);
|
||||
|
||||
/* source side drag signals */
|
||||
static void gtk_color_button_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data);
|
||||
static void gtk_color_button_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
GtkColorButton *button);
|
||||
|
||||
/* target side drag signals */
|
||||
static void gtk_color_button_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
GtkColorButton *button);
|
||||
|
||||
|
||||
static guint color_button_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
@ -245,91 +232,64 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_button_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
GtkColorButton *button)
|
||||
got_color (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorButtonPrivate *priv = gtk_color_button_get_instance_private (button);
|
||||
gint length;
|
||||
guint16 *dropped;
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
const GValue *value;
|
||||
|
||||
length = gtk_selection_data_get_length (selection_data);
|
||||
|
||||
if (length < 0)
|
||||
return;
|
||||
|
||||
/* We accept drops with the wrong format, since the KDE color
|
||||
* chooser incorrectly drops application/x-color with format 8.
|
||||
*/
|
||||
if (length != 8)
|
||||
value = gdk_drop_read_value_finish (drop, result, NULL);
|
||||
if (value)
|
||||
{
|
||||
g_warning ("%s: Received invalid color data", G_STRFUNC);
|
||||
return;
|
||||
GdkRGBA *color = g_value_get_boxed (value);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (data), color);
|
||||
gdk_drop_finish (drop, GDK_ACTION_COPY);
|
||||
}
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_color_button_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkColorButton *button)
|
||||
{
|
||||
if (gdk_drop_has_value (drop, GDK_TYPE_RGBA))
|
||||
{
|
||||
gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, button);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
dropped = (guint16 *) gtk_selection_data_get_data (selection_data);
|
||||
|
||||
priv->rgba.red = dropped[0] / 65535.;
|
||||
priv->rgba.green = dropped[1] / 65535.;
|
||||
priv->rgba.blue = dropped[2] / 65535.;
|
||||
priv->rgba.alpha = dropped[3] / 65535.;
|
||||
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (priv->swatch), &priv->rgba);
|
||||
|
||||
g_signal_emit (button, color_button_signals[COLOR_SET], 0);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (button));
|
||||
g_object_notify (G_OBJECT (button), "rgba");
|
||||
g_object_thaw_notify (G_OBJECT (button));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_color_icon (GdkDrag *drag,
|
||||
const GdkRGBA *rgba)
|
||||
gtk_color_button_drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GtkColorButton *button)
|
||||
{
|
||||
GtkColorButtonPrivate *priv = gtk_color_button_get_instance_private (button);
|
||||
GtkSnapshot *snapshot;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
snapshot = gtk_snapshot_new ();
|
||||
gtk_snapshot_append_color (snapshot,
|
||||
rgba,
|
||||
&GRAPHENE_RECT_INIT(0, 0, 48, 32));
|
||||
gtk_snapshot_append_color (snapshot, &priv->rgba, &GRAPHENE_RECT_INIT(0, 0, 48, 32));
|
||||
paintable = gtk_snapshot_free_to_paintable (snapshot, NULL);
|
||||
|
||||
gtk_drag_set_icon_paintable (drag, paintable, 0, 0);
|
||||
gtk_drag_source_set_icon (source, paintable, 0, 0);
|
||||
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_button_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
get_rgba_value (GValue *value,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorButton *button = data;
|
||||
GtkColorButtonPrivate *priv = gtk_color_button_get_instance_private (button);
|
||||
|
||||
set_color_icon (drag, &priv->rgba);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_button_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
GtkColorButton *button)
|
||||
{
|
||||
GtkColorButtonPrivate *priv = gtk_color_button_get_instance_private (button);
|
||||
guint16 dropped[4];
|
||||
|
||||
dropped[0] = (guint16) (priv->rgba.red * 65535);
|
||||
dropped[1] = (guint16) (priv->rgba.green * 65535);
|
||||
dropped[2] = (guint16) (priv->rgba.blue * 65535);
|
||||
dropped[3] = (guint16) (priv->rgba.alpha * 65535);
|
||||
|
||||
gtk_selection_data_set (selection_data,
|
||||
gtk_selection_data_get_target (selection_data),
|
||||
16, (guchar *)dropped, 8);
|
||||
GtkColorButtonPrivate *priv = gtk_color_button_get_instance_private (GTK_COLOR_BUTTON (data));
|
||||
g_value_set_boxed (value, &priv->rgba);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -340,6 +300,9 @@ gtk_color_button_init (GtkColorButton *button)
|
||||
PangoRectangle rect;
|
||||
GtkStyleContext *context;
|
||||
GdkContentFormats *targets;
|
||||
GdkContentProvider *content;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
priv->button = gtk_button_new ();
|
||||
g_signal_connect (priv->button, "clicked", G_CALLBACK (gtk_color_button_clicked), button);
|
||||
@ -364,23 +327,17 @@ gtk_color_button_init (GtkColorButton *button)
|
||||
priv->use_alpha = FALSE;
|
||||
|
||||
targets = gdk_content_formats_new (drop_types, G_N_ELEMENTS (drop_types));
|
||||
gtk_drag_dest_set (priv->button,
|
||||
GTK_DEST_DEFAULT_MOTION |
|
||||
GTK_DEST_DEFAULT_HIGHLIGHT |
|
||||
GTK_DEST_DEFAULT_DROP,
|
||||
targets,
|
||||
GDK_ACTION_COPY);
|
||||
gtk_drag_source_set (priv->button,
|
||||
GDK_BUTTON1_MASK|GDK_BUTTON3_MASK,
|
||||
targets,
|
||||
GDK_ACTION_COPY);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_COPY);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_color_button_drag_drop), button);
|
||||
gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (targets);
|
||||
g_signal_connect (priv->button, "drag-begin",
|
||||
G_CALLBACK (gtk_color_button_drag_begin), button);
|
||||
g_signal_connect (priv->button, "drag-data-received",
|
||||
G_CALLBACK (gtk_color_button_drag_data_received), button);
|
||||
g_signal_connect (priv->button, "drag-data-get",
|
||||
G_CALLBACK (gtk_color_button_drag_data_get), button);
|
||||
|
||||
source = gtk_drag_source_new ();
|
||||
content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, button);
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_object_unref (content);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_button_drag_begin), button);
|
||||
gtk_widget_add_controller (priv->button, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (priv->button));
|
||||
gtk_style_context_add_class (context, "color");
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "gtkbox.h"
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkgesturelongpress.h"
|
||||
@ -40,6 +39,7 @@
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdragsource.h"
|
||||
|
||||
#include "a11y/gtkcolorswatchaccessibleprivate.h"
|
||||
|
||||
@ -66,6 +66,7 @@ typedef struct
|
||||
GtkWidget *overlay_widget;
|
||||
|
||||
GtkWidget *popover;
|
||||
GtkDropTarget *dest;
|
||||
} GtkColorSwatchPrivate;
|
||||
|
||||
enum
|
||||
@ -73,7 +74,8 @@ enum
|
||||
PROP_ZERO,
|
||||
PROP_RGBA,
|
||||
PROP_SELECTABLE,
|
||||
PROP_HAS_MENU
|
||||
PROP_HAS_MENU,
|
||||
PROP_CAN_DROP
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET)
|
||||
@ -113,87 +115,57 @@ swatch_snapshot (GtkWidget *widget,
|
||||
gtk_widget_snapshot_child (widget, priv->overlay_widget, snapshot);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
drag_set_color_icon (GdkDrag *drag,
|
||||
const GdkRGBA *color)
|
||||
gtk_color_swatch_drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GtkColorSwatch *swatch)
|
||||
{
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
|
||||
GtkSnapshot *snapshot;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
snapshot = gtk_snapshot_new ();
|
||||
gtk_snapshot_append_color (snapshot,
|
||||
color,
|
||||
&GRAPHENE_RECT_INIT(0, 0, 48, 32));
|
||||
gtk_snapshot_append_color (snapshot, &priv->color, &GRAPHENE_RECT_INIT(0, 0, 48, 32));
|
||||
paintable = gtk_snapshot_free_to_paintable (snapshot, NULL);
|
||||
|
||||
gtk_drag_set_icon_paintable (drag, paintable, 4, 4);
|
||||
gtk_drag_source_set_icon (source, paintable, 0, 0);
|
||||
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
got_color (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
GdkRGBA color;
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
const GValue *value;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
drag_set_color_icon (drag, &color);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
guint16 vals[4];
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
|
||||
vals[0] = color.red * 0xffff;
|
||||
vals[1] = color.green * 0xffff;
|
||||
vals[2] = color.blue * 0xffff;
|
||||
vals[3] = color.alpha * 0xffff;
|
||||
|
||||
gtk_selection_data_set (selection_data,
|
||||
g_intern_static_string ("application/x-color"),
|
||||
16, (guchar *)vals, 8);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
gint length;
|
||||
guint16 *vals;
|
||||
GdkRGBA color;
|
||||
|
||||
length = gtk_selection_data_get_length (selection_data);
|
||||
|
||||
if (length < 0)
|
||||
return;
|
||||
|
||||
/* We accept drops with the wrong format, since the KDE color
|
||||
* chooser incorrectly drops application/x-color with format 8.
|
||||
*/
|
||||
if (length != 8)
|
||||
value = gdk_drop_read_value_finish (drop, result, NULL);
|
||||
if (value)
|
||||
{
|
||||
g_warning ("Received invalid color data");
|
||||
return;
|
||||
GdkRGBA *color = g_value_get_boxed (value);
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (data), color);
|
||||
gdk_drop_finish (drop, GDK_ACTION_COPY);
|
||||
}
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swatch_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkColorSwatch *swatch)
|
||||
{
|
||||
if (gdk_drop_has_value (drop, GDK_TYPE_RGBA))
|
||||
{
|
||||
gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, swatch);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
vals = (guint16 *) gtk_selection_data_get_data (selection_data);
|
||||
|
||||
color.red = (gdouble)vals[0] / 0xffff;
|
||||
color.green = (gdouble)vals[1] / 0xffff;
|
||||
color.blue = (gdouble)vals[2] / 0xffff;
|
||||
color.alpha = (gdouble)vals[3] / 0xffff;
|
||||
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -455,6 +427,9 @@ swatch_get_property (GObject *object,
|
||||
case PROP_HAS_MENU:
|
||||
g_value_set_boolean (value, priv->has_menu);
|
||||
break;
|
||||
case PROP_CAN_DROP:
|
||||
g_value_set_boolean (value, priv->dest != NULL);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -481,6 +456,9 @@ swatch_set_property (GObject *object,
|
||||
case PROP_HAS_MENU:
|
||||
priv->has_menu = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_CAN_DROP:
|
||||
gtk_color_swatch_set_can_drop (swatch, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -495,7 +473,7 @@ swatch_finalize (GObject *object)
|
||||
|
||||
g_free (priv->icon);
|
||||
gtk_widget_unparent (priv->overlay_widget);
|
||||
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -523,9 +501,6 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class)
|
||||
|
||||
widget_class->measure = gtk_color_swatch_measure;
|
||||
widget_class->snapshot = swatch_snapshot;
|
||||
widget_class->drag_begin = swatch_drag_begin;
|
||||
widget_class->drag_data_get = swatch_drag_data_get;
|
||||
widget_class->drag_data_received = swatch_drag_data_received;
|
||||
widget_class->popup_menu = swatch_popup_menu;
|
||||
widget_class->size_allocate = swatch_size_allocate;
|
||||
widget_class->state_flags_changed = swatch_state_flags_changed;
|
||||
@ -539,6 +514,9 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class)
|
||||
g_object_class_install_property (object_class, PROP_HAS_MENU,
|
||||
g_param_spec_boolean ("has-menu", P_("Has Menu"), P_("Whether the swatch should offer customization"),
|
||||
TRUE, GTK_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class, PROP_CAN_DROP,
|
||||
g_param_spec_boolean ("can-drop", P_("Can Drop"), P_("Whether the swatch should accept drops"),
|
||||
FALSE, GTK_PARAM_READWRITE));
|
||||
|
||||
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COLOR_SWATCH_ACCESSIBLE);
|
||||
gtk_widget_class_set_css_name (widget_class, I_("colorswatch"));
|
||||
@ -600,6 +578,14 @@ static const char *dnd_targets[] = {
|
||||
"application/x-color"
|
||||
};
|
||||
|
||||
static void
|
||||
get_rgba_value (GValue *value,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (GTK_COLOR_SWATCH (data));
|
||||
g_value_set_boxed (value, &priv->color);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
|
||||
const GdkRGBA *color)
|
||||
@ -611,12 +597,16 @@ gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
|
||||
|
||||
if (!priv->has_color)
|
||||
{
|
||||
GdkContentFormats *targets = gdk_content_formats_new (dnd_targets, G_N_ELEMENTS (dnd_targets));
|
||||
gtk_drag_source_set (GTK_WIDGET (swatch),
|
||||
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
|
||||
targets,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
gdk_content_formats_unref (targets);
|
||||
GdkContentProvider *content;
|
||||
GtkDragSource *source;
|
||||
|
||||
source = gtk_drag_source_new ();
|
||||
content = gdk_content_provider_new_with_callback (GDK_TYPE_RGBA, get_rgba_value, swatch);
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_object_unref (content);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (gtk_color_swatch_drag_begin), swatch);
|
||||
|
||||
gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (source));
|
||||
}
|
||||
|
||||
priv->has_color = TRUE;
|
||||
@ -676,21 +666,28 @@ void
|
||||
gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
|
||||
gboolean can_drop)
|
||||
{
|
||||
if (can_drop)
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
|
||||
|
||||
if (can_drop == (priv->dest != NULL))
|
||||
return;
|
||||
|
||||
if (can_drop && !priv->dest)
|
||||
{
|
||||
GdkContentFormats *targets = gdk_content_formats_new (dnd_targets, G_N_ELEMENTS (dnd_targets));
|
||||
gtk_drag_dest_set (GTK_WIDGET (swatch),
|
||||
GTK_DEST_DEFAULT_HIGHLIGHT |
|
||||
GTK_DEST_DEFAULT_MOTION |
|
||||
GTK_DEST_DEFAULT_DROP,
|
||||
targets,
|
||||
GDK_ACTION_COPY);
|
||||
GdkContentFormats *targets;
|
||||
|
||||
targets = gdk_content_formats_new (dnd_targets, G_N_ELEMENTS (dnd_targets));
|
||||
priv->dest = gtk_drop_target_new (targets, GDK_ACTION_COPY);
|
||||
g_signal_connect (priv->dest, "drag-drop", G_CALLBACK (swatch_drag_drop), swatch);
|
||||
gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (priv->dest));
|
||||
gdk_content_formats_unref (targets);
|
||||
}
|
||||
else
|
||||
if (!can_drop && priv->dest)
|
||||
{
|
||||
gtk_drag_dest_unset (GTK_WIDGET (swatch));
|
||||
gtk_widget_remove_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (priv->dest));
|
||||
priv->dest = NULL;
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (swatch), "can-drop");
|
||||
}
|
||||
|
||||
void
|
||||
|
1425
gtk/gtkdnd.c
1425
gtk/gtkdnd.c
File diff suppressed because it is too large
Load Diff
102
gtk/gtkdnd.h
102
gtk/gtkdnd.h
@ -1,102 +0,0 @@
|
||||
/* -*- 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_DND_H__
|
||||
#define __GTK_DND_H__
|
||||
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtkselection.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Destination side */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_get_data (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GdkAtom target);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget *gtk_drag_get_source_widget (GdkDrag *drag);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_highlight (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_unhighlight (GtkWidget *widget);
|
||||
|
||||
/* Source side */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkDrag *gtk_drag_begin (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GdkContentFormats *targets,
|
||||
GdkDragAction actions,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_cancel (GdkDrag *drag);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_set_icon_widget (GdkDrag *drag,
|
||||
GtkWidget *widget,
|
||||
gint hot_x,
|
||||
gint hot_y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_set_icon_paintable (GdkDrag *drag,
|
||||
GdkPaintable *paintable,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_set_icon_name (GdkDrag *drag,
|
||||
const gchar *icon_name,
|
||||
gint hot_x,
|
||||
gint hot_y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_set_icon_gicon (GdkDrag *drag,
|
||||
GIcon *icon,
|
||||
gint hot_x,
|
||||
gint hot_y);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_set_icon_default (GdkDrag *drag);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_drag_check_threshold (GtkWidget *widget,
|
||||
gint start_x,
|
||||
gint start_y,
|
||||
gint current_x,
|
||||
gint current_y);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_DND_H__ */
|
@ -1,59 +0,0 @@
|
||||
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2015 Red Hat, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_DND_PRIVATE_H__
|
||||
#define __GTK_DND_PRIVATE_H__
|
||||
|
||||
#include "gtkdnd.h"
|
||||
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkimagedefinitionprivate.h"
|
||||
#include "gtkselection.h"
|
||||
#include "gtkwidget.h"
|
||||
|
||||
typedef struct _GtkDragDestSite GtkDragDestSite;
|
||||
struct _GtkDragDestSite
|
||||
{
|
||||
GtkDestDefaults flags;
|
||||
GdkContentFormats *target_list;
|
||||
GdkDragAction actions;
|
||||
guint do_proxy : 1;
|
||||
guint proxy_coords : 1;
|
||||
guint have_drag : 1;
|
||||
guint track_motion : 1;
|
||||
};
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GdkDrag * gtk_drag_begin_internal (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkImageDefinition *icon,
|
||||
GdkContentFormats *target_list,
|
||||
GdkDragAction actions,
|
||||
int x,
|
||||
int y);
|
||||
void gtk_drag_set_icon_definition (GdkDrag *drag,
|
||||
GtkImageDefinition *def,
|
||||
gint hot_x,
|
||||
gint hot_y);
|
||||
void _gtk_drag_dest_handle_event (GtkWidget *toplevel,
|
||||
GdkEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_DND_PRIVATE_H__ */
|
1278
gtk/gtkdragdest.c
1278
gtk/gtkdragdest.c
File diff suppressed because it is too large
Load Diff
@ -37,65 +37,58 @@
|
||||
|
||||
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 widget’s list of possible formats
|
||||
* 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 widget’s list of possible formats 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 gdk_drag_finish(). If
|
||||
* the action was a move, then if the drag was successful, then %TRUE will be
|
||||
* passed for the @delete parameter to gdk_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;
|
||||
typedef struct _GtkDropTarget GtkDropTarget;
|
||||
|
||||
|
||||
#define GTK_TYPE_DROP_TARGET (gtk_drop_target_get_type ())
|
||||
#define GTK_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET, GtkDropTarget))
|
||||
#define GTK_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
|
||||
#define GTK_IS_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET))
|
||||
#define GTK_IS_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET))
|
||||
#define GTK_DROP_TARGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET, GtkDropTargetClass))
|
||||
|
||||
typedef struct _GtkDropTargetClass GtkDropTargetClass;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_dest_set (GtkWidget *widget,
|
||||
GtkDestDefaults flags,
|
||||
GdkContentFormats *targets,
|
||||
GdkDragAction actions);
|
||||
GType gtk_drop_target_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_dest_unset (GtkWidget *widget);
|
||||
GtkDropTarget *gtk_drop_target_new (GdkContentFormats *formats,
|
||||
GdkDragAction actions);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gtk_drag_dest_find_target (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GdkContentFormats *target_list);
|
||||
void gtk_drop_target_set_formats (GtkDropTarget *dest,
|
||||
GdkContentFormats *formats);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentFormats* gtk_drag_dest_get_target_list (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_dest_set_target_list (GtkWidget *widget,
|
||||
GdkContentFormats *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);
|
||||
GdkContentFormats *gtk_drop_target_get_formats (GtkDropTarget *dest);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_dest_set_track_motion (GtkWidget *widget,
|
||||
gboolean track_motion);
|
||||
void gtk_drop_target_set_actions (GtkDropTarget *dest,
|
||||
GdkDragAction actions);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_drag_dest_get_track_motion (GtkWidget *widget);
|
||||
GdkDragAction gtk_drop_target_get_actions (GtkDropTarget *dest);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkDrop *gtk_drop_target_get_drop (GtkDropTarget *dest);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char *gtk_drop_target_find_mimetype (GtkDropTarget *dest);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drop_target_read_selection (GtkDropTarget *dest,
|
||||
GdkAtom target,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer data);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSelectionData *gtk_drop_target_read_selection_finish
|
||||
(GtkDropTarget *dest,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drop_target_deny_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
32
gtk/gtkdragdestprivate.h
Normal file
32
gtk/gtkdragdestprivate.h
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2020 Matthias Clasen
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_DRAG_DEST_PRIVATE_H__
|
||||
#define __GTK_DRAG_DEST_PRIVATE_H__
|
||||
|
||||
#include "gtkdragdest.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
void gtk_drag_dest_handle_event (GtkWidget *toplevel,
|
||||
GdkEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
@ -23,8 +23,25 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtknativeprivate.h"
|
||||
#include "gtkpicture.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:gtkdragicon
|
||||
* @Short_description: A toplevel to use as drag icon
|
||||
* @Title: GtkDragIcon
|
||||
*
|
||||
* GtkDragIcon is a #GtkNative implementation with the sole purpose
|
||||
* to serve as a drag icon during DND operations. A drag icon moves
|
||||
* with the pointer during a drag operation and is destroyed when
|
||||
* the drag ends.
|
||||
*
|
||||
* To set up a drag icon and associate it with an ongoing drag operation,
|
||||
* use gtk_drag_icon_set_from_paintable(). It is also possible to create
|
||||
* a GtkDragIcon with gtk_drag_icon_new_for_drag(() and populate it
|
||||
* with widgets yourself.
|
||||
*/
|
||||
struct _GtkDragIcon
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
@ -374,6 +391,63 @@ gtk_drag_icon_new (void)
|
||||
return g_object_new (GTK_TYPE_DRAG_ICON, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_icon_new_for_drag:
|
||||
* @drag: a #GtkDrag
|
||||
*
|
||||
* Creates a #GtkDragIcon and associates it with the drag operation.
|
||||
*
|
||||
* Returns: the new #GtkDragIcon
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_drag_icon_new_for_drag (GdkDrag *drag)
|
||||
{
|
||||
GtkWidget *icon;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_DRAG (drag), NULL);
|
||||
|
||||
icon = g_object_new (GTK_TYPE_DRAG_ICON, NULL);
|
||||
|
||||
gtk_drag_icon_set_surface (GTK_DRAG_ICON (icon), gdk_drag_get_drag_surface (drag));
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_icon_set_from_paintable:
|
||||
* @drag: a #GdkDrag
|
||||
* @paintable: a #GdkPaintable to display
|
||||
* @hot_x: X coordinate of the hotspot
|
||||
* @hot_y: Y coordinate of the hotspot
|
||||
*
|
||||
* Creates a #GtkDragIcon that shows @paintable, and associates
|
||||
* it with the drag operation. The hotspot position on the paintable
|
||||
* is aligned with the hotspot of the cursor.
|
||||
*/
|
||||
void
|
||||
gtk_drag_icon_set_from_paintable (GdkDrag *drag,
|
||||
GdkPaintable *paintable,
|
||||
int hot_x,
|
||||
int hot_y)
|
||||
{
|
||||
GtkWidget *icon;
|
||||
GtkWidget *picture;
|
||||
|
||||
gdk_drag_set_hotspot (drag, hot_x, hot_y);
|
||||
|
||||
icon = gtk_drag_icon_new_for_drag (drag);
|
||||
|
||||
picture = gtk_picture_new_for_paintable (paintable);
|
||||
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
|
||||
gtk_container_add (GTK_CONTAINER (icon), picture);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (drag),
|
||||
"icon",
|
||||
g_object_ref_sink (icon),
|
||||
(GDestroyNotify)gtk_widget_destroy);
|
||||
gtk_widget_show (icon);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_drag_icon_set_surface (GtkDragIcon *icon,
|
||||
GdkSurface *surface)
|
||||
|
51
gtk/gtkdragicon.h
Normal file
51
gtk/gtkdragicon.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright © 2020 Matthias Clasen
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_DRAG_ICON_H__
|
||||
#define __GTK_DRAG_ICON_H__
|
||||
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtkcontainer.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_DRAG_ICON (gtk_drag_icon_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkDragIcon, gtk_drag_icon, GTK, DRAG_ICON, GtkContainer)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_drag_icon_new_for_drag (GdkDrag *drag);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_icon_set_from_paintable (GdkDrag *drag,
|
||||
GdkPaintable *paintable,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __GTK_DRAG_ICON_H__ */
|
@ -26,14 +26,10 @@
|
||||
#define __GTK_DRAG_ICON_PRIVATE_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtk/gtkdragicon.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_DRAG_ICON (gtk_drag_icon_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GtkDragIcon, gtk_drag_icon, GTK, DRAG_ICON, GtkContainer)
|
||||
|
||||
GtkWidget * gtk_drag_icon_new (void);
|
||||
|
||||
void gtk_drag_icon_set_surface (GtkDragIcon *icon,
|
||||
|
@ -26,365 +26,677 @@
|
||||
|
||||
#include "gtkdragsource.h"
|
||||
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdndprivate.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgesturesingleprivate.h"
|
||||
#include "gtkimagedefinitionprivate.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkstylecontext.h"
|
||||
#include "gtkimageprivate.h"
|
||||
#include "gtkdragiconprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkicontheme.h"
|
||||
#include "gtkpicture.h"
|
||||
#include "gtksettingsprivate.h"
|
||||
#include "gtkgesturesingle.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkdragsource
|
||||
* @Short_description: Event controller to initiate DND operations
|
||||
* @Title: GtkDragSource
|
||||
*
|
||||
* GtkDragSource is an auxiliary object that is used to initiate
|
||||
* Drag-And-Drop operations. It can be set up with the necessary
|
||||
* ingredients for a DND operation ahead of time. This includes
|
||||
* the source for the data that is being transferred, in the form
|
||||
* of a #GdkContentProvider, the desired action, and the icon to
|
||||
* use during the drag operation. After setting it up, the drag
|
||||
* source must be added to a widget as an event controller, using
|
||||
* gtk_widget_add_controller().
|
||||
*
|
||||
* Setting up the content provider and icon ahead of time only
|
||||
* makes sense when the data does not change. More commonly, you
|
||||
* will want to set them up just in time. To do so, #GtkDragSource
|
||||
* has #GtkDragSource::prepare and #GtkDragSource::drag-begin signals.
|
||||
* The ::prepare signal is emitted before a drag is started, and
|
||||
* can be used to set the content provider and actions that the
|
||||
* drag should be started with. The ::drag-begin signal is emitted
|
||||
* after the #GdkDrag object has been created, and can be used
|
||||
* to set up the drag icon.
|
||||
*
|
||||
* During the DND operation, GtkDragSource emits signals that
|
||||
* can be used to obtain updates about the status of the operation,
|
||||
* but it is not normally necessary to connect to any signals,
|
||||
* except for one case: when the supported actions include
|
||||
* %GDK_DRAG_MOVE, you need to listen for the
|
||||
* #GtkDragSource::drag-end signal and delete the
|
||||
* data after it has been transferred.
|
||||
*/
|
||||
|
||||
typedef struct _GtkDragSourceSite GtkDragSourceSite;
|
||||
|
||||
struct _GtkDragSourceSite
|
||||
struct _GtkDragSource
|
||||
{
|
||||
GdkModifierType start_button_mask;
|
||||
GdkContentFormats *target_list; /* Targets for drag data */
|
||||
GdkDragAction actions; /* Possible actions */
|
||||
GtkGestureSingle parent_instance;
|
||||
|
||||
GtkImageDefinition *image_def;
|
||||
GtkGesture *drag_gesture;
|
||||
GdkContentProvider *content;
|
||||
GdkDragAction actions;
|
||||
|
||||
GdkPaintable *paintable;
|
||||
int hot_x;
|
||||
int hot_y;
|
||||
|
||||
gdouble start_x;
|
||||
gdouble start_y;
|
||||
|
||||
GdkDrag *drag;
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_drag_source_gesture_begin (GtkGesture *gesture,
|
||||
GdkEventSequence *sequence,
|
||||
gpointer data)
|
||||
|
||||
struct _GtkDragSourceClass
|
||||
{
|
||||
GtkDragSourceSite *site = data;
|
||||
guint button;
|
||||
GtkGestureSingleClass parent_class;
|
||||
|
||||
if (gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)))
|
||||
button = 1;
|
||||
else
|
||||
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
|
||||
GdkContentProvider *(* prepare) (GtkDragSource *source,
|
||||
double x,
|
||||
double y);
|
||||
};
|
||||
|
||||
g_assert (button >= 1);
|
||||
enum {
|
||||
PROP_CONTENT = 1,
|
||||
PROP_ACTIONS,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
if (!site->start_button_mask ||
|
||||
!(site->start_button_mask & (GDK_BUTTON1_MASK << (button - 1))))
|
||||
gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
|
||||
static GParamSpec *properties[NUM_PROPERTIES];
|
||||
|
||||
enum {
|
||||
PREPARE,
|
||||
DRAG_BEGIN,
|
||||
DRAG_END,
|
||||
DRAG_CANCEL,
|
||||
NUM_SIGNALS
|
||||
};
|
||||
|
||||
static guint signals[NUM_SIGNALS];
|
||||
|
||||
static void gtk_drag_source_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkDragSource *source);
|
||||
static void gtk_drag_source_cancel_cb (GdkDrag *drag,
|
||||
GdkDragCancelReason reason,
|
||||
GtkDragSource *source);
|
||||
|
||||
static GdkContentProvider *gtk_drag_source_prepare (GtkDragSource *source,
|
||||
double x,
|
||||
double y);
|
||||
|
||||
static void gtk_drag_source_drag_begin (GtkDragSource *source);
|
||||
|
||||
G_DEFINE_TYPE (GtkDragSource, gtk_drag_source, GTK_TYPE_GESTURE_SINGLE);
|
||||
|
||||
static void
|
||||
gtk_drag_source_init (GtkDragSource *source)
|
||||
{
|
||||
source->actions = GDK_ACTION_COPY;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_gesture_update (GtkGesture *gesture,
|
||||
GdkEventSequence *sequence,
|
||||
gpointer data)
|
||||
gtk_drag_source_finalize (GObject *object)
|
||||
{
|
||||
gdouble start_x, start_y, offset_x, offset_y;
|
||||
GtkDragSourceSite *site = data;
|
||||
GtkDragSource *source = GTK_DRAG_SOURCE (object);
|
||||
|
||||
g_clear_object (&source->content);
|
||||
g_clear_object (&source->paintable);
|
||||
|
||||
G_OBJECT_CLASS (gtk_drag_source_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkDragSource *source = GTK_DRAG_SOURCE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CONTENT:
|
||||
gtk_drag_source_set_content (source, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_ACTIONS:
|
||||
gtk_drag_source_set_actions (source, g_value_get_flags (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkDragSource *source = GTK_DRAG_SOURCE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CONTENT:
|
||||
g_value_set_object (value, gtk_drag_source_get_content (source));
|
||||
break;
|
||||
|
||||
case PROP_ACTIONS:
|
||||
g_value_set_flags (value, gtk_drag_source_get_actions (source));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_drag_source_filter_event (GtkEventController *controller,
|
||||
const GdkEvent *event)
|
||||
{
|
||||
/* Let touchpad swipe events go through, only if they match n-points */
|
||||
if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_SWIPE)
|
||||
{
|
||||
guint n_points;
|
||||
guint n_fingers;
|
||||
|
||||
g_object_get (G_OBJECT (controller), "n-points", &n_points, NULL);
|
||||
gdk_event_get_touchpad_gesture_n_fingers (event, &n_fingers);
|
||||
|
||||
if (n_fingers == n_points)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return GTK_EVENT_CONTROLLER_CLASS (gtk_drag_source_parent_class)->filter_event (controller, event);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_begin (GtkGesture *gesture,
|
||||
GdkEventSequence *sequence)
|
||||
{
|
||||
GtkDragSource *source = GTK_DRAG_SOURCE (gesture);
|
||||
GdkEventSequence *current;
|
||||
|
||||
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
|
||||
gtk_gesture_get_point (gesture, current, &source->start_x, &source->start_y);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_update (GtkGesture *gesture,
|
||||
GdkEventSequence *sequence)
|
||||
{
|
||||
GtkDragSource *source = GTK_DRAG_SOURCE (gesture);
|
||||
GtkWidget *widget;
|
||||
double x, y;
|
||||
|
||||
if (!gtk_gesture_is_recognized (gesture))
|
||||
return;
|
||||
|
||||
gtk_gesture_get_point (gesture, sequence, &x, &y);
|
||||
|
||||
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
if (gtk_gesture_is_recognized (site->drag_gesture))
|
||||
if (gtk_drag_check_threshold (widget, source->start_x, source->start_y, x, y))
|
||||
{
|
||||
gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (site->drag_gesture),
|
||||
&start_x, &start_y);
|
||||
gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (site->drag_gesture),
|
||||
&offset_x, &offset_y);
|
||||
|
||||
if (gtk_drag_check_threshold (widget, start_x, start_y,
|
||||
start_x + offset_x, start_y + offset_y))
|
||||
{
|
||||
GdkDevice *device = gtk_gesture_get_device (site->drag_gesture);
|
||||
|
||||
gtk_event_controller_reset (GTK_EVENT_CONTROLLER (site->drag_gesture));
|
||||
|
||||
gtk_drag_begin_internal (widget,
|
||||
device,
|
||||
site->image_def, site->target_list,
|
||||
site->actions,
|
||||
start_x, start_y);
|
||||
}
|
||||
gtk_drag_source_drag_begin (source);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_site_destroy (gpointer data)
|
||||
gtk_drag_source_class_init (GtkDragSourceClass *class)
|
||||
{
|
||||
GtkDragSourceSite *site = data;
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
|
||||
GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (class);
|
||||
|
||||
if (site->target_list)
|
||||
gdk_content_formats_unref (site->target_list);
|
||||
object_class->finalize = gtk_drag_source_finalize;
|
||||
object_class->set_property = gtk_drag_source_set_property;
|
||||
object_class->get_property = gtk_drag_source_get_property;
|
||||
|
||||
gtk_image_definition_unref (site->image_def);
|
||||
/* This gets called only during widget finalization.
|
||||
* And widget finalization takes care of gestures. */
|
||||
g_slice_free (GtkDragSourceSite, site);
|
||||
controller_class->filter_event = gtk_drag_source_filter_event;
|
||||
|
||||
gesture_class->begin = gtk_drag_source_begin;
|
||||
gesture_class->update = gtk_drag_source_update;
|
||||
gesture_class->end = NULL;
|
||||
|
||||
class->prepare = gtk_drag_source_prepare;
|
||||
|
||||
/**
|
||||
* GtkDragSource:content:
|
||||
*
|
||||
* The data that is offered by drag operations from this source,
|
||||
* in the form of a #GdkContentProvider.
|
||||
*/
|
||||
properties[PROP_CONTENT] =
|
||||
g_param_spec_object ("content",
|
||||
P_("Content"),
|
||||
P_("The content provider for the dragged data"),
|
||||
GDK_TYPE_CONTENT_PROVIDER,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkDragSource:actions:
|
||||
*
|
||||
* The actions that are supported by drag operations from the source.
|
||||
*
|
||||
* Note that you must handle the #GtkDragSource::drag-end signal
|
||||
* if the actions include %GDK_ACTION_MOVE.
|
||||
*/
|
||||
properties[PROP_ACTIONS] =
|
||||
g_param_spec_flags ("actions",
|
||||
P_("Actions"),
|
||||
P_("Supported actions"),
|
||||
GDK_TYPE_DRAG_ACTION, GDK_ACTION_COPY,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
|
||||
|
||||
/**
|
||||
* GtkDragSource::prepare:
|
||||
* @source: the #GtkDragSource
|
||||
* @x: the X coordinate of the drag starting point
|
||||
* @y: the Y coordinate fo the drag starting point
|
||||
*
|
||||
* The ::prepare signal is emitted when a drag is about to be initiated.
|
||||
* It returns the * #GdkContentProvider to use for the drag that is about
|
||||
* to start. The default handler for this signal returns the value of
|
||||
* the #GtkDragSource::content property, so if you set up that property
|
||||
* ahead of time, you don't need to connect to this signal.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a #GdkContentProvider, or %NULL
|
||||
*/
|
||||
signals[PREPARE] =
|
||||
g_signal_new (I_("prepare"),
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkDragSourceClass, prepare),
|
||||
g_signal_accumulator_first_wins, NULL,
|
||||
NULL,
|
||||
GDK_TYPE_CONTENT_PROVIDER, 2,
|
||||
G_TYPE_DOUBLE, G_TYPE_DOUBLE);
|
||||
|
||||
/**
|
||||
* GtkDragSource::drag-begin:
|
||||
* @source: the #GtkDragSource
|
||||
* @drag: the #GtkDrag object
|
||||
*
|
||||
* The ::drag-begin signal is emitted on the drag source when a drag
|
||||
* is started. It can be used to e.g. set a custom drag icon with
|
||||
* gtk_drag_source_set_icon().
|
||||
*/
|
||||
signals[DRAG_BEGIN] =
|
||||
g_signal_new (I_("drag-begin"),
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_DRAG);
|
||||
|
||||
/**
|
||||
* GtkDragSource::drag-end:
|
||||
* @source: the #GtkDragSource
|
||||
* @drag: the #GtkDrag object
|
||||
* @delete_data: %TRUE if the drag was performing %GDK_ACTION_MOVE,
|
||||
* and the data should be deleted
|
||||
*
|
||||
* The ::drag-end signal is emitted on the drag source when a drag is
|
||||
* finished. A typical reason to connect to this signal is to undo
|
||||
* things done in #GtkDragSource::prepare or #GtkDragSource::drag-begin.
|
||||
*/
|
||||
signals[DRAG_END] =
|
||||
g_signal_new (I_("drag-end"),
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 2,
|
||||
GDK_TYPE_DRAG,
|
||||
G_TYPE_BOOLEAN);
|
||||
|
||||
/**
|
||||
* GtkDragSource::drag-cancel:
|
||||
* @source: the #GtkDragSource
|
||||
* @drag: the #GtkDrag object
|
||||
* @reason: information on why the drag failed
|
||||
*
|
||||
* The ::drag-cancel signal is emitted on the drag source when a drag has
|
||||
* failed. The signal handler may handle a failed drag operation based on
|
||||
* the type of error. It should return %TRUE if the failure has been handled
|
||||
* and the default "drag operation failed" animation should not be shown.
|
||||
*
|
||||
* Returns: %TRUE if the failed drag operation has been already handled
|
||||
*/
|
||||
signals[DRAG_CANCEL] =
|
||||
g_signal_new (I_("drag-cancel"),
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__OBJECT_ENUM,
|
||||
G_TYPE_BOOLEAN, 2,
|
||||
GDK_TYPE_DRAG,
|
||||
GDK_TYPE_DRAG_CANCEL_REASON);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_set: (method)
|
||||
* @widget: a #GtkWidget
|
||||
* @start_button_mask: the bitmask of buttons that can start the drag
|
||||
* @targets: (allow-none): the targets that the drag will support,
|
||||
* may be %NULL
|
||||
* @actions: the bitmask of possible actions for a drag from this widget
|
||||
*
|
||||
* Sets up a widget so that GTK+ will start a drag operation when the user
|
||||
* clicks and drags on the widget. The widget must have a window.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_set (GtkWidget *widget,
|
||||
GdkModifierType start_button_mask,
|
||||
GdkContentFormats *targets,
|
||||
GdkDragAction actions)
|
||||
static GdkContentProvider *
|
||||
gtk_drag_source_prepare (GtkDragSource *source,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkDragSourceSite *site;
|
||||
if (source->actions == 0)
|
||||
return NULL;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
if (source->content == NULL)
|
||||
return NULL;
|
||||
|
||||
site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
|
||||
return g_object_ref (source->content);
|
||||
}
|
||||
|
||||
if (site)
|
||||
static void
|
||||
drag_end (GtkDragSource *source,
|
||||
gboolean success)
|
||||
{
|
||||
gboolean delete_data;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (source->drag, gtk_drag_source_dnd_finished_cb, source);
|
||||
g_signal_handlers_disconnect_by_func (source->drag, gtk_drag_source_cancel_cb, source);
|
||||
|
||||
delete_data = success && gdk_drag_get_selected_action (source->drag) == GDK_ACTION_MOVE;
|
||||
|
||||
g_signal_emit (source, signals[DRAG_END], 0, source->drag, delete_data);
|
||||
|
||||
gdk_drag_drop_done (source->drag, success);
|
||||
g_clear_object (&source->drag);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkDragSource *source)
|
||||
{
|
||||
drag_end (source, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_cancel_cb (GdkDrag *drag,
|
||||
GdkDragCancelReason reason,
|
||||
GtkDragSource *source)
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
|
||||
g_signal_emit (source, signals[DRAG_CANCEL], 0, source->drag, reason, &success);
|
||||
drag_end (source, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_drag_source_drag_begin (GtkDragSource *source)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GdkDevice *device;
|
||||
int x, y;
|
||||
GtkNative *native;
|
||||
GdkSurface *surface;
|
||||
double px, py;
|
||||
int dx, dy;
|
||||
GdkContentProvider *content = NULL;
|
||||
|
||||
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
device = gtk_gesture_get_device (GTK_GESTURE (source));
|
||||
|
||||
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
device = gdk_device_get_associated_device (device);
|
||||
|
||||
native = gtk_widget_get_native (widget);
|
||||
surface = gtk_native_get_surface (native);
|
||||
|
||||
gtk_widget_translate_coordinates (widget, GTK_WIDGET (native), source->start_x, source->start_y, &x, &y);
|
||||
gdk_surface_get_device_position (surface, device, &px, &py, NULL);
|
||||
|
||||
dx = round (px) - x;
|
||||
dy = round (py) - y;
|
||||
|
||||
g_signal_emit (source, signals[PREPARE], 0, source->start_x, source->start_y, &content);
|
||||
if (!content)
|
||||
return;
|
||||
|
||||
source->drag = gdk_drag_begin (surface, device, content, source->actions, dx, dy);
|
||||
|
||||
g_object_unref (content);
|
||||
|
||||
if (source->drag == NULL)
|
||||
return;
|
||||
|
||||
gtk_widget_reset_controllers (widget);
|
||||
|
||||
g_signal_emit (source, signals[DRAG_BEGIN], 0, source->drag);
|
||||
|
||||
if (!source->paintable)
|
||||
{
|
||||
if (site->target_list)
|
||||
gdk_content_formats_unref (site->target_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
site = g_slice_new0 (GtkDragSourceSite);
|
||||
site->image_def = gtk_image_definition_new_empty ();
|
||||
site->drag_gesture = gtk_gesture_drag_new ();
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (site->drag_gesture),
|
||||
GTK_PHASE_CAPTURE);
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (site->drag_gesture), 0);
|
||||
g_signal_connect (site->drag_gesture, "begin",
|
||||
G_CALLBACK (gtk_drag_source_gesture_begin),
|
||||
site);
|
||||
g_signal_connect (site->drag_gesture, "update",
|
||||
G_CALLBACK (gtk_drag_source_gesture_update),
|
||||
site);
|
||||
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (site->drag_gesture));
|
||||
|
||||
g_object_set_data_full (G_OBJECT (widget),
|
||||
I_("gtk-site-data"),
|
||||
site, gtk_drag_source_site_destroy);
|
||||
GtkIconTheme *theme;
|
||||
|
||||
theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (widget));
|
||||
source->paintable = gtk_icon_theme_load_icon (theme, "text-x-generic", 32, 0, NULL);
|
||||
source->hot_x = 0;
|
||||
source->hot_y = 0;
|
||||
}
|
||||
|
||||
site->start_button_mask = start_button_mask;
|
||||
gtk_drag_icon_set_from_paintable (source->drag, source->paintable, source->hot_x, source->hot_y);
|
||||
|
||||
if (targets)
|
||||
site->target_list = gdk_content_formats_ref (targets);
|
||||
else
|
||||
site->target_list = NULL;
|
||||
|
||||
site->actions = actions;
|
||||
g_signal_connect (source->drag, "dnd-finished",
|
||||
G_CALLBACK (gtk_drag_source_dnd_finished_cb), source);
|
||||
g_signal_connect (source->drag, "cancel",
|
||||
G_CALLBACK (gtk_drag_source_cancel_cb), source);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_unset: (method)
|
||||
* @widget: a #GtkWidget
|
||||
* gtk_drag_source_new:
|
||||
*
|
||||
* Undoes the effects of gtk_drag_source_set().
|
||||
* Creates a new #GtkDragSource object.
|
||||
*
|
||||
* Returns: the new #GtkDragSource
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_unset (GtkWidget *widget)
|
||||
GtkDragSource *
|
||||
gtk_drag_source_new (void)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
|
||||
g_object_set_data (G_OBJECT (widget), I_("gtk-site-data"), NULL);
|
||||
return g_object_new (GTK_TYPE_DRAG_SOURCE, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_get_target_list: (method)
|
||||
* @widget: a #GtkWidget
|
||||
* gtk_drag_source_get_content:
|
||||
* @source: a #GtkDragSource
|
||||
*
|
||||
* Gets the list of targets this widget can provide for
|
||||
* drag-and-drop.
|
||||
* Gets the current content provider of a #GtkDragSource.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the #GdkContentFormats, or %NULL if none
|
||||
* Returns: the #GtkContentProvider of @source
|
||||
*/
|
||||
GdkContentFormats *
|
||||
gtk_drag_source_get_target_list (GtkWidget *widget)
|
||||
GdkContentProvider *
|
||||
gtk_drag_source_get_content (GtkDragSource *source)
|
||||
{
|
||||
GtkDragSourceSite *site;
|
||||
g_return_val_if_fail (GTK_IS_DRAG_SOURCE (source), NULL);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
|
||||
|
||||
site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
|
||||
|
||||
return site ? site->target_list : NULL;
|
||||
return source->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_set_target_list: (method)
|
||||
* @widget: a #GtkWidget that’s a drag source
|
||||
* @target_list: (allow-none): list of draggable targets, or %NULL for none
|
||||
* gtk_drag_source_set_content:
|
||||
* @source: a #GtkDragSource
|
||||
* @content: (nullable): a #GtkContentProvider, or %NULL
|
||||
*
|
||||
* Changes the target types that this widget offers for drag-and-drop.
|
||||
* The widget must first be made into a drag source with
|
||||
* gtk_drag_source_set().
|
||||
* Sets a content provider on a #GtkDragSource.
|
||||
*
|
||||
* When the data is requested in the cause of a
|
||||
* DND operation, it will be obtained from the
|
||||
* content provider.
|
||||
*
|
||||
* This function can be called before a drag is started,
|
||||
* or in a handler for the #GtkDragSource::prepare signal.
|
||||
*
|
||||
* You may consider setting the content provider back to
|
||||
* %NULL in a #GTkDragSource::drag-end signal handler.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_set_target_list (GtkWidget *widget,
|
||||
GdkContentFormats *target_list)
|
||||
gtk_drag_source_set_content (GtkDragSource *source,
|
||||
GdkContentProvider *content)
|
||||
{
|
||||
GtkDragSourceSite *site;
|
||||
g_return_if_fail (GTK_IS_DRAG_SOURCE (source));
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
if (!g_set_object (&source->content, content))
|
||||
return;
|
||||
|
||||
site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
|
||||
if (site == NULL)
|
||||
g_object_notify_by_pspec (G_OBJECT (source), properties[PROP_CONTENT]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_get_actions:
|
||||
* @source: a #GtkDragSource
|
||||
*
|
||||
* Gets the actions that are currently set on the #GtkDragSource.
|
||||
*
|
||||
* Returns: the actions set on @source
|
||||
*/
|
||||
GdkDragAction
|
||||
gtk_drag_source_get_actions (GtkDragSource *source)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_DRAG_SOURCE (source), 0);
|
||||
|
||||
return source->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_set_actions:
|
||||
* @source: a #GtkDragSource
|
||||
* @actions: the actions to offer
|
||||
*
|
||||
* Sets the actions on the #GtkDragSource.
|
||||
*
|
||||
* During a DND operation, the actions are offered
|
||||
* to potential drop targets. If @actions include
|
||||
* %GDK_ACTION_MOVE, you need to listen to the
|
||||
* #GtkDraGSource::drag-end signal and handle
|
||||
* @delete_data being %TRUE.
|
||||
*
|
||||
* This function can be called before a drag is started,
|
||||
* or in a handler for the #GtkDragSource::prepare signal.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_set_actions (GtkDragSource *source,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_DRAG_SOURCE (source));
|
||||
|
||||
if (source->actions == actions)
|
||||
return;
|
||||
|
||||
source->actions = actions;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (source), properties[PROP_ACTIONS]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_set_icon:
|
||||
* @source: a #GtkDragSource
|
||||
* @paintable: (nullable): the #GtkPaintable to use as icon, or %NULL
|
||||
* @hot_x: the hotspot X coordinate on the icon
|
||||
* @hot_y: the hotspot Y coordinate on the icon
|
||||
*
|
||||
* Sets a paintable to use as icon during DND operations.
|
||||
*
|
||||
* The hotspot coordinates determine the point on the icon
|
||||
* that gets aligned with the hotspot of the cursor.
|
||||
*
|
||||
* If @paintable is %NULL, a default icon is used.
|
||||
*
|
||||
* This function can be called before a drag is started, or in
|
||||
* a #GtkDragSource::prepare or #GtkDragSource::drag-begin signal handler.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_set_icon (GtkDragSource *source,
|
||||
GdkPaintable *paintable,
|
||||
int hot_x,
|
||||
int hot_y)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_DRAG_SOURCE (source));
|
||||
|
||||
g_set_object (&source->paintable, paintable);
|
||||
|
||||
source->hot_x = hot_x;
|
||||
source->hot_y = hot_y;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_get_drag:
|
||||
* @source: a #GtkDragSource
|
||||
*
|
||||
* Returns the underlying #GtkDrag object for an ongoing drag.
|
||||
*
|
||||
* Returns: (nullable): the #GdkDrag of the current drag operation, or %NULL
|
||||
*/
|
||||
GdkDrag *
|
||||
gtk_drag_source_get_drag (GtkDragSource *source)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_DRAG_SOURCE (source), NULL);
|
||||
|
||||
return source->drag;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_drag_cancel:
|
||||
* @source: a #GtkDragSource
|
||||
*
|
||||
* Cancels a currently ongoing drag operation.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_drag_cancel (GtkDragSource *source)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_DRAG_SOURCE (source));
|
||||
|
||||
if (source->drag)
|
||||
{
|
||||
g_warning ("gtk_drag_source_set_target_list() requires the widget "
|
||||
"to already be a drag source.");
|
||||
return;
|
||||
gboolean success = FALSE;
|
||||
|
||||
g_signal_emit (source, signals[DRAG_CANCEL], 0, source->drag, GDK_DRAG_CANCEL_ERROR, &success);
|
||||
drag_end (source, FALSE);
|
||||
}
|
||||
|
||||
if (target_list)
|
||||
gdk_content_formats_ref (target_list);
|
||||
|
||||
if (site->target_list)
|
||||
gdk_content_formats_unref (site->target_list);
|
||||
|
||||
site->target_list = target_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_add_text_targets: (method)
|
||||
* @widget: a #GtkWidget that’s is a drag source
|
||||
*
|
||||
* Add the text targets supported by #GtkSelectionData to
|
||||
* the target list of the drag source. The targets
|
||||
* are added with @info = 0. If you need another value,
|
||||
* use gtk_content_formats_add_text_targets() and
|
||||
* gtk_drag_source_set_target_list().
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_add_text_targets (GtkWidget *widget)
|
||||
{
|
||||
GdkContentFormats *target_list;
|
||||
|
||||
target_list = gtk_drag_source_get_target_list (widget);
|
||||
if (target_list)
|
||||
gdk_content_formats_ref (target_list);
|
||||
else
|
||||
target_list = gdk_content_formats_new (NULL, 0);
|
||||
target_list = gtk_content_formats_add_text_targets (target_list);
|
||||
gtk_drag_source_set_target_list (widget, target_list);
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_add_image_targets: (method)
|
||||
* @widget: a #GtkWidget that’s is a drag source
|
||||
*
|
||||
* Add the writable image targets supported by #GtkSelectionData to
|
||||
* the target list of the drag source. The targets
|
||||
* are added with @info = 0. If you need another value,
|
||||
* use gtk_target_list_add_image_targets() and
|
||||
* gtk_drag_source_set_target_list().
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_add_image_targets (GtkWidget *widget)
|
||||
{
|
||||
GdkContentFormats *target_list;
|
||||
|
||||
target_list = gtk_drag_source_get_target_list (widget);
|
||||
if (target_list)
|
||||
gdk_content_formats_ref (target_list);
|
||||
else
|
||||
target_list = gdk_content_formats_new (NULL, 0);
|
||||
target_list = gtk_content_formats_add_image_targets (target_list, TRUE);
|
||||
gtk_drag_source_set_target_list (widget, target_list);
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_add_uri_targets: (method)
|
||||
* @widget: a #GtkWidget that’s is a drag source
|
||||
*
|
||||
* Add the URI targets supported by #GtkSelectionData to
|
||||
* the target list of the drag source. The targets
|
||||
* are added with @info = 0. If you need another value,
|
||||
* use gtk_content_formats_add_uri_targets() and
|
||||
* gtk_drag_source_set_target_list().
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_add_uri_targets (GtkWidget *widget)
|
||||
{
|
||||
GdkContentFormats *target_list;
|
||||
|
||||
target_list = gtk_drag_source_get_target_list (widget);
|
||||
if (target_list)
|
||||
gdk_content_formats_ref (target_list);
|
||||
else
|
||||
target_list = gdk_content_formats_new (NULL, 0);
|
||||
target_list = gtk_content_formats_add_uri_targets (target_list);
|
||||
gtk_drag_source_set_target_list (widget, target_list);
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_set_icon_name: (method)
|
||||
* gtk_drag_check_threshold: (method)
|
||||
* @widget: a #GtkWidget
|
||||
* @icon_name: name of icon to use
|
||||
*
|
||||
* Sets the icon that will be used for drags from a particular source
|
||||
* to a themed icon. See the docs for #GtkIconTheme for more details.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_set_icon_name (GtkWidget *widget,
|
||||
const gchar *icon_name)
|
||||
{
|
||||
GtkDragSourceSite *site;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (icon_name != NULL);
|
||||
|
||||
site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
|
||||
g_return_if_fail (site != NULL);
|
||||
|
||||
gtk_image_definition_unref (site->image_def);
|
||||
site->image_def = gtk_image_definition_new_icon_name (icon_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_set_icon_gicon: (method)
|
||||
* @widget: a #GtkWidget
|
||||
* @icon: A #GIcon
|
||||
* @start_x: X coordinate of start of drag
|
||||
* @start_y: Y coordinate of start of drag
|
||||
* @current_x: current X coordinate
|
||||
* @current_y: current Y coordinate
|
||||
*
|
||||
* Sets the icon that will be used for drags from a particular source
|
||||
* to @icon. See the docs for #GtkIconTheme for more details.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_set_icon_gicon (GtkWidget *widget,
|
||||
GIcon *icon)
|
||||
{
|
||||
GtkDragSourceSite *site;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (icon != NULL);
|
||||
|
||||
site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
|
||||
g_return_if_fail (site != NULL);
|
||||
|
||||
gtk_image_definition_unref (site->image_def);
|
||||
site->image_def = gtk_image_definition_new_gicon (icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_source_set_icon_paintable: (method)
|
||||
* @widget: a #GtkWidget
|
||||
* @paintable: A #GdkPaintable
|
||||
* Checks to see if a mouse drag starting at (@start_x, @start_y) and ending
|
||||
* at (@current_x, @current_y) has passed the GTK drag threshold, and thus
|
||||
* should trigger the beginning of a drag-and-drop operation.
|
||||
*
|
||||
* Sets the icon that will be used for drags from a particular source
|
||||
* to @paintable.
|
||||
* Returns: %TRUE if the drag threshold has been passed.
|
||||
*/
|
||||
void
|
||||
gtk_drag_source_set_icon_paintable (GtkWidget *widget,
|
||||
GdkPaintable *paintable)
|
||||
gboolean
|
||||
gtk_drag_check_threshold (GtkWidget *widget,
|
||||
int start_x,
|
||||
int start_y,
|
||||
int current_x,
|
||||
int current_y)
|
||||
{
|
||||
GtkDragSourceSite *site;
|
||||
gint drag_threshold;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (GDK_IS_PAINTABLE (paintable));
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
|
||||
site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
|
||||
g_return_if_fail (site != NULL);
|
||||
drag_threshold = gtk_settings_get_dnd_drag_threshold (gtk_widget_get_settings (widget));
|
||||
|
||||
gtk_image_definition_unref (site->image_def);
|
||||
site->image_def = gtk_image_definition_new_paintable (paintable);
|
||||
return (ABS (current_x - start_x) > drag_threshold ||
|
||||
ABS (current_y - start_y) > drag_threshold);
|
||||
}
|
||||
|
||||
|
@ -37,36 +37,51 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_set (GtkWidget *widget,
|
||||
GdkModifierType start_button_mask,
|
||||
GdkContentFormats *targets,
|
||||
GdkDragAction actions);
|
||||
#define GTK_TYPE_DRAG_SOURCE (gtk_drag_source_get_type ())
|
||||
#define GTK_DRAG_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DRAG_SOURCE, GtkDragSource))
|
||||
#define GTK_DRAG_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DRAG_SOURCE, GtkDragSourceClass))
|
||||
#define GTK_IS_DRAG_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DRAG_SOURCE))
|
||||
#define GTK_IS_DRAG_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DRAG_SOURCE))
|
||||
#define GTK_DRAG_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DRAG_SOURCE, GtkDragSourceClass))
|
||||
|
||||
typedef struct _GtkDragSource GtkDragSource;
|
||||
typedef struct _GtkDragSourceClass GtkDragSourceClass;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_unset (GtkWidget *widget);
|
||||
GType gtk_drag_source_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentFormats * gtk_drag_source_get_target_list (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_set_target_list (GtkWidget *widget,
|
||||
GdkContentFormats *target_list);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_add_text_targets (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_add_image_targets (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_add_uri_targets (GtkWidget *widget);
|
||||
GtkDragSource *gtk_drag_source_new (void);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_set_icon_name (GtkWidget *widget,
|
||||
const gchar *icon_name);
|
||||
void gtk_drag_source_set_content (GtkDragSource *source,
|
||||
GdkContentProvider *content);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_set_icon_gicon (GtkWidget *widget,
|
||||
GIcon *icon);
|
||||
GdkContentProvider *gtk_drag_source_get_content (GtkDragSource *source);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_set_icon_paintable (GtkWidget *widget,
|
||||
GdkPaintable *paintable);
|
||||
void gtk_drag_source_set_actions (GtkDragSource *source,
|
||||
GdkDragAction actions);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkDragAction gtk_drag_source_get_actions (GtkDragSource *source);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_set_icon (GtkDragSource *source,
|
||||
GdkPaintable *paintable,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_drag_source_drag_cancel (GtkDragSource *sourcei);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkDrag * gtk_drag_source_get_drag (GtkDragSource *source);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_drag_check_threshold (GtkWidget *widget,
|
||||
int start_x,
|
||||
int start_y,
|
||||
int current_x,
|
||||
int current_y);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -38,8 +38,6 @@
|
||||
#include "gtkcelllayout.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdndprivate.h"
|
||||
#include "gtkeditable.h"
|
||||
#include "gtkemojichooser.h"
|
||||
#include "gtkemojicompletion.h"
|
||||
@ -70,6 +68,9 @@
|
||||
#include "gtkwindow.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkwidgetpaintable.h"
|
||||
|
||||
#include "a11y/gtkentryaccessible.h"
|
||||
|
||||
@ -172,7 +173,7 @@ struct _EntryIconInfo
|
||||
guint in_drag : 1;
|
||||
|
||||
GdkDragAction actions;
|
||||
GdkContentFormats *target_list;
|
||||
GdkContentProvider *content;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -1320,8 +1321,7 @@ gtk_entry_finalize (GObject *object)
|
||||
if (icon_info == NULL)
|
||||
continue;
|
||||
|
||||
if (icon_info->target_list != NULL)
|
||||
gdk_content_formats_unref (icon_info->target_list);
|
||||
g_clear_object (&icon_info->content);
|
||||
|
||||
gtk_widget_unparent (icon_info->widget);
|
||||
|
||||
@ -1462,17 +1462,25 @@ icon_drag_update_cb (GtkGestureDrag *gesture,
|
||||
pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
|
||||
icon_info = priv->icons[pos];
|
||||
|
||||
if (icon_info->target_list != NULL &&
|
||||
gtk_drag_check_threshold (icon_info->widget,
|
||||
start_x, start_y,
|
||||
x, y))
|
||||
if (icon_info->content != NULL &&
|
||||
gtk_drag_check_threshold (icon_info->widget, start_x, start_y, x, y))
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
GdkDrag *drag;
|
||||
|
||||
icon_info->in_drag = TRUE;
|
||||
gtk_drag_begin (GTK_WIDGET (entry),
|
||||
gtk_gesture_get_device (GTK_GESTURE (gesture)),
|
||||
icon_info->target_list,
|
||||
icon_info->actions,
|
||||
start_x, start_y);
|
||||
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (entry)));
|
||||
device = gtk_gesture_get_device (GTK_GESTURE (gesture));
|
||||
|
||||
drag = gdk_drag_begin (surface, device, icon_info->content, icon_info->actions, start_x, start_y);
|
||||
paintable = gtk_widget_paintable_new (icon_info->widget);
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
|
||||
g_object_unref (paintable);
|
||||
|
||||
g_object_unref (drag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2742,7 +2750,7 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry,
|
||||
void
|
||||
gtk_entry_set_icon_drag_source (GtkEntry *entry,
|
||||
GtkEntryIconPosition icon_pos,
|
||||
GdkContentFormats *formats,
|
||||
GdkContentProvider *provider,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
|
||||
@ -2754,12 +2762,7 @@ gtk_entry_set_icon_drag_source (GtkEntry *entry,
|
||||
if ((icon_info = priv->icons[icon_pos]) == NULL)
|
||||
icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
|
||||
|
||||
if (icon_info->target_list)
|
||||
gdk_content_formats_unref (icon_info->target_list);
|
||||
icon_info->target_list = formats;
|
||||
if (icon_info->target_list)
|
||||
gdk_content_formats_ref (icon_info->target_list);
|
||||
|
||||
g_set_object (&icon_info->content, provider);
|
||||
icon_info->actions = actions;
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,7 @@ gchar * gtk_entry_get_icon_tooltip_markup (GtkEntry *
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_set_icon_drag_source (GtkEntry *entry,
|
||||
GtkEntryIconPosition icon_pos,
|
||||
GdkContentFormats *formats,
|
||||
GdkContentProvider *content,
|
||||
GdkDragAction actions);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gint gtk_entry_get_current_icon_drag_source (GtkEntry *entry);
|
||||
|
@ -693,31 +693,6 @@ typedef enum
|
||||
GTK_TREE_VIEW_GRID_LINES_BOTH
|
||||
} GtkTreeViewGridLines;
|
||||
|
||||
/**
|
||||
* GtkDragResult:
|
||||
* @GTK_DRAG_RESULT_SUCCESS: The drag operation was successful.
|
||||
* @GTK_DRAG_RESULT_NO_TARGET: No suitable drag target.
|
||||
* @GTK_DRAG_RESULT_USER_CANCELLED: The user cancelled the drag operation.
|
||||
* @GTK_DRAG_RESULT_TIMEOUT_EXPIRED: The drag operation timed out.
|
||||
* @GTK_DRAG_RESULT_GRAB_BROKEN: The pointer or keyboard grab used
|
||||
* for the drag operation was broken.
|
||||
* @GTK_DRAG_RESULT_ERROR: The drag operation failed due to some
|
||||
* unspecified error.
|
||||
*
|
||||
* Gives an indication why a drag operation failed.
|
||||
* The value can by obtained by connecting to the
|
||||
* #GtkWidget::drag-failed signal.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GTK_DRAG_RESULT_SUCCESS,
|
||||
GTK_DRAG_RESULT_NO_TARGET,
|
||||
GTK_DRAG_RESULT_USER_CANCELLED,
|
||||
GTK_DRAG_RESULT_TIMEOUT_EXPIRED,
|
||||
GTK_DRAG_RESULT_GRAB_BROKEN,
|
||||
GTK_DRAG_RESULT_ERROR
|
||||
} GtkDragResult;
|
||||
|
||||
/**
|
||||
* GtkSizeGroupMode:
|
||||
* @GTK_SIZE_GROUP_NONE: group has no effect
|
||||
|
@ -115,7 +115,6 @@
|
||||
#include "gtkbox.h"
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkcontainerprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkiconprivate.h"
|
||||
#include "gtkgestureclick.h"
|
||||
@ -193,12 +192,12 @@ static void gtk_expander_size_allocate (GtkWidget *widget,
|
||||
int baseline);
|
||||
static gboolean gtk_expander_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static gboolean gtk_expander_drag_motion (GtkWidget *widget,
|
||||
static gboolean gtk_expander_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gtk_expander_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
GtkExpander *expander);
|
||||
static void gtk_expander_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkExpander *expander);
|
||||
|
||||
static void gtk_expander_add (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
@ -268,8 +267,6 @@ gtk_expander_class_init (GtkExpanderClass *klass)
|
||||
widget_class->destroy = gtk_expander_destroy;
|
||||
widget_class->size_allocate = gtk_expander_size_allocate;
|
||||
widget_class->focus = gtk_expander_focus;
|
||||
widget_class->drag_motion = gtk_expander_drag_motion;
|
||||
widget_class->drag_leave = gtk_expander_drag_leave;
|
||||
widget_class->measure = gtk_expander_measure;
|
||||
|
||||
container_class->add = gtk_expander_add;
|
||||
@ -350,6 +347,8 @@ gtk_expander_init (GtkExpander *expander)
|
||||
{
|
||||
GtkExpanderPrivate *priv = gtk_expander_get_instance_private (expander);
|
||||
GtkGesture *gesture;
|
||||
GtkDropTarget *dest;
|
||||
GdkContentFormats *formats;
|
||||
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (expander), TRUE);
|
||||
|
||||
@ -375,8 +374,12 @@ gtk_expander_init (GtkExpander *expander)
|
||||
GTK_STYLE_CLASS_HORIZONTAL);
|
||||
gtk_container_add (GTK_CONTAINER (priv->title_widget), priv->arrow_widget);
|
||||
|
||||
gtk_drag_dest_set (GTK_WIDGET (expander), 0, NULL, 0);
|
||||
gtk_drag_dest_set_track_motion (GTK_WIDGET (expander), TRUE);
|
||||
formats = gdk_content_formats_new (NULL, 0);
|
||||
dest = gtk_drop_target_new (formats, 0);
|
||||
gdk_content_formats_unref (formats);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (gtk_expander_drag_accept), expander);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_expander_drag_leave), expander);
|
||||
gtk_widget_add_controller (GTK_WIDGET (expander), GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture),
|
||||
@ -544,12 +547,10 @@ expand_timeout (gpointer data)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_expander_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
gtk_expander_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkExpander *expander)
|
||||
{
|
||||
GtkExpander *expander = GTK_EXPANDER (widget);
|
||||
GtkExpanderPrivate *priv = gtk_expander_get_instance_private (expander);
|
||||
|
||||
if (!priv->expanded && !priv->expand_timer)
|
||||
@ -562,10 +563,10 @@ gtk_expander_drag_motion (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_expander_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
gtk_expander_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkExpander *expander)
|
||||
{
|
||||
GtkExpander *expander = GTK_EXPANDER (widget);
|
||||
GtkExpanderPrivate *priv = gtk_expander_get_instance_private (expander);
|
||||
|
||||
if (priv->expand_timer)
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include "gtkcellrendererpixbuf.h"
|
||||
#include "gtkcombobox.h"
|
||||
#include "gtkcssiconthemevalueprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkicontheme.h"
|
||||
#include "gtkimage.h"
|
||||
@ -61,6 +60,7 @@
|
||||
#include "gtksettings.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
#include "gtkbitmaskprivate.h"
|
||||
#include "gtkeventcontroller.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkfilechooserbutton
|
||||
@ -267,9 +267,11 @@ static void gtk_file_chooser_button_finalize (GObject *ob
|
||||
|
||||
/* GtkWidget Functions */
|
||||
static void gtk_file_chooser_button_destroy (GtkWidget *widget);
|
||||
static void gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *data);
|
||||
static gboolean gtk_file_chooser_button_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkWidget *widget);
|
||||
static void gtk_file_chooser_button_show (GtkWidget *widget);
|
||||
static void gtk_file_chooser_button_hide (GtkWidget *widget);
|
||||
static void gtk_file_chooser_button_root (GtkWidget *widget);
|
||||
@ -366,7 +368,6 @@ gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
|
||||
gobject_class->finalize = gtk_file_chooser_button_finalize;
|
||||
|
||||
widget_class->destroy = gtk_file_chooser_button_destroy;
|
||||
widget_class->drag_data_received = gtk_file_chooser_button_drag_data_received;
|
||||
widget_class->show = gtk_file_chooser_button_show;
|
||||
widget_class->hide = gtk_file_chooser_button_hide;
|
||||
widget_class->map = gtk_file_chooser_button_map;
|
||||
@ -443,7 +444,9 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
|
||||
GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
|
||||
GtkWidget *box;
|
||||
GtkWidget *icon;
|
||||
GdkContentFormatsBuilder *builder;
|
||||
GdkContentFormats *target_list;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
priv->button = gtk_button_new ();
|
||||
g_signal_connect (priv->button, "clicked", G_CALLBACK (button_clicked_cb), button);
|
||||
@ -495,13 +498,13 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
|
||||
NULL, NULL);
|
||||
|
||||
/* DnD */
|
||||
target_list = gdk_content_formats_new (NULL, 0);
|
||||
target_list = gtk_content_formats_add_uri_targets (target_list);
|
||||
target_list = gtk_content_formats_add_text_targets (target_list);
|
||||
gtk_drag_dest_set (GTK_WIDGET (button),
|
||||
(GTK_DEST_DEFAULT_ALL),
|
||||
target_list,
|
||||
GDK_ACTION_COPY);
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_gtype (builder, G_TYPE_STRING);
|
||||
gdk_content_formats_builder_add_gtype (builder, GDK_TYPE_FILE_LIST);
|
||||
target_list = gdk_content_formats_builder_free_to_formats (builder);
|
||||
dest = gtk_drop_target_new (target_list, GDK_ACTION_COPY);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_file_chooser_button_drag_drop), button);
|
||||
gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
|
||||
@ -1146,62 +1149,91 @@ dnd_select_folder_get_info_cb (GCancellable *cancellable,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *data)
|
||||
dnd_select_file (GtkFileChooserButton *button,
|
||||
GFile *file)
|
||||
{
|
||||
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (widget);
|
||||
GtkFileChooserButtonPrivate *priv = gtk_file_chooser_button_get_instance_private (button);
|
||||
GFile *file;
|
||||
gchar *text;
|
||||
struct DndSelectFolderData *info;
|
||||
|
||||
if (GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->drag_data_received != NULL)
|
||||
GTK_WIDGET_CLASS (gtk_file_chooser_button_parent_class)->drag_data_received (widget,
|
||||
drop,
|
||||
data);
|
||||
info = g_new0 (struct DndSelectFolderData, 1);
|
||||
info->button = g_object_ref (button);
|
||||
info->i = 0;
|
||||
info->uris = g_new0 (char *, 2);
|
||||
info->selected = FALSE;
|
||||
info->file_system = priv->fs;
|
||||
g_object_get (priv->chooser, "action", &info->action, NULL);
|
||||
|
||||
if (widget == NULL || gtk_selection_data_get_length (data) < 0)
|
||||
return;
|
||||
info->file = g_object_ref (file);
|
||||
|
||||
if (gtk_selection_data_targets_include_uri (data))
|
||||
if (priv->dnd_select_folder_cancellable)
|
||||
g_cancellable_cancel (priv->dnd_select_folder_cancellable);
|
||||
|
||||
priv->dnd_select_folder_cancellable =
|
||||
_gtk_file_system_get_info (priv->fs, info->file,
|
||||
"standard::type",
|
||||
dnd_select_folder_get_info_cb, info);
|
||||
}
|
||||
|
||||
static void
|
||||
got_file (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (data);
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
const GValue *value;
|
||||
|
||||
value = gdk_drop_read_value_finish (drop, result, NULL);
|
||||
if (value)
|
||||
{
|
||||
gchar **uris;
|
||||
struct DndSelectFolderData *info;
|
||||
GFile *file;
|
||||
|
||||
uris = gtk_selection_data_get_uris (data);
|
||||
|
||||
if (uris != NULL)
|
||||
{
|
||||
info = g_new0 (struct DndSelectFolderData, 1);
|
||||
info->button = g_object_ref (button);
|
||||
info->i = 0;
|
||||
info->uris = uris;
|
||||
info->selected = FALSE;
|
||||
info->file_system = priv->fs;
|
||||
g_object_get (priv->chooser, "action", &info->action, NULL);
|
||||
|
||||
info->file = g_file_new_for_uri (info->uris[info->i]);
|
||||
|
||||
if (priv->dnd_select_folder_cancellable)
|
||||
g_cancellable_cancel (priv->dnd_select_folder_cancellable);
|
||||
|
||||
priv->dnd_select_folder_cancellable =
|
||||
_gtk_file_system_get_info (priv->fs, info->file,
|
||||
"standard::type",
|
||||
dnd_select_folder_get_info_cb, info);
|
||||
}
|
||||
file = g_value_get_object (value);
|
||||
dnd_select_file (button, file);
|
||||
}
|
||||
else if (gtk_selection_data_targets_include_text (data))
|
||||
}
|
||||
|
||||
static void
|
||||
got_text (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (data);
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
char *str;
|
||||
|
||||
str = gdk_drop_read_text_finish (drop, result, NULL);
|
||||
if (str)
|
||||
{
|
||||
text = (char*) gtk_selection_data_get_text (data);
|
||||
file = g_file_new_for_uri (text);
|
||||
gtk_file_chooser_select_file (GTK_FILE_CHOOSER (priv->chooser), file, NULL);
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_uri (str);
|
||||
dnd_select_file (button, file);
|
||||
g_object_unref (file);
|
||||
g_free (text);
|
||||
g_signal_emit (button, file_chooser_button_signals[FILE_SET], 0);
|
||||
}
|
||||
|
||||
gdk_drop_finish (drop, GDK_ACTION_COPY);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_file_chooser_button_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkWidget *button)
|
||||
{
|
||||
if (gdk_drop_has_value (drop, G_TYPE_FILE))
|
||||
{
|
||||
gdk_drop_read_value_async (drop, G_TYPE_FILE, G_PRIORITY_DEFAULT, NULL, got_file, button);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_drop_read_text_async (drop, NULL, got_text, button);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1982,25 +1982,26 @@ out:
|
||||
}
|
||||
|
||||
static void
|
||||
file_list_drag_data_received_cb (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer user_data)
|
||||
file_list_drag_data_received_cb (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (user_data);
|
||||
GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
|
||||
GtkDropTarget *dest = GTK_DROP_TARGET (source);
|
||||
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
GdkDrop *drop = gtk_drop_target_get_drop (dest);
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
gchar **uris;
|
||||
char *uri;
|
||||
GFile *file;
|
||||
GtkSelectionData *selection_data;
|
||||
|
||||
selection_data = gtk_drop_target_read_selection_finish (dest, result, NULL);
|
||||
|
||||
/* Allow only drags from other widgets; see bug #533891. */
|
||||
if (gdk_drop_get_drag (drop) &&
|
||||
gtk_drag_get_source_widget (gdk_drop_get_drag (drop)) == widget)
|
||||
{
|
||||
g_signal_stop_emission_by_name (widget, "drag-data-received");
|
||||
return;
|
||||
}
|
||||
|
||||
if (drag && gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (drag)) == widget)
|
||||
return;
|
||||
|
||||
/* Parse the text/uri-list string, navigate to the first one */
|
||||
uris = gtk_selection_data_get_uris (selection_data);
|
||||
@ -2025,60 +2026,34 @@ file_list_drag_data_received_cb (GtkWidget *widget,
|
||||
file_list_drag_data_received_get_info_cb,
|
||||
data);
|
||||
}
|
||||
|
||||
g_signal_stop_emission_by_name (widget, "drag-data-received");
|
||||
}
|
||||
|
||||
/* Don't do anything with the drag_drop signal */
|
||||
static gboolean
|
||||
file_list_drag_drop_cb (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y,
|
||||
file_list_drag_drop_cb (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkFileChooserWidget *impl)
|
||||
{
|
||||
g_signal_stop_emission_by_name (widget, "drag-drop");
|
||||
const char *target = g_intern_static_string ("text/uri-list");
|
||||
|
||||
gtk_drop_target_read_selection (dest, target, NULL, file_list_drag_data_received_cb, impl);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
file_list_drag_begin_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkFileChooserWidget *impl)
|
||||
{
|
||||
GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
|
||||
|
||||
gtk_places_sidebar_set_drop_targets_visible (GTK_PLACES_SIDEBAR (priv->places_sidebar),
|
||||
TRUE,
|
||||
drag);
|
||||
}
|
||||
|
||||
/* Disable the normal tree drag motion handler, it makes it look like you're
|
||||
dropping the dragged item onto a tree item */
|
||||
static gboolean
|
||||
file_list_drag_motion_cb (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y,
|
||||
file_list_drag_accept_cb (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkFileChooserWidget *impl)
|
||||
{
|
||||
g_signal_stop_emission_by_name (widget, "drag-motion");
|
||||
g_signal_stop_emission_by_name (dest, "accept");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
file_list_drag_end_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (user_data);
|
||||
GtkFileChooserWidgetPrivate *priv = gtk_file_chooser_widget_get_instance_private (impl);
|
||||
|
||||
gtk_places_sidebar_set_drop_targets_visible (GTK_PLACES_SIDEBAR (priv->places_sidebar),
|
||||
FALSE,
|
||||
drag);
|
||||
}
|
||||
|
||||
/* Sensitizes the "Copy file’s location" and other context menu items if there is actually
|
||||
* a selection active.
|
||||
*/
|
||||
@ -8468,14 +8443,9 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, box);
|
||||
|
||||
/* And a *lot* of callbacks to bind ... */
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_list_drag_drop_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_list_drag_data_received_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, list_popup_menu_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_list_query_tooltip_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, list_row_activated);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_list_drag_begin_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_list_drag_motion_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_list_drag_end_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, list_selection_changed);
|
||||
gtk_widget_class_bind_template_callback (widget_class, list_cursor_changed);
|
||||
gtk_widget_class_bind_template_callback (widget_class, browse_files_tree_view_keynav_failed_cb);
|
||||
@ -8510,23 +8480,25 @@ post_process_ui (GtkFileChooserWidget *impl)
|
||||
GtkCellRenderer *cell;
|
||||
GList *cells;
|
||||
GFile *file;
|
||||
GtkDropTarget *dest;
|
||||
GdkContentFormats *formats;
|
||||
|
||||
/* Setup file list treeview */
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view));
|
||||
gtk_tree_selection_set_select_function (selection,
|
||||
list_select_func,
|
||||
impl, NULL);
|
||||
formats = gdk_content_formats_new_for_gtype (GDK_TYPE_FILE_LIST);
|
||||
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (priv->browse_files_tree_view),
|
||||
GDK_BUTTON1_MASK,
|
||||
NULL,
|
||||
formats,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
gtk_drag_source_add_uri_targets (priv->browse_files_tree_view);
|
||||
|
||||
gtk_drag_dest_set (priv->browse_files_tree_view,
|
||||
GTK_DEST_DEFAULT_ALL,
|
||||
NULL,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
gtk_drag_dest_add_uri_targets (priv->browse_files_tree_view);
|
||||
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (file_list_drag_accept_cb), impl);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (file_list_drag_drop_cb), impl);
|
||||
gtk_widget_add_controller (priv->browse_files_tree_view, GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (formats);
|
||||
|
||||
/* File browser treemodel columns are shared between GtkFileChooser implementations,
|
||||
* so we don't set cell renderer attributes in GtkBuilder, but rather keep that
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "gtkgesturelongpressprivate.h"
|
||||
#include "gtkgestureprivate.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmarshalers.h"
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "gtkcellrenderertext.h"
|
||||
#include "gtkcombobox.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkentry.h"
|
||||
@ -48,6 +47,11 @@
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkwindow.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkselectionprivate.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
#include "a11y/gtkiconviewaccessibleprivate.h"
|
||||
|
||||
@ -279,30 +283,28 @@ static void update_text_cell (GtkIco
|
||||
static void update_pixbuf_cell (GtkIconView *icon_view);
|
||||
|
||||
/* Source side drag signals */
|
||||
static void gtk_icon_view_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_icon_view_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_icon_view_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data);
|
||||
static void gtk_icon_view_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_icon_view_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkWidget *widget);
|
||||
static GBytes * gtk_icon_view_drag_data_get (const char *mime_type,
|
||||
gpointer data);
|
||||
|
||||
/* Target side drag signals */
|
||||
static void gtk_icon_view_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
static gboolean gtk_icon_view_drag_motion (GtkWidget *widget,
|
||||
static void gtk_icon_view_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static gboolean gtk_icon_view_drag_drop (GtkWidget *widget,
|
||||
GtkIconView *icon_view);
|
||||
static void gtk_icon_view_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gtk_icon_view_drag_data_received (GtkWidget *widget,
|
||||
int x,
|
||||
int y,
|
||||
GtkIconView *icon_view);
|
||||
static gboolean gtk_icon_view_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data);
|
||||
int x,
|
||||
int y,
|
||||
GtkIconView *icon_view);
|
||||
static void gtk_icon_view_drag_data_received (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data);
|
||||
static gboolean gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
|
||||
double x,
|
||||
double y,
|
||||
@ -360,14 +362,6 @@ gtk_icon_view_class_init (GtkIconViewClass *klass)
|
||||
widget_class->measure = gtk_icon_view_measure;
|
||||
widget_class->size_allocate = gtk_icon_view_size_allocate;
|
||||
widget_class->snapshot = gtk_icon_view_snapshot;
|
||||
widget_class->drag_begin = gtk_icon_view_drag_begin;
|
||||
widget_class->drag_end = gtk_icon_view_drag_end;
|
||||
widget_class->drag_data_get = gtk_icon_view_drag_data_get;
|
||||
widget_class->drag_data_delete = gtk_icon_view_drag_data_delete;
|
||||
widget_class->drag_leave = gtk_icon_view_drag_leave;
|
||||
widget_class->drag_motion = gtk_icon_view_drag_motion;
|
||||
widget_class->drag_drop = gtk_icon_view_drag_drop;
|
||||
widget_class->drag_data_received = gtk_icon_view_drag_data_received;
|
||||
|
||||
container_class->remove = gtk_icon_view_remove;
|
||||
container_class->forall = gtk_icon_view_forall;
|
||||
@ -1033,6 +1027,8 @@ gtk_icon_view_dispose (GObject *object)
|
||||
|
||||
g_clear_object (&priv->key_controller);
|
||||
|
||||
g_clear_pointer (&priv->source_formats, gdk_content_formats_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_icon_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@ -1761,9 +1757,14 @@ gtk_icon_view_snapshot (GtkWidget *widget,
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_snapshot_render_focus (snapshot, context,
|
||||
gtk_style_context_save_to_node (context, icon_view->priv->dndnode);
|
||||
gtk_style_context_set_state (context, gtk_style_context_get_state (context) | GTK_STATE_FLAG_DROP_ACTIVE);
|
||||
|
||||
gtk_snapshot_render_frame (snapshot, context,
|
||||
rect.x, rect.y,
|
||||
rect.width, rect.height);
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
|
||||
if (icon_view->priv->doing_rubberband)
|
||||
@ -5712,35 +5713,6 @@ unset_reorderable (GtkIconView *icon_view)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_source_row (GdkDrag *drag,
|
||||
GtkTreeModel *model,
|
||||
GtkTreePath *source_row)
|
||||
{
|
||||
if (source_row)
|
||||
g_object_set_data_full (G_OBJECT (drag),
|
||||
I_("gtk-icon-view-source-row"),
|
||||
gtk_tree_row_reference_new (model, source_row),
|
||||
(GDestroyNotify) gtk_tree_row_reference_free);
|
||||
else
|
||||
g_object_set_data_full (G_OBJECT (drag),
|
||||
I_("gtk-icon-view-source-row"),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
static GtkTreePath*
|
||||
get_source_row (GdkDrag *drag)
|
||||
{
|
||||
GtkTreeRowReference *ref;
|
||||
|
||||
ref = g_object_get_data (G_OBJECT (drag), "gtk-icon-view-source-row");
|
||||
|
||||
if (ref)
|
||||
return gtk_tree_row_reference_get_path (ref);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkTreeRowReference *dest_row;
|
||||
@ -5886,7 +5858,7 @@ drag_scroll_timeout (gpointer data)
|
||||
|
||||
static gboolean
|
||||
set_destination (GtkIconView *icon_view,
|
||||
GdkDrop *drop,
|
||||
GtkDropTarget *dest,
|
||||
gint x,
|
||||
gint y,
|
||||
GdkDragAction *suggested_action,
|
||||
@ -5919,8 +5891,7 @@ set_destination (GtkIconView *icon_view,
|
||||
return FALSE; /* no longer a drop site */
|
||||
}
|
||||
|
||||
*target = gtk_drag_dest_find_target (widget, drop,
|
||||
gtk_drag_dest_get_target_list (widget));
|
||||
*target = gtk_drop_target_find_mimetype (dest);
|
||||
if (*target == NULL)
|
||||
return FALSE;
|
||||
|
||||
@ -6030,11 +6001,14 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
|
||||
double y,
|
||||
GdkDevice *device)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (icon_view);
|
||||
GdkDrag *drag;
|
||||
GtkTreePath *path = NULL;
|
||||
GtkTreeModel *model;
|
||||
gboolean retval = FALSE;
|
||||
GdkContentProvider *content;
|
||||
GdkPaintable *icon;
|
||||
GtkIconViewItem *item;
|
||||
GdkSurface *surface;
|
||||
GdkDrag *drag;
|
||||
|
||||
if (!icon_view->priv->source_set)
|
||||
goto out;
|
||||
@ -6055,16 +6029,19 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
|
||||
|
||||
icon_view->priv->pressed_button = -1;
|
||||
|
||||
path = gtk_icon_view_get_path_at_pos (icon_view,
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y);
|
||||
item = _gtk_icon_view_get_item_at_coords (icon_view,
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y,
|
||||
TRUE,
|
||||
NULL);
|
||||
|
||||
if (path == NULL)
|
||||
if (item == NULL)
|
||||
goto out;
|
||||
|
||||
path = gtk_tree_path_new_from_indices (item->index, -1);
|
||||
|
||||
if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
|
||||
!gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
|
||||
path))
|
||||
!gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model), path))
|
||||
goto out;
|
||||
|
||||
/* FIXME Check whether we're a start button, if not return FALSE and
|
||||
@ -6075,14 +6052,35 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
drag = gtk_drag_begin (widget,
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (icon_view)));
|
||||
|
||||
content = gdk_content_provider_new_with_formats (icon_view->priv->source_formats,
|
||||
gtk_icon_view_drag_data_get,
|
||||
icon_view);
|
||||
|
||||
drag = gdk_drag_begin (surface,
|
||||
device,
|
||||
gtk_drag_source_get_target_list (widget),
|
||||
icon_view->priv->source_actions,
|
||||
content,
|
||||
icon_view->priv->source_actions,
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y);
|
||||
|
||||
set_source_row (drag, model, path);
|
||||
g_object_unref (content);
|
||||
|
||||
g_signal_connect (drag, "dnd-finished", G_CALLBACK (gtk_icon_view_dnd_finished_cb), icon_view);
|
||||
|
||||
icon_view->priv->source_item = gtk_tree_row_reference_new (model, path);
|
||||
|
||||
x = icon_view->priv->press_start_x - item->cell_area.x + icon_view->priv->item_padding;
|
||||
y = icon_view->priv->press_start_y - item->cell_area.y + icon_view->priv->item_padding;
|
||||
|
||||
icon = gtk_icon_view_create_drag_icon (icon_view, path);
|
||||
gtk_drag_icon_set_from_paintable (drag, icon, x, y);
|
||||
g_object_unref (icon);
|
||||
|
||||
icon_view->priv->drag = drag;
|
||||
|
||||
g_object_unref (drag);
|
||||
|
||||
out:
|
||||
if (path)
|
||||
@ -6092,71 +6090,28 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
|
||||
}
|
||||
|
||||
/* Source side drag signals */
|
||||
static void
|
||||
gtk_icon_view_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
static GBytes *
|
||||
gtk_icon_view_drag_data_get (const char *mime_type,
|
||||
gpointer data)
|
||||
{
|
||||
GtkIconView *icon_view;
|
||||
GtkIconViewItem *item;
|
||||
GdkPaintable *icon;
|
||||
gint x, y;
|
||||
GtkTreePath *path;
|
||||
|
||||
icon_view = GTK_ICON_VIEW (widget);
|
||||
|
||||
/* if the user uses a custom DnD impl, we don't set the icon here */
|
||||
if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
|
||||
return;
|
||||
|
||||
item = _gtk_icon_view_get_item_at_coords (icon_view,
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y,
|
||||
TRUE,
|
||||
NULL);
|
||||
|
||||
g_return_if_fail (item != NULL);
|
||||
|
||||
x = icon_view->priv->press_start_x - item->cell_area.x + icon_view->priv->item_padding;
|
||||
y = icon_view->priv->press_start_y - item->cell_area.y + icon_view->priv->item_padding;
|
||||
|
||||
path = gtk_tree_path_new_from_indices (item->index, -1);
|
||||
icon = gtk_icon_view_create_drag_icon (icon_view, path);
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
gtk_drag_set_icon_paintable (drag, icon, x, y);
|
||||
|
||||
g_object_unref (icon);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_icon_view_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_icon_view_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
GtkIconView *icon_view;
|
||||
GtkIconView *icon_view = data;
|
||||
GtkTreeModel *model;
|
||||
GtkTreePath *source_row;
|
||||
GtkSelectionData sdata = { 0, };
|
||||
|
||||
sdata.target = g_intern_string (mime_type);
|
||||
|
||||
icon_view = GTK_ICON_VIEW (widget);
|
||||
model = gtk_icon_view_get_model (icon_view);
|
||||
|
||||
if (model == NULL)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
if (!icon_view->priv->source_set)
|
||||
return;
|
||||
|
||||
source_row = get_source_row (drag);
|
||||
return NULL;
|
||||
|
||||
source_row = gtk_tree_row_reference_get_path (icon_view->priv->source_item);
|
||||
if (source_row == NULL)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
/* We can implement the GTK_TREE_MODEL_ROW target generically for
|
||||
* any model; for DragSource models there are some other formats
|
||||
@ -6164,29 +6119,31 @@ gtk_icon_view_drag_data_get (GtkWidget *widget,
|
||||
*/
|
||||
|
||||
if (GTK_IS_TREE_DRAG_SOURCE (model) &&
|
||||
gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
|
||||
source_row,
|
||||
selection_data))
|
||||
gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model), source_row, &sdata))
|
||||
goto done;
|
||||
|
||||
/* If drag_data_get does nothing, try providing row data. */
|
||||
if (gtk_selection_data_get_target (selection_data) == g_intern_static_string ("GTK_TREE_MODEL_ROW"))
|
||||
gtk_tree_set_row_drag_data (selection_data,
|
||||
model,
|
||||
source_row);
|
||||
if (gtk_selection_data_get_target (&sdata) == g_intern_static_string ("GTK_TREE_MODEL_ROW"))
|
||||
gtk_tree_set_row_drag_data (&sdata, model, source_row);
|
||||
|
||||
done:
|
||||
gtk_tree_path_free (source_row);
|
||||
|
||||
return g_bytes_new_take ((gpointer)gtk_selection_data_get_data (&sdata),
|
||||
gtk_selection_data_get_length (&sdata));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_icon_view_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
gtk_icon_view_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkIconView *icon_view;
|
||||
GtkTreePath *source_row;
|
||||
|
||||
if (gdk_drag_get_selected_action (drag) != GDK_ACTION_MOVE)
|
||||
return;
|
||||
|
||||
icon_view = GTK_ICON_VIEW (widget);
|
||||
model = gtk_icon_view_get_model (icon_view);
|
||||
|
||||
@ -6196,28 +6153,24 @@ gtk_icon_view_drag_data_delete (GtkWidget *widget,
|
||||
if (!icon_view->priv->source_set)
|
||||
return;
|
||||
|
||||
source_row = get_source_row (drag);
|
||||
|
||||
source_row = gtk_tree_row_reference_get_path (icon_view->priv->source_item);
|
||||
if (source_row == NULL)
|
||||
return;
|
||||
|
||||
gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
|
||||
source_row);
|
||||
gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model), source_row);
|
||||
|
||||
gtk_tree_path_free (source_row);
|
||||
|
||||
set_source_row (drag, NULL, NULL);
|
||||
g_clear_pointer (&icon_view->priv->source_item, gtk_tree_row_reference_free);
|
||||
icon_view->priv->drag = NULL;
|
||||
}
|
||||
|
||||
/* Target side drag signals */
|
||||
static void
|
||||
gtk_icon_view_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
gtk_icon_view_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkIconView *icon_view)
|
||||
{
|
||||
GtkIconView *icon_view;
|
||||
|
||||
icon_view = GTK_ICON_VIEW (widget);
|
||||
|
||||
/* unset any highlight row */
|
||||
gtk_icon_view_set_drag_dest_item (icon_view,
|
||||
NULL,
|
||||
@ -6226,26 +6179,24 @@ gtk_icon_view_drag_leave (GtkWidget *widget,
|
||||
remove_scroll_timeout (icon_view);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_icon_view_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
static void
|
||||
gtk_icon_view_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkIconView *icon_view)
|
||||
{
|
||||
GtkTreePath *path = NULL;
|
||||
GtkIconViewDropPosition pos;
|
||||
GtkIconView *icon_view;
|
||||
GdkDragAction suggested_action = 0;
|
||||
GdkAtom target;
|
||||
gboolean empty;
|
||||
|
||||
icon_view = GTK_ICON_VIEW (widget);
|
||||
|
||||
if (!set_destination (icon_view, drop, x, y, &suggested_action, &target))
|
||||
return FALSE;
|
||||
|
||||
icon_view->priv->event_last_x = x;
|
||||
icon_view->priv->event_last_y = y;
|
||||
if (!set_destination (icon_view, dest, x, y, &suggested_action, &target))
|
||||
{
|
||||
gdk_drop_status (drop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
|
||||
|
||||
@ -6271,7 +6222,7 @@ gtk_icon_view_drag_motion (GtkWidget *widget,
|
||||
* determining whether to accept the drop
|
||||
*/
|
||||
set_status_pending (drop, suggested_action);
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
gtk_drop_target_read_selection (dest, target, NULL, gtk_icon_view_drag_data_received, icon_view);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -6282,27 +6233,24 @@ gtk_icon_view_drag_motion (GtkWidget *widget,
|
||||
|
||||
if (path)
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_icon_view_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
gtk_icon_view_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkIconView *icon_view)
|
||||
{
|
||||
GtkIconView *icon_view;
|
||||
GtkTreePath *path;
|
||||
GdkDragAction suggested_action = 0;
|
||||
GdkAtom target = NULL;
|
||||
GtkTreeModel *model;
|
||||
gboolean drop_append_mode;
|
||||
|
||||
icon_view = GTK_ICON_VIEW (widget);
|
||||
model = gtk_icon_view_get_model (icon_view);
|
||||
|
||||
remove_scroll_timeout (GTK_ICON_VIEW (widget));
|
||||
remove_scroll_timeout (icon_view);
|
||||
|
||||
if (!icon_view->priv->dest_set)
|
||||
return FALSE;
|
||||
@ -6310,7 +6258,7 @@ gtk_icon_view_drag_drop (GtkWidget *widget,
|
||||
if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-drop"))
|
||||
return FALSE;
|
||||
|
||||
if (!set_destination (icon_view, drop, x, y, &suggested_action, &target))
|
||||
if (!set_destination (icon_view, dest, x, y, &suggested_action, &target))
|
||||
return FALSE;
|
||||
|
||||
path = get_logical_destination (icon_view, &drop_append_mode);
|
||||
@ -6333,7 +6281,7 @@ gtk_icon_view_drag_drop (GtkWidget *widget,
|
||||
|
||||
if (target != NULL)
|
||||
{
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
gtk_drop_target_read_selection (dest, target, NULL, gtk_icon_view_drag_data_received, icon_view);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -6341,16 +6289,16 @@ gtk_icon_view_drag_drop (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static GdkDragAction
|
||||
gtk_icon_view_get_action (GtkWidget *treeview,
|
||||
gtk_icon_view_get_action (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
GtkIconView *iconview = GTK_ICON_VIEW (widget);
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
GtkWidget *source_widget = gtk_drag_get_source_widget (drag);
|
||||
GdkDragAction actions;
|
||||
|
||||
actions = gdk_drop_get_actions (drop);
|
||||
|
||||
if (source_widget == treeview &&
|
||||
if (drag == iconview->priv->drag &&
|
||||
actions & GDK_ACTION_MOVE)
|
||||
return GDK_ACTION_MOVE;
|
||||
|
||||
@ -6367,25 +6315,31 @@ gtk_icon_view_get_action (GtkWidget *treeview,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_icon_view_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
gtk_icon_view_drag_data_received (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkDropTarget *dest = GTK_DROP_TARGET (source);
|
||||
GtkIconView *icon_view = data;
|
||||
GdkDrop *drop = gtk_drop_target_get_drop (dest);
|
||||
GtkTreePath *path;
|
||||
GtkTreeModel *model;
|
||||
GtkIconView *icon_view;
|
||||
GtkTreePath *dest_row;
|
||||
GdkDragAction suggested_action;
|
||||
gboolean drop_append_mode;
|
||||
|
||||
icon_view = GTK_ICON_VIEW (widget);
|
||||
GtkSelectionData *selection_data;
|
||||
|
||||
selection_data = gtk_drop_target_read_selection_finish (dest, result, NULL);
|
||||
if (!selection_data)
|
||||
return;
|
||||
|
||||
model = gtk_icon_view_get_model (icon_view);
|
||||
|
||||
if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag-data-received"))
|
||||
return;
|
||||
goto out;
|
||||
|
||||
if (!icon_view->priv->dest_set)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
suggested_action = get_status_pending (drop);
|
||||
|
||||
@ -6419,18 +6373,18 @@ gtk_icon_view_drag_data_received (GtkWidget *widget,
|
||||
gtk_icon_view_set_drag_dest_item (icon_view,
|
||||
NULL,
|
||||
GTK_ICON_VIEW_DROP_LEFT);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
dest_row = get_dest_row (drop);
|
||||
|
||||
if (dest_row == NULL)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
if (gtk_selection_data_get_length (selection_data) >= 0)
|
||||
{
|
||||
suggested_action = gtk_icon_view_get_action (widget, drop);
|
||||
suggested_action = gtk_icon_view_get_action (GTK_WIDGET (icon_view), drop);
|
||||
|
||||
if (suggested_action &&
|
||||
!gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
|
||||
@ -6445,9 +6399,13 @@ gtk_icon_view_drag_data_received (GtkWidget *widget,
|
||||
|
||||
/* drop dest_row */
|
||||
set_dest_row (drop, NULL, NULL, FALSE, FALSE);
|
||||
|
||||
out:
|
||||
gtk_selection_data_free (selection_data);
|
||||
}
|
||||
|
||||
/* Drag-and-Drop support */
|
||||
|
||||
/**
|
||||
* gtk_icon_view_enable_model_drag_source:
|
||||
* @icon_view: a #GtkIconView
|
||||
@ -6467,9 +6425,7 @@ gtk_icon_view_enable_model_drag_source (GtkIconView *icon_view,
|
||||
{
|
||||
g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
|
||||
|
||||
gtk_drag_source_set (GTK_WIDGET (icon_view), 0, formats, actions);
|
||||
|
||||
icon_view->priv->start_button_mask = start_button_mask;
|
||||
icon_view->priv->source_formats = gdk_content_formats_ref (formats);
|
||||
icon_view->priv->source_actions = actions;
|
||||
|
||||
icon_view->priv->source_set = TRUE;
|
||||
@ -6486,21 +6442,37 @@ gtk_icon_view_enable_model_drag_source (GtkIconView *icon_view,
|
||||
*
|
||||
* Turns @icon_view into a drop destination for automatic DND. Calling this
|
||||
* method sets #GtkIconView:reorderable to %FALSE.
|
||||
*
|
||||
* Returns: (transfer none): the drop target that was attached
|
||||
**/
|
||||
void
|
||||
GtkDropTarget *
|
||||
gtk_icon_view_enable_model_drag_dest (GtkIconView *icon_view,
|
||||
GdkContentFormats *formats,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
|
||||
g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
|
||||
GtkCssNode *widget_node;
|
||||
|
||||
gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, formats, actions);
|
||||
icon_view->priv->dest = gtk_drop_target_new (formats, actions);
|
||||
g_signal_connect (icon_view->priv->dest, "drag-leave", G_CALLBACK (gtk_icon_view_drag_leave), icon_view);
|
||||
g_signal_connect (icon_view->priv->dest, "drag-motion", G_CALLBACK (gtk_icon_view_drag_motion), icon_view);
|
||||
g_signal_connect (icon_view->priv->dest, "drag-drop", G_CALLBACK (gtk_icon_view_drag_drop), icon_view);
|
||||
gtk_widget_add_controller (GTK_WIDGET (icon_view), GTK_EVENT_CONTROLLER (icon_view->priv->dest));
|
||||
|
||||
icon_view->priv->dest_actions = actions;
|
||||
|
||||
icon_view->priv->dest_set = TRUE;
|
||||
|
||||
unset_reorderable (icon_view);
|
||||
|
||||
widget_node = gtk_widget_get_css_node (GTK_WIDGET (icon_view));
|
||||
icon_view->priv->dndnode = gtk_css_node_new ();
|
||||
gtk_css_node_set_name (icon_view->priv->dndnode, I_("dndtarget"));
|
||||
gtk_css_node_set_parent (icon_view->priv->dndnode, widget_node);
|
||||
gtk_css_node_set_state (icon_view->priv->dndnode, gtk_css_node_get_state (widget_node));
|
||||
g_object_unref (icon_view->priv->dndnode);
|
||||
|
||||
return icon_view->priv->dest;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6517,7 +6489,7 @@ gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
|
||||
|
||||
if (icon_view->priv->source_set)
|
||||
{
|
||||
gtk_drag_source_unset (GTK_WIDGET (icon_view));
|
||||
g_clear_pointer (&icon_view->priv->source_formats, gdk_content_formats_unref);
|
||||
icon_view->priv->source_set = FALSE;
|
||||
}
|
||||
|
||||
@ -6538,8 +6510,12 @@ gtk_icon_view_unset_model_drag_dest (GtkIconView *icon_view)
|
||||
|
||||
if (icon_view->priv->dest_set)
|
||||
{
|
||||
gtk_drag_dest_unset (GTK_WIDGET (icon_view));
|
||||
gtk_widget_remove_controller (GTK_WIDGET (icon_view), GTK_EVENT_CONTROLLER (icon_view->priv->dest));
|
||||
icon_view->priv->dest = NULL;
|
||||
icon_view->priv->dest_set = FALSE;
|
||||
|
||||
gtk_css_node_set_parent (icon_view->priv->dndnode, NULL);
|
||||
icon_view->priv->dndnode = NULL;
|
||||
}
|
||||
|
||||
unset_reorderable (icon_view);
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include <gtk/gtkcellarea.h>
|
||||
#include <gtk/gtkselection.h>
|
||||
#include <gtk/gtktooltip.h>
|
||||
#include <gtk/gtkdragsource.h>
|
||||
#include <gtk/gtkdragdest.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -218,7 +220,7 @@ void gtk_icon_view_enable_model_drag_source (GtkIconView
|
||||
GdkContentFormats *formats,
|
||||
GdkDragAction actions);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_icon_view_enable_model_drag_dest (GtkIconView *icon_view,
|
||||
GtkDropTarget * gtk_icon_view_enable_model_drag_dest (GtkIconView *icon_view,
|
||||
GdkContentFormats *formats,
|
||||
GdkDragAction actions);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "gtk/gtkcssnodeprivate.h"
|
||||
#include "gtk/gtkgestureclick.h"
|
||||
#include "gtk/gtkeventcontrollermotion.h"
|
||||
#include "gtk/gtkdragsource.h"
|
||||
|
||||
#ifndef __GTK_ICON_VIEW_PRIVATE_H__
|
||||
#define __GTK_ICON_VIEW_PRIVATE_H__
|
||||
@ -132,9 +133,16 @@ struct _GtkIconViewPrivate
|
||||
gint press_start_x;
|
||||
gint press_start_y;
|
||||
|
||||
GdkContentFormats *source_formats;
|
||||
GtkDropTarget *dest;
|
||||
GtkCssNode *dndnode;
|
||||
|
||||
GdkDrag *drag;
|
||||
|
||||
GdkDragAction source_actions;
|
||||
GdkDragAction dest_actions;
|
||||
|
||||
GtkTreeRowReference *source_item;
|
||||
GtkTreeRowReference *dest_item;
|
||||
GtkIconViewDropPosition dest_pos;
|
||||
|
||||
|
104
gtk/gtklabel.c
104
gtk/gtklabel.c
@ -32,7 +32,6 @@
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkcssshadowsvalueprivate.h"
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgestureclick.h"
|
||||
@ -54,6 +53,8 @@
|
||||
#include "gtkwindow.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragicon.h"
|
||||
|
||||
#include "a11y/gtklabelaccessibleprivate.h"
|
||||
|
||||
@ -501,9 +502,6 @@ static gboolean gtk_label_mnemonic_activate (GtkWidget *widget,
|
||||
static void gtk_label_setup_mnemonic (GtkLabel *label,
|
||||
GtkWidget *toplevel,
|
||||
guint last_key);
|
||||
static void gtk_label_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data);
|
||||
|
||||
static void gtk_label_buildable_interface_init (GtkBuildableIface *iface);
|
||||
static gboolean gtk_label_buildable_custom_tag_start (GtkBuildable *buildable,
|
||||
@ -652,7 +650,6 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
widget_class->unroot = gtk_label_unroot;
|
||||
widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
|
||||
widget_class->popup_menu = gtk_label_popup_menu;
|
||||
widget_class->drag_data_get = gtk_label_drag_data_get;
|
||||
widget_class->grab_focus = gtk_label_grab_focus;
|
||||
widget_class->focus = gtk_label_focus;
|
||||
widget_class->get_request_mode = gtk_label_get_request_mode;
|
||||
@ -4597,16 +4594,10 @@ connect_mnemonics_visible_notify (GtkLabel *label)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
static GdkPaintable *
|
||||
get_selection_paintable (GtkLabel *label)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
GdkPaintable *paintable = NULL;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
|
||||
|
||||
if ((priv->select_info->selection_anchor !=
|
||||
priv->select_info->selection_end) &&
|
||||
@ -4628,20 +4619,10 @@ drag_begin_cb (GtkWidget *widget,
|
||||
if (start > len)
|
||||
start = len;
|
||||
|
||||
paintable = gtk_text_util_create_drag_icon (widget,
|
||||
priv->text + start,
|
||||
end - start);
|
||||
return gtk_text_util_create_drag_icon (GTK_WIDGET (label), priv->text + start, end - start);
|
||||
}
|
||||
|
||||
if (paintable)
|
||||
{
|
||||
gtk_drag_set_icon_paintable (drag, paintable, 0, 0);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_drag_set_icon_default (drag);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4734,27 +4715,27 @@ gtk_label_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
|
||||
if (info->in_drag)
|
||||
{
|
||||
if (gtk_drag_check_threshold (widget,
|
||||
info->drag_start_x,
|
||||
info->drag_start_y,
|
||||
x, y))
|
||||
if (gtk_drag_check_threshold (widget, info->drag_start_x, info->drag_start_y, x, y))
|
||||
{
|
||||
GdkContentFormats *target_list = gdk_content_formats_new (NULL, 0);
|
||||
GdkDrag *drag;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
|
||||
target_list = gtk_content_formats_add_text_targets (target_list);
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (widget));
|
||||
device = gtk_gesture_get_device (GTK_GESTURE (gesture));
|
||||
|
||||
g_signal_connect (widget, "drag-begin",
|
||||
G_CALLBACK (drag_begin_cb), NULL);
|
||||
gtk_drag_begin (widget,
|
||||
gtk_gesture_get_device (GTK_GESTURE (gesture)),
|
||||
target_list,
|
||||
GDK_ACTION_COPY,
|
||||
info->drag_start_x,
|
||||
info->drag_start_y);
|
||||
drag = gdk_drag_begin (surface,
|
||||
device,
|
||||
info->provider,
|
||||
GDK_ACTION_COPY,
|
||||
info->drag_start_x,
|
||||
info->drag_start_y);
|
||||
|
||||
gtk_drag_icon_set_from_paintable (drag, get_selection_paintable (label), 0, 0);
|
||||
|
||||
g_object_unref (drag);
|
||||
|
||||
info->in_drag = FALSE;
|
||||
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -5140,47 +5121,6 @@ gtk_label_get_selectable (GtkLabel *label)
|
||||
return priv->select_info && priv->select_info->selectable;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_set_selection_text (GtkLabel *label,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
|
||||
if (priv->select_info &&
|
||||
(priv->select_info->selection_anchor !=
|
||||
priv->select_info->selection_end) &&
|
||||
priv->text)
|
||||
{
|
||||
gint start, end;
|
||||
gint len;
|
||||
|
||||
start = MIN (priv->select_info->selection_anchor,
|
||||
priv->select_info->selection_end);
|
||||
end = MAX (priv->select_info->selection_anchor,
|
||||
priv->select_info->selection_end);
|
||||
|
||||
len = strlen (priv->text);
|
||||
|
||||
if (end > len)
|
||||
end = len;
|
||||
|
||||
if (start > len)
|
||||
start = len;
|
||||
|
||||
gtk_selection_data_set_text (selection_data,
|
||||
priv->text + start,
|
||||
end - start);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
gtk_label_set_selection_text (GTK_LABEL (widget), selection_data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_select_region_index (GtkLabel *label,
|
||||
gint anchor_index,
|
||||
|
@ -124,10 +124,6 @@ static void gtk_link_button_set_property (GObject *object,
|
||||
GParamSpec *pspec);
|
||||
static void gtk_link_button_clicked (GtkButton *button);
|
||||
static gboolean gtk_link_button_popup_menu (GtkWidget *widget);
|
||||
static void gtk_link_button_drag_data_get_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection,
|
||||
gpointer user_data);
|
||||
static gboolean gtk_link_button_query_tooltip_cb (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
@ -251,31 +247,97 @@ gtk_link_button_get_menu_model (void)
|
||||
return G_MENU_MODEL (menu);
|
||||
}
|
||||
|
||||
#define GTK_TYPE_LINK_CONTENT (gtk_link_content_get_type ())
|
||||
#define GTK_LINK_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_LINK_CONTENT, GtkLinkContent))
|
||||
|
||||
typedef struct _GtkLinkContent GtkLinkContent;
|
||||
typedef struct _GtkLinkContentClass GtkLinkContentClass;
|
||||
|
||||
struct _GtkLinkContent
|
||||
{
|
||||
GdkContentProvider parent;
|
||||
GtkLinkButton *link;
|
||||
};
|
||||
|
||||
struct _GtkLinkContentClass
|
||||
{
|
||||
GdkContentProviderClass parent_class;
|
||||
};
|
||||
|
||||
GType gtk_link_content_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_TYPE (GtkLinkContent, gtk_link_content, GDK_TYPE_CONTENT_PROVIDER)
|
||||
|
||||
static GdkContentFormats *
|
||||
gtk_link_content_ref_formats (GdkContentProvider *provider)
|
||||
{
|
||||
GtkLinkContent *content = GTK_LINK_CONTENT (provider);
|
||||
|
||||
if (content->link)
|
||||
return gdk_content_formats_union (gdk_content_formats_new_for_gtype (G_TYPE_STRING),
|
||||
gdk_content_formats_new (link_drop_types, G_N_ELEMENTS (link_drop_types)));
|
||||
else
|
||||
return gdk_content_formats_new (NULL, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_link_content_get_value (GdkContentProvider *provider,
|
||||
GValue *value,
|
||||
GError **error)
|
||||
{
|
||||
GtkLinkContent *content = GTK_LINK_CONTENT (provider);
|
||||
|
||||
if (G_VALUE_HOLDS (value, G_TYPE_STRING) &&
|
||||
content->link != NULL)
|
||||
{
|
||||
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (content->link);
|
||||
char *uri;
|
||||
|
||||
uri = g_strdup_printf ("%s\r\n", priv->uri);
|
||||
g_value_set_string (value, uri);
|
||||
g_free (uri);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return GDK_CONTENT_PROVIDER_CLASS (gtk_link_content_parent_class)->get_value (provider, value, error);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_link_content_class_init (GtkLinkContentClass *class)
|
||||
{
|
||||
GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
|
||||
|
||||
provider_class->ref_formats = gtk_link_content_ref_formats;
|
||||
provider_class->get_value = gtk_link_content_get_value;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_link_content_init (GtkLinkContent *content)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_link_button_init (GtkLinkButton *link_button)
|
||||
{
|
||||
GtkStyleContext *context;
|
||||
GdkContentFormats *targets;
|
||||
GtkGesture *gesture;
|
||||
GdkContentProvider *content;
|
||||
GtkDragSource *source;
|
||||
|
||||
gtk_button_set_relief (GTK_BUTTON (link_button), GTK_RELIEF_NONE);
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (link_button), GTK_STATE_FLAG_LINK, FALSE);
|
||||
gtk_widget_set_has_tooltip (GTK_WIDGET (link_button), TRUE);
|
||||
|
||||
g_signal_connect (link_button, "drag-data-get",
|
||||
G_CALLBACK (gtk_link_button_drag_data_get_cb), NULL);
|
||||
|
||||
g_signal_connect (link_button, "query-tooltip",
|
||||
G_CALLBACK (gtk_link_button_query_tooltip_cb), NULL);
|
||||
|
||||
/* enable drag source */
|
||||
targets = gdk_content_formats_new (link_drop_types, G_N_ELEMENTS (link_drop_types));
|
||||
gtk_drag_source_set (GTK_WIDGET (link_button),
|
||||
GDK_BUTTON1_MASK,
|
||||
targets,
|
||||
GDK_ACTION_COPY);
|
||||
gdk_content_formats_unref (targets);
|
||||
gtk_drag_source_set_icon_name (GTK_WIDGET (link_button), "text-x-generic");
|
||||
source = gtk_drag_source_new ();
|
||||
content = g_object_new (GTK_TYPE_LINK_CONTENT, NULL);
|
||||
GTK_LINK_CONTENT (content)->link = link_button;
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_object_unref (content);
|
||||
gtk_widget_add_controller (GTK_WIDGET (link_button), GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
|
||||
@ -449,26 +511,6 @@ gtk_link_button_popup_menu (GtkWidget *widget)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_link_button_drag_data_get_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkLinkButton *link_button = GTK_LINK_BUTTON (widget);
|
||||
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button);
|
||||
gchar *uri;
|
||||
|
||||
uri = g_strdup_printf ("%s\r\n", priv->uri);
|
||||
gtk_selection_data_set (selection,
|
||||
gtk_selection_data_get_target (selection),
|
||||
8,
|
||||
(guchar *) uri,
|
||||
strlen (uri));
|
||||
|
||||
g_free (uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_link_button_new:
|
||||
* @uri: a valid URI
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkcontainerprivate.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
@ -264,8 +264,6 @@ static void gtk_list_box_size_allocate (GtkWidget
|
||||
int width,
|
||||
int height,
|
||||
int baseline);
|
||||
static void gtk_list_box_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
static void gtk_list_box_activate_cursor_row (GtkListBox *box);
|
||||
static void gtk_list_box_toggle_cursor_row (GtkListBox *box);
|
||||
static void gtk_list_box_move_cursor (GtkListBox *box,
|
||||
@ -452,7 +450,6 @@ gtk_list_box_class_init (GtkListBoxClass *klass)
|
||||
widget_class->get_request_mode = gtk_list_box_get_request_mode;
|
||||
widget_class->measure = gtk_list_box_measure;
|
||||
widget_class->size_allocate = gtk_list_box_size_allocate;
|
||||
widget_class->drag_leave = gtk_list_box_drag_leave;
|
||||
container_class->add = gtk_list_box_add;
|
||||
container_class->remove = gtk_list_box_remove;
|
||||
container_class->forall = gtk_list_box_forall;
|
||||
@ -2728,7 +2725,7 @@ gtk_list_box_drag_unhighlight_row (GtkListBox *box)
|
||||
if (priv->drag_highlighted_row == NULL)
|
||||
return;
|
||||
|
||||
gtk_drag_unhighlight (GTK_WIDGET (priv->drag_highlighted_row));
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (priv->drag_highlighted_row), GTK_STATE_FLAG_DROP_ACTIVE);
|
||||
g_clear_object (&priv->drag_highlighted_row);
|
||||
}
|
||||
|
||||
@ -2757,17 +2754,10 @@ gtk_list_box_drag_highlight_row (GtkListBox *box,
|
||||
return;
|
||||
|
||||
gtk_list_box_drag_unhighlight_row (box);
|
||||
gtk_drag_highlight (GTK_WIDGET (row));
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (row), GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
|
||||
priv->drag_highlighted_row = g_object_ref (row);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_box_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
gtk_list_box_drag_unhighlight_row (GTK_LIST_BOX (widget));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_box_activate_cursor_row (GtkListBox *box)
|
||||
{
|
||||
|
@ -116,7 +116,7 @@
|
||||
#include "gtkaccelmapprivate.h"
|
||||
#include "gtkbox.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkdndprivate.h"
|
||||
#include "gtkdragdestprivate.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmediafileprivate.h"
|
||||
#include "gtkmodulesprivate.h"
|
||||
@ -1686,6 +1686,20 @@ is_focus_event (GdkEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_dnd_event (GdkEvent *event)
|
||||
{
|
||||
switch ((guint) event->any.type)
|
||||
{
|
||||
case GDK_DRAG_ENTER:
|
||||
case GDK_DRAG_LEAVE:
|
||||
case GDK_DRAG_MOTION:
|
||||
case GDK_DROP_START:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_widget_active_state (GtkWidget *target,
|
||||
@ -1828,6 +1842,25 @@ handle_key_event (GdkEvent *event)
|
||||
return focus_widget ? focus_widget : event_widget;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
handle_dnd_event (GdkEvent *event)
|
||||
{
|
||||
GtkWidget *event_widget;
|
||||
GtkWidget *target;
|
||||
gdouble x, y;
|
||||
GtkWidget *native;
|
||||
|
||||
event_widget = gtk_get_event_widget (event);
|
||||
|
||||
if (!gdk_event_get_coords (event, &x, &y))
|
||||
return event_widget;
|
||||
|
||||
native = GTK_WIDGET (gtk_widget_get_native (event_widget));
|
||||
target = gtk_widget_pick (native, x, y, GTK_PICK_DEFAULT);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_main_do_event:
|
||||
* @event: An event to process (normally passed by GDK)
|
||||
@ -1924,6 +1957,8 @@ gtk_main_do_event (GdkEvent *event)
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else if (is_dnd_event (event))
|
||||
target_widget = handle_dnd_event (event);
|
||||
|
||||
if (!target_widget)
|
||||
goto cleanup;
|
||||
@ -2038,12 +2073,17 @@ gtk_main_do_event (GdkEvent *event)
|
||||
/* Crossing event propagation happens during picking */
|
||||
break;
|
||||
|
||||
case GDK_DRAG_ENTER:
|
||||
case GDK_DRAG_LEAVE:
|
||||
case GDK_DRAG_MOTION:
|
||||
case GDK_DROP_START:
|
||||
_gtk_drag_dest_handle_event (target_widget, event);
|
||||
if (gtk_propagate_event (target_widget, event))
|
||||
break;
|
||||
G_GNUC_FALLTHROUGH;
|
||||
|
||||
case GDK_DRAG_ENTER:
|
||||
case GDK_DRAG_LEAVE:
|
||||
gtk_drag_dest_handle_event (target_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_EVENT_LAST:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -2633,14 +2673,19 @@ propagate_event_down (GtkWidget *widget,
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
gtk_propagate_event_internal (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
/* Propagate the event down and up */
|
||||
if (!propagate_event_down (widget, event, topmost))
|
||||
propagate_event_up (widget, event, topmost);
|
||||
if (propagate_event_down (widget, event, topmost))
|
||||
return TRUE;
|
||||
|
||||
if (propagate_event_up (widget, event, topmost))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2667,8 +2712,10 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
* certainly better ways to achieve your goals. For example, use
|
||||
* gtk_widget_queue_draw() instead
|
||||
* of making up expose events.
|
||||
*
|
||||
* Returns: %TRUE if the event was handled
|
||||
*/
|
||||
void
|
||||
gboolean
|
||||
gtk_propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
@ -2676,8 +2723,8 @@ gtk_propagate_event (GtkWidget *widget,
|
||||
GtkWidget *event_widget, *topmost = NULL;
|
||||
GdkDevice *device;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (event != NULL);
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
g_return_val_if_fail (event != NULL, FALSE);
|
||||
|
||||
event_widget = gtk_get_event_widget (event);
|
||||
window_group = gtk_main_get_window_group (event_widget);
|
||||
@ -2689,5 +2736,5 @@ gtk_propagate_event (GtkWidget *widget,
|
||||
if (!topmost)
|
||||
topmost = gtk_window_group_get_current_grab (window_group);
|
||||
|
||||
gtk_propagate_event_internal (widget, event, topmost);
|
||||
return gtk_propagate_event_internal (widget, event, topmost);
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ GtkWidget *gtk_get_event_target_with_type (GdkEvent *event,
|
||||
GType type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_propagate_event (GtkWidget *widget,
|
||||
gboolean gtk_propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
|
||||
|
@ -58,6 +58,7 @@ OBJECT:VOID
|
||||
STRING:DOUBLE
|
||||
STRING:STRING
|
||||
VOID:BOOLEAN,BOOLEAN,BOOLEAN
|
||||
VOID:BOXED
|
||||
VOID:BOXED,BOXED
|
||||
VOID:BOXED,BOXED,POINTER
|
||||
VOID:BOXED,ENUM
|
||||
|
@ -33,8 +33,8 @@
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkbutton.h"
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkgizmoprivate.h"
|
||||
@ -52,6 +52,10 @@
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkwidgetpath.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkwidgetpaintable.h"
|
||||
#include "gtkselectionprivate.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
#include "a11y/gtknotebookaccessible.h"
|
||||
|
||||
@ -234,7 +238,6 @@ struct _GtkNotebookPrivate
|
||||
GtkNotebookPage *detached_tab;
|
||||
GdkContentFormats *source_targets;
|
||||
GtkWidget *action_widget[N_ACTION_WIDGETS];
|
||||
GtkWidget *dnd_child;
|
||||
GtkWidget *menu;
|
||||
GtkWidget *menu_box;
|
||||
|
||||
@ -695,29 +698,22 @@ static gboolean gtk_notebook_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
|
||||
/*** Drag and drop Methods ***/
|
||||
static void gtk_notebook_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_notebook_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static gboolean gtk_notebook_drag_failed (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkDragResult result);
|
||||
static gboolean gtk_notebook_drag_motion (GtkWidget *widget,
|
||||
static void gtk_notebook_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkWidget *widget);
|
||||
static void gtk_notebook_drag_cancel_cb (GdkDrag *drag,
|
||||
GdkDragCancelReason reason,
|
||||
GtkWidget *widget);
|
||||
static void gtk_notebook_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gtk_notebook_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
static gboolean gtk_notebook_drag_drop (GtkWidget *widget,
|
||||
int x,
|
||||
int y);
|
||||
static void gtk_notebook_drag_leave (GtkDropTarget *dest);
|
||||
static gboolean gtk_notebook_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gtk_notebook_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *data);
|
||||
static void gtk_notebook_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *data);
|
||||
int x,
|
||||
int y);
|
||||
static GBytes * gtk_notebook_drag_data_get (const char *mime_type,
|
||||
gpointer data);
|
||||
|
||||
/*** GtkContainer Methods ***/
|
||||
static void gtk_notebook_add (GtkContainer *container,
|
||||
@ -964,14 +960,6 @@ gtk_notebook_class_init (GtkNotebookClass *class)
|
||||
widget_class->grab_notify = gtk_notebook_grab_notify;
|
||||
widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
|
||||
widget_class->focus = gtk_notebook_focus;
|
||||
widget_class->drag_begin = gtk_notebook_drag_begin;
|
||||
widget_class->drag_end = gtk_notebook_drag_end;
|
||||
widget_class->drag_motion = gtk_notebook_drag_motion;
|
||||
widget_class->drag_leave = gtk_notebook_drag_leave;
|
||||
widget_class->drag_drop = gtk_notebook_drag_drop;
|
||||
widget_class->drag_data_get = gtk_notebook_drag_data_get;
|
||||
widget_class->drag_data_received = gtk_notebook_drag_data_received;
|
||||
widget_class->drag_failed = gtk_notebook_drag_failed;
|
||||
widget_class->compute_expand = gtk_notebook_compute_expand;
|
||||
|
||||
container_class->add = gtk_notebook_add;
|
||||
@ -1306,6 +1294,7 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
GtkEventController *controller;
|
||||
GtkGesture *gesture;
|
||||
GtkLayoutManager *layout;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
|
||||
|
||||
@ -1337,14 +1326,6 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
priv->detached_tab = NULL;
|
||||
priv->has_scrolled = FALSE;
|
||||
|
||||
targets = gdk_content_formats_new (dst_notebook_targets, G_N_ELEMENTS (dst_notebook_targets));
|
||||
gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
|
||||
targets,
|
||||
GDK_ACTION_MOVE);
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
|
||||
|
||||
priv->header_widget = g_object_new (GTK_TYPE_BOX,
|
||||
"css-name", "header",
|
||||
NULL);
|
||||
@ -1366,6 +1347,14 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
gtk_widget_set_vexpand (priv->stack_widget, TRUE);
|
||||
gtk_widget_set_parent (priv->stack_widget, GTK_WIDGET (notebook));
|
||||
|
||||
targets = gdk_content_formats_new (dst_notebook_targets, G_N_ELEMENTS (dst_notebook_targets));
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_notebook_drag_motion), NULL);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_notebook_drag_leave), NULL);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_notebook_drag_drop), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (priv->tabs_widget), GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), GTK_PHASE_CAPTURE);
|
||||
@ -1835,7 +1824,6 @@ gtk_notebook_get_property (GObject *object,
|
||||
* gtk_notebook_drag_motion
|
||||
* gtk_notebook_drag_drop
|
||||
* gtk_notebook_drag_data_get
|
||||
* gtk_notebook_drag_data_received
|
||||
*/
|
||||
static void
|
||||
remove_switch_tab_timer (GtkNotebook *notebook)
|
||||
@ -2881,12 +2869,43 @@ gtk_notebook_motion (GtkEventController *controller,
|
||||
if (page->detachable &&
|
||||
check_threshold (notebook, priv->mouse_x, priv->mouse_y))
|
||||
{
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
GdkContentProvider *content;
|
||||
GdkDrag *drag;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
priv->detached_tab = priv->cur_page;
|
||||
|
||||
gtk_drag_begin (widget,
|
||||
gtk_get_current_event_device (),
|
||||
priv->source_targets, GDK_ACTION_MOVE,
|
||||
priv->drag_begin_x, priv->drag_begin_y);
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (notebook)));
|
||||
device = gtk_get_current_event_device ();
|
||||
|
||||
content = gdk_content_provider_new_with_formats (priv->source_targets,
|
||||
gtk_notebook_drag_data_get,
|
||||
widget);
|
||||
drag = gdk_drag_begin (surface, device, content, GDK_ACTION_MOVE, priv->drag_begin_x, priv->drag_begin_y);
|
||||
g_object_unref (content);
|
||||
|
||||
g_signal_connect (drag, "dnd-finished", G_CALLBACK (gtk_notebook_dnd_finished_cb), notebook);
|
||||
g_signal_connect (drag, "cancel", G_CALLBACK (gtk_notebook_drag_cancel_cb), notebook);
|
||||
|
||||
paintable = gtk_widget_paintable_new (priv->detached_tab->tab_widget);
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
|
||||
g_object_unref (paintable);
|
||||
|
||||
if (priv->dnd_timer)
|
||||
{
|
||||
g_source_remove (priv->dnd_timer);
|
||||
priv->dnd_timer = 0;
|
||||
}
|
||||
|
||||
priv->operation = DRAG_OPERATION_DETACH;
|
||||
tab_drag_end (notebook, priv->cur_page);
|
||||
|
||||
g_object_set_data (G_OBJECT (drag), "gtk-notebook-drag-origin", notebook);
|
||||
|
||||
g_object_unref (drag);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3088,46 +3107,8 @@ update_arrow_nodes (GtkNotebook *notebook)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
graphene_rect_t bounds;
|
||||
GtkWidget *tab_label;
|
||||
|
||||
if (priv->dnd_timer)
|
||||
{
|
||||
g_source_remove (priv->dnd_timer);
|
||||
priv->dnd_timer = 0;
|
||||
}
|
||||
|
||||
g_assert (priv->cur_page != NULL);
|
||||
|
||||
priv->operation = DRAG_OPERATION_DETACH;
|
||||
|
||||
tab_label = priv->detached_tab->tab_label;
|
||||
|
||||
tab_drag_end (notebook, priv->cur_page);
|
||||
g_object_ref (tab_label);
|
||||
gtk_widget_unparent (tab_label);
|
||||
|
||||
priv->dnd_child = tab_label;
|
||||
if (gtk_widget_compute_bounds (priv->dnd_child, priv->dnd_child, &bounds))
|
||||
gtk_widget_set_size_request (priv->dnd_child,
|
||||
ceilf (bounds.size.width),
|
||||
ceilf (bounds.size.height));
|
||||
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (priv->dnd_child), "background");
|
||||
|
||||
gtk_drag_set_icon_widget (drag, tab_label, -2, -2);
|
||||
g_object_set_data (G_OBJECT (priv->dnd_child), "drag-context", drag);
|
||||
g_object_unref (tab_label);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
gtk_notebook_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
@ -3148,17 +3129,9 @@ gtk_notebook_drag_end (GtkWidget *widget,
|
||||
}
|
||||
else if (priv->detached_tab)
|
||||
{
|
||||
gtk_widget_set_size_request (priv->dnd_child, -1, -1);
|
||||
g_object_ref (priv->dnd_child);
|
||||
gtk_widget_unparent (priv->dnd_child);
|
||||
gtk_widget_set_parent (priv->dnd_child, priv->detached_tab->tab_widget);
|
||||
g_object_unref (priv->dnd_child);
|
||||
gtk_notebook_switch_page (notebook, priv->detached_tab);
|
||||
}
|
||||
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (priv->dnd_child), "background");
|
||||
priv->dnd_child = NULL;
|
||||
|
||||
priv->operation = DRAG_OPERATION_NONE;
|
||||
}
|
||||
|
||||
@ -3169,17 +3142,17 @@ gtk_notebook_create_window (GtkNotebook *notebook,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_notebook_drag_failed (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkDragResult result)
|
||||
static void
|
||||
gtk_notebook_drag_cancel_cb (GdkDrag *drag,
|
||||
GdkDragCancelReason reason,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
|
||||
priv->rootwindow_drop = FALSE;
|
||||
|
||||
if (result == GTK_DRAG_RESULT_NO_TARGET)
|
||||
if (reason == GDK_DRAG_CANCEL_NO_TARGET)
|
||||
{
|
||||
GtkNotebook *dest_notebook = NULL;
|
||||
|
||||
@ -3188,11 +3161,7 @@ gtk_notebook_drag_failed (GtkWidget *widget,
|
||||
|
||||
if (dest_notebook)
|
||||
do_detach_tab (notebook, dest_notebook, priv->detached_tab->child);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -3219,19 +3188,20 @@ gtk_notebook_switch_tab_timeout (gpointer data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_notebook_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
static void
|
||||
gtk_notebook_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GtkWidget *tabs = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
GtkWidget *widget = gtk_widget_get_ancestor (tabs, GTK_TYPE_NOTEBOOK);
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
graphene_rect_t position;
|
||||
GtkNotebookArrow arrow;
|
||||
GdkAtom target, tab_target;
|
||||
GList *tab;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
arrow = gtk_notebook_get_arrow (notebook, x, y);
|
||||
if (arrow != ARROW_NONE)
|
||||
@ -3240,41 +3210,46 @@ gtk_notebook_drag_motion (GtkWidget *widget,
|
||||
gtk_notebook_set_scroll_timer (notebook);
|
||||
gdk_drop_status (drop, 0);
|
||||
|
||||
retval = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
stop_scrolling (notebook);
|
||||
target = gtk_drag_dest_find_target (widget, drop, NULL);
|
||||
target = gtk_drop_target_find_mimetype (dest);
|
||||
tab_target = g_intern_static_string ("GTK_NOTEBOOK_TAB");
|
||||
|
||||
if (target == tab_target)
|
||||
{
|
||||
GQuark group, source_group;
|
||||
GtkNotebook *source;
|
||||
GtkWidget *source_child;
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
source = GTK_NOTEBOOK (gtk_drag_get_source_widget (gdk_drop_get_drag (drop)));
|
||||
g_assert (source->priv->cur_page != NULL);
|
||||
source_child = source->priv->cur_page->child;
|
||||
|
||||
group = notebook->priv->group;
|
||||
source_group = source->priv->group;
|
||||
|
||||
if (group != 0 && group == source_group &&
|
||||
!(widget == source_child ||
|
||||
gtk_widget_is_ancestor (widget, source_child)))
|
||||
if (!drag)
|
||||
{
|
||||
gdk_drop_status (drop, GDK_ACTION_MOVE);
|
||||
goto out;
|
||||
gdk_drop_status (drop, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* it's a tab, but doesn't share
|
||||
* ID with this notebook */
|
||||
gdk_drop_status (drop, 0);
|
||||
GtkNotebook *source = GTK_NOTEBOOK (g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin"));
|
||||
|
||||
g_assert (source->priv->cur_page != NULL);
|
||||
source_child = source->priv->cur_page->child;
|
||||
|
||||
group = notebook->priv->group;
|
||||
source_group = source->priv->group;
|
||||
|
||||
if (group != 0 && group == source_group &&
|
||||
!(widget == source_child ||
|
||||
gtk_widget_is_ancestor (widget, source_child)))
|
||||
{
|
||||
gdk_drop_status (drop, GDK_ACTION_MOVE);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* it's a tab, but doesn't share
|
||||
* ID with this notebook */
|
||||
gdk_drop_status (drop, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3285,8 +3260,6 @@ gtk_notebook_drag_motion (GtkWidget *widget,
|
||||
priv->mouse_x = x;
|
||||
priv->mouse_y = y;
|
||||
|
||||
retval = TRUE;
|
||||
|
||||
if (tab != priv->switch_tab)
|
||||
remove_switch_tab_timer (notebook);
|
||||
|
||||
@ -3303,40 +3276,86 @@ gtk_notebook_drag_motion (GtkWidget *widget,
|
||||
remove_switch_tab_timer (notebook);
|
||||
}
|
||||
|
||||
out:
|
||||
return retval;
|
||||
out:;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
gtk_notebook_drag_leave (GtkDropTarget *dest)
|
||||
{
|
||||
GtkWidget *tabs = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
GtkWidget *widget = gtk_widget_get_ancestor (tabs, GTK_TYPE_NOTEBOOK);
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
|
||||
remove_switch_tab_timer (notebook);
|
||||
stop_scrolling (notebook);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_notebook_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
static void
|
||||
got_page (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (data);
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
GtkWidget *source_widget;
|
||||
GInputStream *stream;
|
||||
const char *mime_type;
|
||||
|
||||
source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL);
|
||||
|
||||
stream = gdk_drop_read_finish (drop, result, &mime_type, NULL);
|
||||
|
||||
if (stream)
|
||||
{
|
||||
GBytes *bytes;
|
||||
GtkWidget **child;
|
||||
|
||||
bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL);
|
||||
child = (gpointer)g_bytes_get_data (bytes, NULL);
|
||||
|
||||
do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child);
|
||||
gdk_drop_finish (drop, GDK_ACTION_MOVE);
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
g_object_unref (stream);
|
||||
}
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_notebook_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GtkWidget *tabs = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
GtkWidget *widget = gtk_widget_get_ancestor (tabs, GTK_TYPE_NOTEBOOK);
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
GtkWidget *source_widget;
|
||||
GdkAtom target, tab_target;
|
||||
|
||||
target = gtk_drag_dest_find_target (widget, drop, NULL);
|
||||
source_widget = GTK_WIDGET (drag ? g_object_get_data (G_OBJECT (drag), "gtk-notebook-drag-origin") : NULL);
|
||||
|
||||
target = gtk_drop_target_find_mimetype (dest);
|
||||
tab_target = g_intern_static_string ("GTK_NOTEBOOK_TAB");
|
||||
|
||||
if (target == tab_target)
|
||||
if (GTK_IS_NOTEBOOK (source_widget) &&
|
||||
target == tab_target &&
|
||||
(gdk_drop_get_actions (drop) & GDK_ACTION_MOVE))
|
||||
{
|
||||
notebook->priv->mouse_x = x;
|
||||
notebook->priv->mouse_y = y;
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
|
||||
gdk_drop_read_async (drop, (const char *[]) { "GTK_NOTEBOOK_TAB", NULL }, G_PRIORITY_DEFAULT, NULL, got_page, notebook);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gdk_drop_finish (drop, 0);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -3419,57 +3438,32 @@ do_detach_tab (GtkNotebook *from,
|
||||
gtk_notebook_set_current_page (to, page_num);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *data)
|
||||
static GBytes *
|
||||
gtk_notebook_drag_data_get (const char *mime_type,
|
||||
gpointer data)
|
||||
{
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (data);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GdkAtom target;
|
||||
GtkSelectionData sdata = { 0, };
|
||||
|
||||
target = gtk_selection_data_get_target (data);
|
||||
if (target == g_intern_static_string ("GTK_NOTEBOOK_TAB"))
|
||||
sdata.target = g_intern_string (mime_type);
|
||||
|
||||
if (sdata.target == g_intern_static_string ("GTK_NOTEBOOK_TAB"))
|
||||
{
|
||||
gtk_selection_data_set (data,
|
||||
target,
|
||||
gtk_selection_data_set (&sdata,
|
||||
sdata.target,
|
||||
8,
|
||||
(void*) &priv->detached_tab->child,
|
||||
sizeof (gpointer));
|
||||
priv->rootwindow_drop = FALSE;
|
||||
}
|
||||
else if (target == g_intern_static_string ("application/x-rootwindow-drop"))
|
||||
else if (sdata.target == g_intern_static_string ("application/x-rootwindow-drop"))
|
||||
{
|
||||
gtk_selection_data_set (data, target, 8, NULL, 0);
|
||||
gtk_selection_data_set (&sdata, sdata.target, 8, NULL, 0);
|
||||
priv->rootwindow_drop = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *data)
|
||||
{
|
||||
GtkNotebook *notebook;
|
||||
GdkDrag *drag;
|
||||
GtkWidget *source_widget;
|
||||
GtkWidget **child;
|
||||
|
||||
notebook = GTK_NOTEBOOK (widget);
|
||||
drag = gdk_drop_get_drag (drop);
|
||||
source_widget = gtk_drag_get_source_widget (drag);
|
||||
|
||||
if (source_widget &&
|
||||
(gdk_drop_get_actions (drop) & GDK_ACTION_MOVE) &&
|
||||
gtk_selection_data_get_target (data) == g_intern_static_string ("GTK_NOTEBOOK_TAB"))
|
||||
{
|
||||
child = (void*) gtk_selection_data_get_data (data);
|
||||
|
||||
do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, *child);
|
||||
gdk_drop_finish (drop, GDK_ACTION_MOVE);
|
||||
}
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
return g_bytes_new_take (sdata.data, sdata.length);
|
||||
}
|
||||
|
||||
/* Private GtkContainer Methods :
|
||||
@ -4249,17 +4243,8 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
|
||||
}
|
||||
|
||||
if (priv->detached_tab == list->data)
|
||||
{
|
||||
priv->detached_tab = NULL;
|
||||
priv->detached_tab = NULL;
|
||||
|
||||
if (priv->operation == DRAG_OPERATION_DETACH && !priv->remove_in_detach)
|
||||
{
|
||||
GdkDrag *drag;
|
||||
|
||||
drag = (GdkDrag *)g_object_get_data (G_OBJECT (priv->dnd_child), "drag-context");
|
||||
gtk_drag_cancel (drag);
|
||||
}
|
||||
}
|
||||
if (priv->switch_tab == list)
|
||||
priv->switch_tab = NULL;
|
||||
|
||||
@ -7099,15 +7084,17 @@ gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
|
||||
* |[<!-- language="C" -->
|
||||
* static void
|
||||
* on_drag_data_received (GtkWidget *widget,
|
||||
* GdkDrag *drag,
|
||||
* GdkDrop *drop,
|
||||
* GtkSelectionData *data,
|
||||
* guint time,
|
||||
* gpointer user_data)
|
||||
* {
|
||||
* GtkDrag *drag;
|
||||
* GtkWidget *notebook;
|
||||
* GtkWidget **child;
|
||||
*
|
||||
* notebook = gtk_drag_get_source_widget (drag);
|
||||
* drag = gtk_drop_get_drag (drop);
|
||||
* notebook = g_object_get_data (drag, "gtk-notebook-drag-origin");
|
||||
* child = (void*) gtk_selection_data_get_data (data);
|
||||
*
|
||||
* // process_widget (*child);
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
#include "gtkbox.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkicontheme.h"
|
||||
#include "gtkimage.h"
|
||||
@ -37,6 +36,7 @@
|
||||
#include "gtkwidgetpath.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkeventcontrollerscroll.h"
|
||||
#include "gtkdragsource.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -1240,15 +1240,8 @@ set_button_image (GtkPathBar *path_bar,
|
||||
static void
|
||||
button_data_free (ButtonData *button_data)
|
||||
{
|
||||
if (button_data->file)
|
||||
g_object_unref (button_data->file);
|
||||
button_data->file = NULL;
|
||||
|
||||
g_clear_object (&button_data->file);
|
||||
g_free (button_data->dir_name);
|
||||
button_data->dir_name = NULL;
|
||||
|
||||
button_data->button = NULL;
|
||||
|
||||
g_free (button_data);
|
||||
}
|
||||
|
||||
@ -1312,25 +1305,6 @@ find_button_type (GtkPathBar *path_bar,
|
||||
return NORMAL_BUTTON;
|
||||
}
|
||||
|
||||
static void
|
||||
button_drag_data_get_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
{
|
||||
ButtonData *button_data;
|
||||
char *uris[2];
|
||||
|
||||
button_data = data;
|
||||
|
||||
uris[0] = g_file_get_uri (button_data->file);
|
||||
uris[1] = NULL;
|
||||
|
||||
gtk_selection_data_set_uris (selection_data, uris);
|
||||
|
||||
g_free (uris[0]);
|
||||
}
|
||||
|
||||
static ButtonData *
|
||||
make_directory_button (GtkPathBar *path_bar,
|
||||
const char *dir_name,
|
||||
@ -1341,6 +1315,9 @@ make_directory_button (GtkPathBar *path_bar,
|
||||
AtkObject *atk_obj;
|
||||
GtkWidget *child = NULL;
|
||||
ButtonData *button_data;
|
||||
GValue value = G_VALUE_INIT;
|
||||
GdkContentProvider *content;
|
||||
GtkDragSource *source;
|
||||
|
||||
file_is_hidden = !! file_is_hidden;
|
||||
/* Is it a special button? */
|
||||
@ -1387,13 +1364,14 @@ make_directory_button (GtkPathBar *path_bar,
|
||||
g_object_weak_ref (G_OBJECT (button_data->button),
|
||||
(GWeakNotify) button_data_free, button_data);
|
||||
|
||||
gtk_drag_source_set (button_data->button,
|
||||
GDK_BUTTON1_MASK,
|
||||
NULL,
|
||||
GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_uri_targets (button_data->button);
|
||||
g_signal_connect (button_data->button, "drag-data-get",
|
||||
G_CALLBACK (button_drag_data_get_cb), button_data);
|
||||
g_value_init (&value, G_TYPE_FILE);
|
||||
g_value_set_object (&value, button_data->file);
|
||||
source = gtk_drag_source_new ();
|
||||
content = gdk_content_provider_new_for_value (&value);
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_object_unref (content);
|
||||
gtk_widget_add_controller (button_data->button, GTK_EVENT_CONTROLLER (source));
|
||||
g_value_unset (&value);
|
||||
|
||||
return button_data;
|
||||
}
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include "gtklistbox.h"
|
||||
#include "gtkselection.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkseparator.h"
|
||||
#include "gtkentry.h"
|
||||
#include "gtkgesturelongpress.h"
|
||||
@ -63,6 +62,10 @@
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkwidgetpaintable.h"
|
||||
#include "gtkselectionprivate.h"
|
||||
|
||||
/*< private >
|
||||
* SECTION:gtkplacessidebar
|
||||
@ -309,16 +312,6 @@ enum {
|
||||
DND_TEXT_URI_LIST
|
||||
};
|
||||
|
||||
/* Target types for dragging from the shortcuts list */
|
||||
static const char *dnd_source_targets[] = {
|
||||
"DND_GTK_SIDEBAR_ROW"
|
||||
};
|
||||
|
||||
/* Target types for dropping into the shortcuts list */
|
||||
static const char *dnd_drop_targets [] = {
|
||||
"DND_GTK_SIDEBAR_ROW"
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkPlacesSidebar, gtk_places_sidebar, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
@ -1641,21 +1634,25 @@ update_possible_drop_targets (GtkPlacesSidebar *sidebar,
|
||||
g_list_free (rows);
|
||||
}
|
||||
|
||||
static void drag_data_received_callback (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data);
|
||||
|
||||
static gboolean
|
||||
get_drag_data (GtkWidget *list_box,
|
||||
GdkDrop *drop,
|
||||
GtkDropTarget *dest,
|
||||
GtkListBoxRow *row)
|
||||
{
|
||||
GdkAtom target;
|
||||
|
||||
target = gtk_drag_dest_find_target (list_box, drop, NULL);
|
||||
target = gtk_drop_target_find_mimetype (dest);
|
||||
|
||||
if (target == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (row)
|
||||
g_object_set_data_full (G_OBJECT (drop), "places-sidebar-row", g_object_ref (row), g_object_unref);
|
||||
gtk_drag_get_data (list_box, drop, target);
|
||||
g_object_set_data_full (G_OBJECT (dest), "places-sidebar-row", g_object_ref (row), g_object_unref);
|
||||
gtk_drop_target_read_selection (dest, target, NULL, drag_data_received_callback, list_box);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -1678,7 +1675,8 @@ start_drop_feedback (GtkPlacesSidebar *sidebar,
|
||||
GtkSidebarRow *row,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
if (sidebar->drag_data_info != DND_GTK_SIDEBAR_ROW)
|
||||
if (sidebar->drag_data_received &&
|
||||
sidebar->drag_data_info != DND_GTK_SIDEBAR_ROW)
|
||||
{
|
||||
gtk_sidebar_row_reveal (GTK_SIDEBAR_ROW (sidebar->new_bookmark_row));
|
||||
/* If the state is permanent, don't change it. The application controls it. */
|
||||
@ -1719,48 +1717,22 @@ stop_drop_feedback (GtkPlacesSidebar *sidebar)
|
||||
sidebar->drag_data_info = DND_UNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin_callback (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
|
||||
GtkAllocation allocation;
|
||||
GtkWidget *drag_widget;
|
||||
|
||||
gtk_widget_get_allocation (sidebar->drag_row, &allocation);
|
||||
gtk_widget_hide (sidebar->drag_row);
|
||||
|
||||
drag_widget = GTK_WIDGET (gtk_sidebar_row_clone (GTK_SIDEBAR_ROW (sidebar->drag_row)));
|
||||
sidebar->drag_row_height = allocation.height;
|
||||
gtk_widget_set_size_request (drag_widget, allocation.width, allocation.height);
|
||||
|
||||
gtk_widget_set_opacity (drag_widget, 0.8);
|
||||
|
||||
gtk_drag_set_icon_widget (drag,
|
||||
drag_widget,
|
||||
sidebar->drag_row_x,
|
||||
sidebar->drag_row_y);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_placeholder_row (GtkPlacesSidebar *sidebar)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_SIDEBAR_ROW,
|
||||
"placeholder", TRUE,
|
||||
NULL);
|
||||
return g_object_new (GTK_TYPE_SIDEBAR_ROW, "placeholder", TRUE, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_motion_callback (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y,
|
||||
gpointer user_data)
|
||||
static void
|
||||
drag_motion_callback (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
|
||||
gint action;
|
||||
GtkListBoxRow *row;
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
|
||||
GtkPlacesSidebarPlaceType place_type;
|
||||
gchar *drop_target_uri = NULL;
|
||||
gint row_index;
|
||||
@ -1776,7 +1748,7 @@ drag_motion_callback (GtkWidget *widget,
|
||||
|
||||
/* Nothing to do if no drag data */
|
||||
if (!sidebar->drag_data_received &&
|
||||
!get_drag_data (sidebar->list_box, drop, row))
|
||||
!get_drag_data (sidebar->list_box, dest, row))
|
||||
goto out;
|
||||
|
||||
/* Nothing to do if the target is not valid drop destination */
|
||||
@ -1791,7 +1763,6 @@ drag_motion_callback (GtkWidget *widget,
|
||||
if (sidebar->row_placeholder == NULL)
|
||||
{
|
||||
sidebar->row_placeholder = create_placeholder_row (sidebar);
|
||||
gtk_widget_show (sidebar->row_placeholder);
|
||||
g_object_ref_sink (sidebar->row_placeholder);
|
||||
}
|
||||
else if (GTK_WIDGET (row) == sidebar->row_placeholder)
|
||||
@ -1822,7 +1793,7 @@ drag_motion_callback (GtkWidget *widget,
|
||||
* of the row, we need to increase the order-index.
|
||||
*/
|
||||
row_placeholder_index = row_index;
|
||||
gtk_widget_translate_coordinates (widget, GTK_WIDGET (row),
|
||||
gtk_widget_translate_coordinates (GTK_WIDGET (sidebar), GTK_WIDGET (row),
|
||||
x, y,
|
||||
&dest_x, &dest_y);
|
||||
|
||||
@ -1879,12 +1850,7 @@ drag_motion_callback (GtkWidget *widget,
|
||||
|
||||
out:
|
||||
start_drop_feedback (sidebar, GTK_SIDEBAR_ROW (row), drag);
|
||||
|
||||
g_signal_stop_emission_by_name (sidebar->list_box, "drag-motion");
|
||||
|
||||
gdk_drop_status (drop, action);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Takes an array of URIs and turns it into a list of GFile */
|
||||
@ -1950,42 +1916,41 @@ drop_files_as_bookmarks (GtkPlacesSidebar *sidebar,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_data_get_callback (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *data,
|
||||
gpointer user_data)
|
||||
static GBytes *
|
||||
drag_data_get_callback (const char *mimetype,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
|
||||
GdkAtom target = gtk_selection_data_get_target (data);
|
||||
|
||||
if (target == g_intern_static_string ("DND_GTK_SIDEBAR_ROW"))
|
||||
{
|
||||
gtk_selection_data_set (data,
|
||||
target,
|
||||
8,
|
||||
(void*)&sidebar->drag_row,
|
||||
sizeof (gpointer));
|
||||
}
|
||||
if (mimetype == g_intern_static_string ("DND_GTK_SIDEBAR_ROW"))
|
||||
return g_bytes_new ((gpointer)&sidebar->drag_row, sizeof (gpointer));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_data_received_callback (GtkWidget *list_box,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer user_data)
|
||||
drag_data_received_callback (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkDropTarget *dest = GTK_DROP_TARGET (source);
|
||||
GtkWidget *list_box = user_data;
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (gtk_widget_get_ancestor (list_box, GTK_TYPE_PLACES_SIDEBAR));
|
||||
GdkDrop *drop = gtk_drop_target_get_drop (dest);
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
gint target_order_index;
|
||||
GtkPlacesSidebarPlaceType target_place_type;
|
||||
GtkPlacesSidebarSectionType target_section_type;
|
||||
gchar *target_uri;
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
|
||||
GtkListBoxRow *target_row;
|
||||
GdkDragAction real_action;
|
||||
GtkSelectionData *selection_data;
|
||||
|
||||
selection_data = gtk_drop_target_read_selection_finish (dest, result, NULL);
|
||||
|
||||
if (!sidebar->drag_data_received)
|
||||
{
|
||||
if (gtk_selection_data_targets_include_uri (selection_data))
|
||||
if (gtk_selection_data_get_target (selection_data) == g_intern_static_string ("text/uri-list"))
|
||||
{
|
||||
gchar **uris;
|
||||
|
||||
@ -2001,19 +1966,22 @@ drag_data_received_callback (GtkWidget *list_box,
|
||||
{
|
||||
sidebar->drag_list = NULL;
|
||||
if (gtk_selection_data_get_target (selection_data) == g_intern_static_string ("DND_GTK_SIDEBAR_ROW"))
|
||||
sidebar->drag_data_info = DND_GTK_SIDEBAR_ROW;
|
||||
{
|
||||
sidebar->drag_data_info = DND_GTK_SIDEBAR_ROW;
|
||||
}
|
||||
}
|
||||
sidebar->drag_data_received = TRUE;
|
||||
}
|
||||
|
||||
g_signal_stop_emission_by_name (list_box, "drag-data-received");
|
||||
|
||||
if (!sidebar->drop_occurred)
|
||||
return;
|
||||
goto out_free;
|
||||
|
||||
target_row = g_object_get_data (G_OBJECT (drop), "places-sidebar-row");
|
||||
target_row = g_object_get_data (G_OBJECT (dest), "places-sidebar-row");
|
||||
if (target_row == NULL)
|
||||
return;
|
||||
goto out_free;
|
||||
|
||||
if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (target_row), drag))
|
||||
goto out_free;
|
||||
|
||||
g_object_get (target_row,
|
||||
"place-type", &target_place_type,
|
||||
@ -2021,12 +1989,8 @@ drag_data_received_callback (GtkWidget *list_box,
|
||||
"order-index", &target_order_index,
|
||||
"uri", &target_uri,
|
||||
NULL);
|
||||
|
||||
real_action = 0;
|
||||
|
||||
if (!check_valid_drop_target (sidebar, GTK_SIDEBAR_ROW (target_row), gdk_drop_get_drag (drop)))
|
||||
goto out;
|
||||
|
||||
if (sidebar->drag_data_info == DND_GTK_SIDEBAR_ROW)
|
||||
{
|
||||
GtkWidget **source_row;
|
||||
@ -2081,18 +2045,20 @@ drag_data_received_callback (GtkWidget *list_box,
|
||||
|
||||
out:
|
||||
sidebar->drop_occurred = FALSE;
|
||||
g_object_set_data (G_OBJECT (drop), "places-sidebar-row", NULL);
|
||||
g_object_set_data (G_OBJECT (dest), "places-sidebar-row", NULL);
|
||||
gdk_drop_finish (drop, real_action);
|
||||
stop_drop_feedback (sidebar);
|
||||
g_free (target_uri);
|
||||
|
||||
out_free:
|
||||
gtk_selection_data_free (selection_data);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_end_callback (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer user_data)
|
||||
dnd_finished_cb (GdkDrag *drag,
|
||||
GtkPlacesSidebar *sidebar)
|
||||
{
|
||||
stop_drop_feedback (GTK_PLACES_SIDEBAR (user_data));
|
||||
stop_drop_feedback (sidebar);
|
||||
}
|
||||
|
||||
/* This functions is called every time the drag source leaves
|
||||
@ -2105,8 +2071,8 @@ drag_end_callback (GtkWidget *widget,
|
||||
* but that's not true, because this function is called also before drag_drop,
|
||||
* which needs the data from the drag so we cannot free the drag data here.
|
||||
* So now one could think we could just do nothing here, and wait for
|
||||
* drag-end or drag-failed signals and just stop_drop_feedback there. But that
|
||||
* is also not true, since when the drag comes from a diferent widget than the
|
||||
* drag-end or drag-cancel signals and just stop_drop_feedback there. But that
|
||||
* is also not true, since when the drag comes from a different widget than the
|
||||
* sidebar, when the drag stops the last drag signal we receive is drag-leave.
|
||||
* So here what we will do is restore the state of the sidebar as if no drag
|
||||
* is being done (and if the application didnt request for permanent hints with
|
||||
@ -2114,9 +2080,9 @@ drag_end_callback (GtkWidget *widget,
|
||||
* we build new drag data in drag_data_received.
|
||||
*/
|
||||
static void
|
||||
drag_leave_callback (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gpointer user_data)
|
||||
drag_leave_callback (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
|
||||
|
||||
@ -2133,20 +2099,20 @@ drag_leave_callback (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_drop_callback (GtkWidget *list_box,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y,
|
||||
gpointer user_data)
|
||||
drag_drop_callback (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
gpointer user_data)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
|
||||
gboolean retval = FALSE;
|
||||
GtkListBoxRow *row;
|
||||
|
||||
row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (sidebar->list_box), y);
|
||||
sidebar->drop_occurred = TRUE;
|
||||
retval = get_drag_data (sidebar->list_box, drop, row);
|
||||
g_signal_stop_emission_by_name (sidebar->list_box, "drag-drop");
|
||||
|
||||
retval = get_drag_data (sidebar->list_box, dest, row);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -3778,6 +3744,13 @@ on_row_dragged (GtkGestureDrag *gesture,
|
||||
{
|
||||
gdouble start_x, start_y;
|
||||
gint drag_x, drag_y;
|
||||
GdkContentProvider *content;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
GtkAllocation allocation;
|
||||
GtkWidget *drag_widget;
|
||||
GdkPaintable *paintable;
|
||||
GdkDrag *drag;
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
|
||||
gtk_widget_translate_coordinates (GTK_WIDGET (row),
|
||||
@ -3787,10 +3760,35 @@ on_row_dragged (GtkGestureDrag *gesture,
|
||||
|
||||
sidebar->dragging_over = TRUE;
|
||||
|
||||
gtk_drag_begin (GTK_WIDGET (sidebar),
|
||||
gtk_gesture_get_device (GTK_GESTURE (gesture)),
|
||||
sidebar->source_targets, GDK_ACTION_MOVE,
|
||||
drag_x, drag_y);
|
||||
content = gdk_content_provider_new_with_formats (sidebar->source_targets,
|
||||
drag_data_get_callback,
|
||||
sidebar);
|
||||
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (sidebar)));
|
||||
device = gtk_gesture_get_device (GTK_GESTURE (gesture));
|
||||
|
||||
drag = gdk_drag_begin (surface, device, content, GDK_ACTION_MOVE, drag_x, drag_y);
|
||||
|
||||
g_object_unref (content);
|
||||
|
||||
g_signal_connect (drag, "dnd-finished", G_CALLBACK (dnd_finished_cb), sidebar);
|
||||
|
||||
gtk_widget_get_allocation (sidebar->drag_row, &allocation);
|
||||
gtk_widget_hide (sidebar->drag_row);
|
||||
|
||||
drag_widget = GTK_WIDGET (gtk_sidebar_row_clone (GTK_SIDEBAR_ROW (sidebar->drag_row)));
|
||||
sidebar->drag_row_height = allocation.height;
|
||||
gtk_widget_set_size_request (drag_widget, allocation.width, allocation.height);
|
||||
|
||||
gtk_widget_set_opacity (drag_widget, 0.8);
|
||||
|
||||
paintable = gtk_widget_paintable_new (drag_widget);
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, sidebar->drag_row_x, sidebar->drag_row_y);
|
||||
g_object_unref (paintable);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (drag), "row-widget", drag_widget, (GDestroyNotify)gtk_widget_destroy);
|
||||
|
||||
g_object_unref (drag);
|
||||
}
|
||||
|
||||
g_object_unref (sidebar);
|
||||
@ -4022,11 +4020,13 @@ shell_shows_desktop_changed (GtkSettings *settings,
|
||||
static void
|
||||
gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
|
||||
{
|
||||
GdkContentFormats *target_list;
|
||||
GdkContentFormats *formats;
|
||||
GtkDropTarget *dest;
|
||||
gboolean show_desktop;
|
||||
GtkStyleContext *context;
|
||||
GtkEventController *controller;
|
||||
GtkGesture *gesture;
|
||||
GdkContentFormatsBuilder *builder;
|
||||
|
||||
sidebar->cancellable = g_cancellable_new ();
|
||||
|
||||
@ -4079,31 +4079,22 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
|
||||
gtk_widget_add_controller (GTK_WIDGET (sidebar), GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
/* DND support */
|
||||
gtk_drag_dest_set (sidebar->list_box,
|
||||
0,
|
||||
NULL,
|
||||
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
|
||||
target_list = gdk_content_formats_new (dnd_drop_targets, G_N_ELEMENTS (dnd_drop_targets));
|
||||
target_list = gtk_content_formats_add_uri_targets (target_list);
|
||||
gtk_drag_dest_set_target_list (sidebar->list_box, target_list);
|
||||
gdk_content_formats_unref (target_list);
|
||||
sidebar->source_targets = gdk_content_formats_new (dnd_source_targets, G_N_ELEMENTS (dnd_source_targets));
|
||||
sidebar->source_targets = gtk_content_formats_add_text_targets (sidebar->source_targets);
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_mime_type (builder, "DND_GTK_SIDEBAR_ROW");
|
||||
gdk_content_formats_builder_add_gtype (builder, GDK_TYPE_FILE_LIST);
|
||||
formats = gdk_content_formats_builder_free_to_formats (builder);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
|
||||
gdk_content_formats_unref (formats);
|
||||
g_signal_connect (dest, "drag-motion", G_CALLBACK (drag_motion_callback), sidebar);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop_callback), sidebar);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (drag_leave_callback), sidebar);
|
||||
gtk_widget_add_controller (sidebar->list_box, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_mime_type (builder, "DND_GTK_SIDEBAR_ROW");
|
||||
gdk_content_formats_builder_add_gtype (builder, G_TYPE_STRING);
|
||||
sidebar->source_targets = gdk_content_formats_builder_free_to_formats (builder);
|
||||
|
||||
g_signal_connect (sidebar->list_box, "drag-begin",
|
||||
G_CALLBACK (drag_begin_callback), sidebar);
|
||||
g_signal_connect (sidebar->list_box, "drag-motion",
|
||||
G_CALLBACK (drag_motion_callback), sidebar);
|
||||
g_signal_connect (sidebar->list_box, "drag-data-get",
|
||||
G_CALLBACK (drag_data_get_callback), sidebar);
|
||||
g_signal_connect (sidebar->list_box, "drag-data-received",
|
||||
G_CALLBACK (drag_data_received_callback), sidebar);
|
||||
g_signal_connect (sidebar->list_box, "drag-drop",
|
||||
G_CALLBACK (drag_drop_callback), sidebar);
|
||||
g_signal_connect (sidebar->list_box, "drag-end",
|
||||
G_CALLBACK (drag_end_callback), sidebar);
|
||||
g_signal_connect (sidebar->list_box, "drag-leave",
|
||||
G_CALLBACK (drag_leave_callback), sidebar);
|
||||
sidebar->drag_row = NULL;
|
||||
sidebar->row_placeholder = NULL;
|
||||
sidebar->dragging_over = FALSE;
|
||||
|
@ -1482,7 +1482,8 @@ gtk_popover_set_relative_to (GtkPopover *popover,
|
||||
|
||||
if (priv->relative_to)
|
||||
{
|
||||
g_signal_connect (priv->relative_to, "size-allocate", G_CALLBACK (size_changed), popover);
|
||||
g_signal_connect_object (priv->relative_to, "size-allocate",
|
||||
G_CALLBACK (size_changed), popover, 0);
|
||||
gtk_css_node_set_parent (gtk_widget_get_css_node (GTK_WIDGET (popover)),
|
||||
gtk_widget_get_css_node (relative_to));
|
||||
gtk_widget_set_parent (GTK_WIDGET (popover), relative_to);
|
||||
|
@ -90,7 +90,7 @@ gboolean _gtk_translate_keyboard_accel_state (GdkKeymap *keymap,
|
||||
gint *level,
|
||||
GdkModifierType *consumed_modifiers);
|
||||
|
||||
void gtk_propagate_event_internal (GtkWidget *widget,
|
||||
gboolean gtk_propagate_event_internal (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost);
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkadjustmentprivate.h"
|
||||
#include "gtkbindings.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkeventcontrollerscroll.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
|
544
gtk/gtksearchlistmodel.c
Normal file
544
gtk/gtksearchlistmodel.c
Normal file
@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtksearchlistmodel.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtkselectionmodel.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtksearchlistmodel
|
||||
* @Short_description: A selection model that allows incremental searching
|
||||
* @Title: GtkSearchListModel
|
||||
* @see_also: #GtkSelectionModel
|
||||
*
|
||||
* GtkSearchListModel is an implementation of the #GtkSelectionModel interface
|
||||
* that allows selecting a single element. The selected element can be determined
|
||||
* interactively via a filter.
|
||||
*/
|
||||
struct _GtkSearchListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GListModel *model;
|
||||
guint selected;
|
||||
gpointer selected_item;
|
||||
|
||||
GtkFilter *filter;
|
||||
};
|
||||
|
||||
struct _GtkSearchListModelClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_MODEL,
|
||||
PROP_FILTER,
|
||||
PROP_SELECTED,
|
||||
PROP_SELECTED_ITEM,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
static GType
|
||||
gtk_search_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (list);
|
||||
|
||||
return g_list_model_get_item_type (self->model);
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_search_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (list);
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_search_list_model_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (list);
|
||||
|
||||
return g_list_model_get_item (self->model, position);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_list_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_search_list_model_get_item_type;
|
||||
iface->get_n_items = gtk_search_list_model_get_n_items;
|
||||
iface->get_item = gtk_search_list_model_get_item;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_search_list_model_is_selected (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (model);
|
||||
|
||||
return self->selected == position;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_range,
|
||||
gboolean *selected)
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (model);
|
||||
guint n_items;
|
||||
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
|
||||
if (position >= n_items)
|
||||
{
|
||||
*start_range = position;
|
||||
*n_range = 0;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else if (self->selected == GTK_INVALID_LIST_POSITION)
|
||||
{
|
||||
*start_range = 0;
|
||||
*n_range = n_items;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else if (position < self->selected)
|
||||
{
|
||||
*start_range = 0;
|
||||
*n_range = self->selected;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else if (position > self->selected)
|
||||
{
|
||||
*start_range = self->selected + 1;
|
||||
*n_range = n_items - *start_range;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*start_range = self->selected;
|
||||
*n_range = 1;
|
||||
*selected = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_selection_model_init (GtkSelectionModelInterface *iface)
|
||||
{
|
||||
iface->is_selected = gtk_search_list_model_is_selected;
|
||||
iface->query_range = gtk_search_list_model_query_range;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkSearchListModel, gtk_search_list_model, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
|
||||
gtk_search_list_model_list_model_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SELECTION_MODEL,
|
||||
gtk_search_list_model_selection_model_init))
|
||||
|
||||
static void
|
||||
gtk_search_list_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkSearchListModel *self)
|
||||
{
|
||||
g_object_freeze_notify (G_OBJECT (self));
|
||||
|
||||
if (self->selected_item == NULL)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
else if (self->selected < position)
|
||||
{
|
||||
/* unchanged */
|
||||
}
|
||||
else if (self->selected >= position + removed)
|
||||
{
|
||||
self->selected += added - removed;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
|
||||
}
|
||||
else
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < added; i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (model, position + i);
|
||||
if (item == self->selected_item)
|
||||
{
|
||||
/* the item moved */
|
||||
//TODO refilter
|
||||
if (self->selected != position + i)
|
||||
{
|
||||
self->selected = position + i;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == added)
|
||||
{
|
||||
/* the item really was deleted */
|
||||
g_clear_object (&self->selected_item);
|
||||
self->selected = GTK_INVALID_LIST_POSITION;
|
||||
//TODO refilter
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (self));
|
||||
}
|
||||
|
||||
static void
|
||||
set_selected (GtkSearchListModel *self,
|
||||
guint position)
|
||||
{
|
||||
gpointer new_selected = NULL;
|
||||
guint old_position;
|
||||
|
||||
if (self->selected == position)
|
||||
return;
|
||||
|
||||
new_selected = g_list_model_get_item (self->model, position);
|
||||
|
||||
if (new_selected == NULL)
|
||||
position = GTK_INVALID_LIST_POSITION;
|
||||
|
||||
if (self->selected == position)
|
||||
return;
|
||||
|
||||
old_position = self->selected;
|
||||
self->selected = position;
|
||||
g_clear_object (&self->selected_item);
|
||||
self->selected_item = new_selected;
|
||||
|
||||
if (old_position == GTK_INVALID_LIST_POSITION)
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), position, 1);
|
||||
else if (position == GTK_INVALID_LIST_POSITION)
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), old_position, 1);
|
||||
else if (position < old_position)
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), position, old_position - position + 1);
|
||||
else
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), old_position, position - old_position + 1);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_item (GtkSearchListModel *self,
|
||||
guint position)
|
||||
{
|
||||
gpointer item;
|
||||
gboolean result;
|
||||
|
||||
item = g_list_model_get_item (self->model, position);
|
||||
result = gtk_filter_match (self->filter, item);
|
||||
g_object_unref (item);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static guint
|
||||
find_next_match (GtkSearchListModel *self,
|
||||
guint position,
|
||||
gboolean forward)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (position == GTK_INVALID_LIST_POSITION)
|
||||
position = 0;
|
||||
|
||||
g_print ("search %s from %u\n", forward ? "forward" : "backward", position);
|
||||
if (forward)
|
||||
for (i = position; i < g_list_model_get_n_items (self->model); i++)
|
||||
{
|
||||
if (match_item (self, i))
|
||||
return i;
|
||||
}
|
||||
else
|
||||
for (i = position; ; i--)
|
||||
{
|
||||
if (match_item (self, i))
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return GTK_INVALID_LIST_POSITION;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_filter_changed_cb (GtkFilter *filter,
|
||||
GtkFilterChange change,
|
||||
GtkSearchListModel *self)
|
||||
{
|
||||
guint position;
|
||||
|
||||
g_print ("filter changed: change %d, strictness %d\n", change, gtk_filter_get_strictness (self->filter));
|
||||
|
||||
if (gtk_filter_get_strictness (self->filter) == GTK_FILTER_MATCH_NONE)
|
||||
position = GTK_INVALID_LIST_POSITION;
|
||||
else
|
||||
switch (change)
|
||||
{
|
||||
case GTK_FILTER_CHANGE_DIFFERENT:
|
||||
case GTK_FILTER_CHANGE_LESS_STRICT:
|
||||
position = find_next_match (self, 0, TRUE);
|
||||
break;
|
||||
case GTK_FILTER_CHANGE_MORE_STRICT:
|
||||
position = find_next_match (self, self->selected, TRUE);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
g_print ("select %u\n", position);
|
||||
set_selected (self, position);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_clear_model (GtkSearchListModel *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model,
|
||||
gtk_search_list_model_items_changed_cb,
|
||||
self);
|
||||
g_clear_object (&self->model);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_clear_filter (GtkSearchListModel *self)
|
||||
{
|
||||
if (self->filter == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->filter,
|
||||
gtk_search_list_model_filter_changed_cb,
|
||||
self);
|
||||
|
||||
g_clear_object (&self->filter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
self->model = g_value_dup_object (value);
|
||||
g_signal_connect (self->model, "items-changed",
|
||||
G_CALLBACK (gtk_search_list_model_items_changed_cb), self);
|
||||
break;
|
||||
|
||||
case PROP_FILTER:
|
||||
self->filter = g_value_dup_object (value);
|
||||
g_signal_connect (self->filter, "changed",
|
||||
G_CALLBACK (gtk_search_list_model_filter_changed_cb), self);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_FILTER:
|
||||
g_value_set_object (value, self->filter);
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
g_value_set_uint (value, self->selected);
|
||||
break;
|
||||
|
||||
case PROP_SELECTED_ITEM:
|
||||
g_value_set_object (value, self->selected_item);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_dispose (GObject *object)
|
||||
{
|
||||
GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (object);
|
||||
|
||||
gtk_search_list_model_clear_model (self);
|
||||
gtk_search_list_model_clear_filter (self);
|
||||
|
||||
self->selected = GTK_INVALID_LIST_POSITION;
|
||||
g_clear_object (&self->selected_item);
|
||||
|
||||
G_OBJECT_CLASS (gtk_search_list_model_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_class_init (GtkSearchListModelClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = gtk_search_list_model_get_property;
|
||||
gobject_class->set_property = gtk_search_list_model_set_property;
|
||||
gobject_class->dispose = gtk_search_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkSearchListModel:selected:
|
||||
*
|
||||
* Position of the selected item
|
||||
*/
|
||||
properties[PROP_SELECTED] =
|
||||
g_param_spec_uint ("selected",
|
||||
P_("Selected"),
|
||||
P_("Position of the selected item"),
|
||||
0, G_MAXUINT, GTK_INVALID_LIST_POSITION,
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkSearchListModel:selected-item:
|
||||
*
|
||||
* The selected item
|
||||
*/
|
||||
properties[PROP_SELECTED_ITEM] =
|
||||
g_param_spec_object ("selected-item",
|
||||
P_("Selected Item"),
|
||||
P_("The selected item"),
|
||||
G_TYPE_OBJECT,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkSearchListModel:model:
|
||||
*
|
||||
* The model being managed
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("The model"),
|
||||
P_("The model being managed"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkSearchListModel:filter:
|
||||
*
|
||||
* The filter determining the selected item
|
||||
*/
|
||||
properties[PROP_FILTER] =
|
||||
g_param_spec_object ("filter",
|
||||
P_("The filter"),
|
||||
P_("The filter being used"),
|
||||
GTK_TYPE_FILTER,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_search_list_model_init (GtkSearchListModel *self)
|
||||
{
|
||||
self->selected = GTK_INVALID_LIST_POSITION;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_search_list_model_new:
|
||||
* @model: (transfer none): the #GListModel to manage
|
||||
* @filter: (transfer none): the #GtkFilter to use
|
||||
*
|
||||
* Creates a new selection to handle @model.
|
||||
*
|
||||
* Returns: (transfer full) (type GtkSearchListModel): a new #GtkSearchListModel
|
||||
**/
|
||||
GtkSearchListModel *
|
||||
gtk_search_list_model_new (GListModel *model,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SEARCH_LIST_MODEL,
|
||||
"model", model,
|
||||
"filter", filter,
|
||||
NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_search_list_model_next_match (GtkSearchListModel *self)
|
||||
{
|
||||
guint position;
|
||||
|
||||
position = find_next_match (self, self->selected, TRUE);
|
||||
if (position == GTK_INVALID_LIST_POSITION)
|
||||
return FALSE;
|
||||
|
||||
set_selected (self, position);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_search_list_model_previous_match (GtkSearchListModel *self)
|
||||
{
|
||||
guint position;
|
||||
|
||||
position = find_next_match (self, self->selected, FALSE);
|
||||
if (position == GTK_INVALID_LIST_POSITION)
|
||||
return FALSE;
|
||||
|
||||
set_selected (self, position);
|
||||
|
||||
return TRUE;
|
||||
}
|
50
gtk/gtksearchlistmodel.h
Normal file
50
gtk/gtksearchlistmodel.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* 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.1 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/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SEARCH_LIST_MODEL_H__
|
||||
#define __GTK_SEARCH_LIST_MODEL_H__
|
||||
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtkfilter.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_SEARCH_LIST_MODEL (gtk_search_list_model_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkSearchListModel, gtk_search_list_model, GTK, SEARCH_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSearchListModel * gtk_search_list_model_new (GListModel *model,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_search_list_model_next_match (GtkSearchListModel *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_search_list_model_previous_match (GtkSearchListModel *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SEARCH_LIST_MODEL_H__ */
|
@ -143,130 +143,6 @@ init_atoms (void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_content_formats_add_text_targets:
|
||||
* @list: a #GdkContentFormats
|
||||
*
|
||||
* Appends the text targets supported by #GtkSelectionData to
|
||||
* the target list. All targets are added with the same @info.
|
||||
**/
|
||||
GdkContentFormats *
|
||||
gtk_content_formats_add_text_targets (GdkContentFormats *list)
|
||||
{
|
||||
GdkContentFormatsBuilder *builder;
|
||||
|
||||
g_return_val_if_fail (list != NULL, NULL);
|
||||
|
||||
init_atoms ();
|
||||
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_formats (builder, list);
|
||||
gdk_content_formats_unref (list);
|
||||
|
||||
/* Keep in sync with gtk_selection_data_targets_include_text()
|
||||
*/
|
||||
gdk_content_formats_builder_add_mime_type (builder, utf8_atom);
|
||||
gdk_content_formats_builder_add_mime_type (builder, ctext_atom);
|
||||
gdk_content_formats_builder_add_mime_type (builder, text_atom);
|
||||
gdk_content_formats_builder_add_mime_type (builder, g_intern_static_string ("STRING"));
|
||||
gdk_content_formats_builder_add_mime_type (builder, text_plain_utf8_atom);
|
||||
if (!g_get_charset (NULL))
|
||||
gdk_content_formats_builder_add_mime_type (builder, text_plain_locale_atom);
|
||||
gdk_content_formats_builder_add_mime_type (builder, text_plain_atom);
|
||||
|
||||
return gdk_content_formats_builder_free_to_formats (builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_content_formats_add_image_targets:
|
||||
* @list: a #GdkContentFormats
|
||||
* @writable: whether to add only targets for which GTK+ knows
|
||||
* how to convert a pixbuf into the format
|
||||
*
|
||||
* Appends the image targets supported by #GtkSelectionData to
|
||||
* the target list. All targets are added with the same @info.
|
||||
**/
|
||||
GdkContentFormats *
|
||||
gtk_content_formats_add_image_targets (GdkContentFormats *list,
|
||||
gboolean writable)
|
||||
{
|
||||
GdkContentFormatsBuilder *builder;
|
||||
GSList *formats, *f;
|
||||
gchar **mimes, **m;
|
||||
|
||||
g_return_val_if_fail (list != NULL, NULL);
|
||||
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_formats (builder, list);
|
||||
gdk_content_formats_unref (list);
|
||||
|
||||
formats = gdk_pixbuf_get_formats ();
|
||||
|
||||
/* Make sure png comes first */
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
gchar *name;
|
||||
|
||||
name = gdk_pixbuf_format_get_name (fmt);
|
||||
if (strcmp (name, "png") == 0)
|
||||
{
|
||||
formats = g_slist_delete_link (formats, f);
|
||||
formats = g_slist_prepend (formats, fmt);
|
||||
|
||||
g_free (name);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
|
||||
if (writable && !gdk_pixbuf_format_is_writable (fmt))
|
||||
continue;
|
||||
|
||||
mimes = gdk_pixbuf_format_get_mime_types (fmt);
|
||||
for (m = mimes; *m; m++)
|
||||
{
|
||||
gdk_content_formats_builder_add_mime_type (builder, *m);
|
||||
}
|
||||
g_strfreev (mimes);
|
||||
}
|
||||
|
||||
g_slist_free (formats);
|
||||
|
||||
return gdk_content_formats_builder_free_to_formats (builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_content_formats_add_uri_targets:
|
||||
* @list: a #GdkContentFormats
|
||||
*
|
||||
* Appends the URI targets supported by #GtkSelectionData to
|
||||
* the target list. All targets are added with the same @info.
|
||||
**/
|
||||
GdkContentFormats *
|
||||
gtk_content_formats_add_uri_targets (GdkContentFormats *list)
|
||||
{
|
||||
GdkContentFormatsBuilder *builder;
|
||||
|
||||
g_return_val_if_fail (list != NULL, NULL);
|
||||
|
||||
init_atoms ();
|
||||
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_formats (builder, list);
|
||||
gdk_content_formats_unref (list);
|
||||
|
||||
gdk_content_formats_builder_add_mime_type (builder, text_uri_list_atom);
|
||||
|
||||
return gdk_content_formats_builder_free_to_formats (builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_data_get_target:
|
||||
* @selection_data: a pointer to a #GtkSelectionData-struct.
|
||||
@ -1158,8 +1034,11 @@ gtk_targets_include_image (GdkAtom *targets,
|
||||
|
||||
g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
|
||||
|
||||
list = gdk_content_formats_new (NULL, 0);
|
||||
list = gtk_content_formats_add_image_targets (list, writable);
|
||||
list = gdk_content_formats_new_for_gtype (GDK_TYPE_TEXTURE);
|
||||
if (writable)
|
||||
list = gdk_content_formats_union_serialize_mime_types (list);
|
||||
else
|
||||
list = gdk_content_formats_union_deserialize_mime_types (list);
|
||||
for (i = 0; i < n_targets && !result; i++)
|
||||
{
|
||||
if (gdk_content_formats_contain_mime_type (list, targets[i]))
|
||||
|
@ -36,13 +36,6 @@ G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_SELECTION_DATA (gtk_selection_data_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentFormats * gtk_content_formats_add_text_targets (GdkContentFormats *list) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentFormats * gtk_content_formats_add_image_targets (GdkContentFormats *list,
|
||||
gboolean writable) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentFormats * gtk_content_formats_add_uri_targets (GdkContentFormats *list) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkAtom gtk_selection_data_get_target (const GtkSelectionData *selection_data);
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "gtkstackswitcher.h"
|
||||
|
||||
#include "gtkboxlayout.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkimage.h"
|
||||
#include "gtkintl.h"
|
||||
@ -93,6 +92,19 @@ enum {
|
||||
PROP_STACK
|
||||
};
|
||||
|
||||
static void gtk_stack_switcher_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkStackSwitcher *self);
|
||||
static gboolean gtk_stack_switcher_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkStackSwitcher *self);
|
||||
static void gtk_stack_switcher_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkStackSwitcher *self);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkStackSwitcher, gtk_stack_switcher, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
@ -100,14 +112,21 @@ gtk_stack_switcher_init (GtkStackSwitcher *switcher)
|
||||
{
|
||||
GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (switcher);
|
||||
GtkStyleContext *context;
|
||||
GdkContentFormats *formats;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
priv->buttons = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (switcher));
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_LINKED);
|
||||
|
||||
gtk_drag_dest_set (GTK_WIDGET (switcher), 0, NULL, 0);
|
||||
gtk_drag_dest_set_track_motion (GTK_WIDGET (switcher), TRUE);
|
||||
formats = gdk_content_formats_new (NULL, 0);
|
||||
dest = gtk_drop_target_new (formats, 0);
|
||||
gdk_content_formats_unref (formats);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_stack_switcher_drag_leave), switcher);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (gtk_stack_switcher_drag_accept), switcher);
|
||||
g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_stack_switcher_drag_motion), switcher);
|
||||
gtk_widget_add_controller (GTK_WIDGET (switcher), GTK_EVENT_CONTROLLER (dest));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -249,17 +268,24 @@ gtk_stack_switcher_switch_timeout (gpointer data)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_stack_switcher_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
gtk_stack_switcher_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkStackSwitcher *self)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_stack_switcher_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkStackSwitcher *self)
|
||||
{
|
||||
GtkStackSwitcher *self = GTK_STACK_SWITCHER (widget);
|
||||
GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (self);
|
||||
GtkWidget *button;
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
button = NULL;
|
||||
g_hash_table_iter_init (&iter, priv->buttons);
|
||||
@ -270,7 +296,6 @@ gtk_stack_switcher_drag_motion (GtkWidget *widget,
|
||||
if (gtk_widget_contains (GTK_WIDGET (value), cx, cy))
|
||||
{
|
||||
button = GTK_WIDGET (value);
|
||||
retval = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -287,16 +312,13 @@ gtk_stack_switcher_drag_motion (GtkWidget *widget,
|
||||
self);
|
||||
g_source_set_name_by_id (priv->switch_timer, "[gtk] gtk_stack_switcher_switch_timeout");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_stack_switcher_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
gtk_stack_switcher_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkStackSwitcher *self)
|
||||
{
|
||||
GtkStackSwitcher *self = GTK_STACK_SWITCHER (widget);
|
||||
|
||||
remove_switch_timer (self);
|
||||
}
|
||||
|
||||
@ -562,9 +584,6 @@ gtk_stack_switcher_class_init (GtkStackSwitcherClass *class)
|
||||
object_class->dispose = gtk_stack_switcher_dispose;
|
||||
object_class->finalize = gtk_stack_switcher_finalize;
|
||||
|
||||
widget_class->drag_motion = gtk_stack_switcher_drag_motion;
|
||||
widget_class->drag_leave = gtk_stack_switcher_drag_leave;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_STACK,
|
||||
g_param_spec_object ("stack",
|
||||
|
333
gtk/gtktext.c
333
gtk/gtktext.c
@ -30,8 +30,6 @@
|
||||
#include "gtkbutton.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdndprivate.h"
|
||||
#include "gtkeditable.h"
|
||||
#include "gtkemojichooser.h"
|
||||
#include "gtkemojicompletion.h"
|
||||
@ -67,6 +65,9 @@
|
||||
#include "gtkwindow.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkactionmuxerprivate.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdragicon.h"
|
||||
|
||||
#include "a11y/gtktextaccessible.h"
|
||||
|
||||
@ -179,6 +180,8 @@ struct _GtkTextPrivate
|
||||
|
||||
GtkTextHistory *history;
|
||||
|
||||
GdkDrag *drag;
|
||||
|
||||
float xalign;
|
||||
|
||||
int ascent; /* font ascent in pango units */
|
||||
@ -331,28 +334,22 @@ static void gtk_text_state_flags_changed (GtkWidget *widget,
|
||||
GtkStateFlags previous_state);
|
||||
static void gtk_text_root (GtkWidget *widget);
|
||||
|
||||
static gboolean gtk_text_drag_drop (GtkWidget *widget,
|
||||
static gboolean gtk_text_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y);
|
||||
static gboolean gtk_text_drag_motion (GtkWidget *widget,
|
||||
int y,
|
||||
GtkText *text);
|
||||
static gboolean gtk_text_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkText *self);
|
||||
static void gtk_text_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y);
|
||||
static void gtk_text_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
static void gtk_text_drag_data_received (GtkWidget *widget,
|
||||
int y,
|
||||
GtkText *text);
|
||||
static void gtk_text_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data);
|
||||
static void gtk_text_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data);
|
||||
static void gtk_text_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_text_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_text_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
GtkText *text);
|
||||
|
||||
|
||||
/* GtkEditable method implementations
|
||||
@ -729,19 +726,11 @@ gtk_text_class_init (GtkTextClass *class)
|
||||
widget_class->snapshot = gtk_text_snapshot;
|
||||
widget_class->grab_focus = gtk_text_grab_focus;
|
||||
widget_class->style_updated = gtk_text_style_updated;
|
||||
widget_class->drag_begin = gtk_text_drag_begin;
|
||||
widget_class->drag_end = gtk_text_drag_end;
|
||||
widget_class->direction_changed = gtk_text_direction_changed;
|
||||
widget_class->state_flags_changed = gtk_text_state_flags_changed;
|
||||
widget_class->root = gtk_text_root;
|
||||
widget_class->mnemonic_activate = gtk_text_mnemonic_activate;
|
||||
widget_class->popup_menu = gtk_text_popup_menu;
|
||||
widget_class->drag_drop = gtk_text_drag_drop;
|
||||
widget_class->drag_motion = gtk_text_drag_motion;
|
||||
widget_class->drag_leave = gtk_text_drag_leave;
|
||||
widget_class->drag_data_received = gtk_text_drag_data_received;
|
||||
widget_class->drag_data_get = gtk_text_drag_data_get;
|
||||
widget_class->drag_data_delete = gtk_text_drag_data_delete;
|
||||
|
||||
class->move_cursor = gtk_text_move_cursor;
|
||||
class->insert_at_cursor = gtk_text_insert_at_cursor;
|
||||
@ -1722,6 +1711,8 @@ gtk_text_init (GtkText *self)
|
||||
GtkGesture *gesture;
|
||||
GtkEventController *controller;
|
||||
int i;
|
||||
GtkDropTarget *dest;
|
||||
GdkContentFormats *formats;
|
||||
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
|
||||
gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
|
||||
@ -1742,9 +1733,14 @@ gtk_text_init (GtkText *self)
|
||||
priv->selection_content = g_object_new (GTK_TYPE_TEXT_CONTENT, NULL);
|
||||
GTK_TEXT_CONTENT (priv->selection_content)->self = self;
|
||||
|
||||
gtk_drag_dest_set (GTK_WIDGET (self), 0, NULL,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
gtk_drag_dest_add_text_targets (GTK_WIDGET (self));
|
||||
formats = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (gtk_text_drag_accept), self);
|
||||
g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_drag_motion), self);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_drag_leave), self);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_drag_drop), self);
|
||||
gdk_content_formats_unref (formats);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
/* This object is completely private. No external entity can gain a reference
|
||||
* to it; so we create it here and destroy it in finalize().
|
||||
@ -2803,6 +2799,18 @@ gtk_text_motion_controller_motion (GtkEventControllerMotion *controller,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dnd_finished_cb (GdkDrag *drag,
|
||||
GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
if (gdk_drag_get_selected_action (drag) == GDK_ACTION_MOVE)
|
||||
gtk_text_delete_selection (self);
|
||||
|
||||
priv->drag = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
double offset_x,
|
||||
@ -2839,23 +2847,48 @@ gtk_text_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
{
|
||||
int *ranges;
|
||||
int n_ranges;
|
||||
GdkContentFormats *target_list = gdk_content_formats_new (NULL, 0);
|
||||
guint actions = priv->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
|
||||
|
||||
target_list = gtk_content_formats_add_text_targets (target_list);
|
||||
char *text;
|
||||
GdkDragAction actions;
|
||||
GdkDrag *drag;
|
||||
GdkPaintable *paintable;
|
||||
GdkContentProvider *content;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
text = _gtk_text_get_selected_text (self);
|
||||
gtk_text_get_pixel_ranges (self, &ranges, &n_ranges);
|
||||
|
||||
gtk_drag_begin (widget,
|
||||
gdk_event_get_device ((GdkEvent*) event),
|
||||
target_list, actions,
|
||||
priv->drag_start_x + ranges[0],
|
||||
priv->drag_start_y);
|
||||
if (priv->editable)
|
||||
actions = GDK_ACTION_COPY|GDK_ACTION_MOVE;
|
||||
else
|
||||
actions = GDK_ACTION_COPY;
|
||||
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
g_value_set_string (&value, text);
|
||||
content = gdk_content_provider_new_for_value (&value);
|
||||
g_value_unset (&value);
|
||||
|
||||
drag = gdk_drag_begin (gdk_event_get_surface ((GdkEvent*) event),
|
||||
gdk_event_get_device ((GdkEvent*) event),
|
||||
content,
|
||||
actions,
|
||||
priv->drag_start_x,
|
||||
priv->drag_start_y);
|
||||
g_object_unref (content);
|
||||
|
||||
g_signal_connect (drag, "dnd-finished", G_CALLBACK (dnd_finished_cb), self);
|
||||
|
||||
paintable = gtk_text_util_create_drag_icon (widget, text, -1);
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, ranges[0], 0);
|
||||
g_clear_object (&paintable);
|
||||
|
||||
priv->drag = drag;
|
||||
|
||||
g_object_unref (drag);
|
||||
|
||||
g_free (ranges);
|
||||
g_free (text);
|
||||
|
||||
priv->in_drag = FALSE;
|
||||
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -6097,137 +6130,28 @@ gtk_text_selection_bubble_popup_set (GtkText *self)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
gtk_text_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkText *self)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
char *text;
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
|
||||
text = _gtk_text_get_selected_text (self);
|
||||
|
||||
if (self)
|
||||
{
|
||||
int *ranges, n_ranges;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
paintable = gtk_text_util_create_drag_icon (widget, text, -1);
|
||||
gtk_text_get_pixel_ranges (self, &ranges, &n_ranges);
|
||||
|
||||
gtk_drag_set_icon_paintable (drag,
|
||||
paintable,
|
||||
priv->drag_start_x - ranges[0],
|
||||
priv->drag_start_y);
|
||||
|
||||
g_free (ranges);
|
||||
g_object_unref (paintable);
|
||||
g_free (text);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
gtk_drag_unhighlight (widget);
|
||||
priv->dnd_position = -1;
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GdkAtom target = NULL;
|
||||
|
||||
if (priv->editable)
|
||||
target = gtk_drag_dest_find_target (widget, drop, NULL);
|
||||
|
||||
if (target != NULL)
|
||||
{
|
||||
priv->drop_position = gtk_text_find_position (self, x + priv->scroll_offset);
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
}
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GdkDragAction suggested_action;
|
||||
int new_position, old_position;
|
||||
|
||||
old_position = priv->dnd_position;
|
||||
new_position = gtk_text_find_position (self, x + priv->scroll_offset);
|
||||
|
||||
if (priv->editable &&
|
||||
gtk_drag_dest_find_target (widget, drop, NULL) != NULL)
|
||||
{
|
||||
suggested_action = GDK_ACTION_COPY | GDK_ACTION_MOVE;
|
||||
|
||||
if (priv->selection_bound == priv->current_pos ||
|
||||
new_position < priv->selection_bound ||
|
||||
new_position > priv->current_pos)
|
||||
{
|
||||
priv->dnd_position = new_position;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->dnd_position = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Entry not editable, or no text */
|
||||
suggested_action = 0;
|
||||
priv->dnd_position = -1;
|
||||
}
|
||||
|
||||
gdk_drop_status (drop, suggested_action);
|
||||
if (suggested_action == 0)
|
||||
gtk_drag_unhighlight (widget);
|
||||
else
|
||||
gtk_drag_highlight (widget);
|
||||
|
||||
if (priv->dnd_position != old_position)
|
||||
gtk_widget_queue_draw (widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GdkDragAction
|
||||
gtk_text_get_action (GtkText *self,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
GtkWidget *source_widget = gtk_drag_get_source_widget (drag);
|
||||
GdkDragAction actions;
|
||||
|
||||
actions = gdk_drop_get_actions (drop);
|
||||
|
||||
if (source_widget == widget &&
|
||||
if (drag == priv->drag &&
|
||||
actions & GDK_ACTION_MOVE)
|
||||
return GDK_ACTION_MOVE;
|
||||
|
||||
@ -6241,19 +6165,20 @@ gtk_text_get_action (GtkText *self,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
got_text (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GtkText *self = GTK_TEXT (data);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GdkDragAction action;
|
||||
char *str;
|
||||
GdkDragAction action;
|
||||
|
||||
str = (char *) gtk_selection_data_get_text (selection_data);
|
||||
str = gdk_drop_read_text_finish (drop, result, NULL);
|
||||
action = gtk_text_get_action (self, drop);
|
||||
|
||||
if (action && str && priv->editable)
|
||||
if (action && str)
|
||||
{
|
||||
int length = -1;
|
||||
int pos;
|
||||
@ -6288,34 +6213,84 @@ gtk_text_drag_data_received (GtkWidget *widget,
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data)
|
||||
static gboolean
|
||||
gtk_text_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkText *self)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
if (priv->selection_bound != priv->current_pos)
|
||||
if (priv->editable && gdk_drop_has_value (drop, G_TYPE_STRING))
|
||||
{
|
||||
char *str = gtk_text_get_display_text (self, priv->selection_bound, priv->current_pos);
|
||||
|
||||
gtk_selection_data_set_text (selection_data, str, -1);
|
||||
|
||||
g_free (str);
|
||||
priv->drop_position = gtk_text_find_position (self, x + priv->scroll_offset);
|
||||
gdk_drop_read_text_async (drop, NULL, got_text, self);
|
||||
}
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_drag_accept (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GdkDragAction suggested_action;
|
||||
|
||||
if (priv->editable &&
|
||||
gtk_drop_target_find_mimetype (dest) != NULL)
|
||||
{
|
||||
suggested_action = GDK_ACTION_COPY | GDK_ACTION_MOVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Entry not editable, or no text */
|
||||
suggested_action = 0;
|
||||
}
|
||||
|
||||
gdk_drop_status (drop, suggested_action);
|
||||
return suggested_action != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
gtk_text_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkText *self)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
int new_position, old_position;
|
||||
|
||||
old_position = priv->dnd_position;
|
||||
new_position = gtk_text_find_position (self, x + priv->scroll_offset);
|
||||
|
||||
if (priv->editable &&
|
||||
priv->selection_bound != priv->current_pos)
|
||||
gtk_text_delete_selection (self);
|
||||
gtk_drop_target_find_mimetype (dest) != NULL)
|
||||
{
|
||||
if (priv->selection_bound == priv->current_pos ||
|
||||
new_position < priv->selection_bound ||
|
||||
new_position > priv->current_pos)
|
||||
{
|
||||
priv->dnd_position = new_position;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->dnd_position = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Entry not editable, or no text */
|
||||
priv->dnd_position = -1;
|
||||
}
|
||||
|
||||
if (priv->dnd_position != old_position)
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
/* We display the cursor when
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtktextbuffer.h"
|
||||
#include "gtktexthistoryprivate.h"
|
||||
@ -4078,6 +4077,13 @@ cut_or_copy (GtkTextBuffer *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
GdkContentProvider *
|
||||
gtk_text_buffer_get_selection_content (GtkTextBuffer *buffer)
|
||||
{
|
||||
return gtk_text_buffer_content_new (buffer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_cut_clipboard:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
|
@ -453,6 +453,10 @@ gboolean gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
|
||||
gboolean interactive,
|
||||
gboolean default_editable);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkContentProvider *
|
||||
gtk_text_buffer_get_selection_content (GtkTextBuffer *buffer);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_text_buffer_get_can_undo (GtkTextBuffer *buffer);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#include "gtktextbuffer.h"
|
||||
|
||||
/* This is a private uninstalled header shared between
|
||||
* GtkTextView and GtkEntry
|
||||
*/
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
#include "gtkadjustmentprivate.h"
|
||||
#include "gtkbindings.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
@ -233,6 +232,8 @@ struct _GtkTextViewPrivate
|
||||
|
||||
GtkCssNode *selection_node;
|
||||
|
||||
GdkDrag *drag;
|
||||
|
||||
/* Default style settings */
|
||||
gint pixels_above_lines;
|
||||
gint pixels_below_lines;
|
||||
@ -418,31 +419,20 @@ static gboolean get_middle_click_paste (GtkTextView *text_view);
|
||||
|
||||
static GtkTextBuffer* gtk_text_view_create_buffer (GtkTextView *text_view);
|
||||
|
||||
/* Source side drag signals */
|
||||
static void gtk_text_view_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_text_view_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_text_view_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data);
|
||||
static void gtk_text_view_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
|
||||
/* Target side drag signals */
|
||||
static void gtk_text_view_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
static gboolean gtk_text_view_drag_motion (GtkWidget *widget,
|
||||
static void gtk_text_view_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static gboolean gtk_text_view_drag_drop (GtkWidget *widget,
|
||||
GtkTextView *text_view);
|
||||
static gboolean gtk_text_view_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gtk_text_view_drag_data_received (GtkWidget *widget,
|
||||
int x,
|
||||
int y,
|
||||
GtkTextView *text_view);
|
||||
static gboolean gtk_text_view_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data);
|
||||
int x,
|
||||
int y,
|
||||
GtkTextView *text_view);
|
||||
|
||||
static gboolean gtk_text_view_popup_menu (GtkWidget *widget);
|
||||
static void gtk_text_view_move_cursor (GtkTextView *text_view,
|
||||
@ -712,15 +702,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
|
||||
widget_class->size_allocate = gtk_text_view_size_allocate;
|
||||
widget_class->snapshot = gtk_text_view_snapshot;
|
||||
widget_class->focus = gtk_text_view_focus;
|
||||
widget_class->drag_begin = gtk_text_view_drag_begin;
|
||||
widget_class->drag_end = gtk_text_view_drag_end;
|
||||
widget_class->drag_data_get = gtk_text_view_drag_data_get;
|
||||
widget_class->drag_data_delete = gtk_text_view_drag_data_delete;
|
||||
|
||||
widget_class->drag_leave = gtk_text_view_drag_leave;
|
||||
widget_class->drag_motion = gtk_text_view_drag_motion;
|
||||
widget_class->drag_drop = gtk_text_view_drag_drop;
|
||||
widget_class->drag_data_received = gtk_text_view_drag_data_received;
|
||||
|
||||
widget_class->popup_menu = gtk_text_view_popup_menu;
|
||||
|
||||
@ -1623,7 +1604,8 @@ static void
|
||||
gtk_text_view_init (GtkTextView *text_view)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (text_view);
|
||||
GdkContentFormats *target_list;
|
||||
GdkContentFormats *formats;
|
||||
GtkDropTarget *dest;
|
||||
GtkTextViewPrivate *priv;
|
||||
GtkStyleContext *context;
|
||||
GtkEventController *controller;
|
||||
@ -1652,12 +1634,13 @@ gtk_text_view_init (GtkTextView *text_view)
|
||||
|
||||
priv->scroll_after_paste = FALSE;
|
||||
|
||||
gtk_drag_dest_set (widget, 0, NULL,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
|
||||
target_list = gdk_content_formats_new_for_gtype (GTK_TYPE_TEXT_BUFFER);
|
||||
gtk_drag_dest_set_target_list (widget, target_list);
|
||||
gdk_content_formats_unref (target_list);
|
||||
formats = gdk_content_formats_new_for_gtype (GTK_TYPE_TEXT_BUFFER);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
gdk_content_formats_unref (formats);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_view_drag_leave), text_view);
|
||||
g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_view_drag_motion), text_view);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_view_drag_drop), text_view);
|
||||
gtk_widget_add_controller (GTK_WIDGET (text_view), GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
priv->virtual_cursor_x = -1;
|
||||
priv->virtual_cursor_y = -1;
|
||||
@ -6698,8 +6681,7 @@ gtk_text_view_copy_clipboard (GtkTextView *text_view)
|
||||
{
|
||||
GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view));
|
||||
|
||||
gtk_text_buffer_copy_clipboard (get_buffer (text_view),
|
||||
clipboard);
|
||||
gtk_text_buffer_copy_clipboard (get_buffer (text_view), clipboard);
|
||||
|
||||
/* on copy do not scroll, we are already onscreen */
|
||||
}
|
||||
@ -6933,9 +6915,7 @@ drag_scan_timeout (gpointer data)
|
||||
priv->dnd_x + priv->xoffset,
|
||||
priv->dnd_y + priv->yoffset);
|
||||
|
||||
gtk_text_buffer_move_mark (get_buffer (text_view),
|
||||
priv->dnd_mark,
|
||||
&newplace);
|
||||
gtk_text_buffer_move_mark (get_buffer (text_view), priv->dnd_mark, &newplace);
|
||||
|
||||
pointer_xoffset = (gdouble) priv->dnd_x / text_window_get_width (priv->text_window);
|
||||
pointer_yoffset = (gdouble) priv->dnd_y / text_window_get_height (priv->text_window);
|
||||
@ -7691,30 +7671,13 @@ gtk_text_view_im_context_filter_keypress (GtkTextView *text_view,
|
||||
*/
|
||||
|
||||
static void
|
||||
drag_begin_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
dnd_finished_cb (GdkDrag *drag,
|
||||
GtkTextView *self)
|
||||
{
|
||||
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
GdkPaintable *paintable = NULL;
|
||||
if (gdk_drag_get_selected_action (drag) == GDK_ACTION_MOVE)
|
||||
gtk_text_buffer_delete_selection (self->priv->buffer, TRUE, self->priv->editable);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
paintable = gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
|
||||
|
||||
if (paintable)
|
||||
{
|
||||
gtk_drag_set_icon_paintable (drag, paintable, 0, 0);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_drag_set_icon_default (drag);
|
||||
}
|
||||
self->priv->drag = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -7724,89 +7687,48 @@ gtk_text_view_start_selection_dnd (GtkTextView *text_view,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GdkContentFormats *formats;
|
||||
|
||||
formats = gdk_content_formats_new_for_gtype (GTK_TYPE_TEXT_BUFFER);
|
||||
|
||||
g_signal_connect (text_view, "drag-begin",
|
||||
G_CALLBACK (drag_begin_cb), NULL);
|
||||
gtk_drag_begin (GTK_WIDGET (text_view),
|
||||
gdk_event_get_device (event),
|
||||
formats,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE,
|
||||
x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
GtkTextView *text_view;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (widget);
|
||||
text_view->priv->dnd_x = text_view->priv->dnd_y = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
|
||||
GtkWidget *widget = GTK_WIDGET (text_view);
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
|
||||
GdkContentProvider *content;
|
||||
GtkTextIter start, end;
|
||||
GdkDragAction actions;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
GdkDrag *drag;
|
||||
|
||||
if (gtk_selection_data_get_target (selection_data) == g_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
{
|
||||
gtk_selection_data_set (selection_data,
|
||||
g_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
|
||||
8, /* bytes */
|
||||
(void*)&buffer,
|
||||
sizeof (buffer));
|
||||
}
|
||||
if (text_view->priv->editable)
|
||||
actions = GDK_ACTION_COPY | GDK_ACTION_MOVE;
|
||||
else
|
||||
actions = GDK_ACTION_COPY;
|
||||
|
||||
content = gtk_text_buffer_get_selection_content (buffer);
|
||||
|
||||
surface = gdk_event_get_surface (event);
|
||||
device = gdk_event_get_device (event);
|
||||
drag = gdk_drag_begin (surface, device, content, actions, x, y);
|
||||
g_object_unref (content);
|
||||
|
||||
g_signal_connect (drag, "dnd-finished", G_CALLBACK (dnd_finished_cb), text_view);
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
{
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
gchar *str = NULL;
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
{
|
||||
/* Extract the selected text */
|
||||
str = gtk_text_iter_get_visible_text (&start, &end);
|
||||
}
|
||||
|
||||
if (str)
|
||||
{
|
||||
gtk_selection_data_set_text (selection_data, str, -1);
|
||||
g_free (str);
|
||||
}
|
||||
GdkPaintable *paintable;
|
||||
paintable = gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, 0, 0);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
text_view->priv->drag = drag;
|
||||
|
||||
g_object_unref (drag);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
gtk_text_view_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkTextView *text_view)
|
||||
{
|
||||
gtk_text_buffer_delete_selection (GTK_TEXT_VIEW (widget)->priv->buffer,
|
||||
TRUE, GTK_TEXT_VIEW (widget)->priv->editable);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
GtkTextView *text_view;
|
||||
GtkTextViewPrivate *priv;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (widget);
|
||||
priv = text_view->priv;
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
|
||||
gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
|
||||
|
||||
@ -7816,28 +7738,23 @@ gtk_text_view_drag_leave (GtkWidget *widget,
|
||||
g_source_remove (priv->scroll_timeout);
|
||||
|
||||
priv->scroll_timeout = 0;
|
||||
|
||||
gtk_drag_unhighlight (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_view_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
gtk_text_view_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkTextView *text_view)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
GtkTextIter newplace;
|
||||
GtkTextView *text_view;
|
||||
GtkTextViewPrivate *priv;
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
GdkRectangle target_rect;
|
||||
gint bx, by;
|
||||
GdkAtom target;
|
||||
gboolean can_accept = FALSE;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (widget);
|
||||
priv = text_view->priv;
|
||||
|
||||
target_rect = priv->text_window->allocation;
|
||||
|
||||
@ -7856,8 +7773,7 @@ gtk_text_view_drag_motion (GtkWidget *widget,
|
||||
&newplace,
|
||||
bx, by);
|
||||
|
||||
target = gtk_drag_dest_find_target (widget, drop,
|
||||
gtk_drag_dest_get_target_list (widget));
|
||||
target = gtk_drop_target_find_mimetype (dest);
|
||||
|
||||
if (target == NULL)
|
||||
{
|
||||
@ -7898,83 +7814,22 @@ gtk_text_view_drag_motion (GtkWidget *widget,
|
||||
g_source_set_name_by_id (text_view->priv->scroll_timeout, "[gtk] drag_scan_timeout");
|
||||
}
|
||||
|
||||
gtk_drag_highlight (widget);
|
||||
|
||||
/* TRUE return means don't propagate the drag motion to parent
|
||||
* widgets that may also be drop sites.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_view_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkTextView *text_view;
|
||||
GtkTextViewPrivate *priv;
|
||||
GtkTextIter drop_point;
|
||||
GdkAtom target = NULL;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (widget);
|
||||
priv = text_view->priv;
|
||||
|
||||
if (priv->scroll_timeout != 0)
|
||||
g_source_remove (priv->scroll_timeout);
|
||||
|
||||
priv->scroll_timeout = 0;
|
||||
|
||||
gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
|
||||
&drop_point,
|
||||
priv->dnd_mark);
|
||||
|
||||
if (gtk_text_iter_can_insert (&drop_point, priv->editable))
|
||||
target = gtk_drag_dest_find_target (widget, drop, NULL);
|
||||
|
||||
if (target != NULL)
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
insert_text_data (GtkTextView *text_view,
|
||||
GtkTextIter *drop_point,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
guchar *str;
|
||||
|
||||
str = gtk_selection_data_get_text (selection_data);
|
||||
|
||||
if (str)
|
||||
{
|
||||
if (!gtk_text_buffer_insert_interactive (get_buffer (text_view),
|
||||
drop_point, (gchar *) str, -1,
|
||||
text_view->priv->editable))
|
||||
{
|
||||
gtk_widget_error_bell (GTK_WIDGET (text_view));
|
||||
}
|
||||
|
||||
g_free (str);
|
||||
}
|
||||
}
|
||||
|
||||
static GdkDragAction
|
||||
gtk_text_view_get_action (GtkWidget *textview,
|
||||
GdkDrop *drop)
|
||||
gtk_text_view_get_action (GtkTextView *textview,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
GtkWidget *source_widget = gtk_drag_get_source_widget (drag);
|
||||
GdkDragAction actions;
|
||||
|
||||
actions = gdk_drop_get_actions (drop);
|
||||
|
||||
if (source_widget == textview &&
|
||||
if (drag == textview->priv->drag &&
|
||||
actions & GDK_ACTION_MOVE)
|
||||
return GDK_ACTION_MOVE;
|
||||
|
||||
@ -7988,98 +7843,85 @@ gtk_text_view_get_action (GtkWidget *textview,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
got_text (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GtkTextView *text_view = GTK_TEXT_VIEW (data);
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
GtkTextBuffer *buffer;
|
||||
char *str;
|
||||
GtkTextIter drop_point;
|
||||
GtkTextView *text_view;
|
||||
GtkTextViewPrivate *priv;
|
||||
GtkTextBuffer *buffer = NULL;
|
||||
GdkDragAction action = 0;
|
||||
GdkDragAction action;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (widget);
|
||||
priv = text_view->priv;
|
||||
|
||||
if (!priv->dnd_mark)
|
||||
goto done;
|
||||
str = gdk_drop_read_text_finish (drop, result, NULL);
|
||||
if (!str)
|
||||
{
|
||||
gdk_drop_finish (drop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = get_buffer (text_view);
|
||||
gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (buffer,
|
||||
&drop_point,
|
||||
priv->dnd_mark);
|
||||
action = gtk_text_view_get_action (text_view, drop);
|
||||
|
||||
gtk_text_buffer_begin_user_action (buffer);
|
||||
|
||||
if (!gtk_text_buffer_insert_interactive (buffer,
|
||||
&drop_point, (gchar *) str, -1,
|
||||
text_view->priv->editable))
|
||||
gtk_widget_error_bell (GTK_WIDGET (text_view));
|
||||
|
||||
g_free (str);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
|
||||
gtk_text_buffer_place_cursor (buffer, &drop_point);
|
||||
|
||||
gtk_text_buffer_end_user_action (buffer);
|
||||
|
||||
gdk_drop_finish (drop, action);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_view_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkTextView *text_view)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
GtkTextIter drop_point;
|
||||
GtkTextBuffer *buffer = NULL;
|
||||
|
||||
if (priv->scroll_timeout != 0)
|
||||
g_source_remove (priv->scroll_timeout);
|
||||
|
||||
priv->scroll_timeout = 0;
|
||||
|
||||
gtk_text_mark_set_visible (priv->dnd_mark, FALSE);
|
||||
|
||||
buffer = get_buffer (text_view);
|
||||
gtk_text_buffer_get_iter_at_mark (buffer, &drop_point, priv->dnd_mark);
|
||||
|
||||
if (!gtk_text_iter_can_insert (&drop_point, priv->editable))
|
||||
goto done;
|
||||
|
||||
action = gtk_text_view_get_action (widget, drop);
|
||||
if (action == 0)
|
||||
if (gtk_text_view_get_action (text_view, drop) == 0)
|
||||
goto done;
|
||||
|
||||
gtk_text_buffer_begin_user_action (buffer);
|
||||
|
||||
if (gtk_selection_data_get_target (selection_data) == g_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
if (gdk_drop_has_value (drop, G_TYPE_STRING))
|
||||
{
|
||||
GtkTextBuffer *src_buffer = NULL;
|
||||
GtkTextIter start, end;
|
||||
gboolean copy_tags = TRUE;
|
||||
|
||||
if (gtk_selection_data_get_length (selection_data) != sizeof (src_buffer))
|
||||
return;
|
||||
|
||||
memcpy (&src_buffer, gtk_selection_data_get_data (selection_data), sizeof (src_buffer));
|
||||
|
||||
if (src_buffer == NULL)
|
||||
return;
|
||||
|
||||
g_return_if_fail (GTK_IS_TEXT_BUFFER (src_buffer));
|
||||
|
||||
if (gtk_text_buffer_get_tag_table (src_buffer) !=
|
||||
gtk_text_buffer_get_tag_table (buffer))
|
||||
{
|
||||
copy_tags = FALSE;
|
||||
}
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (src_buffer,
|
||||
&start,
|
||||
&end))
|
||||
{
|
||||
if (copy_tags)
|
||||
gtk_text_buffer_insert_range_interactive (buffer,
|
||||
&drop_point,
|
||||
&start,
|
||||
&end,
|
||||
priv->editable);
|
||||
else
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
str = gtk_text_iter_get_visible_text (&start, &end);
|
||||
gtk_text_buffer_insert_interactive (buffer,
|
||||
&drop_point, str, -1,
|
||||
priv->editable);
|
||||
g_free (str);
|
||||
}
|
||||
}
|
||||
gdk_drop_read_text_async (drop, NULL, got_text, text_view);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
insert_text_data (text_view, &drop_point, selection_data);
|
||||
|
||||
done:
|
||||
gdk_drop_finish (drop, action);
|
||||
|
||||
if (action)
|
||||
{
|
||||
gtk_text_buffer_get_iter_at_mark (buffer,
|
||||
&drop_point,
|
||||
priv->dnd_mark);
|
||||
gtk_text_buffer_place_cursor (buffer, &drop_point);
|
||||
|
||||
gtk_text_buffer_end_user_action (buffer);
|
||||
}
|
||||
done:
|
||||
gdk_drop_finish (drop, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_text_view_set_hadjustment (GtkTextView *text_view,
|
||||
GtkAdjustment *adjustment)
|
||||
|
@ -22,8 +22,8 @@
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtkselection.h>
|
||||
#include <gtk/gtktreemodel.h>
|
||||
#include <gtk/gtkdnd.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtkdragdest.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkentryprivate.h"
|
||||
#include "gtksearchentryprivate.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
@ -64,6 +65,7 @@
|
||||
#include "gtkwindowgroup.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkpopover.h"
|
||||
#include "gtkselectionprivate.h"
|
||||
|
||||
#include "a11y/gtktreeviewaccessibleprivate.h"
|
||||
|
||||
@ -149,13 +151,17 @@
|
||||
* ┊ ┊
|
||||
* │ ╰── <column header>
|
||||
* │
|
||||
* ╰── [rubberband]
|
||||
* ├── [rubberband]
|
||||
* ╰── [dndtarget]
|
||||
* ]|
|
||||
*
|
||||
* GtkTreeView has a main CSS node with name treeview and style class .view.
|
||||
* It has a subnode with name header, which is the parent for all the column
|
||||
* header widgets' CSS nodes.
|
||||
*
|
||||
* For rubberband selection, a subnode with name rubberband is used.
|
||||
*
|
||||
* For the drop target location during DND, a subnode with name dndtarget is used.
|
||||
*/
|
||||
|
||||
enum
|
||||
@ -300,8 +306,14 @@ struct _GtkTreeViewChild
|
||||
typedef struct _TreeViewDragInfo TreeViewDragInfo;
|
||||
struct _TreeViewDragInfo
|
||||
{
|
||||
GdkModifierType start_button_mask;
|
||||
GdkContentFormats *source_formats;
|
||||
GdkDragAction source_actions;
|
||||
GdkDrag *drag;
|
||||
GtkTreeRowReference *source_item;
|
||||
|
||||
GtkCssNode *cssnode;
|
||||
GtkDropTarget *dest;
|
||||
GdkModifierType start_button_mask;
|
||||
|
||||
guint source_set : 1;
|
||||
guint dest_set : 1;
|
||||
@ -674,30 +686,28 @@ static void gtk_tree_view_forall (GtkContainer *container,
|
||||
gpointer callback_data);
|
||||
|
||||
/* Source side drag signals */
|
||||
static void gtk_tree_view_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_tree_view_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_tree_view_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data);
|
||||
static void gtk_tree_view_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
static void gtk_tree_view_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkWidget *widget);
|
||||
static GBytes *gtk_tree_view_drag_data_get (const char *mimetype,
|
||||
gpointer data);
|
||||
|
||||
/* Target side drag signals */
|
||||
static void gtk_tree_view_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
static gboolean gtk_tree_view_drag_motion (GtkWidget *widget,
|
||||
static void gtk_tree_view_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static gboolean gtk_tree_view_drag_drop (GtkWidget *widget,
|
||||
GtkTreeView *tree_view);
|
||||
static void gtk_tree_view_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
static void gtk_tree_view_drag_data_received (GtkWidget *widget,
|
||||
int x,
|
||||
int y,
|
||||
GtkTreeView *tree_view);
|
||||
static gboolean gtk_tree_view_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data);
|
||||
int x,
|
||||
int y,
|
||||
GtkTreeView *tree_view);
|
||||
static void gtk_tree_view_drag_data_received (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data);
|
||||
|
||||
/* tree_model signals */
|
||||
static gboolean gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
|
||||
@ -832,6 +842,7 @@ static inline gint gtk_tree_view_get_row_y_offset (GtkTreeView
|
||||
GtkTreeRBNode *node);
|
||||
static inline gint gtk_tree_view_get_row_height (GtkTreeView *tree_view,
|
||||
GtkTreeRBNode *node);
|
||||
static TreeViewDragInfo* get_info (GtkTreeView *tree_view);
|
||||
|
||||
/* interactive search */
|
||||
static void gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
|
||||
@ -1016,14 +1027,6 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
|
||||
widget_class->measure = gtk_tree_view_measure;
|
||||
widget_class->size_allocate = gtk_tree_view_size_allocate;
|
||||
widget_class->snapshot = gtk_tree_view_snapshot;
|
||||
widget_class->drag_begin = gtk_tree_view_drag_begin;
|
||||
widget_class->drag_end = gtk_tree_view_drag_end;
|
||||
widget_class->drag_data_get = gtk_tree_view_drag_data_get;
|
||||
widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
|
||||
widget_class->drag_leave = gtk_tree_view_drag_leave;
|
||||
widget_class->drag_motion = gtk_tree_view_drag_motion;
|
||||
widget_class->drag_drop = gtk_tree_view_drag_drop;
|
||||
widget_class->drag_data_received = gtk_tree_view_drag_data_received;
|
||||
widget_class->focus = gtk_tree_view_focus;
|
||||
widget_class->grab_focus = gtk_tree_view_grab_focus;
|
||||
widget_class->style_updated = gtk_tree_view_style_updated;
|
||||
@ -4863,41 +4866,47 @@ gtk_tree_view_bin_snapshot (GtkWidget *widget,
|
||||
|
||||
if (node == drag_highlight)
|
||||
{
|
||||
/* Draw indicator for the drop
|
||||
*/
|
||||
GtkTreeRBTree *drag_tree = NULL;
|
||||
GtkTreeRBNode *drag_node = NULL;
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_set_state (context, gtk_style_context_get_state (context) | GTK_STATE_FLAG_DROP_ACTIVE);
|
||||
|
||||
switch (tree_view->drag_dest_pos)
|
||||
{
|
||||
case GTK_TREE_VIEW_DROP_BEFORE:
|
||||
gtk_style_context_add_class (context, "before");
|
||||
break;
|
||||
|
||||
case GTK_TREE_VIEW_DROP_AFTER:
|
||||
gtk_style_context_add_class (context, "after");
|
||||
break;
|
||||
|
||||
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
|
||||
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
|
||||
gtk_style_context_add_class (context, "into");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_gtk_tree_view_find_node (tree_view, drag_dest_path, &drag_tree, &drag_node);
|
||||
if (drag_tree != NULL)
|
||||
{
|
||||
TreeViewDragInfo *di;
|
||||
|
||||
di = get_info (tree_view);
|
||||
/* Draw indicator for the drop
|
||||
*/
|
||||
|
||||
switch (tree_view->drag_dest_pos)
|
||||
{
|
||||
case GTK_TREE_VIEW_DROP_BEFORE:
|
||||
gtk_css_node_set_classes (di->cssnode, (const char *[]){"before", NULL});
|
||||
break;
|
||||
|
||||
case GTK_TREE_VIEW_DROP_AFTER:
|
||||
gtk_css_node_set_classes (di->cssnode, (const char *[]){"after", NULL});
|
||||
break;
|
||||
|
||||
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
|
||||
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
|
||||
gtk_css_node_set_classes (di->cssnode, (const char *[]){"into", NULL});
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_style_context_save_to_node (context, di->cssnode);
|
||||
gtk_style_context_set_state (context, gtk_style_context_get_state (context) | GTK_STATE_FLAG_DROP_ACTIVE);
|
||||
|
||||
gtk_snapshot_render_frame (snapshot, context,
|
||||
0, gtk_tree_view_get_row_y_offset (tree_view, drag_tree, drag_node),
|
||||
bin_window_width,
|
||||
gtk_tree_view_get_row_height (tree_view, drag_node));
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
}
|
||||
|
||||
/* draw the big row-spanning focus rectangle, if needed */
|
||||
@ -6621,29 +6630,6 @@ _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
|
||||
|
||||
/* Drag-and-drop */
|
||||
|
||||
static void
|
||||
set_source_row (GdkDrag *drag,
|
||||
GtkTreeModel *model,
|
||||
GtkTreePath *source_row)
|
||||
{
|
||||
g_object_set_data_full (G_OBJECT (drag),
|
||||
I_("gtk-tree-view-source-row"),
|
||||
source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
|
||||
(GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
|
||||
}
|
||||
|
||||
static GtkTreePath*
|
||||
get_source_row (GdkDrag *drag)
|
||||
{
|
||||
GtkTreeRowReference *ref =
|
||||
g_object_get_data (G_OBJECT (drag), "gtk-tree-view-source-row");
|
||||
|
||||
if (ref)
|
||||
return gtk_tree_row_reference_get_path (ref);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkTreeRowReference *dest_row;
|
||||
@ -6749,6 +6735,10 @@ get_info (GtkTreeView *tree_view)
|
||||
static void
|
||||
destroy_info (TreeViewDragInfo *di)
|
||||
{
|
||||
g_clear_pointer (&di->source_formats, gdk_content_formats_unref);
|
||||
g_clear_pointer (&di->source_item, gtk_tree_row_reference_free);
|
||||
g_clear_object (&di->dest);
|
||||
|
||||
g_slice_free (TreeViewDragInfo, di);
|
||||
}
|
||||
|
||||
@ -6775,6 +6765,11 @@ ensure_info (GtkTreeView *tree_view)
|
||||
static void
|
||||
remove_info (GtkTreeView *tree_view)
|
||||
{
|
||||
TreeViewDragInfo *di;
|
||||
|
||||
di = get_info (tree_view);
|
||||
if (di && di->dest)
|
||||
gtk_widget_remove_controller (GTK_WIDGET (tree_view), GTK_EVENT_CONTROLLER (di->dest));
|
||||
g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
|
||||
}
|
||||
|
||||
@ -6881,7 +6876,7 @@ scroll_row_timeout (gpointer data)
|
||||
/* Returns TRUE if event should not be propagated to parent widgets */
|
||||
static gboolean
|
||||
set_destination_row (GtkTreeView *tree_view,
|
||||
GdkDrop *drop,
|
||||
GtkDropTarget *dest,
|
||||
/* coordinates relative to the widget */
|
||||
gint x,
|
||||
gint y,
|
||||
@ -6919,12 +6914,9 @@ set_destination_row (GtkTreeView *tree_view,
|
||||
return FALSE; /* no longer a drop site */
|
||||
}
|
||||
|
||||
*target = gtk_drag_dest_find_target (widget, drop,
|
||||
gtk_drag_dest_get_target_list (widget));
|
||||
*target = gtk_drop_target_find_mimetype (dest);
|
||||
if (*target == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
|
||||
x, y,
|
||||
@ -7058,13 +7050,17 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (tree_view);
|
||||
gdouble start_x, start_y, offset_x, offset_y;
|
||||
GdkDrag *drag;
|
||||
TreeViewDragInfo *di;
|
||||
GtkTreePath *path = NULL;
|
||||
gint button;
|
||||
GtkTreeModel *model;
|
||||
gboolean retval = FALSE;
|
||||
gint bin_x, bin_y;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
GdkContentProvider *content;
|
||||
GdkDrag *drag;
|
||||
GdkPaintable *icon;
|
||||
|
||||
di = get_info (tree_view);
|
||||
|
||||
@ -7115,13 +7111,23 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
|
||||
gtk_gesture_set_state (GTK_GESTURE (tree_view->drag_gesture),
|
||||
GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
drag = gtk_drag_begin (widget,
|
||||
gtk_gesture_get_device (GTK_GESTURE (tree_view->drag_gesture)),
|
||||
gtk_drag_source_get_target_list (widget),
|
||||
di->source_actions,
|
||||
start_x, start_y);
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (tree_view)));
|
||||
device = gtk_gesture_get_device (GTK_GESTURE (tree_view->drag_gesture)),
|
||||
content = gdk_content_provider_new_with_formats (di->source_formats, gtk_tree_view_drag_data_get, tree_view);
|
||||
|
||||
set_source_row (drag, model, path);
|
||||
drag = gdk_drag_begin (surface, device, content, di->source_actions, start_x, start_y);
|
||||
|
||||
g_signal_connect (drag, "dnd-finished", G_CALLBACK (gtk_tree_view_dnd_finished_cb), tree_view);
|
||||
|
||||
icon = gtk_tree_view_create_row_drag_icon (tree_view, path);
|
||||
gtk_drag_icon_set_from_paintable (drag, icon, tree_view->press_start_x + 1, 1);
|
||||
g_object_unref (icon);
|
||||
|
||||
di->drag = drag;
|
||||
|
||||
g_object_unref (drag);
|
||||
|
||||
di->source_item = gtk_tree_row_reference_new (model, path);
|
||||
|
||||
out:
|
||||
if (path)
|
||||
@ -7130,121 +7136,21 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_tree_view_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreePath *path = NULL;
|
||||
gint cell_x, cell_y;
|
||||
GdkPaintable *row_pix;
|
||||
TreeViewDragInfo *di;
|
||||
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
|
||||
/* if the user uses a custom DND source impl, we don't set the icon here */
|
||||
di = get_info (tree_view);
|
||||
|
||||
if (di == NULL || !di->source_set)
|
||||
return;
|
||||
|
||||
gtk_tree_view_get_path_at_pos (tree_view,
|
||||
tree_view->press_start_x,
|
||||
tree_view->press_start_y,
|
||||
&path,
|
||||
NULL,
|
||||
&cell_x,
|
||||
&cell_y);
|
||||
|
||||
/* If path is NULL, there's nothing we can drag. For now, we silently
|
||||
* bail out. Actually, dragging should not be possible from an empty
|
||||
* tree view, but there's no way we can cancel that from here.
|
||||
* Automatically unsetting the tree view as drag source for empty models
|
||||
* is something that would likely break other people's code ...
|
||||
*/
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
row_pix = gtk_tree_view_create_row_drag_icon (tree_view, path);
|
||||
|
||||
gtk_drag_set_icon_paintable (drag, row_pix, tree_view->press_start_x + 1, 1);
|
||||
|
||||
g_object_unref (row_pix);
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tree_view_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
gtk_tree_view_dnd_finished_cb (GdkDrag *drag,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
|
||||
TreeViewDragInfo *di;
|
||||
GtkTreeModel *model;
|
||||
GtkTreePath *source_row;
|
||||
|
||||
tree_view->event_last_x = -10000;
|
||||
tree_view->event_last_y = -10000;
|
||||
}
|
||||
|
||||
/* Default signal implementations for the drag signals */
|
||||
static void
|
||||
gtk_tree_view_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreeModel *model;
|
||||
TreeViewDragInfo *di;
|
||||
GtkTreePath *source_row;
|
||||
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
if (model == NULL)
|
||||
if (gdk_drag_get_selected_action (drag) != GDK_ACTION_MOVE)
|
||||
return;
|
||||
|
||||
di = get_info (GTK_TREE_VIEW (widget));
|
||||
|
||||
if (di == NULL)
|
||||
return;
|
||||
|
||||
source_row = get_source_row (drag);
|
||||
|
||||
if (source_row == NULL)
|
||||
return;
|
||||
|
||||
/* We can implement the GTK_TREE_MODEL_ROW target generically for
|
||||
* any model; for DragSource models there are some other targets
|
||||
* we also support.
|
||||
*/
|
||||
|
||||
if (GTK_IS_TREE_DRAG_SOURCE (model) &&
|
||||
gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
|
||||
source_row,
|
||||
selection_data))
|
||||
goto done;
|
||||
|
||||
/* If drag_data_get does nothing, try providing row data. */
|
||||
if (gtk_selection_data_get_target (selection_data) == g_intern_static_string ("GTK_TREE_MODEL_ROW"))
|
||||
{
|
||||
gtk_tree_set_row_drag_data (selection_data,
|
||||
model,
|
||||
source_row);
|
||||
}
|
||||
|
||||
done:
|
||||
gtk_tree_path_free (source_row);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_tree_view_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag)
|
||||
{
|
||||
TreeViewDragInfo *di;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreePath *source_row;
|
||||
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
@ -7253,10 +7159,10 @@ gtk_tree_view_drag_data_delete (GtkWidget *widget,
|
||||
|
||||
di = get_info (tree_view);
|
||||
|
||||
if (di == NULL)
|
||||
if (di == NULL || di->source_item == NULL)
|
||||
return;
|
||||
|
||||
source_row = get_source_row (drag);
|
||||
source_row = gtk_tree_row_reference_get_path (di->source_item);
|
||||
|
||||
if (source_row == NULL)
|
||||
return;
|
||||
@ -7265,45 +7171,97 @@ gtk_tree_view_drag_data_delete (GtkWidget *widget,
|
||||
|
||||
gtk_tree_path_free (source_row);
|
||||
|
||||
set_source_row (drag, NULL, NULL);
|
||||
g_clear_pointer (&di->source_item, gtk_tree_row_reference_free);
|
||||
}
|
||||
|
||||
/* Default signal implementations for the drag signals */
|
||||
static GBytes *
|
||||
gtk_tree_view_drag_data_get (const char *mime_type,
|
||||
gpointer data)
|
||||
{
|
||||
GtkTreeView *tree_view = data;
|
||||
GtkTreeModel *model;
|
||||
TreeViewDragInfo *di;
|
||||
GtkTreePath *source_row;
|
||||
GtkSelectionData sdata = { 0, };
|
||||
|
||||
sdata.target = g_intern_string (mime_type);
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
if (model == NULL)
|
||||
return NULL;
|
||||
|
||||
di = get_info (tree_view);
|
||||
|
||||
if (di == NULL || di->source_item == NULL)
|
||||
return NULL;
|
||||
|
||||
source_row = gtk_tree_row_reference_get_path (di->source_item);
|
||||
|
||||
if (source_row == NULL)
|
||||
return NULL;
|
||||
|
||||
/* We can implement the GTK_TREE_MODEL_ROW target generically for
|
||||
* any model; for DragSource models there are some other targets
|
||||
* we also support.
|
||||
*/
|
||||
|
||||
if (GTK_IS_TREE_DRAG_SOURCE (model) &&
|
||||
gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
|
||||
source_row,
|
||||
&sdata))
|
||||
goto done;
|
||||
|
||||
/* If drag_data_get does nothing, try providing row data. */
|
||||
if (mime_type == g_intern_static_string ("GTK_TREE_MODEL_ROW"))
|
||||
{
|
||||
gtk_tree_set_row_drag_data (&sdata, model, source_row);
|
||||
}
|
||||
|
||||
done:
|
||||
gtk_tree_path_free (source_row);
|
||||
|
||||
return g_bytes_new_take ((gpointer)gtk_selection_data_get_data (&sdata),
|
||||
gtk_selection_data_get_length (&sdata));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tree_view_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
gtk_tree_view_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkTreeView *tree_view)
|
||||
{
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
|
||||
|
||||
/* unset any highlight row */
|
||||
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
|
||||
gtk_tree_view_set_drag_dest_row (tree_view,
|
||||
NULL,
|
||||
GTK_TREE_VIEW_DROP_BEFORE);
|
||||
|
||||
remove_scroll_timeout (GTK_TREE_VIEW (widget));
|
||||
remove_open_timeout (GTK_TREE_VIEW (widget));
|
||||
remove_scroll_timeout (tree_view);
|
||||
remove_open_timeout (tree_view);
|
||||
|
||||
tree_view->event_last_x = -10000;
|
||||
tree_view->event_last_y = -10000;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_tree_view_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
static void
|
||||
gtk_tree_view_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkTreeView *tree_view)
|
||||
{
|
||||
gboolean empty;
|
||||
GtkTreePath *path = NULL;
|
||||
GtkTreeViewDropPosition pos;
|
||||
GtkTreeView *tree_view;
|
||||
GdkDragAction suggested_action = 0;
|
||||
GdkAtom target;
|
||||
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
|
||||
if (!set_destination_row (tree_view, drop, x, y, &suggested_action, &target))
|
||||
return FALSE;
|
||||
if (!set_destination_row (tree_view, dest, x, y, &suggested_action, &target))
|
||||
{
|
||||
gdk_drop_status (drop, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
tree_view->event_last_x = x;
|
||||
tree_view->event_last_y = y;
|
||||
@ -7339,7 +7297,7 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
|
||||
* determining whether to accept the drop
|
||||
*/
|
||||
set_status_pending (drop, suggested_action);
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
gtk_drop_target_read_selection (dest, target, NULL, gtk_tree_view_drag_data_received, tree_view);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -7350,18 +7308,16 @@ gtk_tree_view_drag_motion (GtkWidget *widget,
|
||||
|
||||
if (path)
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_tree_view_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
gtk_tree_view_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkTreeView *tree_view)
|
||||
{
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreePath *path;
|
||||
GdkDragAction suggested_action = 0;
|
||||
GdkAtom target = NULL;
|
||||
@ -7370,12 +7326,10 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
|
||||
gboolean path_down_mode;
|
||||
gboolean drop_append_mode;
|
||||
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
remove_scroll_timeout (GTK_TREE_VIEW (widget));
|
||||
remove_open_timeout (GTK_TREE_VIEW (widget));
|
||||
remove_scroll_timeout (tree_view);
|
||||
remove_open_timeout (tree_view);
|
||||
|
||||
di = get_info (tree_view);
|
||||
|
||||
@ -7385,7 +7339,7 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
|
||||
if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
|
||||
return FALSE;
|
||||
|
||||
if (!set_destination_row (tree_view, drop, x, y, &suggested_action, &target))
|
||||
if (!set_destination_row (tree_view, dest, x, y, &suggested_action, &target))
|
||||
return FALSE;
|
||||
|
||||
path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
|
||||
@ -7405,13 +7359,13 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
/* Unset this thing */
|
||||
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
|
||||
gtk_tree_view_set_drag_dest_row (tree_view,
|
||||
NULL,
|
||||
GTK_TREE_VIEW_DROP_BEFORE);
|
||||
|
||||
if (target != NULL)
|
||||
{
|
||||
gtk_drag_get_data (widget, drop, target);
|
||||
gtk_drop_target_read_selection (dest, target, NULL, gtk_tree_view_drag_data_received, tree_view);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -7419,16 +7373,19 @@ gtk_tree_view_drag_drop (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static GdkDragAction
|
||||
gtk_tree_view_get_action (GtkWidget *treeview,
|
||||
gtk_tree_view_get_action (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
|
||||
TreeViewDragInfo *di;
|
||||
GdkDrag *drag = gdk_drop_get_drag (drop);
|
||||
GtkWidget *source_widget = gtk_drag_get_source_widget (drag);
|
||||
GdkDragAction actions;
|
||||
|
||||
di = get_info (tree_view);
|
||||
|
||||
actions = gdk_drop_get_actions (drop);
|
||||
|
||||
if (source_widget == treeview &&
|
||||
if (di && di->drag == drag &&
|
||||
actions & GDK_ACTION_MOVE)
|
||||
return GDK_ACTION_MOVE;
|
||||
|
||||
@ -7442,20 +7399,23 @@ gtk_tree_view_get_action (GtkWidget *treeview,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tree_view_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
gtk_tree_view_drag_data_received (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkDropTarget *dest = GTK_DROP_TARGET (source);
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (data);
|
||||
GdkDrop *drop = gtk_drop_target_get_drop (dest);
|
||||
GtkTreePath *path;
|
||||
TreeViewDragInfo *di;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreePath *dest_row;
|
||||
GdkDragAction suggested_action;
|
||||
gboolean path_down_mode;
|
||||
gboolean drop_append_mode;
|
||||
GtkSelectionData *selection_data;
|
||||
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
selection_data = gtk_drop_target_read_selection_finish (dest, result, NULL);
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
@ -7512,7 +7472,7 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
|
||||
|
||||
/* If you can't drop, remove user drop indicator until the next motion */
|
||||
if (suggested_action == 0)
|
||||
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
|
||||
gtk_tree_view_set_drag_dest_row (tree_view,
|
||||
NULL,
|
||||
GTK_TREE_VIEW_DROP_BEFORE);
|
||||
|
||||
@ -7537,7 +7497,7 @@ gtk_tree_view_drag_data_received (GtkWidget *widget,
|
||||
|
||||
if (gtk_selection_data_get_length (selection_data) >= 0)
|
||||
{
|
||||
suggested_action = gtk_tree_view_get_action (widget, drop);
|
||||
suggested_action = gtk_tree_view_get_action (GTK_WIDGET (tree_view), drop);
|
||||
|
||||
if (suggested_action &&
|
||||
!gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
|
||||
@ -12915,15 +12875,13 @@ gtk_tree_view_enable_model_drag_source (GtkTreeView *tree_view,
|
||||
|
||||
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
|
||||
|
||||
gtk_drag_source_set (GTK_WIDGET (tree_view),
|
||||
0,
|
||||
formats,
|
||||
actions);
|
||||
|
||||
di = ensure_info (tree_view);
|
||||
|
||||
di->start_button_mask = start_button_mask;
|
||||
di->source_formats = gdk_content_formats_ref (formats);
|
||||
di->source_actions = actions;
|
||||
di->drag = NULL;
|
||||
|
||||
di->start_button_mask = start_button_mask;
|
||||
di->source_set = TRUE;
|
||||
|
||||
unset_reorderable (tree_view);
|
||||
@ -12938,25 +12896,39 @@ gtk_tree_view_enable_model_drag_source (GtkTreeView *tree_view,
|
||||
*
|
||||
* Turns @tree_view into a drop destination for automatic DND. Calling
|
||||
* this method sets #GtkTreeView:reorderable to %FALSE.
|
||||
*
|
||||
* Returns: (transfer none): the drop target that has been attached
|
||||
**/
|
||||
void
|
||||
GtkDropTarget *
|
||||
gtk_tree_view_enable_model_drag_dest (GtkTreeView *tree_view,
|
||||
GdkContentFormats *formats,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
TreeViewDragInfo *di;
|
||||
GtkCssNode *widget_node;
|
||||
|
||||
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
|
||||
|
||||
gtk_drag_dest_set (GTK_WIDGET (tree_view),
|
||||
0,
|
||||
formats,
|
||||
actions);
|
||||
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
|
||||
|
||||
di = ensure_info (tree_view);
|
||||
di->dest_set = TRUE;
|
||||
|
||||
di->dest = gtk_drop_target_new (formats, actions);
|
||||
g_signal_connect (di->dest, "drag-leave", G_CALLBACK (gtk_tree_view_drag_leave), tree_view);
|
||||
g_signal_connect (di->dest, "drag-motion", G_CALLBACK (gtk_tree_view_drag_motion), tree_view);
|
||||
g_signal_connect (di->dest, "drag-drop", G_CALLBACK (gtk_tree_view_drag_drop), tree_view);
|
||||
gtk_widget_add_controller (GTK_WIDGET (tree_view), GTK_EVENT_CONTROLLER (di->dest));
|
||||
g_object_ref (di->dest);
|
||||
|
||||
widget_node = gtk_widget_get_css_node (GTK_WIDGET (tree_view));
|
||||
di->cssnode = gtk_css_node_new ();
|
||||
gtk_css_node_set_name (di->cssnode, I_("dndtarget"));
|
||||
gtk_css_node_set_parent (di->cssnode, widget_node);
|
||||
gtk_css_node_set_state (di->cssnode, gtk_css_node_get_state (widget_node));
|
||||
g_object_unref (di->cssnode);
|
||||
|
||||
unset_reorderable (tree_view);
|
||||
|
||||
return di->dest;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -12980,7 +12952,7 @@ gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
|
||||
{
|
||||
if (di->source_set)
|
||||
{
|
||||
gtk_drag_source_unset (GTK_WIDGET (tree_view));
|
||||
g_clear_pointer (&di->source_formats, gdk_content_formats_unref);
|
||||
di->source_set = FALSE;
|
||||
}
|
||||
|
||||
@ -13012,8 +12984,12 @@ gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
|
||||
{
|
||||
if (di->dest_set)
|
||||
{
|
||||
gtk_drag_dest_unset (GTK_WIDGET (tree_view));
|
||||
gtk_widget_remove_controller (GTK_WIDGET (tree_view), GTK_EVENT_CONTROLLER (di->dest));
|
||||
di->dest = NULL;
|
||||
di->dest_set = FALSE;
|
||||
|
||||
gtk_css_node_set_parent (di->cssnode, NULL);
|
||||
di->cssnode = NULL;
|
||||
}
|
||||
|
||||
if (!di->dest_set && !di->source_set)
|
||||
|
@ -25,8 +25,9 @@
|
||||
#include <gtk/gtkcontainer.h>
|
||||
#include <gtk/gtktreemodel.h>
|
||||
#include <gtk/gtktreeviewcolumn.h>
|
||||
#include <gtk/gtkdnd.h>
|
||||
#include <gtk/gtkentry.h>
|
||||
#include <gtk/gtkdragsource.h>
|
||||
#include <gtk/gtkdragdest.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -319,7 +320,7 @@ void gtk_tree_view_enable_model_drag_source (GtkTreeView
|
||||
GdkContentFormats *formats,
|
||||
GdkDragAction actions);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_tree_view_enable_model_drag_dest (GtkTreeView *tree_view,
|
||||
GtkDropTarget * gtk_tree_view_enable_model_drag_dest (GtkTreeView *tree_view,
|
||||
GdkContentFormats *formats,
|
||||
GdkDragAction actions);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
377
gtk/gtkwidget.c
377
gtk/gtkwidget.c
@ -517,14 +517,6 @@ enum {
|
||||
MNEMONIC_ACTIVATE,
|
||||
MOVE_FOCUS,
|
||||
KEYNAV_FAILED,
|
||||
DRAG_BEGIN,
|
||||
DRAG_END,
|
||||
DRAG_DATA_DELETE,
|
||||
DRAG_LEAVE,
|
||||
DRAG_MOTION,
|
||||
DRAG_DROP,
|
||||
DRAG_DATA_GET,
|
||||
DRAG_DATA_RECEIVED,
|
||||
POPUP_MENU,
|
||||
ACCEL_CLOSURES_CHANGED,
|
||||
DISPLAY_CHANGED,
|
||||
@ -919,13 +911,6 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
klass->focus = gtk_widget_real_focus;
|
||||
klass->move_focus = gtk_widget_real_move_focus;
|
||||
klass->keynav_failed = gtk_widget_real_keynav_failed;
|
||||
klass->drag_begin = NULL;
|
||||
klass->drag_end = NULL;
|
||||
klass->drag_data_delete = NULL;
|
||||
klass->drag_leave = NULL;
|
||||
klass->drag_motion = NULL;
|
||||
klass->drag_drop = NULL;
|
||||
klass->drag_data_received = NULL;
|
||||
klass->can_activate_accel = gtk_widget_real_can_activate_accel;
|
||||
klass->query_tooltip = gtk_widget_real_query_tooltip;
|
||||
klass->style_updated = gtk_widget_real_style_updated;
|
||||
@ -1657,368 +1642,6 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
_gtk_marshal_BOOLEAN__ENUMv);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-leave:
|
||||
* @widget: the object which received the signal.
|
||||
* @context: the drag context
|
||||
* @time: the timestamp of the motion event
|
||||
*
|
||||
* The ::drag-leave signal is emitted on the drop site when the cursor
|
||||
* leaves the widget. A typical reason to connect to this signal is to
|
||||
* undo things done in #GtkWidget::drag-motion, e.g. undo highlighting
|
||||
* with gtk_drag_unhighlight().
|
||||
*
|
||||
*
|
||||
* Likewise, the #GtkWidget::drag-leave signal is also emitted before the
|
||||
* ::drag-drop signal, for instance to allow cleaning up of a preview item
|
||||
* created in the #GtkWidget::drag-motion signal handler.
|
||||
*/
|
||||
widget_signals[DRAG_LEAVE] =
|
||||
g_signal_new (I_("drag-leave"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_leave),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_DROP);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-begin:
|
||||
* @widget: the object which received the signal
|
||||
* @context: the drag context
|
||||
*
|
||||
* The ::drag-begin signal is emitted on the drag source when a drag is
|
||||
* started. A typical reason to connect to this signal is to set up a
|
||||
* custom drag icon with e.g. gtk_drag_source_set_icon_paintable().
|
||||
*
|
||||
* Note that some widgets set up a drag icon in the default handler of
|
||||
* this signal, so you may have to use g_signal_connect_after() to
|
||||
* override what the default handler did.
|
||||
*/
|
||||
widget_signals[DRAG_BEGIN] =
|
||||
g_signal_new (I_("drag-begin"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_begin),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_DRAG);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-end:
|
||||
* @widget: the object which received the signal
|
||||
* @context: the drag context
|
||||
*
|
||||
* The ::drag-end signal is emitted on the drag source when a drag is
|
||||
* finished. A typical reason to connect to this signal is to undo
|
||||
* things done in #GtkWidget::drag-begin.
|
||||
*/
|
||||
widget_signals[DRAG_END] =
|
||||
g_signal_new (I_("drag-end"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_end),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_DRAG);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-data-delete:
|
||||
* @widget: the object which received the signal
|
||||
* @context: the drag context
|
||||
*
|
||||
* The ::drag-data-delete signal is emitted on the drag source when a drag
|
||||
* with the action %GDK_ACTION_MOVE is successfully completed. The signal
|
||||
* handler is responsible for deleting the data that has been dropped. What
|
||||
* "delete" means depends on the context of the drag operation.
|
||||
*/
|
||||
widget_signals[DRAG_DATA_DELETE] =
|
||||
g_signal_new (I_("drag-data-delete"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_data_delete),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_DRAG);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-failed:
|
||||
* @widget: the object which received the signal
|
||||
* @context: the drag context
|
||||
* @result: the result of the drag operation
|
||||
*
|
||||
* The ::drag-failed signal is emitted on the drag source when a drag has
|
||||
* failed. The signal handler may hook custom code to handle a failed DnD
|
||||
* operation based on the type of error, it returns %TRUE is the failure has
|
||||
* been already handled (not showing the default "drag operation failed"
|
||||
* animation), otherwise it returns %FALSE.
|
||||
*
|
||||
* Returns: %TRUE if the failed drag operation has been already handled.
|
||||
*/
|
||||
widget_signals[DRAG_FAILED] =
|
||||
g_signal_new (I_("drag-failed"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_failed),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__OBJECT_ENUM,
|
||||
G_TYPE_BOOLEAN, 2,
|
||||
GDK_TYPE_DRAG,
|
||||
GTK_TYPE_DRAG_RESULT);
|
||||
g_signal_set_va_marshaller (widget_signals[DRAG_FAILED],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
_gtk_marshal_BOOLEAN__OBJECT_ENUMv);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-motion:
|
||||
* @widget: the object which received the signal
|
||||
* @drop: the #GdkDrop
|
||||
* @x: the x coordinate of the current cursor position
|
||||
* @y: the y coordinate of the current cursor position
|
||||
*
|
||||
* The ::drag-motion signal is emitted on the drop site when the user
|
||||
* moves the cursor over the widget during a drag. The signal handler
|
||||
* must determine whether the cursor position is in a drop zone or not.
|
||||
* If it is not in a drop zone, it returns %FALSE and no further processing
|
||||
* is necessary. Otherwise, the handler returns %TRUE. In this case, the
|
||||
* handler is responsible for providing the necessary information for
|
||||
* displaying feedback to the user, by calling gdk_drag_status().
|
||||
*
|
||||
* If the decision whether the drop will be accepted or rejected can't be
|
||||
* made based solely on the cursor position and the type of the data, the
|
||||
* handler may inspect the dragged data by calling gtk_drag_get_data() and
|
||||
* defer the gdk_drag_status() call to the #GtkWidget::drag-data-received
|
||||
* handler. Note that you must pass #GTK_DEST_DEFAULT_DROP,
|
||||
* #GTK_DEST_DEFAULT_MOTION or #GTK_DEST_DEFAULT_ALL to gtk_drag_dest_set()
|
||||
* when using the drag-motion signal that way.
|
||||
*
|
||||
* Also note that there is no drag-enter signal. The drag receiver has to
|
||||
* keep track of whether he has received any drag-motion signals since the
|
||||
* last #GtkWidget::drag-leave and if not, treat the drag-motion signal as
|
||||
* an "enter" signal. Upon an "enter", the handler will typically highlight
|
||||
* the drop site with gtk_drag_highlight().
|
||||
* |[<!-- language="C" -->
|
||||
* static void
|
||||
* drag_motion (GtkWidget *widget,
|
||||
* GdkDrop *drop,
|
||||
* gint x,
|
||||
* gint y,
|
||||
* {
|
||||
* GdkAtom target;
|
||||
*
|
||||
* PrivateData *private_data = GET_PRIVATE_DATA (widget);
|
||||
*
|
||||
* if (!private_data->drag_highlight)
|
||||
* {
|
||||
* private_data->drag_highlight = 1;
|
||||
* gtk_drag_highlight (widget);
|
||||
* }
|
||||
*
|
||||
* target = gtk_drag_dest_find_target (widget, drop, NULL);
|
||||
* if (target == NULL)
|
||||
* gdk_drop_status (drop, 0);
|
||||
* else
|
||||
* {
|
||||
* private_data->pending_status
|
||||
* = gdk_drop_get_actions (drop);
|
||||
* gtk_drag_get_data (widget, drop, target);
|
||||
* }
|
||||
*
|
||||
* return TRUE;
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* drag_data_received (GtkWidget *widget,
|
||||
* GdkDrop *drop,
|
||||
* GtkSelectionData *selection_data)
|
||||
* {
|
||||
* PrivateData *private_data = GET_PRIVATE_DATA (widget);
|
||||
*
|
||||
* if (private_data->suggested_action)
|
||||
* {
|
||||
* private_data->suggested_action = 0;
|
||||
*
|
||||
* // We are getting this data due to a request in drag_motion,
|
||||
* // rather than due to a request in drag_drop, so we are just
|
||||
* // supposed to call gdk_drag_status(), not actually paste in
|
||||
* // the data.
|
||||
*
|
||||
* str = gtk_selection_data_get_text (selection_data);
|
||||
* if (!data_is_acceptable (str))
|
||||
* gdk_drop_status (drop, 0);
|
||||
* else
|
||||
* gdk_drag_status (drop, GDK_ACTION_ALL);
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // accept the drop
|
||||
* }
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Returns: whether the cursor position is in a drop zone
|
||||
*/
|
||||
widget_signals[DRAG_MOTION] =
|
||||
g_signal_new (I_("drag-motion"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_motion),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__OBJECT_INT_INT,
|
||||
G_TYPE_BOOLEAN, 3,
|
||||
GDK_TYPE_DROP,
|
||||
G_TYPE_INT,
|
||||
G_TYPE_INT);
|
||||
g_signal_set_va_marshaller (widget_signals[DRAG_MOTION],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
_gtk_marshal_BOOLEAN__OBJECT_INT_INTv);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-drop:
|
||||
* @widget: the object which received the signal
|
||||
* @drop: the #GdkDrop
|
||||
* @x: the x coordinate of the current cursor position
|
||||
* @y: the y coordinate of the current cursor position
|
||||
*
|
||||
* The ::drag-drop signal is emitted on the drop site when the user drops
|
||||
* the data onto the widget. The signal handler must determine whether
|
||||
* the cursor position is in a drop zone or not. If it is not in a drop
|
||||
* zone, it returns %FALSE and no further processing is necessary.
|
||||
* Otherwise, the handler returns %TRUE. In this case, the handler must
|
||||
* ensure that gdk_drag_finish() is called to let the source know that
|
||||
* the drop is done. The call to gdk_drag_finish() can be done either
|
||||
* directly or in a #GtkWidget::drag-data-received handler which gets
|
||||
* triggered by calling gtk_drag_get_data() to receive the data for one
|
||||
* or more of the supported targets.
|
||||
*
|
||||
* Returns: whether the cursor position is in a drop zone
|
||||
*/
|
||||
widget_signals[DRAG_DROP] =
|
||||
g_signal_new (I_("drag-drop"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_drop),
|
||||
_gtk_boolean_handled_accumulator, NULL,
|
||||
_gtk_marshal_BOOLEAN__OBJECT_INT_INT,
|
||||
G_TYPE_BOOLEAN, 3,
|
||||
GDK_TYPE_DROP,
|
||||
G_TYPE_INT,
|
||||
G_TYPE_INT);
|
||||
g_signal_set_va_marshaller (widget_signals[DRAG_DROP],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
_gtk_marshal_BOOLEAN__OBJECT_INT_INTv);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-data-get:
|
||||
* @widget: the object which received the signal
|
||||
* @context: the drag context
|
||||
* @data: the #GtkSelectionData to be filled with the dragged data
|
||||
* @info: the info that has been registered with the target in the
|
||||
* #GtkTargetList
|
||||
*
|
||||
* The ::drag-data-get signal is emitted on the drag source when the drop
|
||||
* site requests the data which is dragged. It is the responsibility of
|
||||
* the signal handler to fill @data with the data in the format which
|
||||
* is indicated by @info. See gtk_selection_data_set() and
|
||||
* gtk_selection_data_set_text().
|
||||
*/
|
||||
widget_signals[DRAG_DATA_GET] =
|
||||
g_signal_new (I_("drag-data-get"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_data_get),
|
||||
NULL, NULL,
|
||||
_gtk_marshal_VOID__OBJECT_BOXED,
|
||||
G_TYPE_NONE, 2,
|
||||
GDK_TYPE_DRAG,
|
||||
GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
g_signal_set_va_marshaller (widget_signals[DRAG_DATA_GET],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
_gtk_marshal_VOID__OBJECT_BOXEDv);
|
||||
|
||||
/**
|
||||
* GtkWidget::drag-data-received:
|
||||
* @widget: the object which received the signal
|
||||
* @drop: the #GdkDrop
|
||||
* @x: where the drop happened
|
||||
* @y: where the drop happened
|
||||
* @data: the received data
|
||||
*
|
||||
* The ::drag-data-received signal is emitted on the drop site when the
|
||||
* dragged data has been received. If the data was received in order to
|
||||
* determine whether the drop will be accepted, the handler is expected
|
||||
* to call gdk_drag_status() and not finish the drag.
|
||||
* If the data was received in response to a #GtkWidget::drag-drop signal
|
||||
* (and this is the last target to be received), the handler for this
|
||||
* signal is expected to process the received data and then call
|
||||
* gdk_drag_finish(), setting the @success parameter depending on
|
||||
* whether the data was processed successfully.
|
||||
*
|
||||
* Applications must create some means to determine why the signal was emitted
|
||||
* and therefore whether to call gdk_drag_status() or gdk_drag_finish().
|
||||
*
|
||||
* The handler may inspect the selected action with
|
||||
* gdk_drag_context_get_selected_action() before calling
|
||||
* gdk_drag_finish(), e.g. to implement %GDK_ACTION_ASK as
|
||||
* shown in the following example:
|
||||
* |[<!-- language="C" -->
|
||||
* void
|
||||
* drag_data_received (GtkWidget *widget,
|
||||
* GdkDrop *drop,
|
||||
* GtkSelectionData *data)
|
||||
* {
|
||||
* if ((data->length >= 0) && (data->format == 8))
|
||||
* {
|
||||
* GdkDragAction action;
|
||||
*
|
||||
* // handle data here
|
||||
*
|
||||
* action = gdk_drop_get_actions (drop);
|
||||
* if (!gdk_drag_action_is_unique (action))
|
||||
* {
|
||||
* GtkWidget *dialog;
|
||||
* gint response;
|
||||
*
|
||||
* dialog = gtk_message_dialog_new (NULL,
|
||||
* GTK_DIALOG_MODAL |
|
||||
* GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
* GTK_MESSAGE_INFO,
|
||||
* GTK_BUTTONS_YES_NO,
|
||||
* "Move the data ?\n");
|
||||
* response = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
* gtk_widget_destroy (dialog);
|
||||
*
|
||||
* if (response == GTK_RESPONSE_YES)
|
||||
* action = GDK_ACTION_MOVE;
|
||||
* else
|
||||
* action = GDK_ACTION_COPY;
|
||||
* }
|
||||
*
|
||||
* gdk_drop_finish (context, action);
|
||||
* }
|
||||
* else
|
||||
* gdk_drop_finish (context, 0);
|
||||
* }
|
||||
* ]|
|
||||
*/
|
||||
widget_signals[DRAG_DATA_RECEIVED] =
|
||||
g_signal_new (I_("drag-data-received"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkWidgetClass, drag_data_received),
|
||||
NULL, NULL,
|
||||
_gtk_marshal_VOID__OBJECT_BOXED,
|
||||
G_TYPE_NONE, 2,
|
||||
GDK_TYPE_DROP,
|
||||
GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
g_signal_set_va_marshaller (widget_signals[DRAG_DATA_RECEIVED],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
_gtk_marshal_VOID__OBJECT_BOXEDv);
|
||||
|
||||
/**
|
||||
* GtkWidget::query-tooltip:
|
||||
* @widget: the object which received the signal
|
||||
|
@ -187,24 +187,6 @@ struct _GtkWidget
|
||||
* @focus:
|
||||
* @move_focus: Signal emitted when a change of focus is requested
|
||||
* @keynav_failed: Signal emitted if keyboard navigation fails.
|
||||
* @drag_begin: Signal emitted on the drag source when a drag is
|
||||
* started.
|
||||
* @drag_end: Signal emitted on the drag source when a drag is
|
||||
* finished.
|
||||
* @drag_data_get: Signal emitted on the drag source when the drop
|
||||
* site requests the data which is dragged.
|
||||
* @drag_data_delete: Signal emitted on the drag source when a drag
|
||||
* with the action %GDK_ACTION_MOVE is successfully completed.
|
||||
* @drag_leave: Signal emitted on the drop site when the cursor leaves
|
||||
* the widget.
|
||||
* @drag_motion: signal emitted on the drop site when the user moves
|
||||
* the cursor over the widget during a drag.
|
||||
* @drag_drop: Signal emitted on the drop site when the user drops the
|
||||
* data onto the widget.
|
||||
* @drag_data_received: Signal emitted on the drop site when the
|
||||
* dragged data has been received.
|
||||
* @drag_failed: Signal emitted on the drag source when a drag has
|
||||
* failed.
|
||||
* @popup_menu: Signal emitted whenever a widget should pop up a
|
||||
* context menu.
|
||||
* @get_accessible: Returns the accessible object that describes the
|
||||
@ -276,35 +258,6 @@ struct _GtkWidgetClass
|
||||
gboolean (* keynav_failed) (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
|
||||
/* Source side drag signals */
|
||||
void (* drag_begin) (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
void (* drag_end) (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
void (* drag_data_get) (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data);
|
||||
void (* drag_data_delete) (GtkWidget *widget,
|
||||
GdkDrag *drag);
|
||||
|
||||
/* Target side drag signals */
|
||||
void (* drag_leave) (GtkWidget *widget,
|
||||
GdkDrop *drop);
|
||||
gboolean (* drag_motion) (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
gboolean (* drag_drop) (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y);
|
||||
void (* drag_data_received) (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data);
|
||||
gboolean (* drag_failed) (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkDragResult result);
|
||||
|
||||
/* Signals used only for keybindings */
|
||||
gboolean (* popup_menu) (GtkWidget *widget);
|
||||
|
||||
|
@ -1784,6 +1784,7 @@ gtk_window_init (GtkWindow *window)
|
||||
GtkEventController *motion_controller;
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
GdkContentFormats *targets;
|
||||
GtkDropTarget *dest;
|
||||
#endif
|
||||
|
||||
widget = GTK_WIDGET (window);
|
||||
@ -1838,11 +1839,9 @@ gtk_window_init (GtkWindow *window)
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
targets = gdk_content_formats_new (dnd_dest_targets, G_N_ELEMENTS (dnd_dest_targets));
|
||||
gtk_drag_dest_set (GTK_WIDGET (window),
|
||||
GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
|
||||
targets,
|
||||
GDK_ACTION_MOVE);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_MOVE);
|
||||
gdk_content_formats_unref (targets);
|
||||
gtk_widget_add_controller (GTK_WIDGET (window), GTK_EVENT_CONTROLLER (dest));
|
||||
#endif
|
||||
|
||||
seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
|
||||
|
@ -213,7 +213,6 @@ gtk_public_sources = files([
|
||||
'gtkcontainer.c',
|
||||
'gtkcssprovider.c',
|
||||
'gtkdialog.c',
|
||||
'gtkdnd.c',
|
||||
'gtkdragdest.c',
|
||||
'gtkdragsource.c',
|
||||
'gtkdrawingarea.c',
|
||||
@ -472,7 +471,6 @@ gtk_public_headers = files([
|
||||
'gtkcustomlayout.h',
|
||||
'gtkdebug.h',
|
||||
'gtkdialog.h',
|
||||
'gtkdnd.h',
|
||||
'gtkdragdest.h',
|
||||
'gtkdragsource.h',
|
||||
'gtkdrawingarea.h',
|
||||
|
@ -142,7 +142,19 @@ textview {
|
||||
|
||||
textview border { background-color: mix($bg_color, $base_color, 50%); }
|
||||
|
||||
iconview { @extend .view; }
|
||||
iconview {
|
||||
@extend .view;
|
||||
|
||||
&:drop(active) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
dndtarget:drop(active) {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: $selected_borders_color;
|
||||
}
|
||||
}
|
||||
|
||||
.rubberband,
|
||||
rubberband {
|
||||
@ -1906,6 +1918,9 @@ treeview.view {
|
||||
border-top: $backdrop_bg_color;
|
||||
}
|
||||
&:drop(active) {
|
||||
box-shadow: none;
|
||||
}
|
||||
dndtarget:drop(active) {
|
||||
border-style: solid none;
|
||||
border-width: 1px;
|
||||
border-color: $selected_borders_color;
|
||||
@ -3893,6 +3908,15 @@ expander-widget title:hover > expander {
|
||||
color: lighten($fg_color,30%); //only lightens the icon
|
||||
}
|
||||
|
||||
placessidebar,
|
||||
stackswitcher,
|
||||
expander-widget {
|
||||
&:not(decoration):not(window):drop(active):focus,
|
||||
&:not(decoration):not(window):drop(active) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
* Calendar *
|
||||
|
@ -156,11 +156,6 @@
|
||||
<signal name="key-pressed" handler="treeview_key_press_cb" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<signal name="drag-data-received" handler="file_list_drag_data_received_cb" swapped="no"/>
|
||||
<signal name="drag-drop" handler="file_list_drag_drop_cb" swapped="no"/>
|
||||
<signal name="drag-begin" handler="file_list_drag_begin_cb" swapped="no"/>
|
||||
<signal name="drag-motion" handler="file_list_drag_motion_cb" swapped="no"/>
|
||||
<signal name="drag-end" handler="file_list_drag_end_cb" swapped="no"/>
|
||||
<signal name="popup-menu" handler="list_popup_menu_cb" swapped="no"/>
|
||||
<signal name="query-tooltip" handler="file_list_query_tooltip_cb" swapped="no"/>
|
||||
<signal name="row-activated" handler="list_row_activated" swapped="no"/>
|
||||
|
@ -31,6 +31,7 @@ gtk_tests = [
|
||||
['testdialog'],
|
||||
['testdnd'],
|
||||
['testdnd2'],
|
||||
['testdnd3'],
|
||||
['testellipsise'],
|
||||
['testemblems'],
|
||||
['testentrycompletion'],
|
||||
@ -53,7 +54,6 @@ gtk_tests = [
|
||||
['testiconview-keynav'],
|
||||
['testicontheme'],
|
||||
['testinfobar'],
|
||||
['testimage'],
|
||||
['testkineticscrolling'],
|
||||
['testlist'],
|
||||
['testlist2'],
|
||||
|
264
tests/testdnd.c
264
tests/testdnd.c
@ -298,9 +298,9 @@ static const char *target_table[] = {
|
||||
static guint n_targets = sizeof(target_table) / sizeof(target_table[0]);
|
||||
|
||||
void
|
||||
target_drag_leave (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
guint time)
|
||||
target_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
g_print("leave\n");
|
||||
have_drag = FALSE;
|
||||
@ -308,13 +308,12 @@ target_drag_leave (GtkWidget *widget,
|
||||
}
|
||||
|
||||
gboolean
|
||||
target_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
target_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *source_widget;
|
||||
GdkDrag *drag;
|
||||
char *s;
|
||||
|
||||
if (!have_drag)
|
||||
@ -323,12 +322,6 @@ target_drag_motion (GtkWidget *widget,
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE (widget), trashcan_open);
|
||||
}
|
||||
|
||||
drag = gdk_drop_get_drag (drop);
|
||||
source_widget = drag ? gtk_drag_get_source_widget (drag) : NULL;
|
||||
g_print ("motion, source %s\n", source_widget ?
|
||||
G_OBJECT_TYPE_NAME (source_widget) :
|
||||
"NULL");
|
||||
|
||||
s = gdk_content_formats_to_string (gdk_drop_get_formats (drop));
|
||||
g_print ("%s\n", s);
|
||||
|
||||
@ -337,11 +330,29 @@ target_drag_motion (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
got_text_in_target (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
char *str;
|
||||
|
||||
str = gdk_drop_read_text_finish (GDK_DROP (object), result, NULL);
|
||||
if (str)
|
||||
{
|
||||
g_print ("Received \"%s\" in target\n", str);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
gdk_drop_finish (GDK_DROP (object), GDK_ACTION_MOVE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
target_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
target_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GdkContentFormats *formats;
|
||||
const char *format;
|
||||
@ -355,10 +366,12 @@ target_drag_drop (GtkWidget *widget,
|
||||
format = gdk_content_formats_match_mime_type (formats, formats);
|
||||
if (format)
|
||||
{
|
||||
gtk_drag_get_data (widget, drop, format);
|
||||
gdk_drop_read_text_async (drop, NULL, got_text_in_target, widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gdk_drop_status (drop, 0);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -381,55 +394,33 @@ action_make_unique (GdkDragAction action)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
target_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
static void
|
||||
got_text (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
if (gtk_selection_data_get_length (selection_data) >= 0 &&
|
||||
gtk_selection_data_get_format (selection_data) == 8)
|
||||
char *str;
|
||||
|
||||
str = gdk_drop_read_text_finish (GDK_DROP (object), result, NULL);
|
||||
if (str)
|
||||
{
|
||||
GdkDragAction action = gdk_drop_get_actions (drop);
|
||||
g_print ("Received \"%s\" in trashcan\n", (gchar *) gtk_selection_data_get_data (selection_data));
|
||||
action = action_make_unique (action);
|
||||
gdk_drop_finish (drop, action);
|
||||
return;
|
||||
g_print ("Received \"%s\" in label\n", str);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
gdk_drop_finish (drop, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
label_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data)
|
||||
label_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
if (gtk_selection_data_get_length (selection_data) >= 0 &&
|
||||
gtk_selection_data_get_format (selection_data) == 8)
|
||||
{
|
||||
GdkDragAction action = action_make_unique (gdk_drop_get_actions (drop));
|
||||
g_print ("Received \"%s\" in label\n", (gchar *) gtk_selection_data_get_data (selection_data));
|
||||
gdk_drop_finish (drop, action);
|
||||
return;
|
||||
}
|
||||
|
||||
gdk_drop_finish (drop, 0);
|
||||
gdk_drop_read_text_async (drop, NULL, got_text, widget);
|
||||
GdkDragAction action = action_make_unique (gdk_drop_get_actions (drop));
|
||||
gdk_drop_finish (drop, action);
|
||||
}
|
||||
|
||||
void
|
||||
source_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
{
|
||||
if (gtk_selection_data_get_target (selection_data) == g_intern_static_string ("application/x-rootwindow-drop"))
|
||||
g_print ("I was dropped on the rootwin\n");
|
||||
else
|
||||
gtk_selection_data_set (selection_data,
|
||||
gtk_selection_data_get_target (selection_data),
|
||||
8, (guchar *) "I'm Data!", 9);
|
||||
}
|
||||
|
||||
/* The following is a rather elaborate example demonstrating/testing
|
||||
* changing of the window hierarchy during a drag - in this case,
|
||||
* via a "spring-loaded" popup window.
|
||||
@ -453,11 +444,17 @@ popdown_cb (gpointer data)
|
||||
}
|
||||
|
||||
gboolean
|
||||
popup_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
popup_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
gdk_drop_status (drop, GDK_ACTION_COPY);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
popup_enter (GtkDropTarget *dest)
|
||||
{
|
||||
g_print ("popup enter\n");
|
||||
if (!in_popup)
|
||||
{
|
||||
in_popup = TRUE;
|
||||
@ -468,14 +465,12 @@ popup_motion (GtkWidget *widget,
|
||||
popdown_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
popup_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
popup_leave (GtkDropTarget *dest)
|
||||
{
|
||||
g_print ("popup leave\n");
|
||||
if (in_popup)
|
||||
{
|
||||
in_popup = FALSE;
|
||||
@ -487,6 +482,15 @@ popup_leave (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
popup_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
gdk_drop_finish (drop, GDK_ACTION_COPY);
|
||||
popdown_cb (NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
popup_cb (gpointer data)
|
||||
{
|
||||
@ -502,26 +506,26 @@ popup_cb (gpointer data)
|
||||
popup_window = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
targets = gdk_content_formats_new (target_table, n_targets - 1); /* no rootwin */
|
||||
targets = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
|
||||
|
||||
for (i=0; i<3; i++)
|
||||
for (j=0; j<3; j++)
|
||||
{
|
||||
char buffer[128];
|
||||
GtkDropTarget *dest;
|
||||
|
||||
g_snprintf(buffer, sizeof(buffer), "%d,%d", i, j);
|
||||
button = gtk_button_new_with_label (buffer);
|
||||
gtk_widget_set_hexpand (button, TRUE);
|
||||
gtk_widget_set_vexpand (button, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), button, i, j, 1, 1);
|
||||
|
||||
gtk_drag_dest_set (button,
|
||||
GTK_DEST_DEFAULT_ALL,
|
||||
targets,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
g_signal_connect (button, "drag-motion",
|
||||
G_CALLBACK (popup_motion), NULL);
|
||||
g_signal_connect (button, "drag-leave",
|
||||
G_CALLBACK (popup_leave), NULL);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (popup_motion), NULL);
|
||||
g_signal_connect (dest, "drag-enter", G_CALLBACK (popup_enter), NULL);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (popup_leave), NULL);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (popup_drop), NULL);
|
||||
gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (dest));
|
||||
}
|
||||
gtk_container_add (GTK_CONTAINER (popup_window), grid);
|
||||
gdk_content_formats_unref (targets);
|
||||
@ -531,30 +535,33 @@ popup_cb (gpointer data)
|
||||
popped_up = TRUE;
|
||||
}
|
||||
|
||||
popdown_timer = g_timeout_add (500, popdown_cb, NULL);
|
||||
g_print ("added popdown\n");
|
||||
|
||||
popup_timer = FALSE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
popsite_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y)
|
||||
popsite_motion (GtkDropTarget *dest,
|
||||
int x,
|
||||
int y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
if (!popup_timer)
|
||||
popup_timer = g_timeout_add (500, popup_cb, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
popsite_leave (GtkWidget *widget,
|
||||
GdkDrop *drop)
|
||||
popsite_enter (GtkDropTarget *dest)
|
||||
{
|
||||
g_print ("popsite enter\n");
|
||||
if (!popup_timer)
|
||||
popup_timer = g_timeout_add (500, popup_cb, NULL);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
popsite_leave (GtkDropTarget *dest)
|
||||
{
|
||||
g_print ("popsite leave\n");
|
||||
if (popup_timer)
|
||||
{
|
||||
g_source_remove (popup_timer);
|
||||
@ -562,10 +569,9 @@ popsite_leave (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
source_drag_data_delete (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
void
|
||||
source_drag_data_delete (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
g_print ("Delete the data!\n");
|
||||
}
|
||||
@ -587,7 +593,11 @@ main (int argc, char **argv)
|
||||
GtkWidget *button;
|
||||
GdkPixbuf *drag_icon;
|
||||
GdkTexture *texture;
|
||||
GdkContentProvider *content;
|
||||
GValue value = G_VALUE_INIT;
|
||||
GtkDragSource *source;
|
||||
GdkContentFormats *targets;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
test_init ();
|
||||
|
||||
@ -610,13 +620,9 @@ main (int argc, char **argv)
|
||||
label = gtk_label_new ("Drop Here\n");
|
||||
|
||||
targets = gdk_content_formats_new (target_table, n_targets - 1); /* no rootwin */
|
||||
gtk_drag_dest_set (label,
|
||||
GTK_DEST_DEFAULT_ALL,
|
||||
targets,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
|
||||
g_signal_connect (label, "drag_data_received",
|
||||
G_CALLBACK( label_drag_data_received), NULL);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (label_drag_drop), NULL);
|
||||
gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_set_vexpand (label, TRUE);
|
||||
@ -624,49 +630,46 @@ main (int argc, char **argv)
|
||||
|
||||
label = gtk_label_new ("Popup\n");
|
||||
|
||||
gtk_drag_dest_set (label,
|
||||
GTK_DEST_DEFAULT_ALL,
|
||||
targets,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (popsite_motion), NULL);
|
||||
g_signal_connect (dest, "drag-enter", G_CALLBACK (popsite_enter), NULL);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (popsite_leave), NULL);
|
||||
gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_set_vexpand (label, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
|
||||
|
||||
g_signal_connect (label, "drag-motion",
|
||||
G_CALLBACK (popsite_motion), NULL);
|
||||
g_signal_connect (label, "drag-leave",
|
||||
G_CALLBACK (popsite_leave), NULL);
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
pixmap = gtk_image_new_from_pixbuf (trashcan_closed);
|
||||
gtk_drag_dest_set (pixmap, 0, NULL, 0);
|
||||
targets = gdk_content_formats_new (NULL, 0);
|
||||
dest = gtk_drop_target_new (targets, 0);
|
||||
g_signal_connect (dest, "drag-leave", G_CALLBACK (target_drag_leave), pixmap);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (target_drag_motion), pixmap);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (target_drag_drop), pixmap);
|
||||
gtk_widget_add_controller (pixmap, GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
gtk_widget_set_hexpand (pixmap, TRUE);
|
||||
gtk_widget_set_vexpand (pixmap, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), pixmap, 1, 0, 1, 1);
|
||||
|
||||
g_signal_connect (pixmap, "drag-leave",
|
||||
G_CALLBACK (target_drag_leave), NULL);
|
||||
|
||||
g_signal_connect (pixmap, "drag-motion",
|
||||
G_CALLBACK (target_drag_motion), NULL);
|
||||
|
||||
g_signal_connect (pixmap, "drag-drop",
|
||||
G_CALLBACK (target_drag_drop), NULL);
|
||||
|
||||
g_signal_connect (pixmap, "drag-data-received",
|
||||
G_CALLBACK (target_drag_data_received), NULL);
|
||||
|
||||
/* Drag site */
|
||||
|
||||
button = gtk_button_new_with_label ("Drag Here\n");
|
||||
button = gtk_label_new ("Drag Here\n");
|
||||
|
||||
targets = gdk_content_formats_new (target_table, n_targets);
|
||||
gtk_drag_source_set (button, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
|
||||
targets,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
gtk_drag_source_set_icon_paintable (button, GDK_PAINTABLE (texture));
|
||||
gdk_content_formats_unref (targets);
|
||||
source = gtk_drag_source_new ();
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
g_value_set_string (&value, "I'm data!");
|
||||
content = gdk_content_provider_new_for_value (&value);
|
||||
g_value_unset (&value);
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_object_unref (content);
|
||||
gtk_drag_source_set_actions (source, GDK_ACTION_COPY|GDK_ACTION_MOVE);
|
||||
gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (source));
|
||||
gtk_drag_source_set_icon (source, GDK_PAINTABLE (texture), 0, 0);
|
||||
|
||||
g_object_unref (texture);
|
||||
|
||||
@ -674,11 +677,6 @@ main (int argc, char **argv)
|
||||
gtk_widget_set_vexpand (button, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 1, 1);
|
||||
|
||||
g_signal_connect (button, "drag-data-get",
|
||||
G_CALLBACK (source_drag_data_get), NULL);
|
||||
g_signal_connect (button, "drag-data-delete",
|
||||
G_CALLBACK (source_drag_data_delete), NULL);
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
gtk_main ();
|
||||
|
503
tests/testdnd2.c
503
tests/testdnd2.c
@ -1,3 +1,4 @@
|
||||
#include <unistd.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GdkPaintable *
|
||||
@ -37,122 +38,6 @@ enum {
|
||||
BOTTOM_RIGHT
|
||||
};
|
||||
|
||||
static void
|
||||
image_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
gint hotspot;
|
||||
gint hot_x, hot_y;
|
||||
gint size;
|
||||
|
||||
paintable = get_image_paintable (GTK_IMAGE (data), &size);
|
||||
hotspot = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (data), "hotspot"));
|
||||
switch (hotspot)
|
||||
{
|
||||
default:
|
||||
case TOP_LEFT:
|
||||
hot_x = 0;
|
||||
hot_y = 0;
|
||||
break;
|
||||
case CENTER:
|
||||
hot_x = size / 2;
|
||||
hot_y = size / 2;
|
||||
break;
|
||||
case BOTTOM_RIGHT:
|
||||
hot_x = size;
|
||||
hot_y = size;
|
||||
break;
|
||||
}
|
||||
gtk_drag_set_icon_paintable (drag, paintable, hot_x, hot_y);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_widget_destroyed (GtkWidget *image, gpointer data)
|
||||
{
|
||||
GtkWidget *widget = data;
|
||||
|
||||
g_print ("drag widget destroyed\n");
|
||||
g_object_unref (image);
|
||||
g_object_set_data (G_OBJECT (widget), "drag widget", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
window_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *window = data;
|
||||
|
||||
gtk_widget_destroy (window);
|
||||
g_signal_handlers_disconnect_by_func (widget, window_drag_end, data);
|
||||
}
|
||||
|
||||
static void
|
||||
window_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
GtkWidget *image;
|
||||
int hotspot;
|
||||
int size;
|
||||
|
||||
hotspot = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (data), "hotspot"));
|
||||
|
||||
image = g_object_get_data (G_OBJECT (widget), "drag widget");
|
||||
if (image == NULL)
|
||||
{
|
||||
g_print ("creating new drag widget\n");
|
||||
paintable = get_image_paintable (GTK_IMAGE (data), &size);
|
||||
image = gtk_image_new_from_paintable (paintable);
|
||||
g_object_unref (paintable);
|
||||
g_object_ref (image);
|
||||
g_object_set_data (G_OBJECT (widget), "drag widget", image);
|
||||
g_signal_connect (image, "destroy", G_CALLBACK (drag_widget_destroyed), widget);
|
||||
}
|
||||
else
|
||||
g_print ("reusing drag widget\n");
|
||||
|
||||
gtk_drag_set_icon_widget (drag, image, 0, 0);
|
||||
|
||||
if (hotspot == CENTER)
|
||||
g_signal_connect (widget, "drag-end", G_CALLBACK (window_drag_end), image);
|
||||
}
|
||||
|
||||
static void
|
||||
update_source_target_list (GtkWidget *image)
|
||||
{
|
||||
GdkContentFormats *target_list;
|
||||
|
||||
target_list = gdk_content_formats_new (NULL, 0);
|
||||
|
||||
target_list = gtk_content_formats_add_image_targets (target_list, FALSE);
|
||||
if (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME)
|
||||
target_list = gtk_content_formats_add_text_targets (target_list);
|
||||
|
||||
gtk_drag_source_set_target_list (image, target_list);
|
||||
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
|
||||
static void
|
||||
update_dest_target_list (GtkWidget *image)
|
||||
{
|
||||
GdkContentFormats *target_list;
|
||||
|
||||
target_list = gdk_content_formats_new (NULL, 0);
|
||||
|
||||
target_list = gtk_content_formats_add_image_targets (target_list, FALSE);
|
||||
target_list = gtk_content_formats_add_text_targets (target_list);
|
||||
|
||||
gtk_drag_dest_set_target_list (image, target_list);
|
||||
|
||||
gdk_content_formats_unref (target_list);
|
||||
}
|
||||
|
||||
void
|
||||
image_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
@ -186,154 +71,320 @@ image_drag_data_get (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
image_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
got_texture (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
gchar *text;
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GtkWidget *image = data;
|
||||
const GValue *value;
|
||||
GError *error = NULL;
|
||||
|
||||
if (gtk_selection_data_get_length (selection_data) == 0)
|
||||
return;
|
||||
|
||||
if (gtk_selection_data_targets_include_image (selection_data, FALSE))
|
||||
value = gdk_drop_read_value_finish (drop, result, &error);
|
||||
if (value)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
|
||||
texture = gtk_selection_data_get_texture (selection_data);
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
|
||||
|
||||
g_object_unref (texture);
|
||||
}
|
||||
else if (gtk_selection_data_targets_include_text (selection_data))
|
||||
{
|
||||
text = (gchar *)gtk_selection_data_get_text (selection_data);
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (data), text);
|
||||
g_free (text);
|
||||
GdkTexture *texture = g_value_get_object (value);
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
|
||||
gdk_drop_finish (drop, GDK_ACTION_COPY);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
g_error_free (error);
|
||||
gdk_drop_finish (drop, 0);
|
||||
}
|
||||
|
||||
g_object_set_data (G_OBJECT (image), "drop", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
perform_drop (GdkDrop *drop,
|
||||
GtkWidget *image)
|
||||
{
|
||||
if (gdk_drop_has_value (drop, GDK_TYPE_TEXTURE))
|
||||
gdk_drop_read_value_async (drop, GDK_TYPE_TEXTURE, G_PRIORITY_DEFAULT, NULL, got_texture, image);
|
||||
else
|
||||
{
|
||||
gdk_drop_finish (drop, 0);
|
||||
g_object_set_data (G_OBJECT (image), "drop", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_copy (GtkWidget *button)
|
||||
{
|
||||
GtkWidget *popover = gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER);
|
||||
GtkWidget *image = gtk_popover_get_relative_to (GTK_POPOVER (popover));
|
||||
GdkDrop *drop = GDK_DROP (g_object_get_data (G_OBJECT (image), "drop"));
|
||||
|
||||
gtk_popover_popdown (GTK_POPOVER (popover));
|
||||
perform_drop (drop, image);
|
||||
}
|
||||
|
||||
static void
|
||||
do_cancel (GtkWidget *button)
|
||||
{
|
||||
GtkWidget *popover = gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER);
|
||||
GtkWidget *image = gtk_popover_get_relative_to (GTK_POPOVER (popover));
|
||||
GdkDrop *drop = GDK_DROP (g_object_get_data (G_OBJECT (image), "drop"));
|
||||
|
||||
gtk_popover_popdown (GTK_POPOVER (popover));
|
||||
gdk_drop_finish (drop, 0);
|
||||
|
||||
g_object_set_data (G_OBJECT (image), "drop", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ask_actions (GdkDrop *drop,
|
||||
GtkWidget *image)
|
||||
{
|
||||
GtkWidget *popover, *box, *button;
|
||||
|
||||
popover = g_object_get_data (G_OBJECT (image), "popover");
|
||||
if (!popover)
|
||||
{
|
||||
popover = gtk_popover_new (image);
|
||||
g_object_set_data (G_OBJECT (image), "popover", popover);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (popover), box);
|
||||
button = gtk_button_new_with_label ("Copy");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (do_copy), NULL);
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
button = gtk_button_new_with_label ("Move");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (do_copy), NULL);
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
button = gtk_button_new_with_label ("Cancel");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (do_cancel), NULL);
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
}
|
||||
gtk_popover_popup (GTK_POPOVER (popover));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
delayed_deny (gpointer data)
|
||||
{
|
||||
GtkDropTarget *dest = data;
|
||||
GtkWidget *image = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
GdkDrop *drop = GDK_DROP (g_object_get_data (G_OBJECT (image), "drop"));
|
||||
|
||||
if (drop)
|
||||
{
|
||||
g_print ("denying drop, late\n");
|
||||
gtk_drop_target_deny_drop (dest, drop);
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
image_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *image = data;
|
||||
g_object_set_data_full (G_OBJECT (image), "drop", g_object_ref (drop), g_object_unref);
|
||||
|
||||
g_timeout_add (1000, delayed_deny, dest);
|
||||
|
||||
gdk_drop_status (drop, gtk_drop_target_get_actions (dest));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
image_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *image = data;
|
||||
GdkDragAction action = gdk_drop_get_actions (drop);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (image), "drop", g_object_ref (drop), g_object_unref);
|
||||
|
||||
g_print ("drop, actions %d\n", action);
|
||||
if (!gdk_drag_action_is_unique (action))
|
||||
ask_actions (drop, image);
|
||||
else
|
||||
perform_drop (drop, image);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
update_source_icon (GtkDragSource *source,
|
||||
const char *icon_name,
|
||||
int hotspot)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
int hot_x, hot_y;
|
||||
int size = 48;
|
||||
|
||||
paintable = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
|
||||
icon_name, size, 0, NULL);
|
||||
switch (hotspot)
|
||||
{
|
||||
default:
|
||||
case TOP_LEFT:
|
||||
hot_x = 0;
|
||||
hot_y = 0;
|
||||
break;
|
||||
case CENTER:
|
||||
hot_x = size / 2;
|
||||
hot_y = size / 2;
|
||||
break;
|
||||
case BOTTOM_RIGHT:
|
||||
hot_x = size;
|
||||
hot_y = size;
|
||||
break;
|
||||
}
|
||||
gtk_drag_source_set_icon (source, paintable, hot_x, hot_y);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
get_data (const char *mimetype,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *image = data;
|
||||
GdkContentFormats *formats;
|
||||
gboolean want_text;
|
||||
|
||||
formats = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
|
||||
formats = gdk_content_formats_union_serialize_mime_types (formats);
|
||||
want_text = gdk_content_formats_contain_mime_type (formats, mimetype);
|
||||
gdk_content_formats_unref (formats);
|
||||
|
||||
if (want_text)
|
||||
{
|
||||
const char *text = gtk_image_get_icon_name (GTK_IMAGE (image));
|
||||
|
||||
return g_bytes_new (text, strlen (text) + 1);
|
||||
}
|
||||
else if (strcmp (mimetype, "image/png") == 0)
|
||||
{
|
||||
int size;
|
||||
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (image), &size);
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
{
|
||||
char *name = g_strdup ("drag-data-XXXXXX");
|
||||
int fd;
|
||||
char *data;
|
||||
gsize size;
|
||||
|
||||
// FIXME: this is horrible
|
||||
|
||||
fd = g_mkstemp (name);
|
||||
close (fd);
|
||||
|
||||
gdk_texture_save_to_png (GDK_TEXTURE (paintable), name);
|
||||
|
||||
g_file_get_contents (name, &data, &size, NULL);
|
||||
g_free (name);
|
||||
|
||||
return g_bytes_new_take (data, size);
|
||||
}
|
||||
|
||||
g_clear_object (&paintable);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkDragSource *source)
|
||||
{
|
||||
g_print ("drag begin\n");
|
||||
}
|
||||
|
||||
static void
|
||||
drag_end (GtkDragSource *source)
|
||||
{
|
||||
g_print ("drag end\n");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_cancel (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GdkDragCancelReason reason)
|
||||
{
|
||||
g_print ("drag failed: %d\n", reason);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
make_image (const gchar *icon_name, int hotspot)
|
||||
{
|
||||
GtkWidget *image;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
GdkContentFormats *formats;
|
||||
GdkContentFormatsBuilder *builder;
|
||||
GdkContentProvider *content;
|
||||
|
||||
image = gtk_image_new_from_icon_name (icon_name);
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
update_source_target_list (image);
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
gdk_content_formats_builder_add_gtype (builder, GDK_TYPE_TEXTURE);
|
||||
gdk_content_formats_builder_add_gtype (builder, G_TYPE_STRING);
|
||||
formats = gdk_content_formats_builder_free_to_formats (builder);
|
||||
|
||||
g_object_set_data (G_OBJECT (image), "hotspot", GINT_TO_POINTER (hotspot));
|
||||
content = gdk_content_provider_new_with_formats (formats, get_data, image);
|
||||
source = gtk_drag_source_new ();
|
||||
gtk_drag_source_set_content (source, content);
|
||||
gtk_drag_source_set_actions (source, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
|
||||
g_object_unref (content);
|
||||
update_source_icon (source, icon_name, hotspot);
|
||||
|
||||
g_signal_connect (image, "drag-begin", G_CALLBACK (image_drag_begin), image);
|
||||
g_signal_connect (image, "drag-data-get", G_CALLBACK (image_drag_data_get), image);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL);
|
||||
g_signal_connect (source, "drag-cancel", G_CALLBACK (drag_cancel), NULL);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL, NULL, GDK_ACTION_COPY);
|
||||
g_signal_connect (image, "drag-data-received", G_CALLBACK (image_drag_data_received), image);
|
||||
update_dest_target_list (image);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY|GDK_ACTION_MOVE|GDK_ACTION_ASK);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (image_drag_motion), image);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (image_drag_drop), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
make_image2 (const gchar *icon_name, int hotspot)
|
||||
{
|
||||
GtkWidget *image;
|
||||
|
||||
image = gtk_image_new_from_icon_name (icon_name);
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
update_source_target_list (image);
|
||||
|
||||
g_object_set_data (G_OBJECT (image), "hotspot", GINT_TO_POINTER (hotspot));
|
||||
|
||||
g_signal_connect (image, "drag-begin", G_CALLBACK (window_drag_begin), image);
|
||||
g_signal_connect (image, "drag-data-get", G_CALLBACK (image_drag_data_get), image);
|
||||
|
||||
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL, NULL, GDK_ACTION_COPY);
|
||||
g_signal_connect (image, "drag-data-received", G_CALLBACK (image_drag_data_received), image);
|
||||
update_dest_target_list (image);
|
||||
gdk_content_formats_unref (formats);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
static void
|
||||
spinner_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
spinner_drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *spinner;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
g_print ("GtkWidget::drag-begin\n");
|
||||
spinner = g_object_new (GTK_TYPE_SPINNER,
|
||||
"visible", TRUE,
|
||||
"active", TRUE,
|
||||
NULL);
|
||||
gtk_drag_set_icon_widget (drag, spinner, 0, 0);
|
||||
g_object_set_data (G_OBJECT (drag), "spinner", spinner);
|
||||
}
|
||||
|
||||
static void
|
||||
spinner_drag_end (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *spinner;
|
||||
|
||||
g_print ("GtkWidget::drag-end\n");
|
||||
spinner = g_object_get_data (G_OBJECT (drag), "spinner");
|
||||
gtk_widget_destroy (spinner);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
spinner_drag_failed (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkDragResult result,
|
||||
gpointer data)
|
||||
{
|
||||
GTypeClass *class;
|
||||
GEnumValue *value;
|
||||
|
||||
class = g_type_class_ref (GTK_TYPE_DRAG_RESULT);
|
||||
value = g_enum_get_value (G_ENUM_CLASS (class), result);
|
||||
g_print ("GtkWidget::drag-failed %s\n", value->value_nick);
|
||||
g_type_class_unref (class);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
spinner_drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
{
|
||||
g_print ("GtkWidget::drag-data-get\n");
|
||||
gtk_selection_data_set_text (selection_data, "ACTIVE", -1);
|
||||
paintable = gtk_widget_paintable_new (widget);
|
||||
gtk_drag_source_set_icon (source, paintable, 0, 0);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
make_spinner (void)
|
||||
{
|
||||
GtkWidget *spinner;
|
||||
GtkDragSource *source;
|
||||
GdkContentProvider *content;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
spinner = gtk_spinner_new ();
|
||||
gtk_spinner_start (GTK_SPINNER (spinner));
|
||||
|
||||
gtk_drag_source_set (spinner, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_text_targets (spinner);
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
g_value_set_string (&value, "ACTIVE");
|
||||
content = gdk_content_provider_new_for_value (&value);
|
||||
source = gtk_drag_source_new ();
|
||||
gtk_drag_source_set_content (source, content);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (spinner_drag_begin), spinner);
|
||||
gtk_widget_add_controller (spinner, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
g_signal_connect (spinner, "drag-begin", G_CALLBACK (spinner_drag_begin), spinner);
|
||||
g_signal_connect (spinner, "drag-end", G_CALLBACK (spinner_drag_end), spinner);
|
||||
g_signal_connect (spinner, "drag-failed", G_CALLBACK (spinner_drag_failed), spinner);
|
||||
g_signal_connect (spinner, "drag-data-get", G_CALLBACK (spinner_drag_data_get), spinner);
|
||||
g_object_unref (content);
|
||||
g_value_unset (&value);
|
||||
|
||||
return spinner;
|
||||
}
|
||||
@ -367,9 +418,9 @@ main (int argc, char *Argv[])
|
||||
gtk_grid_attach (GTK_GRID (grid), make_spinner (), 0, 2, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), make_image ("weather-clear", CENTER), 1, 2, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), make_image2 ("dialog-question", TOP_LEFT), 0, 3, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), make_image ("dialog-question", TOP_LEFT), 0, 3, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), make_image2 ("dialog-information", CENTER), 1, 3, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), make_image ("dialog-information", CENTER), 1, 3, 1, 1);
|
||||
|
||||
gtk_widget_show (window);
|
||||
gtk_main ();
|
||||
|
398
tests/testdnd3.c
Normal file
398
tests/testdnd3.c
Normal file
@ -0,0 +1,398 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GdkContentProvider *
|
||||
prepare (GtkDragSource *source, double x, double y)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *item;
|
||||
GdkContentProvider *provider;
|
||||
GBytes *bytes;
|
||||
|
||||
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
item = gtk_widget_pick (canvas, x, y, GTK_PICK_DEFAULT);
|
||||
|
||||
if (!GTK_IS_LABEL (item))
|
||||
return NULL;
|
||||
|
||||
bytes = g_bytes_new (&item, sizeof (gpointer));
|
||||
provider = gdk_content_provider_new_for_bytes ("CANVAS_ITEM", bytes);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
g_object_set_data (G_OBJECT (canvas), "dragged-item", item);
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkDragSource *source, GdkDrag *drag)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *item;
|
||||
|
||||
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
item = g_object_get_data (G_OBJECT (canvas), "dragged-item");
|
||||
|
||||
gtk_widget_set_opacity (item, 0.5);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_end (GtkDragSource *source, GdkDrag *drag)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *item;
|
||||
|
||||
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
item = g_object_get_data (G_OBJECT (canvas), "dragged-item");
|
||||
g_object_set_data (G_OBJECT (canvas), "dragged-item", NULL);
|
||||
|
||||
gtk_widget_set_opacity (item, 1.0);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *canvas;
|
||||
double x;
|
||||
double y;
|
||||
} DropData;
|
||||
|
||||
typedef struct {
|
||||
double x, y;
|
||||
double angle;
|
||||
double delta;
|
||||
} TransformData;
|
||||
|
||||
static void
|
||||
apply_transform (GtkWidget *item)
|
||||
{
|
||||
GtkWidget *canvas = gtk_widget_get_parent (item);
|
||||
TransformData *data;
|
||||
GskTransform *transform;
|
||||
|
||||
data = g_object_get_data (G_OBJECT (item), "transform-data");
|
||||
transform = gsk_transform_rotate (gsk_transform_translate (NULL, &(graphene_point_t){data->x, data->y}),
|
||||
data->angle + data->delta);
|
||||
gtk_fixed_set_child_transform (GTK_FIXED (canvas), item, transform);
|
||||
gsk_transform_unref (transform);
|
||||
}
|
||||
|
||||
static void
|
||||
got_data (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
DropData *data = user_data;
|
||||
GInputStream *stream;
|
||||
GBytes *bytes;
|
||||
GtkWidget *item;
|
||||
const char *mime_type;
|
||||
GError *error = NULL;
|
||||
TransformData *transform_data;
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *last_child;
|
||||
|
||||
stream = gdk_drop_read_finish (drop, result, &mime_type, &error);
|
||||
bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL);
|
||||
item = (gpointer) *(gpointer *)g_bytes_get_data (bytes, NULL);
|
||||
|
||||
transform_data = g_object_get_data (G_OBJECT (item), "transform-data");
|
||||
|
||||
transform_data->x = data->x;
|
||||
transform_data->y = data->y;
|
||||
|
||||
canvas = gtk_widget_get_parent (item);
|
||||
last_child = gtk_widget_get_last_child (canvas);
|
||||
if (item != last_child)
|
||||
gtk_widget_insert_after (item, canvas, last_child);
|
||||
|
||||
apply_transform (item);
|
||||
|
||||
gdk_drop_finish (drop, GDK_ACTION_MOVE);
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
g_object_unref (stream);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
DropData *data;
|
||||
|
||||
data = g_new (DropData, 1);
|
||||
data->canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
data->x = x;
|
||||
data->y = y;
|
||||
|
||||
gdk_drop_read_async (drop, (const char *[]){"CANVAS_ITEM", NULL}, G_PRIORITY_DEFAULT, NULL, got_data, data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
canvas_new (void)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
GdkContentFormats *formats;
|
||||
|
||||
canvas = gtk_fixed_new ();
|
||||
gtk_widget_set_hexpand (canvas, TRUE);
|
||||
gtk_widget_set_vexpand (canvas, TRUE);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (canvas), "frame");
|
||||
|
||||
source = gtk_drag_source_new ();
|
||||
gtk_drag_source_set_actions (source, GDK_ACTION_MOVE);
|
||||
g_signal_connect (source, "prepare", G_CALLBACK (prepare), NULL);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL);
|
||||
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
formats = gdk_content_formats_new ((const char *[]){"CANVAS_ITEM", NULL}, 1);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL);
|
||||
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (formats);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
static void
|
||||
set_color (GtkWidget *item,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
char *css;
|
||||
char *str;
|
||||
GtkStyleContext *context;
|
||||
GtkCssProvider *provider;
|
||||
|
||||
str = gdk_rgba_to_string (color);
|
||||
css = g_strdup_printf ("* { background: %s; padding: 10px; }", str);
|
||||
|
||||
context = gtk_widget_get_style_context (item);
|
||||
provider = g_object_get_data (G_OBJECT (context), "style-provider");
|
||||
if (provider)
|
||||
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (item), GTK_STYLE_PROVIDER (provider), 800);
|
||||
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
|
||||
|
||||
g_free (str);
|
||||
g_free (css);
|
||||
}
|
||||
|
||||
static void
|
||||
got_color (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GtkDropTarget *dest = data;
|
||||
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
const GValue *value;
|
||||
GdkRGBA *color;
|
||||
|
||||
value = gdk_drop_read_value_finish (drop, result, NULL);
|
||||
color = g_value_get_boxed (value);
|
||||
set_color (item, color);
|
||||
|
||||
gdk_drop_finish (drop, GDK_ACTION_COPY);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
item_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
if (gtk_drop_target_find_mimetype (dest))
|
||||
{
|
||||
gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, dest);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
item_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop)
|
||||
{
|
||||
if (gtk_drop_target_find_mimetype (dest) != NULL)
|
||||
{
|
||||
gdk_drop_status (drop, GDK_ACTION_COPY);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
angle_changed (GtkGestureRotate *gesture,
|
||||
double angle,
|
||||
double delta)
|
||||
{
|
||||
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data");
|
||||
|
||||
data->delta = angle / M_PI * 180.0;
|
||||
|
||||
apply_transform (item);
|
||||
}
|
||||
|
||||
static void
|
||||
rotate_done (GtkGesture *gesture)
|
||||
{
|
||||
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data");
|
||||
|
||||
data->angle = data->angle + data->delta;
|
||||
data->delta = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
click_done (GtkGesture *gesture)
|
||||
{
|
||||
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
GtkWidget *canvas = gtk_widget_get_parent (item);
|
||||
GtkWidget *last_child;
|
||||
|
||||
last_child = gtk_widget_get_last_child (canvas);
|
||||
if (item != last_child)
|
||||
gtk_widget_insert_after (item, canvas, last_child);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
canvas_item_new (int i,
|
||||
double x,
|
||||
double y,
|
||||
double angle)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
char *label;
|
||||
char *id;
|
||||
TransformData *transform_data;
|
||||
GdkRGBA rgba;
|
||||
GtkDropTarget *dest;
|
||||
GdkContentFormats *formats;
|
||||
GtkGesture *gesture;
|
||||
|
||||
label = g_strdup_printf ("Item %d", i);
|
||||
id = g_strdup_printf ("item%d", i);
|
||||
|
||||
gdk_rgba_parse (&rgba, "yellow");
|
||||
|
||||
widget = gtk_label_new (label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "frame");
|
||||
gtk_widget_set_name (widget, id);
|
||||
|
||||
set_color (widget, &rgba);
|
||||
transform_data = g_new0 (TransformData, 1);
|
||||
transform_data->x = x;
|
||||
transform_data->y = y;
|
||||
transform_data->angle = angle;
|
||||
g_object_set_data_full (G_OBJECT (widget), "transform-data", transform_data, g_free);
|
||||
|
||||
g_free (label);
|
||||
g_free (id);
|
||||
|
||||
formats = gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA);
|
||||
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (item_drag_drop), NULL);
|
||||
g_signal_connect (dest, "accept", G_CALLBACK (item_drag_motion), NULL);
|
||||
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (formats);
|
||||
|
||||
gesture = gtk_gesture_rotate_new ();
|
||||
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
|
||||
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
|
||||
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
|
||||
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *sw;
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *widget;
|
||||
GtkWidget *box, *box2, *box3;
|
||||
const char *colors[] = {
|
||||
"red", "green", "blue", "magenta", "orange", "gray", "black", "yellow",
|
||||
"white", "gray", "brown", "pink", "cyan", "bisque", "gold", "maroon",
|
||||
"navy", "orchid", "olive", "peru", "salmon", "silver", "wheat",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
int x, y;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
widget = gtk_color_button_new ();
|
||||
gtk_widget_destroy (widget);
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (box), box2);
|
||||
|
||||
canvas = canvas_new ();
|
||||
gtk_container_add (GTK_CONTAINER (box2), canvas);
|
||||
|
||||
x = y = 40;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
GtkWidget *item;
|
||||
|
||||
item = canvas_item_new (i, x, y, 0);
|
||||
gtk_container_add (GTK_CONTAINER (canvas), item);
|
||||
apply_transform (item);
|
||||
|
||||
x += 150;
|
||||
y += 100;
|
||||
}
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_NEVER);
|
||||
gtk_container_add (GTK_CONTAINER (box), sw);
|
||||
|
||||
box3 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (box3), "linked");
|
||||
gtk_container_add (GTK_CONTAINER (sw), box3);
|
||||
|
||||
for (i = 0; colors[i]; i++)
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
GtkWidget *swatch;
|
||||
|
||||
gdk_rgba_parse (&rgba, colors[i]);
|
||||
|
||||
swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
|
||||
"rgba", &rgba,
|
||||
"selectable", FALSE,
|
||||
NULL);
|
||||
gtk_container_add (GTK_CONTAINER (box3), swatch);
|
||||
}
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
@ -8,45 +8,6 @@ clear_pressed (GtkEntry *entry, gint icon, gpointer data)
|
||||
gtk_editable_set_text (GTK_EDITABLE (entry), "");
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint pos;
|
||||
|
||||
pos = gtk_entry_get_current_icon_drag_source (GTK_ENTRY (widget));
|
||||
if (pos != -1)
|
||||
gtk_drag_set_icon_name (drag, "dialog-information", 2, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_data_get_cb (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *data,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint pos;
|
||||
|
||||
pos = gtk_entry_get_current_icon_drag_source (GTK_ENTRY (widget));
|
||||
|
||||
if (pos == GTK_ENTRY_ICON_PRIMARY)
|
||||
{
|
||||
gint start, end;
|
||||
|
||||
if (gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), &start, &end))
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
str = gtk_editable_get_chars (GTK_EDITABLE (widget), start, end);
|
||||
gtk_selection_data_set_text (data, str, -1);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
gtk_selection_data_set_text (data, "XXX", -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_blank (GtkWidget *button,
|
||||
GtkEntry *entry)
|
||||
@ -127,7 +88,8 @@ main (int argc, char **argv)
|
||||
GtkWidget *button3;
|
||||
GtkWidget *button4;
|
||||
GIcon *icon;
|
||||
GdkContentFormats *tlist;
|
||||
GdkContentProvider *content;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
@ -190,16 +152,15 @@ main (int argc, char **argv)
|
||||
gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
|
||||
GTK_ENTRY_ICON_PRIMARY,
|
||||
"Save a file");
|
||||
tlist = gdk_content_formats_new (NULL, 0);
|
||||
tlist = gtk_content_formats_add_text_targets (tlist);
|
||||
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
g_value_set_string (&value, "Amazing");
|
||||
content = gdk_content_provider_new_for_value (&value);
|
||||
g_value_unset (&value);
|
||||
gtk_entry_set_icon_drag_source (GTK_ENTRY (entry),
|
||||
GTK_ENTRY_ICON_PRIMARY,
|
||||
tlist, GDK_ACTION_COPY);
|
||||
g_signal_connect_after (entry, "drag-begin",
|
||||
G_CALLBACK (drag_begin_cb), NULL);
|
||||
g_signal_connect (entry, "drag-data-get",
|
||||
G_CALLBACK (drag_data_get_cb), NULL);
|
||||
gdk_content_formats_unref (tlist);
|
||||
content, GDK_ACTION_COPY);
|
||||
g_object_unref (content);
|
||||
|
||||
/*
|
||||
* Search - Uses a helper function
|
||||
|
@ -1,178 +0,0 @@
|
||||
/* testimage.c
|
||||
* Copyright (C) 2004 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
static void
|
||||
drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *image = GTK_WIDGET (data);
|
||||
GdkPaintable *paintable;
|
||||
|
||||
paintable = gtk_image_get_paintable (GTK_IMAGE (image));
|
||||
gtk_drag_set_icon_paintable (drag, paintable, -2, -2);
|
||||
}
|
||||
|
||||
void
|
||||
drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *image = GTK_WIDGET (data);
|
||||
GdkPaintable *paintable;
|
||||
|
||||
paintable = gtk_image_get_paintable (GTK_IMAGE (image));
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
gtk_selection_data_set_texture (selection_data, GDK_TEXTURE (paintable));
|
||||
}
|
||||
|
||||
static void
|
||||
drag_data_received (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint32 time,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *image = GTK_WIDGET (data);
|
||||
GdkTexture *texture;
|
||||
|
||||
if (gtk_selection_data_get_length (selection_data) < 0)
|
||||
return;
|
||||
|
||||
texture = gtk_selection_data_get_texture (selection_data);
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
|
||||
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
idle_func (gpointer data)
|
||||
{
|
||||
g_print ("keep me busy\n");
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *grid;
|
||||
GtkWidget *label, *image;
|
||||
GtkIconTheme *theme;
|
||||
GdkPaintable *paintable;
|
||||
gchar *icon_name = "help-browser";
|
||||
gchar *anim_filename = NULL;
|
||||
GtkIconInfo *icon_info;
|
||||
GIcon *icon;
|
||||
GFile *file;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
if (argc > 1)
|
||||
icon_name = argv[1];
|
||||
|
||||
if (argc > 2)
|
||||
anim_filename = argv[2];
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
|
||||
gtk_container_add (GTK_CONTAINER (window), grid);
|
||||
|
||||
label = gtk_label_new ("symbolic size");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
|
||||
label = gtk_label_new ("fixed size");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 2, 0, 1, 1);
|
||||
|
||||
label = gtk_label_new ("GTK_IMAGE_PIXBUF");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
|
||||
|
||||
theme = gtk_icon_theme_get_default ();
|
||||
icon_info = gtk_icon_theme_lookup_icon_for_scale (theme, icon_name, 48, gtk_widget_get_scale_factor (window), GTK_ICON_LOOKUP_GENERIC_FALLBACK);
|
||||
paintable = gtk_icon_info_load_icon (icon_info, NULL);
|
||||
g_object_unref (icon_info);
|
||||
image = gtk_image_new_from_paintable (paintable);
|
||||
g_object_unref (paintable);
|
||||
gtk_grid_attach (GTK_GRID (grid), image, 2, 1, 1, 1);
|
||||
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK,
|
||||
NULL,
|
||||
GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_image_targets (image);
|
||||
g_signal_connect (image, "drag_begin", G_CALLBACK (drag_begin), image);
|
||||
g_signal_connect (image, "drag_data_get", G_CALLBACK (drag_data_get), image);
|
||||
|
||||
gtk_drag_dest_set (image,
|
||||
GTK_DEST_DEFAULT_MOTION |
|
||||
GTK_DEST_DEFAULT_HIGHLIGHT |
|
||||
GTK_DEST_DEFAULT_DROP,
|
||||
NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_dest_add_image_targets (image);
|
||||
g_signal_connect (image, "drag_data_received",
|
||||
G_CALLBACK (drag_data_received), image);
|
||||
|
||||
label = gtk_label_new ("GTK_IMAGE_ICON_NAME");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 4, 1, 1);
|
||||
image = gtk_image_new_from_icon_name (icon_name);
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
gtk_grid_attach (GTK_GRID (grid), image, 1, 4, 1, 1);
|
||||
image = gtk_image_new_from_icon_name (icon_name);
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), 30);
|
||||
gtk_grid_attach (GTK_GRID (grid), image, 2, 4, 1, 1);
|
||||
|
||||
label = gtk_label_new ("GTK_IMAGE_GICON");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 5, 1, 1);
|
||||
icon = g_themed_icon_new_with_default_fallbacks ("folder-remote");
|
||||
image = gtk_image_new_from_gicon (icon);
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
g_object_unref (icon);
|
||||
gtk_grid_attach (GTK_GRID (grid), image, 1, 5, 1, 1);
|
||||
file = g_file_new_for_path ("apple-red.png");
|
||||
icon = g_file_icon_new (file);
|
||||
image = gtk_image_new_from_gicon (icon);
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
g_object_unref (icon);
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), 30);
|
||||
gtk_grid_attach (GTK_GRID (grid), image, 2, 5, 1, 1);
|
||||
|
||||
if (anim_filename)
|
||||
{
|
||||
label = gtk_label_new ("GTK_IMAGE_ANIMATION (from file)");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 6, 1, 1);
|
||||
image = gtk_image_new_from_file (anim_filename);
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (image), 30);
|
||||
gtk_grid_attach (GTK_GRID (grid), image, 2, 6, 1, 1);
|
||||
|
||||
/* produce high load */
|
||||
g_idle_add_full (G_PRIORITY_DEFAULT,
|
||||
idle_func, NULL, NULL);
|
||||
}
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
@ -5,9 +5,9 @@ static const char *entries[] = {
|
||||
};
|
||||
|
||||
static void
|
||||
drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *row;
|
||||
GtkAllocation alloc;
|
||||
@ -19,43 +19,31 @@ drag_begin (GtkWidget *widget,
|
||||
|
||||
paintable = gtk_widget_paintable_new (row);
|
||||
gtk_widget_translate_coordinates (widget, row, 0, 0, &x, &y);
|
||||
gtk_drag_set_icon_paintable (drag, paintable, -x, -y);
|
||||
gtk_drag_source_set_icon (source, paintable, -x, -y);
|
||||
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_selection_data_set (selection_data,
|
||||
g_intern_static_string ("GTK_LIST_BOX_ROW"),
|
||||
32,
|
||||
(const guchar *)&widget,
|
||||
sizeof (gpointer));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
got_row (GObject *src,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *target;
|
||||
GtkDropTarget *dest = GTK_DROP_TARGET (src);
|
||||
GtkWidget *target = data;
|
||||
GtkWidget *row;
|
||||
GtkWidget *source;
|
||||
int pos;
|
||||
GtkSelectionData *selection_data;
|
||||
|
||||
target = widget;
|
||||
selection_data = gtk_drop_target_read_selection_finish (dest, result, NULL);
|
||||
|
||||
pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
|
||||
row = (gpointer)* (gpointer*)gtk_selection_data_get_data (selection_data);
|
||||
source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW);
|
||||
|
||||
gtk_selection_data_free (selection_data);
|
||||
|
||||
if (source == target)
|
||||
return;
|
||||
|
||||
@ -65,11 +53,25 @@ drag_data_received (GtkWidget *widget,
|
||||
g_object_unref (source);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_drop_target_read_selection (dest, "GTK_LIST_BOX_ROW", NULL, got_row, data);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_row (const gchar *text)
|
||||
{
|
||||
GtkWidget *row, *box, *label, *image;
|
||||
GBytes *bytes;
|
||||
GdkContentProvider *content;
|
||||
GdkContentFormats *targets;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
image = gtk_image_new_from_icon_name ("open-menu-symbolic");
|
||||
@ -81,14 +83,18 @@ create_row (const gchar *text)
|
||||
gtk_container_add (GTK_CONTAINER (box), label);
|
||||
gtk_container_add (GTK_CONTAINER (box), image);
|
||||
|
||||
bytes = g_bytes_new (&row, sizeof (gpointer));
|
||||
content = gdk_content_provider_new_for_bytes ("GTK_LIST_BOX_ROW", bytes);
|
||||
source = gtk_drag_source_new ();
|
||||
gtk_drag_source_set_content (source, content);
|
||||
gtk_drag_source_set_actions (source, GDK_ACTION_MOVE);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
targets = gdk_content_formats_new (entries, 1);
|
||||
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, targets, GDK_ACTION_MOVE);
|
||||
g_signal_connect (image, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
g_signal_connect (image, "drag-data-get", G_CALLBACK (drag_data_get), NULL);
|
||||
|
||||
gtk_drag_dest_set (row, GTK_DEST_DEFAULT_ALL, targets, GDK_ACTION_MOVE);
|
||||
g_signal_connect (row, "drag-data-received", G_CALLBACK (drag_data_received), NULL);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), row);
|
||||
gtk_widget_add_controller (GTK_WIDGET (row), GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
|
@ -90,26 +90,11 @@ on_page_reordered (GtkNotebook *notebook, GtkWidget *child, guint page_num, gpoi
|
||||
g_print ("page %d reordered\n", page_num);
|
||||
}
|
||||
|
||||
static void
|
||||
on_notebook_drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
guint page_num;
|
||||
|
||||
page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (widget));
|
||||
|
||||
if (page_num > 2)
|
||||
gtk_drag_set_icon_name (drag,
|
||||
(page_num % 2) ? "help-browser" : "process-stop",
|
||||
0, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
remove_in_idle (gpointer data)
|
||||
{
|
||||
GtkWidget *child = data;
|
||||
GtkWidget *parent = gtk_widget_get_parent (child);
|
||||
GtkWidget *parent = gtk_widget_get_ancestor (child, GTK_TYPE_NOTEBOOK);
|
||||
GtkWidget *tab_label;
|
||||
|
||||
tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (parent), child);
|
||||
@ -120,16 +105,45 @@ remove_in_idle (gpointer data)
|
||||
}
|
||||
|
||||
static void
|
||||
on_button_drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *data,
|
||||
gpointer user_data)
|
||||
got_page (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget **child;
|
||||
GdkDrop *drop = GDK_DROP (source);
|
||||
GInputStream *stream;
|
||||
const char *mime_type;
|
||||
|
||||
child = (void*) gtk_selection_data_get_data (data);
|
||||
stream = gdk_drop_read_finish (drop, result, &mime_type, NULL);
|
||||
|
||||
g_idle_add (remove_in_idle, *child);
|
||||
if (stream)
|
||||
{
|
||||
GBytes *bytes;
|
||||
GtkWidget **child;
|
||||
|
||||
bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL);
|
||||
child = (gpointer)g_bytes_get_data (bytes, NULL);
|
||||
|
||||
g_idle_add (remove_in_idle, *child);
|
||||
|
||||
gdk_drop_finish (drop, GDK_ACTION_MOVE);
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
g_object_unref (stream);
|
||||
}
|
||||
else
|
||||
gdk_drop_finish (drop, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_button_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gpointer user_data)
|
||||
{
|
||||
gdk_drop_read_async (drop, (const char *[]) { "GTK_NOTEBOOK_TAB", NULL }, G_PRIORITY_DEFAULT, NULL, got_page, NULL);
|
||||
|
||||
gdk_drop_finish (drop, GDK_ACTION_MOVE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -186,8 +200,6 @@ create_notebook (gchar **labels,
|
||||
|
||||
g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
|
||||
G_CALLBACK (on_page_reordered), NULL);
|
||||
g_signal_connect_after (G_OBJECT (notebook), "drag-begin",
|
||||
G_CALLBACK (on_notebook_drag_begin), NULL);
|
||||
return notebook;
|
||||
}
|
||||
|
||||
@ -216,12 +228,18 @@ create_notebook_non_dragable_content (gchar **labels,
|
||||
while (*labels)
|
||||
{
|
||||
GtkWidget *button;
|
||||
button = gtk_button_new_with_label (*labels);
|
||||
button = gtk_button_new_with_label ("example content");
|
||||
/* Use GtkListBox since it bubbles up motion notify event, which can
|
||||
* experience more issues than GtkBox. */
|
||||
page = gtk_list_box_new ();
|
||||
gtk_container_add (GTK_CONTAINER (page), button);
|
||||
|
||||
button = gtk_button_new_with_label ("row 2");
|
||||
gtk_container_add (GTK_CONTAINER (page), button);
|
||||
|
||||
button = gtk_button_new_with_label ("third row");
|
||||
gtk_container_add (GTK_CONTAINER (page), button);
|
||||
|
||||
title = gtk_label_new (*labels);
|
||||
|
||||
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, title);
|
||||
@ -233,8 +251,6 @@ create_notebook_non_dragable_content (gchar **labels,
|
||||
|
||||
g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
|
||||
G_CALLBACK (on_page_reordered), NULL);
|
||||
g_signal_connect_after (G_OBJECT (notebook), "drag-begin",
|
||||
G_CALLBACK (on_notebook_drag_begin), NULL);
|
||||
return notebook;
|
||||
}
|
||||
|
||||
@ -271,8 +287,6 @@ create_notebook_with_notebooks (gchar **labels,
|
||||
|
||||
g_signal_connect (GTK_NOTEBOOK (notebook), "page-reordered",
|
||||
G_CALLBACK (on_page_reordered), NULL);
|
||||
g_signal_connect_after (G_OBJECT (notebook), "drag-begin",
|
||||
G_CALLBACK (on_notebook_drag_begin), NULL);
|
||||
return notebook;
|
||||
}
|
||||
|
||||
@ -281,18 +295,16 @@ create_trash_button (void)
|
||||
{
|
||||
GdkContentFormats *targets;
|
||||
GtkWidget *button;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
button = gtk_button_new_with_mnemonic ("_Delete");
|
||||
|
||||
targets = gdk_content_formats_new (button_targets, G_N_ELEMENTS (button_targets));
|
||||
gtk_drag_dest_set (button,
|
||||
GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
|
||||
targets,
|
||||
GDK_ACTION_MOVE);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (on_button_drag_drop), NULL);
|
||||
gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
g_signal_connect_after (G_OBJECT (button), "drag-data-received",
|
||||
G_CALLBACK (on_button_drag_data_received), NULL);
|
||||
return button;
|
||||
}
|
||||
|
||||
|
@ -293,11 +293,12 @@ bold_toggled (GtkToggleToolButton *button)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
toolbar_drag_drop (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
toolbar_drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x, gint y,
|
||||
GtkWidget *label)
|
||||
{
|
||||
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
gchar buf[32];
|
||||
|
||||
g_snprintf(buf, sizeof(buf), "%d",
|
||||
@ -323,12 +324,11 @@ rtl_toggled (GtkCheckButton *check)
|
||||
static GtkToolItem *drag_item = NULL;
|
||||
|
||||
static gboolean
|
||||
toolbar_drag_motion (GtkToolbar *toolbar,
|
||||
GdkDrop *drop,
|
||||
toolbar_drag_motion (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
gint y,
|
||||
guint time,
|
||||
gpointer null)
|
||||
GtkToolbar *toolbar)
|
||||
{
|
||||
gint index;
|
||||
|
||||
@ -348,9 +348,9 @@ toolbar_drag_motion (GtkToolbar *toolbar,
|
||||
}
|
||||
|
||||
static void
|
||||
toolbar_drag_leave (GtkToolbar *toolbar,
|
||||
GdkDrop *drop,
|
||||
gpointer null)
|
||||
toolbar_drag_leave (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
GtkToolbar *toolbar)
|
||||
{
|
||||
if (drag_item)
|
||||
{
|
||||
@ -389,6 +389,9 @@ main (gint argc, gchar **argv)
|
||||
GtkWidget *hbox, *hbox1, *hbox2, *checkbox, *option_menu, *menu;
|
||||
gint i;
|
||||
GdkContentFormats *targets;
|
||||
GdkContentProvider *content;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
static const gchar *toolbar_styles[] = { "icons", "text", "both (vertical)",
|
||||
"both (horizontal)" };
|
||||
GtkToolItem *item;
|
||||
@ -616,19 +619,18 @@ main (gint argc, gchar **argv)
|
||||
gtk_container_add (GTK_CONTAINER (hbox), checkbox);
|
||||
|
||||
targets = gdk_content_formats_new (target_table, G_N_ELEMENTS (target_table));
|
||||
gtk_drag_source_set (button, GDK_BUTTON1_MASK,
|
||||
targets,
|
||||
GDK_ACTION_MOVE);
|
||||
gtk_drag_dest_set (toolbar, GTK_DEST_DEFAULT_DROP,
|
||||
targets,
|
||||
GDK_ACTION_MOVE);
|
||||
content = gdk_content_provider_new_for_bytes (target_table[0], g_bytes_new ("", 1));
|
||||
source = gtk_drag_source_new ();
|
||||
gtk_drag_source_set_content (source, content);
|
||||
gtk_drag_source_set_actions (source, GDK_ACTION_MOVE);
|
||||
g_object_unref (content);
|
||||
gtk_widget_add_controller (button, GTK_EVENT_CONTROLLER (source));
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "drag_motion", G_CALLBACK (toolbar_drag_motion), toolbar);
|
||||
g_signal_connect (dest, "drag_leave", G_CALLBACK (toolbar_drag_leave), toolbar);
|
||||
g_signal_connect (dest, "drag_drop", G_CALLBACK (toolbar_drag_drop), label);
|
||||
gtk_widget_add_controller (toolbar, GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (targets);
|
||||
g_signal_connect (toolbar, "drag_motion",
|
||||
G_CALLBACK (toolbar_drag_motion), NULL);
|
||||
g_signal_connect (toolbar, "drag_leave",
|
||||
G_CALLBACK (toolbar_drag_leave), NULL);
|
||||
g_signal_connect (toolbar, "drag_drop",
|
||||
G_CALLBACK (toolbar_drag_drop), label);
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
|
@ -89,16 +89,32 @@ get_dragsource (void)
|
||||
}
|
||||
|
||||
static void
|
||||
drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selda,
|
||||
gpointer dada)
|
||||
got_text (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkDropTarget *dest = GTK_DROP_TARGET (source);
|
||||
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
gchar *text;
|
||||
GtkSelectionData *selda;
|
||||
|
||||
selda = gtk_drop_target_read_selection_finish (dest, result, NULL);
|
||||
|
||||
text = (gchar*) gtk_selection_data_get_text (selda);
|
||||
gtk_label_set_label (GTK_LABEL (widget), text);
|
||||
g_free (text);
|
||||
|
||||
gtk_selection_data_free (selda);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_drop (GtkDropTarget *dest,
|
||||
GdkDrop *drop,
|
||||
int x,
|
||||
int y,
|
||||
gpointer dada)
|
||||
{
|
||||
gtk_drop_target_read_selection (dest, "text/plain", NULL, got_text, dada);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
@ -106,11 +122,13 @@ get_droptarget (void)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GdkContentFormats *targets;
|
||||
GtkDropTarget *dest;
|
||||
|
||||
label = gtk_label_new ("Drop here");
|
||||
targets = gdk_content_formats_new (entries, G_N_ELEMENTS (entries));
|
||||
gtk_drag_dest_set (label, GTK_DEST_DEFAULT_ALL, targets, GDK_ACTION_COPY);
|
||||
g_signal_connect (label, "drag-data-received", G_CALLBACK (drag_data_received), NULL);
|
||||
dest = gtk_drop_target_new (targets, GDK_ACTION_COPY);
|
||||
g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL);
|
||||
gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (dest));
|
||||
gdk_content_formats_unref (targets);
|
||||
|
||||
return label;
|
||||
|
Loading…
Reference in New Issue
Block a user