[gtk+/wip/csoriano/bookmarks: 37/40] gtkplacessidebar: add API for emulate drag sources



commit d31a374793c9854bdd0bde4cc733bd9087167428
Author: Carlos Soriano <csoriano gnome org>
Date:   Sat Apr 11 17:35:23 2015 +0200

    gtkplacessidebar: add API for emulate drag sources
    
    It is convenient to allow applications to show all the drop
    targets at once.
    This improves the user experience with drag an drop.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=747793

 gtk/gtkplacessidebar.c |  127 +++++++++++++++++++++++++++++++++++++++--------
 gtk/gtkplacessidebar.h |    5 ++
 2 files changed, 110 insertions(+), 22 deletions(-)
---
diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c
index 3b75598..e55ad86 100644
--- a/gtk/gtkplacessidebar.c
+++ b/gtk/gtkplacessidebar.c
@@ -121,8 +121,9 @@
 typedef enum {
   DROP_STATE_NORMAL,
   DROP_STATE_NEW_BOOKMARK_FADING_IN,
+  DROP_STATE_NEW_BOOKMARK_FADING_OUT,
   DROP_STATE_NEW_BOOKMARK_ARMED,
-  DROP_STATE_NEW_BOOKMARK_FADING_OUT
+  DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT,
 } DropState;
 
 struct _GtkPlacesSidebar {
@@ -152,6 +153,7 @@ struct _GtkPlacesSidebar {
   /* DND */
   GList     *drag_list; /* list of GFile */
   gint       drag_data_info;
+  gboolean   dragging_over;
 
   /* volume mounting - delayed open process */
   GtkPlacesOpenFlags go_to_after_mount_open_flags;
@@ -1692,12 +1694,15 @@ show_new_bookmark_row (GtkPlacesSidebar *sidebar,
     }
 
   /* Highlight the new bookmark row */
-  drop_target_index = gtk_tree_path_get_indices (path)[0];
-  if (drop_target_index == bookmarks_index)
+  if (path != NULL)
     {
-      new_bookmark_path = gtk_tree_path_new_from_indices (bookmarks_index, -1);
-      gtk_tree_view_set_drag_dest_row (sidebar->tree_view, new_bookmark_path, 
GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
-      gtk_tree_path_free (new_bookmark_path);
+      drop_target_index = gtk_tree_path_get_indices (path)[0];
+      if (drop_target_index == bookmarks_index)
+        {
+          new_bookmark_path = gtk_tree_path_new_from_indices (bookmarks_index, -1);
+          gtk_tree_view_set_drag_dest_row (sidebar->tree_view, new_bookmark_path, 
GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
+          gtk_tree_path_free (new_bookmark_path);
+        }
     }
 }
 
@@ -1710,7 +1715,12 @@ start_drop_feedback (GtkPlacesSidebar        *sidebar,
   if (drop_as_bookmarks)
     {
       show_new_bookmark_row (sidebar, path);
-      sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED;
+      /* If the state is permanent, don't change it. Is the application that
+       * controls this */
+      if (sidebar->drop_state != DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT)
+        {
+          sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED;
+        }
     }
   else
     {
@@ -1740,6 +1750,8 @@ drag_motion_callback (GtkTreeView      *tree_view,
   gboolean drop_as_bookmarks;
   gchar *drop_target_uri = NULL;
 
+  sidebar->dragging_over = TRUE;
+
   action = 0;
   drop_as_bookmarks = FALSE;
   path = NULL;
@@ -1829,17 +1841,40 @@ drag_motion_callback (GtkTreeView      *tree_view,
   return TRUE;
 }
 
-static gboolean
-drag_leave_timeout_cb (gpointer data)
+static void
+on_drag_end (GtkPlacesSidebar *sidebar)
 {
-  GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (data);
+  g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
 
   free_drag_data (sidebar);
-  stop_drop_feedback (sidebar);
+  /* we could call finalize when disposing the widget */
+  if (sidebar->tree_view != NULL)
+    stop_drop_feedback (sidebar);
   remove_drop_bookmark_feedback_row (sidebar);
 
+  if (sidebar->drag_leave_timeout_id)
+    g_source_remove (sidebar->drag_leave_timeout_id);
+
   sidebar->drag_leave_timeout_id = 0;
-  return FALSE;
+  sidebar->drop_state = DROP_STATE_NORMAL;
+  sidebar->dragging_over = FALSE;
+}
+
+static gboolean
+drag_leave_timeout_cb (gpointer data)
+{
+  GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (data);
+
+  if (sidebar->drop_state != DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT)
+    {
+      on_drag_end (sidebar);
+      return FALSE;
+    }
+  else
+    {
+      sidebar->dragging_over = FALSE;
+      return TRUE;
+    }
 }
 
 static void
@@ -1848,6 +1883,8 @@ drag_leave_callback (GtkTreeView      *tree_view,
                      guint             time,
                      GtkPlacesSidebar *sidebar)
 {
+  sidebar->dragging_over = FALSE;
+
   if (sidebar->drag_leave_timeout_id)
     g_source_remove (sidebar->drag_leave_timeout_id);
 
@@ -2086,9 +2123,8 @@ drag_data_received_callback (GtkWidget        *widget,
 
 out:
   sidebar->drop_occured = FALSE;
-  free_drag_data (sidebar);
-  remove_drop_bookmark_feedback_row (sidebar);
   gtk_drag_finish (context, success, FALSE, time);
+  on_drag_end (sidebar);
 
   gtk_tree_path_free (tree_path);
 }
@@ -4404,15 +4440,9 @@ gtk_places_sidebar_dispose (GObject *object)
       sidebar->cancellable = NULL;
     }
 
-  sidebar->tree_view = NULL;
-
-  if (sidebar->drag_leave_timeout_id)
-    {
-      g_source_remove (sidebar->drag_leave_timeout_id);
-      sidebar->drag_leave_timeout_id = 0;
-    }
+  on_drag_end (sidebar);
 
-  free_drag_data (sidebar);
+  sidebar->tree_view = NULL;
 
   if (sidebar->bookmarks_manager != NULL)
     {
@@ -5343,3 +5373,56 @@ gtk_places_sidebar_get_nth_bookmark (GtkPlacesSidebar *sidebar,
 
   return file;
 }
+
+/**
+ * gtk_places_sidebar_drop_hints_start:
+ * @sidebar: a places sidebar
+ *
+ * Make the GtkPlacesSidebar show drop hints, so it can show the available drop
+ * targets and a "new bookmark" row. This improves the drag and drop
+ * experience of the user and allow applications to show at once the available
+ * drop targets.
+ * This needs to be called when the application is aware of a drag, and
+ * gtk_places_sidebar_hide_drop_hints needs to be called when the drag
+ * has been finished.
+ *
+ * Since: 3.18
+ */
+void
+gtk_places_sidebar_drop_hints_start (GtkPlacesSidebar *sidebar)
+{
+  show_new_bookmark_row (sidebar, NULL);
+  sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT;
+}
+
+/**
+ * gtk_places_sidebar_drop_hints_stop:
+ * @sidebar: a places sidebar
+ *
+ * Stop the dragnts that started with gtk_places_sidebar_drop_hints_start.
+ * It's not needed to take care of the drag if it finish in GtkPlacesSidebar, so
+ * it's not needed to conect to their signals to call gtk_places_sidebar_drop_hints_stop
+ * manually, just call it when the drag ends on some other widget on your application.
+ *
+ * Since: 3.18
+ */
+void
+gtk_places_sidebar_drop_hints_stop (GtkPlacesSidebar *sidebar)
+{
+  if (sidebar->drop_state == DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT ||
+      sidebar->drop_state == DROP_STATE_NEW_BOOKMARK_ARMED)
+    {
+      if (!sidebar->dragging_over)
+        {
+          on_drag_end (sidebar);
+        }
+      else
+        {
+          /* In case this is called while we are dragging we need to mark the
+           * drop state as no permanent so the leave timeout can do its job.
+           * This will only happen in applications that call this in a wrong
+           * time */
+          sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED;
+        }
+    }
+}
diff --git a/gtk/gtkplacessidebar.h b/gtk/gtkplacessidebar.h
index f703cf8..27da473 100644
--- a/gtk/gtkplacessidebar.h
+++ b/gtk/gtkplacessidebar.h
@@ -131,6 +131,11 @@ GSList *           gtk_places_sidebar_list_shortcuts             (GtkPlacesSideb
 GDK_AVAILABLE_IN_3_10
 GFile *            gtk_places_sidebar_get_nth_bookmark           (GtkPlacesSidebar   *sidebar,
                                                                   gint                n);
+GDK_AVAILABLE_IN_3_18
+void               gtk_places_sidebar_emulate_dragging_start      (GtkPlacesSidebar   *sidebar);
+
+GDK_AVAILABLE_IN_3_18
+void               gtk_places_sidebar_emulate_dragging_stop       (GtkPlacesSidebar   *sidebar);
 
 G_END_DECLS
 


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