From c8ad4d5debc48e8d348cd704a6c5f1835536a71f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Jun 2021 07:49:04 -0700 Subject: [PATCH 1/5] dnd: Add another assertion Assert that gdk_drop_finish() is called after the drop is performed. --- gdk/gdkdrop.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gdk/gdkdrop.c b/gdk/gdkdrop.c index 0825df69d2..37a63c5a7b 100644 --- a/gdk/gdkdrop.c +++ b/gdk/gdkdrop.c @@ -294,8 +294,11 @@ gdk_drop_finalize (GObject *object) /* someone forgot to send a LEAVE signal */ g_warn_if_fail (!priv->entered); + /* Should we emit finish() here if necessary? - * For now that's the backends' job */ + * For now that's the backends' job + */ + g_warn_if_fail (priv->state != GDK_DROP_STATE_DROPPING); g_clear_object (&priv->device); g_clear_object (&priv->drag); From 4df93140398f911ee310566928027f4865903c4e Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Jun 2021 06:57:38 -0700 Subject: [PATCH 2/5] wayland: Fix some dnd corner case We must call gdk_drag_drop_done() when the drag ends, successfully or not. Without this, we get an unwarranted emission of ::cancel after a successful drop. Since only the first call to gdk_drag_drop_done() is taking effect, it is safe to call as a fallback, after emitting ::dnd-finished. If the application connects to that signal and calls gdk_drag_drop_done() itself, its call will take precedence. This matches what the X11 implementation does. --- gdk/wayland/gdkdrag-wayland.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gdk/wayland/gdkdrag-wayland.c b/gdk/wayland/gdkdrag-wayland.c index de80afe020..8a8c4cc058 100644 --- a/gdk/wayland/gdkdrag-wayland.c +++ b/gdk/wayland/gdkdrag-wayland.c @@ -163,6 +163,7 @@ gdk_wayland_drag_cancel (GdkDrag *drag, GdkDragCancelReason reason) { gdk_drag_set_cursor (drag, NULL); + gdk_drag_drop_done (drag, FALSE); } static void @@ -290,6 +291,7 @@ data_source_dnd_finished (void *data, GdkDrag *drag = data; g_signal_emit_by_name (drag, "dnd-finished"); + gdk_drag_drop_done (drag, TRUE); } static void From 92c6485adfd413aa716985c3a2cea7a5d2439067 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Jun 2021 08:01:57 -0700 Subject: [PATCH 3/5] docs: Tweak wording Instead of drag'n'drop, say drag-and-drop. That is easier to read, and less unclear on the markdown syntax implications. --- demos/gtk-demo/peg_solitaire.c | 4 ++-- gdk/gdkdrop.c | 4 ++-- gtk/gtkdragicon.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/demos/gtk-demo/peg_solitaire.c b/demos/gtk-demo/peg_solitaire.c index 4fe4f11d44..0f5761408c 100644 --- a/demos/gtk-demo/peg_solitaire.c +++ b/demos/gtk-demo/peg_solitaire.c @@ -1,7 +1,7 @@ /* Peg Solitaire * #Keywords: GtkGridView, game * - * This demo demonstrates how to use drag'n'drop to implement peg solitaire. + * This demo demonstrates how to use drag-and-drop to implement peg solitaire. * */ @@ -98,7 +98,7 @@ solitaire_peg_init (SolitairePeg *peg) /* Add a little setter for the peg's position. * We want to track those so that we can check for legal moves - * during drag'n'drop operations. + * during drag-and-drop operations. */ static void solitaire_peg_set_position (SolitairePeg *peg, diff --git a/gdk/gdkdrop.c b/gdk/gdkdrop.c index 37a63c5a7b..fc70822cb0 100644 --- a/gdk/gdkdrop.c +++ b/gdk/gdkdrop.c @@ -574,7 +574,7 @@ gdk_drop_get_drag (GdkDrop *self) * the ones provided by [method@Gdk.Drop.get_actions]. Those actions may * change in the future, even depending on the actions you provide here. * - * The @preferred action is a hint to the drag'n'drop mechanism about which + * The @preferred action is a hint to the drag-and-drop mechanism about which * action to use when multiple actions are possible. * * This function should be called by drag destinations in response to @@ -865,7 +865,7 @@ gdk_drop_read_value_internal (GdkDrop *self, * then call [method@Gdk.Drop.read_value_finish] to get the resulting * `GValue`. * - * For local drag'n'drop operations that are available in the given + * For local drag-and-drop operations that are available in the given * `GType`, the value will be copied directly. Otherwise, GDK will * try to use [func@Gdk.content_deserialize_async] to convert the data. */ diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c index 0b37d59119..b8b31671f9 100644 --- a/gtk/gtkdragicon.c +++ b/gtk/gtkdragicon.c @@ -512,7 +512,7 @@ gtk_drag_icon_get_child (GtkDragIcon *self) * If GTK does not know how to create a widget for a given value, * it will return %NULL. * - * This method is used to set the default drag icon on drag'n'drop + * This method is used to set the default drag icon on drag-and-drop * operations started by `GtkDragSource`, so you don't need to set * a drag icon using this function there. * From d7915fbca825924b098c5339a0b5c8048d774187 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Jun 2021 12:23:27 -0700 Subject: [PATCH 4/5] docs: Add a section about Drag-and-Drop --- docs/reference/gtk/drag-and-drop.md | 54 +++++++++++++++++++++++++++++ docs/reference/gtk/gtk4.toml.in | 1 + 2 files changed, 55 insertions(+) create mode 100644 docs/reference/gtk/drag-and-drop.md diff --git a/docs/reference/gtk/drag-and-drop.md b/docs/reference/gtk/drag-and-drop.md new file mode 100644 index 0000000000..15370f1655 --- /dev/null +++ b/docs/reference/gtk/drag-and-drop.md @@ -0,0 +1,54 @@ +Title: Drag-and-Drop in GTK + +Drag-and-Drop (DND) is a user interaction pattern where users drag a UI element +from one place to another, either inside a single application or between +different application windows. + +When the element is 'dropped', data is transferred from the source to the +destination, according to the drag action that is negotiated between both +sides. Most commonly, that is a _copy_, but it can also be a _move_ or a +_link_, depending on the kind of data and how the drag operation has been +set up. + +This chapter gives an overview over how Drag-and-Drop is handled with event +controllers in GTK. + +## Drag sources + +To make data available via DND, you create a [class@Gtk.DragSource]. Drag sources +are event controllers, which initiate a Drag-and-Drop operation when the user clicks +and drags the widget. + +A drag source can be set up ahead of time, with the desired drag action(s) and the data +to be transferred. But it is also possible to provide the data when a drag operation +is about to begin, by connecting to the [signal@Gtk.DragSource::prepare] signal. + +The GtkDragSource emits the [signal@Gtk.DragSource::drag-begin] signal when the DND +operation starts, and the [signal@Gtk.DragSource::drag-end] signal when it is done. +But it is not normally necessary to handle these signals. One case in which a ::drag-end +handler is necessary is to implement `GDK_ACTION_MOVE`. + +## Drop targets + +To receive data via DND, you create a [class@Gtk.DropTarget], and tell it what kind of +data to accept. You need to connect to the [signal@Gtk.DropTarget::drop] signal to receive +the data when a DND operation occurs. + +While a DND operation is ongoing, GTK provides updates when the pointer moves over +the widget to which the drop target is associated. The [signal@Gtk.DropTarget::enter], +[signal@Gtk.DropTarget::leave] and [signal@Gtk.DropTarget::motion] signals get emitted +for this purpose. + +GtkDropTarget provides a simple API, and only provides the data when it has been completely +transferred. If you need to handle the data transfer yourself (for example to provide progress +information during the transfer), you can use the more complicated [class@Gtk.DropTargetAsync]. + +## Other considerations + +It is sometimes necessary to update the UI of the destination while a DND operation is ongoing, +say to scroll or expand a view, or to switch pages. Typically, such UI changes are triggered +by hovering over the widget in question. + +[class@Gtk.DropControllerMotion] is an event controller that can help with implementing such +behaviors. It is very similar to [class@Gtk.EventControllerMotion], but provides events during +a DND operation. diff --git a/docs/reference/gtk/gtk4.toml.in b/docs/reference/gtk/gtk4.toml.in index 2a0d57e922..e1cc9f34cb 100644 --- a/docs/reference/gtk/gtk4.toml.in +++ b/docs/reference/gtk/gtk4.toml.in @@ -57,6 +57,7 @@ content_files = [ "initialization.md", "actions.md", "input-handling.md", + "drag-and-drop.md", "drawing-model.md", "css-overview.md", "css-properties.md", From 1cebf406aa97329980c1144058ddaae0af055e8b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Jun 2021 12:24:12 -0700 Subject: [PATCH 5/5] docs: Fix a typo --- gtk/gtkdroptarget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk/gtkdroptarget.c b/gtk/gtkdroptarget.c index 4012a41928..da1bbe6640 100644 --- a/gtk/gtkdroptarget.c +++ b/gtk/gtkdroptarget.c @@ -824,7 +824,7 @@ gtk_drop_target_class_init (GtkDropTargetClass *class) * and no further processing is necessary. * * Otherwise, the handler returns %TRUE. In this case, this handler will - * accept the drop. The handler is responsible for rading the given @value + * accept the drop. The handler is responsible for using the given @value * and performing the drop operation. * * Returns: whether the drop was accepted at the given pointer position