[gedit] dnd: Implement XDS dnd support for GeditView and GeditWindow
- From: Nelson Benítez León <nbenitez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gedit] dnd: Implement XDS dnd support for GeditView and GeditWindow
- Date: Mon, 28 Oct 2013 15:11:39 +0000 (UTC)
commit c1c3b568ec6294f49d1ce7e90ae64109c4dc3a93
Author: Nelson Benítez León <nbenitezl+gnome gmail com>
Date: Sat Oct 26 18:56:07 2013 +0200
dnd: Implement XDS dnd support for GeditView and GeditWindow
So we can open files directly when dropped from file-roller.
Fixes bug 430798
gedit/gedit-utils.c | 70 ++++++++++++++++++
gedit/gedit-utils.h | 2 +
gedit/gedit-view.c | 163 +++++++++++++++++++++++++++++-------------
gedit/gedit-window-private.h | 2 +
gedit/gedit-window.c | 110 ++++++++++++++++++++++++++---
5 files changed, 287 insertions(+), 60 deletions(-)
---
diff --git a/gedit/gedit-utils.c b/gedit/gedit-utils.c
index 0a587ac..a638b27 100644
--- a/gedit/gedit-utils.c
+++ b/gedit/gedit-utils.c
@@ -43,6 +43,7 @@
#include <glib.h>
#include <glib/gi18n.h>
+#include <glib/gstdio.h>
#include <gio/gio.h>
#include "gedit-utils.h"
@@ -1455,4 +1456,73 @@ gedit_utils_get_compression_type_from_content_type (const gchar *content_type)
return GEDIT_DOCUMENT_COMPRESSION_TYPE_NONE;
}
+/* Copied from nautilus */
+static gchar *
+get_direct_save_filename (GdkDragContext *context)
+{
+ guchar *prop_text;
+ gint prop_len;
+
+ if (!gdk_property_get (gdk_drag_context_get_source_window (context), gdk_atom_intern
("XdndDirectSave0", FALSE),
+ gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL,
+ &prop_len, &prop_text) && prop_text != NULL) {
+ return NULL;
+ }
+
+ /* Zero-terminate the string */
+ prop_text = g_realloc (prop_text, prop_len + 1);
+ prop_text[prop_len] = '\0';
+
+ /* Verify that the file name provided by the source is valid */
+ if (*prop_text == '\0' ||
+ strchr ((const gchar *) prop_text, G_DIR_SEPARATOR) != NULL) {
+ gedit_debug_message (DEBUG_UTILS, "Invalid filename provided by XDS drag site");
+ g_free (prop_text);
+ return NULL;
+ }
+
+ return (gchar *)prop_text;
+}
+
+gchar *
+gedit_utils_set_direct_save_filename (GdkDragContext *context)
+{
+ gchar *uri;
+ gchar *filename;
+
+ uri = NULL;
+ filename = get_direct_save_filename (context);
+
+ if (filename != NULL)
+ {
+ gchar *tempdir;
+ gchar *path;
+
+ tempdir = g_dir_make_tmp ("gedit-drop-XXXXXX", NULL);
+ if (tempdir == NULL)
+ {
+ tempdir = g_strdup (g_get_tmp_dir ());
+ }
+
+ path = g_build_filename (tempdir,
+ filename,
+ NULL);
+
+ uri = g_filename_to_uri (path, NULL, NULL);
+
+ /* Change the property */
+ gdk_property_change (gdk_drag_context_get_source_window (context),
+ gdk_atom_intern ("XdndDirectSave0", FALSE),
+ gdk_atom_intern ("text/plain", FALSE), 8,
+ GDK_PROP_MODE_REPLACE, (const guchar *) uri,
+ strlen (uri));
+
+ g_free (tempdir);
+ g_free (path);
+ g_free (filename);
+ }
+
+ return uri;
+}
+
/* ex:set ts=8 noet: */
diff --git a/gedit/gedit-utils.h b/gedit/gedit-utils.h
index f568be6..5c185cb 100644
--- a/gedit/gedit-utils.h
+++ b/gedit/gedit-utils.h
@@ -152,6 +152,8 @@ GeditDocumentCompressionType
gedit_utils_get_compression_type_from_content_type
(const gchar *content_type);
+gchar *gedit_utils_set_direct_save_filename (GdkDragContext *context);
+
G_END_DECLS
#endif /* __GEDIT_UTILS_H__ */
diff --git a/gedit/gedit-view.c b/gedit/gedit-view.c
index d191410..17ae078 100644
--- a/gedit/gedit-view.c
+++ b/gedit/gedit-view.c
@@ -57,6 +57,7 @@
enum
{
TARGET_URI_LIST = 100,
+ TARGET_XDNDDIRECTSAVE,
TARGET_TAB
};
@@ -65,6 +66,7 @@ struct _GeditViewPrivate
GSettings *editor_settings;
GtkTextBuffer *current_buffer;
PeasExtensionSet *extensions;
+ gchar *direct_save_uri;
};
G_DEFINE_TYPE_WITH_PRIVATE (GeditView, gedit_view, GTK_SOURCE_TYPE_VIEW)
@@ -138,10 +140,15 @@ gedit_view_init (GeditView *view)
view->priv->editor_settings = g_settings_new ("org.gnome.gedit.preferences.editor");
/* Drag and drop support */
+ view->priv->direct_save_uri = NULL;
tl = gtk_drag_dest_get_target_list (GTK_WIDGET (view));
if (tl != NULL)
{
+ gtk_target_list_add (tl,
+ gdk_atom_intern ("XdndDirectSave0", FALSE),
+ 0,
+ TARGET_XDNDDIRECTSAVE);
gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST);
gtk_target_list_add (tl,
gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"),
@@ -370,58 +377,98 @@ gedit_view_drag_data_received (GtkWidget *widget,
guint timestamp)
{
/* If this is an URL emit DROP_URIS, otherwise chain up the signal */
- if (info == TARGET_URI_LIST)
+ switch (info)
{
- gchar **uri_list;
+ case TARGET_URI_LIST:
+ gchar **uri_list;
- uri_list = gedit_utils_drop_get_uris (selection_data);
+ uri_list = gedit_utils_drop_get_uris (selection_data);
- if (uri_list != NULL)
- {
- g_signal_emit (widget, view_signals[DROP_URIS], 0, uri_list);
- g_strfreev (uri_list);
+ if (uri_list != NULL)
+ {
+ g_signal_emit (widget, view_signals[DROP_URIS], 0, uri_list);
+ g_strfreev (uri_list);
- gtk_drag_finish (context, TRUE, FALSE, timestamp);
- }
- }
- else if (info == TARGET_TAB)
- {
- GtkWidget *notebook;
- GtkWidget *new_notebook;
- GtkWidget *page;
+ gtk_drag_finish (context, TRUE, FALSE, timestamp);
+ }
- notebook = gtk_drag_get_source_widget (context);
+ break;
- if (!GTK_IS_WIDGET (notebook))
- {
- return;
- }
+ case TARGET_TAB:
+ GtkWidget *notebook;
+ GtkWidget *new_notebook;
+ GtkWidget *page;
- page = *(GtkWidget **) gtk_selection_data_get_data (selection_data);
- g_return_if_fail (page != NULL);
+ notebook = gtk_drag_get_source_widget (context);
- /* We need to iterate and get the notebook of the target view
- because we can have several notebooks per window */
- new_notebook = get_notebook_from_view (widget);
+ if (!GTK_IS_WIDGET (notebook))
+ {
+ return;
+ }
- if (notebook != new_notebook)
- {
- gedit_notebook_move_tab (GEDIT_NOTEBOOK (notebook),
- GEDIT_NOTEBOOK (new_notebook),
- GEDIT_TAB (page),
- 0);
- }
+ page = *(GtkWidget **) gtk_selection_data_get_data (selection_data);
+ g_return_if_fail (page != NULL);
- gtk_drag_finish (context, TRUE, TRUE, timestamp);
- }
- else
- {
- GTK_WIDGET_CLASS (gedit_view_parent_class)->drag_data_received (widget,
- context,
- x, y,
- selection_data,
- info,
- timestamp);
+ /* We need to iterate and get the notebook of the target view
+ because we can have several notebooks per window */
+ new_notebook = get_notebook_from_view (widget);
+
+ if (notebook != new_notebook)
+ {
+ gedit_notebook_move_tab (GEDIT_NOTEBOOK (notebook),
+ GEDIT_NOTEBOOK (new_notebook),
+ GEDIT_TAB (page),
+ 0);
+ }
+
+ gtk_drag_finish (context, TRUE, TRUE, timestamp);
+
+ break;
+
+ case TARGET_XDNDDIRECTSAVE:
+ GeditView *view;
+
+ view = GEDIT_VIEW (widget);
+
+ /* Indicate that we don't provide "F" fallback */
+ if (gtk_selection_data_get_format (selection_data) == 8 &&
+ gtk_selection_data_get_length (selection_data) == 1 &&
+ gtk_selection_data_get_data (selection_data)[0] == 'F')
+ {
+ gdk_property_change (gdk_drag_context_get_source_window (context),
+ gdk_atom_intern ("XdndDirectSave0", FALSE),
+ gdk_atom_intern ("text/plain", FALSE), 8,
+ GDK_PROP_MODE_REPLACE, (const guchar *) "", 0);
+ }
+ else if (gtk_selection_data_get_format (selection_data) == 8 &&
+ gtk_selection_data_get_length (selection_data) == 1 &&
+ gtk_selection_data_get_data (selection_data)[0] == 'S' &&
+ view->priv->direct_save_uri != NULL)
+ {
+ gchar **uris;
+
+ uris = g_new (gchar *, 2);
+ uris[0] = view->priv->direct_save_uri;
+ uris[1] = NULL;
+ g_signal_emit (widget, view_signals[DROP_URIS], 0, uris);
+ g_free (uris);
+ }
+
+ g_free (view->priv->direct_save_uri);
+ view->priv->direct_save_uri = NULL;
+
+ gtk_drag_finish (context, TRUE, FALSE, timestamp);
+
+ break;
+
+ default:
+ GTK_WIDGET_CLASS (gedit_view_parent_class)->drag_data_received (widget,
+ context,
+ x, y,
+ selection_data,
+ info,
+ timestamp);
+ break;
}
}
@@ -434,12 +481,28 @@ gedit_view_drag_drop (GtkWidget *widget,
{
gboolean result;
GdkAtom target;
+ guint info;
+ gboolean found;
+ GtkTargetList *target_list;
- /* If this is a URL, just get the drag data */
- target = drag_get_uri_target (widget, context);
+ target_list = gtk_drag_dest_get_target_list (widget);
+ target = gtk_drag_dest_find_target (widget, context, target_list);
+ found = gtk_target_list_find (target_list, target, &info);
- if (target != GDK_NONE)
+ if (found && (info == TARGET_URI_LIST || info == TARGET_XDNDDIRECTSAVE))
{
+ if (info == TARGET_XDNDDIRECTSAVE)
+ {
+ gchar *uri;
+ uri = gedit_utils_set_direct_save_filename (context);
+
+ if (uri != NULL)
+ {
+ g_free (GEDIT_VIEW (widget)->priv->direct_save_uri);
+ GEDIT_VIEW (widget)->priv->direct_save_uri = uri;
+ }
+ }
+
gtk_drag_get_data (widget, context, target, timestamp);
result = TRUE;
}
diff --git a/gedit/gedit-window-private.h b/gedit/gedit-window-private.h
index ccd2bdf..a56c915 100644
--- a/gedit/gedit-window-private.h
+++ b/gedit/gedit-window-private.h
@@ -119,6 +119,8 @@ struct _GeditWindowPrivate
GFile *default_location;
+ gchar *direct_save_uri;
+
#ifdef OS_OSX
GtkOSXApplicationMenuGroup *mac_menu_group;
#endif
diff --git a/gedit/gedit-window.c b/gedit/gedit-window.c
index 7b20183..49d93bc 100644
--- a/gedit/gedit-window.c
+++ b/gedit/gedit-window.c
@@ -90,7 +90,13 @@ enum
enum
{
- TARGET_URI_LIST = 100
+ TARGET_URI_LIST = 100,
+ TARGET_XDNDDIRECTSAVE
+};
+
+static const GtkTargetEntry drop_types [] = {
+ { "XdndDirectSave0", 0, TARGET_XDNDDIRECTSAVE }, /* XDS Protocol Type */
+ { "text/uri-list", 0, TARGET_URI_LIST}
};
G_DEFINE_TYPE_WITH_PRIVATE (GeditWindow, gedit_window, GTK_TYPE_APPLICATION_WINDOW)
@@ -2642,11 +2648,91 @@ drag_data_received_cb (GtkWidget *widget,
if (window == NULL)
return;
- if (info == TARGET_URI_LIST)
+ switch (info)
{
- uri_list = gedit_utils_drop_get_uris (selection_data);
- load_uris_from_drop (window, uri_list);
- g_strfreev (uri_list);
+ case TARGET_URI_LIST:
+ uri_list = gedit_utils_drop_get_uris(selection_data);
+ load_uris_from_drop (window, uri_list);
+ g_strfreev (uri_list);
+
+ gtk_drag_finish (context, TRUE, FALSE, timestamp);
+
+ break;
+
+ case TARGET_XDNDDIRECTSAVE:
+ /* Indicate that we don't provide "F" fallback */
+ if (gtk_selection_data_get_format (selection_data) == 8 &&
+ gtk_selection_data_get_length (selection_data) == 1 &&
+ gtk_selection_data_get_data (selection_data)[0] == 'F')
+ {
+ gdk_property_change (gdk_drag_context_get_source_window (context),
+ gdk_atom_intern ("XdndDirectSave0", FALSE),
+ gdk_atom_intern ("text/plain", FALSE), 8,
+ GDK_PROP_MODE_REPLACE, (const guchar *) "", 0);
+ }
+ else if (gtk_selection_data_get_format (selection_data) == 8 &&
+ gtk_selection_data_get_length (selection_data) == 1 &&
+ gtk_selection_data_get_data (selection_data)[0] == 'S' &&
+ window->priv->direct_save_uri != NULL)
+ {
+ gchar **uris;
+
+ uris = g_new (gchar *, 2);
+ uris[0] = window->priv->direct_save_uri;
+ uris[1] = NULL;
+
+ load_uris_from_drop (window, uris);
+ g_free (uris);
+ }
+
+ g_free (window->priv->direct_save_uri);
+ window->priv->direct_save_uri = NULL;
+
+ gtk_drag_finish (context, TRUE, FALSE, timestamp);
+
+ break;
+ }
+}
+
+static void
+drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ gpointer user_data)
+{
+ GeditWindow *window;
+ GtkTargetList *target_list;
+ GdkAtom target;
+
+ window = get_drop_window (widget);
+
+ target_list = gtk_drag_dest_get_target_list (widget);
+ target = gtk_drag_dest_find_target (widget, context, target_list);
+
+ if (target != GDK_NONE)
+ {
+ guint info;
+ gboolean found;
+
+ found = gtk_target_list_find (target_list, target, &info);
+ g_assert (found);
+
+ if (info == TARGET_XDNDDIRECTSAVE)
+ {
+ gchar *uri;
+ uri = gedit_utils_set_direct_save_filename (context);
+
+ if (uri != NULL)
+ {
+ g_free (window->priv->direct_save_uri);
+ window->priv->direct_save_uri = uri;
+ }
+ }
+
+ gtk_drag_get_data (GTK_WIDGET (widget), context,
+ target, time);
}
}
@@ -3697,6 +3783,7 @@ gedit_window_init (GeditWindow *window)
window->priv->dispose_has_run = FALSE;
window->priv->fullscreen_controls = NULL;
window->priv->fullscreen_animation_timeout_id = 0;
+ window->priv->direct_save_uri = NULL;
window->priv->editor_settings = g_settings_new ("org.gnome.gedit.preferences.editor");
window->priv->ui_settings = g_settings_new ("org.gnome.gedit.preferences.ui");
@@ -3810,14 +3897,13 @@ gedit_window_init (GeditWindow *window)
gtk_widget_show (window->priv->hpaned);
gtk_widget_show (window->priv->vpaned);
- /* Drag and drop support, set targets to NULL because we add the
- default uri_targets below */
+ /* Drag and drop support */
gtk_drag_dest_set (GTK_WIDGET (window),
GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_HIGHLIGHT |
GTK_DEST_DEFAULT_DROP,
- NULL,
- 0,
+ drop_types,
+ G_N_ELEMENTS (drop_types),
GDK_ACTION_COPY);
/* Add uri targets */
@@ -3825,7 +3911,7 @@ gedit_window_init (GeditWindow *window)
if (tl == NULL)
{
- tl = gtk_target_list_new (NULL, 0);
+ tl = gtk_target_list_new (drop_types, G_N_ELEMENTS (drop_types));
gtk_drag_dest_set_target_list (GTK_WIDGET (window), tl);
gtk_target_list_unref (tl);
}
@@ -3838,6 +3924,10 @@ gedit_window_init (GeditWindow *window)
"drag_data_received",
G_CALLBACK (drag_data_received_cb),
NULL);
+ g_signal_connect (window,
+ "drag_drop",
+ G_CALLBACK (drag_drop_cb),
+ NULL);
/* we can get the clipboard only after the widget
* is realized */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]