Drag and Drop#
Drag and drop is an essential part of applications that deal with many files, and very easy to add to an application.
Adding a drop target#
You will need to create a GtkDropTarget
, which is an event controller that,
connected to a widget, emits the “drop” signal if the dragged object is dropped
on the widget. To receive the data, connect to that signal.
For this first example, we will setup the program to receive files from another program, such as Nautilus. Signal connections are included in this snippet for ease of copy-and-paste.
GtkDropTarget *target = gtk_drop_target_new (G_TYPE_INVALID, GDK_ACTION_COPY);
gtk_drop_target_set_gtypes (target, (GType[1]) { GDK_TYPE_FILE_LIST, }, 1);
g_signal_connect (target, "drop", G_CALLBACK (on_drop), NULL);
/* Visually emphasize the user that he is dropping a widget. */
g_signal_connect (target, "enter", G_CALLBACK (on_enter), my_window);
g_signal_connect (target, "leave", G_CALLBACK (on_leave), my_window);
gtk_widget_add_controller (GTK_WIDGET (my_window), GTK_EVENT_CONTROLLER (target));
content = Gdk.ContentFormats.new_for_gtype(Gdk.FileList)
target = Gtk.DropTarget(formats=content, actions=Gdk.DragAction.COPY)
target.connect('drop', on_drop)
# Visually emphasize the user that he is dropping a widget.
target.connect('enter', on_enter)
target.connect('leave', on_leave)
# self here is a widget.
self.add_controller(target)
We have told GTK that this widget is ready to be used for dragging and dropping. If you drag a file from your file manager, it will show the drag and drop icon. Next, we have to retrieve the data.
static gboolean
on_drop (GtkDropTarget *target,
const GValue *value,
double x,
double y,
gpointer data)
{
/* GdkFileList is a boxed value so we use the boxed API. */
GdkFileList *file_list = g_value_get_boxed (value);
GSList *list = gdk_file_list_get_files (file_list);
/* Loop through the files and print their names. */
for (GSList *l = list; l != NULL; l = l->next)
{
GFile* file = l->data;
g_print ("%s\n", g_file_get_path (file));
}
return TRUE;
}
def on_drop(self, drop_target, value: Gdk.FileList, x, y, user_data=None):
files: List[Gio.File] = value.get_files()
# Loop through the files and print their names.
for file in files:
print(file.get_path())
For the visual emphasis, these callbacks add and remove CSS classes to a widget, which results in a thin line drawn around the interior of the widget (highlighting).
/* Style the widget when a dragged object enters into its area. */
static GdkDragAction
on_enter (GtkDropTarget *target,
double x,
double y,
gpointer data)
{
gtk_widget_add_css_class (GTK_WIDGET (data), "drop_hover");
/* Tell the callee to continue. */
return GDK_ACTION_COPY;
}
/* Remove the style class added by on_enter. */
static void
on_leave (GtkDropTarget *target,
gpointer data)
{
gtk_widget_remove_css_class (GTK_WIDGET (data), "drop_hover");
}
# Style the widget when a dragged object enters into its area.
def on_enter(self, drop_target, x, y):
self.add_css_class('drop_hover')
# Tell the callee to continue
return Gdk.DragAction.COPY
# Remove the style class added by on_enter.
def on_leave(self, drop_target):
self.remove_css_class('drop_hover')
It is possible to use any type supported by the GObject type system for drag and drop operations within the same application, including complex types.
If you want to support drag and drop of complex types across applications, you will have to use the GdkContentSerializer and GdkContentDeserializer API.