[gtk+] gtkdnd: Introduce a new API for more accurate drag origin data



commit 030b62d122d825c3f043116bca29dd6cc7896210
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Aug 7 05:10:42 2013 -0400

    gtkdnd: Introduce a new API for more accurate drag origin data
    
    When trying to drag, we currently the position of the first motion
    event to determine where the drag came from. This might be alright
    in the case of the old animation, but the data will be inaccurate
    if the user has moved the pointer quite a bit since pressing the
    cursor to start dragging. While we could monkey patch the GdkEvent
    at the widget layer, this is unintuitive and strange.
    
    Add a new API that takes a set of pointer coordinates describing
    the origin of the drag. Additionally, adapt most widgets to use
    it and use it with correct coordinates.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=705605

 gtk/gtkcalendar.c |    5 ++-
 gtk/gtkdnd.c      |   85 ++++++++++++++++++++++++++++++++++++++++++----------
 gtk/gtkdnd.h      |   11 ++++++-
 gtk/gtkentry.c    |   28 ++++++++++++-----
 gtk/gtkiconview.c |   12 ++++---
 gtk/gtklabel.c    |    8 +++--
 gtk/gtknotebook.c |    5 ++-
 gtk/gtktextview.c |   16 +++++----
 gtk/gtktreeview.c |   17 +++++++---
 9 files changed, 137 insertions(+), 50 deletions(-)
---
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index 2f0646e..81ed6e2 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -3058,8 +3058,9 @@ gtk_calendar_motion_notify (GtkWidget      *widget,
           GdkDragContext *context;
           GtkTargetList *target_list = gtk_target_list_new (NULL, 0);
           gtk_target_list_add_text_targets (target_list, 0);
-          context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY,
-                                    1, (GdkEvent *)event);
+          context = gtk_drag_begin_with_coordinates (widget, target_list, GDK_ACTION_COPY,
+                                                     1, (GdkEvent *)event,
+                                                     priv->drag_start_x, priv->drag_start_y);
 
           priv->in_drag = 0;
           gtk_target_list_unref (target_list);
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index 21ca429..e7cb5eb 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -2460,7 +2460,9 @@ gtk_drag_begin_internal (GtkWidget         *widget,
                         GtkTargetList     *target_list,
                         GdkDragAction      actions,
                         gint               button,
-                        GdkEvent          *event)
+                        GdkEvent          *event,
+                         int                x,
+                         int                y)
 {
   GtkDragSourceInfo *info;
   GList *targets = NULL;
@@ -2570,16 +2572,27 @@ gtk_drag_begin_internal (GtkWidget         *widget,
   /* Set cur_x, cur_y here so if the "drag-begin" signal shows
    * the drag icon, it will be in the right place
    */
-  if (event && event->type == GDK_MOTION_NOTIFY)
+  if (event)
+    info->cur_screen = gdk_event_get_screen (event);
+  else
+    gdk_device_get_position (pointer, &info->cur_screen, NULL, NULL);
+
+  if (x != -1 && y != -1)
     {
-      info->cur_screen = gtk_widget_get_screen (widget);
-      info->cur_x = event->motion.x_root;
-      info->cur_y = event->motion.y_root;
+      GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+      gtk_widget_translate_coordinates (widget, toplevel,
+                                        x, y, &x, &y);
+      gdk_window_get_root_coords (gtk_widget_get_window (toplevel),
+                                  x, y, &info->start_x, &info->start_y);
     }
-  else
+  else if (event && event->type == GDK_MOTION_NOTIFY)
     {
-      gdk_device_get_position (pointer, &info->cur_screen, &info->cur_x, &info->cur_y);
+      info->start_x = event->motion.x_root;
+      info->start_y = event->motion.y_root;
     }
+  else
+    gdk_device_get_position (pointer, NULL, &info->start_x, &info->start_y);
+
 
   g_signal_emit_by_name (widget, "drag-begin", info->context);
 
@@ -2610,15 +2623,15 @@ gtk_drag_begin_internal (GtkWidget         *widget,
           info->cursor = cursor;
         }
     }
-    
+
+  info->cur_x = info->start_x;
+  info->cur_y = info->start_y;
+
   if (event && event->type == GDK_MOTION_NOTIFY)
     gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
   else
     gtk_drag_update (info, info->cur_screen, info->cur_x, info->cur_y, event);
 
-  info->start_x = info->cur_x;
-  info->start_y = info->cur_y;
-
   g_signal_connect (info->ipc_widget, "grab-broken-event",
                    G_CALLBACK (gtk_drag_grab_broken_event_cb), info);
   g_signal_connect (info->ipc_widget, "grab-notify",
@@ -2641,13 +2654,19 @@ gtk_drag_begin_internal (GtkWidget         *widget,
 }
 
 /**
- * gtk_drag_begin: (method)
+ * gtk_drag_begin_with_coordinates: (method)
  * @widget: the source widget.
  * @targets: The targets (data formats) in which the
  *    source can provide the data.
  * @actions: A bitmask of the allowed drag actions for this drag.
  * @button: The button the user clicked to start the drag.
  * @event: The event that triggered the start of the drag.
+ * @x: The initial x coordinate to start dragging from, in the coordinate space
+ *    of @widget. If -1 is passed, the coordinates are retrieved from @event or
+ *    the current pointer position.
+ * @y: The initial y coordinate to start dragging from, in the coordinate space
+ *    of @widget. If -1 is passed, the coordinates are retrieved from @event or
+ *    the current pointer position.
  *
  * Initiates a drag on the source side. The function only needs to be used
  * when the application is starting drags itself, and is not needed when
@@ -2656,8 +2675,7 @@ gtk_drag_begin_internal (GtkWidget         *widget,
  * The @event is used to retrieve the timestamp that will be used internally to
  * grab the pointer.  If @event is %NULL, then %GDK_CURRENT_TIME will be used.
  * However, you should try to pass a real event in all cases, since that can be
- * used by GTK+ to get information about the start position of the drag, for
- * example if the @event is a motion event.
+ * used to get information about the drag.
  *
  * Generally there are three cases when you want to start a drag by hand by
  * calling this function:
@@ -2679,6 +2697,39 @@ gtk_drag_begin_internal (GtkWidget         *widget,
  * Return value: (transfer none): the context for this drag.
  **/
 GdkDragContext *
+gtk_drag_begin_with_coordinates (GtkWidget         *widget,
+                                 GtkTargetList     *targets,
+                                 GdkDragAction      actions,
+                                 gint               button,
+                                 GdkEvent          *event,
+                                 gint               x,
+                                 gint               y)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+  g_return_val_if_fail (gtk_widget_get_realized (widget), NULL);
+  g_return_val_if_fail (targets != NULL, NULL);
+
+  return gtk_drag_begin_internal (widget, NULL, targets,
+                                 actions, button, event, x, y);
+}
+
+/**
+ * gtk_drag_begin: (method)
+ * @widget: the source widget.
+ * @targets: The targets (data formats) in which the
+ *    source can provide the data.
+ * @actions: A bitmask of the allowed drag actions for this drag.
+ * @button: The button the user clicked to start the drag.
+ * @event: The event that triggered the start of the drag.
+ *
+ * This is equivalent to gtk_drag_begin_with_coordinates(), passing -1, -1
+ * as coordinates.
+ *
+ * Return value: (transfer none): the context for this drag.
+ *
+ * Deprecated: 3.10: Use gtk_drag_begin_with_coordinates() instead.
+ **/
+GdkDragContext *
 gtk_drag_begin (GtkWidget         *widget,
                GtkTargetList     *targets,
                GdkDragAction      actions,
@@ -2690,7 +2741,7 @@ gtk_drag_begin (GtkWidget         *widget,
   g_return_val_if_fail (targets != NULL, NULL);
 
   return gtk_drag_begin_internal (widget, NULL, targets,
-                                 actions, button, event);
+                                 actions, button, event, -1, -1);
 }
 
 /**
@@ -3872,8 +3923,8 @@ gtk_drag_source_event_cb (GtkWidget      *widget,
            {
              site->state = 0;
              gtk_drag_begin_internal (widget, site, site->target_list,
-                                      site->actions, 
-                                      i, event);
+                                      site->actions, i, event,
+                                       site->x, site->y);
 
              retval = TRUE;
            }
diff --git a/gtk/gtkdnd.h b/gtk/gtkdnd.h
index 3ac12cd..c3fc90f 100644
--- a/gtk/gtkdnd.h
+++ b/gtk/gtkdnd.h
@@ -187,7 +187,16 @@ void gtk_drag_source_set_icon_gicon   (GtkWidget       *widget,
  * as a GtkTargetList
  */
 
-GDK_AVAILABLE_IN_ALL
+GDK_AVAILABLE_IN_3_10
+GdkDragContext *gtk_drag_begin_with_coordinates (GtkWidget         *widget,
+                                                 GtkTargetList     *targets,
+                                                 GdkDragAction      actions,
+                                                 gint               button,
+                                                 GdkEvent          *event,
+                                                 gint               x,
+                                                 gint               y);
+
+GDK_DEPRECATED_IN_3_10_FOR(gtk_drag_begin_with_coordinates)
 GdkDragContext *gtk_drag_begin (GtkWidget         *widget,
                                GtkTargetList     *targets,
                                GdkDragAction      actions,
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 7e1bb3a..9283d8b 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -4435,11 +4435,13 @@ gtk_entry_motion_notify (GtkWidget      *widget,
             {
               icon_info->in_drag = TRUE;
               icon_info->pressed = FALSE;
-              gtk_drag_begin (widget,
-                              icon_info->target_list,
-                              icon_info->actions,
-                              1,
-                              (GdkEvent*)event);
+              gtk_drag_begin_with_coordinates (widget,
+                                               icon_info->target_list,
+                                               icon_info->actions,
+                                               1,
+                                               (GdkEvent*)event,
+                                               priv->start_x,
+                                               priv->start_y);
             }
 
           return TRUE;
@@ -4471,6 +4473,8 @@ gtk_entry_motion_notify (GtkWidget      *widget,
                                     priv->drag_start_x, priv->drag_start_y,
                                     event->x + priv->scroll_offset, event->y))
         {
+          gint *ranges;
+          gint n_ranges;
           GdkDragContext *context;
           GtkTargetList  *target_list = gtk_target_list_new (NULL, 0);
           guint actions = priv->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
@@ -4482,9 +4486,17 @@ gtk_entry_motion_notify (GtkWidget      *widget,
           text = _gtk_entry_get_selected_text (entry);
           surface = _gtk_text_util_create_drag_icon (widget, text, -1);
 
-          context = gtk_drag_begin (widget, target_list, actions,
-                                    priv->button, (GdkEvent *)event);
-          
+          gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
+          cairo_surface_set_device_offset (surface,
+                                           -(priv->drag_start_x - ranges[0]),
+                                           -(priv->drag_start_y));
+
+          context = gtk_drag_begin_with_coordinates (widget, target_list, actions,
+                                                     priv->button, (GdkEvent *)event,
+                                                     priv->drag_start_x + ranges[0],
+                                                     priv->drag_start_y);
+          g_free (ranges);
+
           if (surface)
             gtk_drag_set_icon_surface (context, surface);
           else
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 0524979..070378a 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -6446,11 +6446,13 @@ gtk_icon_view_maybe_begin_drag (GtkIconView    *icon_view,
   
   retval = TRUE;
 
-  context = gtk_drag_begin (widget,
-                            gtk_drag_source_get_target_list (widget),
-                            icon_view->priv->source_actions,
-                            button,
-                            (GdkEvent*)event);
+  context = gtk_drag_begin_with_coordinates (widget,
+                                             gtk_drag_source_get_target_list (widget),
+                                             icon_view->priv->source_actions,
+                                             button,
+                                             (GdkEvent*)event,
+                                             icon_view->priv->press_start_x,
+                                             icon_view->priv->press_start_y);
 
   set_source_row (context, model, path);
   
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 4d13cac..f8abece 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -4944,9 +4944,11 @@ gtk_label_motion (GtkWidget      *widget,
 
           g_signal_connect (widget, "drag-begin",
                             G_CALLBACK (drag_begin_cb), NULL);
-         gtk_drag_begin (widget, target_list,
-                         GDK_ACTION_COPY,
-                         1, (GdkEvent *)event);
+         gtk_drag_begin_with_coordinates (widget, target_list,
+                                           GDK_ACTION_COPY,
+                                           1, (GdkEvent *)event,
+                                           info->drag_start_x,
+                                           info->drag_start_y);
 
          info->in_drag = FALSE;
 
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index b44c84a..48a0580 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -3415,8 +3415,9 @@ gtk_notebook_motion_notify (GtkWidget      *widget,
       priv->detached_tab = priv->cur_page;
       priv->during_detach = TRUE;
 
-      gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
-                      priv->pressed_button, (GdkEvent*) event);
+      gtk_drag_begin_with_coordinates (widget, priv->source_targets, GDK_ACTION_MOVE,
+                                       priv->pressed_button, (GdkEvent*) event,
+                                       priv->drag_begin_x, priv->drag_begin_y);
       return TRUE;
     }
 
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index bbfa166..3aa1047 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -7291,17 +7291,19 @@ gtk_text_view_start_selection_dnd (GtkTextView       *text_view,
 {
   GtkTargetList *target_list;
 
-  text_view->priv->drag_start_x = -1;
-  text_view->priv->drag_start_y = -1;
-  text_view->priv->pending_place_cursor_button = 0;
-
   target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
 
   g_signal_connect (text_view, "drag-begin",
                     G_CALLBACK (drag_begin_cb), NULL);
-  gtk_drag_begin (GTK_WIDGET (text_view), target_list,
-                 GDK_ACTION_COPY | GDK_ACTION_MOVE,
-                 1, (GdkEvent*)event);
+  gtk_drag_begin_with_coordinates (GTK_WIDGET (text_view), target_list,
+                                   GDK_ACTION_COPY | GDK_ACTION_MOVE,
+                                   1, (GdkEvent*)event,
+                                   text_view->priv->drag_start_x,
+                                   text_view->priv->drag_start_y);
+
+  text_view->priv->drag_start_x = -1;
+  text_view->priv->drag_start_y = -1;
+  text_view->priv->pending_place_cursor_button = 0;
 }
 
 static void
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index b9c2bb5..718174c 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -7570,6 +7570,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
   GtkTreePath *path = NULL;
   gint button;
   gint cell_x, cell_y;
+  gint drag_start_x, drag_start_y;
   GtkTreeModel *model;
   gboolean retval = FALSE;
 
@@ -7618,11 +7619,17 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
 
   retval = TRUE;
 
-  context = gtk_drag_begin (widget,
-                            gtk_drag_source_get_target_list (widget),
-                            di->source_actions,
-                            button,
-                            (GdkEvent*)event);
+  gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+                                                     tree_view->priv->press_start_x,
+                                                     tree_view->priv->press_start_y,
+                                                     &drag_start_x, &drag_start_y);
+
+  context = gtk_drag_begin_with_coordinates (widget,
+                                             gtk_drag_source_get_target_list (widget),
+                                             di->source_actions,
+                                             button,
+                                             (GdkEvent*)event,
+                                             drag_start_x, drag_start_y);
 
   set_source_row (context, model, path);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]