[gtk+/wip/csoriano/bookmarks: 1/4] gtkplacessidebar: add API for emulate drag sources
- From: Carlos Soriano Sánchez <csoriano src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/csoriano/bookmarks: 1/4] gtkplacessidebar: add API for emulate drag sources
- Date: Mon, 13 Apr 2015 18:06:19 +0000 (UTC)
commit 45c522c95cfc276d2efbd902e1f4e1127c31b32a
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.
gtk/gtkplacessidebar.c | 149 +++++++++++++++++++++++++++++++++++++-----------
gtk/gtkplacessidebar.h | 5 ++
2 files changed, 120 insertions(+), 34 deletions(-)
---
diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c
index 6caef4f..671e22a 100644
--- a/gtk/gtkplacessidebar.c
+++ b/gtk/gtkplacessidebar.c
@@ -117,8 +117,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 {
@@ -142,6 +143,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;
@@ -291,7 +293,7 @@ static void check_unmount_and_eject (GMount *mount,
GDrive *drive,
gboolean *show_unmount,
gboolean *show_eject);
-static int bookmarks_get_heading_index (GtkPlacesSidebar *sidebar);
+static int bookmarks_get_first_index (GtkPlacesSidebar *sidebar);
/* Identifiers for target types */
enum {
@@ -1645,12 +1647,11 @@ remove_drop_bookmark_feedback_row (GtkPlacesSidebar *sidebar)
{
gboolean success;
GtkTreeIter iter;
- int bookmarks_heading_index;
+ int bookmarks_index;
- bookmarks_heading_index = bookmarks_get_heading_index (sidebar);
- bookmarks_heading_index++;
+ bookmarks_index = bookmarks_get_first_index (sidebar);
- success = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (sidebar->store), &iter, NULL,
bookmarks_heading_index);
+ success = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (sidebar->store), &iter, NULL,
bookmarks_index);
g_assert (success);
gtk_list_store_remove (sidebar->store, &iter);
@@ -1664,32 +1665,34 @@ show_new_bookmark_row (GtkPlacesSidebar *sidebar,
GtkTreePath *path)
{
GtkTreeIter iter;
- int bookmarks_heading_index;
+ int bookmarks_index;
gint drop_target_index;
GtkTreePath *new_bookmark_path;
- bookmarks_heading_index = bookmarks_get_heading_index (sidebar);
- bookmarks_heading_index++;
+ bookmarks_index = bookmarks_get_first_index (sidebar);
/* Add the row if it doesn't exists yet */
if (sidebar->drop_state == DROP_STATE_NORMAL)
{
- gtk_list_store_insert_with_values (sidebar->store, &iter, bookmarks_heading_index,
+ gtk_list_store_insert_with_values (sidebar->store, &iter, bookmarks_index,
PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_DROP_FEEDBACK,
PLACES_SIDEBAR_COLUMN_SECTION_TYPE, SECTION_BOOKMARKS,
PLACES_SIDEBAR_COLUMN_NAME, _("New bookmark"),
- PLACES_SIDEBAR_COLUMN_INDEX, bookmarks_heading_index,
+ PLACES_SIDEBAR_COLUMN_INDEX, bookmarks_index,
PLACES_SIDEBAR_COLUMN_NO_EJECT, TRUE,
-1);
}
/* Highlight the new bookmark row */
- drop_target_index = gtk_tree_path_get_indices (path)[0];
- if (drop_target_index == bookmarks_heading_index)
+ if (path != NULL)
{
- new_bookmark_path = gtk_tree_path_new_from_indices (bookmarks_heading_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);
+ }
}
}
@@ -1702,7 +1705,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
{
@@ -1732,6 +1740,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;
@@ -1821,17 +1831,40 @@ drag_motion_callback (GtkTreeView *tree_view,
return TRUE;
}
-static gboolean
-drag_leave_timeout_cb (gpointer data)
+static void
+drag_finalize (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)
+ {
+ drag_finalize (sidebar);
+ return FALSE;
+ }
+ else
+ {
+ sidebar->dragging_over = FALSE;
+ return TRUE;
+ }
}
static void
@@ -1840,6 +1873,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);
@@ -2078,9 +2113,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);
+ drag_finalize (sidebar);
gtk_tree_path_free (tree_path);
}
@@ -3755,7 +3789,7 @@ tree_selection_func (GtkTreeSelection *selection,
}
static int
-bookmarks_get_heading_index (GtkPlacesSidebar *sidebar)
+bookmarks_get_first_index (GtkPlacesSidebar *sidebar)
{
GtkTreeIter iter;
@@ -3775,7 +3809,7 @@ bookmarks_get_heading_index (GtkPlacesSidebar *sidebar)
PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
-1);
if (place_type == PLACES_HEADING && section_type == SECTION_BOOKMARKS)
- return bookmarks_heading_index;
+ return ++bookmarks_heading_index;
bookmarks_heading_index++;
}
@@ -4300,15 +4334,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;
- }
+ drag_finalize (sidebar);
- free_drag_data (sidebar);
+ sidebar->tree_view = NULL;
if (sidebar->bookmarks_manager != NULL)
{
@@ -5242,3 +5270,56 @@ gtk_places_sidebar_get_nth_bookmark (GtkPlacesSidebar *sidebar,
return file;
}
+
+/**
+ * gtk_places_sidebar_emulate_dragging_start:
+ * @sidebar: a places sidebar
+ *
+ * Make the GtkPlacesSidebar emulate like some drop source is over it, so it
+ * can show the drop targets and show hints, like the new bookmark row or dim
+ * the items that are not drop targets. 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_emulate_dragging_stop needs to be called when the drag
+ * has been finished.
+ *
+ * Since: 3.16
+ */
+void
+gtk_places_sidebar_emulate_dragging_start (GtkPlacesSidebar *sidebar)
+{
+ show_new_bookmark_row (sidebar, NULL);
+ sidebar->drop_state = DROP_STATE_NEW_BOOKMARK_ARMED_PERMANENT;
+}
+
+/**
+ * gtk_places_sidebar_emulate_dragging_stop:
+ * @sidebar: a places sidebar
+ *
+ * Stop the drag emulation that started with gtk_places_sidebar_emulate_dragging_start.
+ * It's not needed to take care of the drags that finish in GtkPlacesSidebar, so
+ * it's not needed to conect to their signals to call gtk_places_sidebar_emulate_dragging_stop.
+ *
+ * Since: 3.16
+ */
+void
+gtk_places_sidebar_emulate_dragging_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)
+ {
+ drag_finalize (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]