[gnome-applets/wip/segeiger/windowpicker: 2/2] windowpicker: fix drag and drop crash



commit b09b560c193bd1131d4ca13c6d9b21b473ed50bb
Author: Sebastian Geiger <sbastig gmx net>
Date:   Tue Oct 15 19:51:40 2019 +0200

    windowpicker: fix drag and drop crash
    
    This fixes several issues in the drag and drop logic:
    
     * The value 0 for info parameter in drop_types of 'STRING',
       'text/plain' and 'text/uri-list' collided with the first enum value
       of TARGET_WIDGET_DRAGGED.
       This caused a crash in the applet when strings were dragged onto
       a task item.
     * The entries for TARGET_ITEM_DRAGGED in drag_types and drop_types were unnecessary,
       since they only applied with flag GTK_TARGET_SAME_WIDGET, but we are only
       interested in dragging a task item onto another task item.
     * The lookup for the target atom in the 'on_drag_motion' handler was incorrect,
       since it ignored the type of the drag source and assumed that a lookup
       of the target atom was possible with a fixed index of TARGET_WIDGET_DRAGGED.
       The correct solution is to check each target atom of the context against the
       possible targets in drop_types and return the first match.

 windowpicker/src/task-item.c | 134 +++++++++++++++++++++++++++----------------
 1 file changed, 85 insertions(+), 49 deletions(-)
---
diff --git a/windowpicker/src/task-item.c b/windowpicker/src/task-item.c
index bd36a2481..a029479d4 100644
--- a/windowpicker/src/task-item.c
+++ b/windowpicker/src/task-item.c
@@ -56,23 +56,21 @@ static guint task_item_signals[LAST_SIGNAL] = { 0 };
 /* D&D stuff */
 
 enum {
-    TARGET_WIDGET_DRAGGED, /* if this item is dragged */
-    TARGET_ITEM_DRAGGED
+  TARGET_STRING_DRAGGED,
+  TARGET_TASK_ITEM_DRAGGED /* if this item is dragged */
 };
 
 static const GtkTargetEntry drop_types[] = {
-    { (gchar *) "STRING", 0, 0 },
-    { (gchar *) "text/plain", 0, 0},
-    { (gchar *) "text/uri-list", 0, 0},
-    { (gchar *) "widget", GTK_TARGET_OTHER_WIDGET, TARGET_WIDGET_DRAGGED }, //drag and drop target
-    { (gchar *) "item", GTK_TARGET_SAME_WIDGET, TARGET_ITEM_DRAGGED }
+    { (gchar *) "STRING", 0, TARGET_STRING_DRAGGED },
+    { (gchar *) "text/plain", 0, TARGET_STRING_DRAGGED },
+    { (gchar *) "text/uri-list", 0, TARGET_STRING_DRAGGED },
+    { (gchar *) "task-item", GTK_TARGET_OTHER_WIDGET | GTK_TARGET_SAME_APP, TARGET_TASK_ITEM_DRAGGED } // 
drag and drop target
 };
 
 static const gint n_drop_types = G_N_ELEMENTS(drop_types);
 
 static const GtkTargetEntry drag_types[] = {
-    { (gchar *) "widget", GTK_TARGET_OTHER_WIDGET, TARGET_WIDGET_DRAGGED }, //drag and drop source
-    { (gchar *) "item", GTK_TARGET_SAME_WIDGET, TARGET_ITEM_DRAGGED }
+    { (gchar *) "task-item", GTK_TARGET_OTHER_WIDGET | GTK_TARGET_SAME_APP, TARGET_TASK_ITEM_DRAGGED } // 
drag and drop source
 };
 
 static const gint n_drag_types = G_N_ELEMENTS(drag_types);
@@ -630,36 +628,74 @@ static void on_drag_leave (
     g_object_set_data (G_OBJECT (item), "drag-true", GINT_TO_POINTER (0));
 }
 
+static gboolean
+find_drop_type_by_name (char *source_name)
+{
+  for (gulong i = 0; i < G_N_ELEMENTS (drop_types); i++)
+    {
+      gchar * target_name;
+
+      target_name = drop_types[i].target;
+
+      if (g_strcmp0 (source_name, target_name) == 0)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
 /* Emitted when a drag is over the destination */
-static gboolean on_drag_motion (
-    GtkWidget      *item,
-    GdkDragContext *context,
-    gint            x,
-    gint            y,
-    guint           time)
+static gboolean
+on_drag_motion (GtkWidget      *item,
+                GdkDragContext *context,
+                gint            x,
+                gint            y,
+                guint           time)
 {
-    GdkAtom         target_type = NULL;
+    GdkAtom target;
+    GList *targets;
+    GList *current;
 
-    if (gdk_drag_context_list_targets(context)) {
-        /* Choose the best target type */
-        target_type = GDK_POINTER_TO_ATOM (
-            g_list_nth_data (
-                gdk_drag_context_list_targets(context),
-                    TARGET_WIDGET_DRAGGED
-            )
-        );
-        g_assert(target_type != NULL);
+    target = NULL;
+    targets = gdk_drag_context_list_targets(context);
 
-        gtk_drag_get_data (
-            item,         // will receive 'drag-data-received' signal
-            context,        // represents the current state of the DnD
-            target_type,    // the target type we want
-            time            // time stamp
-        );
-    } else {
+    if (targets == NULL)
+      {
         g_warning("Drag ended without target");
-    }
-    return FALSE;
+        return FALSE;
+      }
+
+    current = targets;
+
+    while (current != NULL)
+      {
+        GdkAtom *atom = current->data;
+        char *name;
+        gboolean found;
+
+        found = FALSE;
+
+        /* Choose the best target type */
+        target = GDK_POINTER_TO_ATOM (atom);
+        name = gdk_atom_name (target);
+
+        found = find_drop_type_by_name (name);
+        g_free (name);
+
+        if (found)
+          break;
+
+        current = g_list_next (current);
+      }
+
+    g_assert(target != NULL);
+
+    gtk_drag_get_data (item,    // will receive 'drag-data-received' signal
+                       context, // represents the current state of the DnD
+                       target,  // the target type we want
+                       time);   // time stamp
+
+  return FALSE;
 }
 
 
@@ -685,20 +721,20 @@ on_drag_get_data (GtkWidget        *widget,
                   guint             time,
                   gpointer          user_data)
 {
-    switch(target_type) {
-        case TARGET_WIDGET_DRAGGED:
-            g_assert(user_data != NULL && TASK_IS_ITEM(user_data));
-            gtk_selection_data_set(
-                selection_data,
-                gtk_selection_data_get_target (selection_data),
-                8,
-                (guchar*) &user_data,
-                sizeof(gpointer*)
-            );
-            break;
-        default:
-            g_assert_not_reached ();
-    }
+    TaskItem *item;
+
+    g_assert(user_data != NULL && TASK_IS_ITEM(user_data));
+
+    item = TASK_ITEM (user_data);
+
+    if (target_type != TARGET_TASK_ITEM_DRAGGED)
+      g_assert_not_reached ();
+
+    gtk_selection_data_set (selection_data,
+                            gtk_selection_data_get_target (selection_data),
+                            8,
+                            (guchar*) &item,
+                            sizeof (TaskItem*));
 }
 
 static void on_drag_end (
@@ -737,7 +773,7 @@ static void on_drag_received_data (
     if((selection_data != NULL) && (gtk_selection_data_get_length(selection_data) >= 0)) {
         gint active;
         switch (target_type) {
-            case TARGET_WIDGET_DRAGGED: {
+            case TARGET_TASK_ITEM_DRAGGED: {
                 GtkWidget *taskItem;
                 GtkWidget *taskList;
                 gint target_position;


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