[gnome-builder] app: Implement support for drag and drop



commit 5261beb638391d61411dbeeed4706eb62ee6943f
Author: Dimitris Zenios <dimitris zenios gmail com>
Date:   Sat Jan 17 15:15:22 2015 +0200

    app: Implement support for drag and drop
    
    - Current support "text/uri-list" drop type on GbEditorWorkspace and GbSourceView
    - Missing support for dnd on GbDevhelpView
    - Missing support for dnd on GbHtmlView
    - Missing support for XdndDirectSave0 drop type
    
    https://bugzilla.gnome.org/show_bug.cgi?id=742865

 src/editor/gb-editor-frame.c     |   39 ++++++++++++++
 src/editor/gb-editor-workspace.c |  103 ++++++++++++++++++++++++++++++++++++-
 src/editor/gb-source-view.c      |   63 +++++++++++++++++++++++
 src/editor/gb-source-view.h      |    2 +
 src/gnome-builder.mk             |    2 +
 src/util/gb-dnd.c                |   41 +++++++++++++++
 src/util/gb-dnd.h                |   30 +++++++++++
 7 files changed, 277 insertions(+), 3 deletions(-)
---
diff --git a/src/editor/gb-editor-frame.c b/src/editor/gb-editor-frame.c
index eee712b..d67f7b1 100644
--- a/src/editor/gb-editor-frame.c
+++ b/src/editor/gb-editor-frame.c
@@ -1128,6 +1128,39 @@ gb_editor_frame_on_jump_to_doc (GbEditorFrame *self,
 }
 
 static void
+gb_editor_frame_on_drop_uris (GbEditorFrame *self,
+                              const gchar   **uri_list,
+                              GbSourceView  *source_view)
+{
+  GActionGroup *action_group;
+  GbWorkbench *workbench;
+  GVariantBuilder *builder;
+  GVariant *variant;
+  int i;
+
+  ENTRY;
+
+  g_return_if_fail (GB_IS_EDITOR_FRAME (self));
+  g_return_if_fail (GB_IS_SOURCE_VIEW (source_view));
+  g_return_if_fail (uri_list);
+
+  builder = g_variant_builder_new (G_VARIANT_TYPE_STRING_ARRAY);
+  for (i = 0; uri_list[i] != NULL; i++)
+    {
+      g_variant_builder_add (builder, "s", uri_list[i]);
+    }
+  variant = g_variant_builder_end (builder);
+  g_variant_builder_unref (builder);
+
+  workbench = gb_widget_get_workbench (GTK_WIDGET (self));
+  action_group = gtk_widget_get_action_group (GTK_WIDGET (workbench),
+                                              "workspace");
+  g_action_group_activate_action (action_group, "open-uri-list", variant);
+
+  EXIT;
+}
+
+static void
 gb_editor_frame_grab_focus (GtkWidget *widget)
 {
   GbEditorFrame *self = (GbEditorFrame *)widget;
@@ -1481,6 +1514,12 @@ gb_editor_frame_constructed (GObject *object)
                            G_CONNECT_SWAPPED);
 
   g_signal_connect_object (priv->source_view,
+                           "drop-uris",
+                           G_CALLBACK (gb_editor_frame_on_drop_uris),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (priv->source_view,
                            "focus-in-event",
                            G_CALLBACK (gb_editor_frame_on_focus_in_event),
                            self,
diff --git a/src/editor/gb-editor-workspace.c b/src/editor/gb-editor-workspace.c
index 11b9048..239ed2e 100644
--- a/src/editor/gb-editor-workspace.c
+++ b/src/editor/gb-editor-workspace.c
@@ -30,6 +30,16 @@
 #include "gb-tree.h"
 #include "gb-widget.h"
 #include "gb-workbench.h"
+#include "gb-dnd.h"
+
+enum
+{
+       TARGET_URI_LIST = 100
+};
+
+static const GtkTargetEntry drop_types [] = {
+       { "text/uri-list", 0, TARGET_URI_LIST}
+};
 
 struct _GbEditorWorkspacePrivate
 {
@@ -73,6 +83,59 @@ gb_editor_workspace_open (GbEditorWorkspace *workspace,
 }
 
 static void
+gb_editor_workspace_open_uri_list (GbEditorWorkspace *workspace,
+                                   const gchar        **uri_list)
+{
+  int i;
+  GFile *file;
+
+  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
+  g_return_if_fail (uri_list);
+
+  for (i = 0; uri_list[i] != NULL; i++)
+    {
+      file = g_file_new_for_commandline_arg (uri_list[i]);
+      gb_editor_workspace_open (workspace, file);
+      g_clear_object (&file);
+    }
+}
+
+static void
+gb_editor_workspace_drag_data_received (GtkWidget        *widget,
+                                        GdkDragContext   *context,
+                                        gint              x,
+                                        gint              y,
+                                        GtkSelectionData *selection_data,
+                                        guint             info,
+                                        guint             timestamp,
+                                        gpointer          data)
+{
+  GbEditorWorkspace *workspace = (GbEditorWorkspace *)widget;
+  gchar **uri_list;
+  gboolean handled = FALSE;
+
+  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
+
+  switch (info)
+    {
+    case TARGET_URI_LIST:
+      uri_list = gb_dnd_get_uri_list (selection_data);
+      if (uri_list != NULL)
+        {
+          gb_editor_workspace_open_uri_list (workspace, (const gchar **) uri_list);
+                               g_strfreev (uri_list);
+        }
+      handled = TRUE;
+      break;
+
+    default:
+      break;
+    }
+
+  gtk_drag_finish (context, handled, FALSE, timestamp);
+}
+
+static void
 gb_editor_workspace_action_jump_to_doc (GSimpleAction *action,
                                         GVariant      *parameter,
                                         gpointer       user_data)
@@ -112,6 +175,24 @@ gb_editor_workspace_action_jump_to_doc (GSimpleAction *action,
 }
 
 static void
+gb_editor_workspace_action_open_uri_list (GSimpleAction *action,
+                                          GVariant      *parameter,
+                                          gpointer       user_data)
+{
+  GbEditorWorkspace *workspace = user_data;
+  const gchar **uri_list;
+
+  g_return_if_fail (GB_IS_EDITOR_WORKSPACE (workspace));
+
+  uri_list = g_variant_get_strv (parameter, NULL);
+  if(uri_list != NULL)
+    {
+      gb_editor_workspace_open_uri_list (workspace, uri_list);
+      g_free (uri_list);
+    }
+}
+
+static void
 gb_editor_workspace_action_new_document (GSimpleAction *action,
                                          GVariant      *parameter,
                                          gpointer       user_data)
@@ -275,9 +356,10 @@ static void
 gb_editor_workspace_init (GbEditorWorkspace *workspace)
 {
   const GActionEntry entries[] = {
-    { "open",         gb_editor_workspace_action_open },
-    { "new-document", gb_editor_workspace_action_new_document },
-    { "jump-to-doc",  gb_editor_workspace_action_jump_to_doc, "s" },
+    { "open",          gb_editor_workspace_action_open },
+    { "new-document",  gb_editor_workspace_action_new_document },
+    { "jump-to-doc",   gb_editor_workspace_action_jump_to_doc,   "s" },
+    { "open-uri-list", gb_editor_workspace_action_open_uri_list, "as" }
   };
   GSimpleActionGroup *actions;
 
@@ -295,4 +377,19 @@ gb_editor_workspace_init (GbEditorWorkspace *workspace)
   gtk_widget_insert_action_group (GTK_WIDGET (workspace), "workspace",
                                   G_ACTION_GROUP (actions));
   g_clear_object (&actions);
+
+  /* Drag and drop support*/
+  gtk_drag_dest_set (GTK_WIDGET (workspace),
+                     GTK_DEST_DEFAULT_MOTION |
+                     GTK_DEST_DEFAULT_HIGHLIGHT |
+                     GTK_DEST_DEFAULT_DROP,
+                     drop_types,
+                     G_N_ELEMENTS (drop_types),
+                     GDK_ACTION_COPY);
+
+  g_signal_connect (workspace,
+                    "drag-data-received",
+                    G_CALLBACK(gb_editor_workspace_drag_data_received),
+                    NULL);
+
 }
diff --git a/src/editor/gb-source-view.c b/src/editor/gb-source-view.c
index 56a175b..886c59e 100644
--- a/src/editor/gb-source-view.c
+++ b/src/editor/gb-source-view.c
@@ -29,6 +29,7 @@
 #include "gb-source-auto-indenter-xml.h"
 #include "gb-box-theatric.h"
 #include "gb-cairo.h"
+#include "gb-dnd.h"
 #include "gb-editor-document.h"
 #include "gb-gtk.h"
 #include "gb-html-completion-provider.h"
@@ -45,6 +46,11 @@
 #include "gb-source-vim.h"
 #include "gb-widget.h"
 
+enum
+{
+       TARGET_URI_LIST = 100
+};
+
 struct _GbSourceViewPrivate
 {
   GQueue                      *snippets;
@@ -101,6 +107,7 @@ enum {
   POP_SNIPPET,
   PUSH_SNIPPET,
   REQUEST_DOCUMENTATION,
+  DROP_URIS,
   LAST_SIGNAL
 };
 
@@ -1982,6 +1989,42 @@ gb_source_view_constructed (GObject *object)
                                       NULL);
 }
 
+static void
+gb_source_view_drag_data_received (GtkWidget        *widget,
+                                   GdkDragContext   *context,
+                                   gint              x,
+                                   gint              y,
+                                   GtkSelectionData *selection_data,
+                                   guint             info,
+                                   guint             timestamp)
+{
+  gchar **uri_list;
+
+  g_return_if_fail (GB_IS_SOURCE_VIEW (widget));
+
+  switch (info)
+    {
+    case TARGET_URI_LIST:
+      uri_list = gb_dnd_get_uri_list (selection_data);
+      if (uri_list != NULL)
+        {
+          g_signal_emit (widget, gSignals[DROP_URIS], 0, uri_list);
+          g_strfreev (uri_list);
+        }
+      gtk_drag_finish (context, TRUE, FALSE, timestamp);
+      break;
+
+    default:
+      GTK_WIDGET_CLASS (gb_source_view_parent_class)->drag_data_received (widget,
+                                                                          context,
+                                                                          x, y,
+                                                                          selection_data,
+                                                                          info,
+                                                                          timestamp);
+      break;
+    }
+}
+
 static gboolean
 gb_source_view_focus_in_event (GtkWidget     *widget,
                                GdkEventFocus *event)
@@ -2159,6 +2202,7 @@ gb_source_view_class_init (GbSourceViewClass *klass)
   widget_class->focus_out_event = gb_source_view_focus_out_event;
   widget_class->grab_focus = gb_source_view_grab_focus;
   widget_class->key_press_event = gb_source_view_key_press_event;
+  widget_class->drag_data_received = gb_source_view_drag_data_received;
 
   text_view_class->draw_layer = gb_source_view_draw_layer;
 
@@ -2308,6 +2352,17 @@ gb_source_view_class_init (GbSourceViewClass *klass)
                   G_TYPE_NONE,
                   0);
 
+  gSignals [DROP_URIS] =
+    g_signal_new ("drop-uris",
+                  GB_TYPE_SOURCE_VIEW,
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GbSourceViewClass, drop_uris),
+                  NULL, NULL,
+                  g_cclosure_marshal_generic,
+                  G_TYPE_NONE,
+                  1,
+                  G_TYPE_STRV);
+
   binding_set = gtk_binding_set_by_class (klass);
   gtk_binding_entry_add_signal (binding_set,
                                 GDK_KEY_k,
@@ -2320,6 +2375,7 @@ static void
 gb_source_view_init (GbSourceView *view)
 {
   GtkSourceCompletion *completion;
+  GtkTargetList *tl;
 
   view->priv = gb_source_view_get_instance_private (view);
 
@@ -2359,4 +2415,11 @@ gb_source_view_init (GbSourceView *view)
 
   completion = gtk_source_view_get_completion (GTK_SOURCE_VIEW (view));
   gtk_source_completion_block_interactive (completion);
+
+  /* Drag and drop support */
+  tl = gtk_drag_dest_get_target_list (GTK_WIDGET (view));
+  if (tl != NULL)
+    {
+      gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST);
+    }
 }
diff --git a/src/editor/gb-source-view.h b/src/editor/gb-source-view.h
index 9746c6f..d1be242 100644
--- a/src/editor/gb-source-view.h
+++ b/src/editor/gb-source-view.h
@@ -66,6 +66,8 @@ struct _GbSourceViewClass
   void (*request_documentation) (GbSourceView           *view);
   void (*display_documentation) (GbSourceView           *view,
                                  const gchar            *search_text);
+  void (*drop_uris)             (GbSourceViewClass      *view,
+                                 const gchar            **uri_list);
 };
 
 void                  gb_source_view_begin_search         (GbSourceView         *view,
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index b1df7df..8dd5f32 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -203,6 +203,8 @@ libgnome_builder_la_SOURCES = \
        src/util/gb-string.h \
        src/util/gb-widget.c \
        src/util/gb-widget.h \
+       src/util/gb-dnd.c \
+       src/util/gb-dnd.h \
        src/vim/gb-source-vim.c \
        src/vim/gb-source-vim.h \
        src/workbench/gb-workbench-types.h \
diff --git a/src/util/gb-dnd.c b/src/util/gb-dnd.c
new file mode 100644
index 0000000..0e0820b
--- /dev/null
+++ b/src/util/gb-dnd.c
@@ -0,0 +1,41 @@
+/* gb-dnd.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gb-dnd.h"
+
+/**
+ * gb_dnd_get_uri_list:
+ * @selection_data: the #GtkSelectionData from drag_data_received
+ *
+ * Create a list of valid uri's from a uri-list drop.
+ *
+ * Returns: (transfer full): a string array which will hold the uris or
+ *           %NULL if there were no valid uris. g_strfreev should be used when
+ *           the string array is no longer used
+ */
+gchar **
+gb_dnd_get_uri_list (GtkSelectionData *selection_data)
+{
+  const gchar *data;
+
+  g_return_val_if_fail (selection_data, NULL);
+  g_return_val_if_fail (gtk_selection_data_get_length (selection_data) > 0, NULL);
+
+  data = (const gchar*) gtk_selection_data_get_data (selection_data);
+  return g_uri_list_extract_uris (data);
+}
diff --git a/src/util/gb-dnd.h b/src/util/gb-dnd.h
new file mode 100644
index 0000000..3e440fd
--- /dev/null
+++ b/src/util/gb-dnd.h
@@ -0,0 +1,30 @@
+/* gb-dnd.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GB_DND_H
+#define GB_DND_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+gchar **gb_dnd_get_uri_list (GtkSelectionData *selection_data);
+
+G_END_DECLS
+
+#endif /* GB_RGBA_H */


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