Commit c1c3b568 authored by Nelson Benítez León's avatar Nelson Benítez León

dnd: Implement XDS dnd support for GeditView and GeditWindow

So we can open files directly when dropped from file-roller.

Fixes bug 430798
parent e155bf02
......@@ -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: */
......@@ -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__ */
......
......@@ -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;
}
......
......@@ -119,6 +119,8 @@ struct _GeditWindowPrivate
GFile *default_location;
gchar *direct_save_uri;
#ifdef OS_OSX
GtkOSXApplicationMenuGroup *mac_menu_group;
#endif
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment