textview: remove drag selection after dnd move action
authorChristian Hergert <chergert@redhat.com>
Fri, 7 Jan 2022 00:30:34 +0000 (16:30 -0800)
committerChristian Hergert <chergert@redhat.com>
Fri, 7 Jan 2022 00:30:34 +0000 (16:30 -0800)
If we have a GDK_ACTION_MOVE, we need to delete the selection. However,
previously this only worked when the drop target and drag source were
different applications, as the selection would get messed up along the
way.

Instead, we stash marks for the duration of the operation so that we can
delete the appropriate selection when completing the move.

gtk/gtktextview.c

index db23e9ad868d9ee79322e1de9484bf1fe028e8e8..44fd7c75766cc24532133f2c6ec4d99f67ce5b04 100644 (file)
@@ -231,8 +231,13 @@ struct _GtkTextViewPrivate
   guint first_validate_idle;        /* Idle to revalidate onscreen portion, runs before resize */
   guint incremental_validate_idle;  /* Idle to revalidate offscreen portions, runs after redraw */
 
+  /* Mark for drop target */
   GtkTextMark *dnd_mark;
 
+  /* Mark for selection of drag source */
+  GtkTextMark *dnd_drag_begin_mark;
+  GtkTextMark *dnd_drag_end_mark;
+
   GtkIMContext *im_context;
   GtkWidget *popup_menu;
   GMenuModel *extra_menu;
@@ -8056,8 +8061,26 @@ static void
 dnd_finished_cb (GdkDrag     *drag,
                  GtkTextView *self)
 {
-  if (gdk_drag_get_selected_action (drag) == GDK_ACTION_MOVE)
-    gtk_text_buffer_delete_selection (self->priv->buffer, TRUE, self->priv->editable);
+  GtkTextBuffer *buffer = self->priv->buffer;
+
+  if (self->priv->dnd_drag_begin_mark)
+    {
+      if (gdk_drag_get_selected_action (drag) == GDK_ACTION_MOVE)
+        {
+            {
+              GtkTextIter begin, end;
+
+              gtk_text_buffer_get_iter_at_mark (buffer, &begin, self->priv->dnd_drag_begin_mark);
+              gtk_text_buffer_get_iter_at_mark (buffer, &end, self->priv->dnd_drag_end_mark);
+              gtk_text_buffer_delete (buffer, &begin, &end);
+            }
+        }
+
+      gtk_text_buffer_delete_mark (buffer, self->priv->dnd_drag_begin_mark);
+      gtk_text_buffer_delete_mark (buffer, self->priv->dnd_drag_end_mark);
+      self->priv->dnd_drag_begin_mark = NULL;
+      self->priv->dnd_drag_end_mark = NULL;
+    }
 
   self->priv->drag = NULL;
 }
@@ -8067,6 +8090,16 @@ dnd_cancel_cb (GdkDrag *drag,
                GdkDragCancelReason reason,
                GtkTextView *self)
 {
+  GtkTextBuffer *buffer = self->priv->buffer;
+
+  if (self->priv->dnd_drag_begin_mark)
+    {
+      gtk_text_buffer_delete_mark (buffer, self->priv->dnd_drag_begin_mark);
+      gtk_text_buffer_delete_mark (buffer, self->priv->dnd_drag_end_mark);
+      self->priv->dnd_drag_begin_mark = NULL;
+      self->priv->dnd_drag_end_mark = NULL;
+    }
+
   self->priv->drag = NULL;
 }
 
@@ -8108,6 +8141,9 @@ gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
       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->dnd_drag_begin_mark = gtk_text_buffer_create_mark (buffer, NULL, &start, TRUE);
+      text_view->priv->dnd_drag_end_mark = gtk_text_buffer_create_mark (buffer, NULL, &end, TRUE);
     }
 
   text_view->priv->drag = drag;