Filesel drag and drop



Here is a patch that adds some drag and drop support too the file 
selector. Can i commit this?

/ Alex

Index: gtkfilesel.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkfilesel.c,v
retrieving revision 1.84
diff -u -p -r1.84 gtkfilesel.c
--- gtkfilesel.c	2001/07/18 23:39:22	1.84
+++ gtkfilesel.c	2001/08/02 21:29:50
@@ -44,6 +44,7 @@
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
+#include <ctype.h>
 
 #include "fnmatch.h"
 
@@ -68,6 +69,7 @@
 #include "gtkdialog.h"
 #include "gtkmessagedialog.h"
 #include "gtkintl.h"
+#include "gtkdnd.h"
 
 #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
 #define STRICT
@@ -588,6 +590,7 @@ gtk_file_selection_init (GtkFileSelectio
   GtkWidget *confirm_area;
   GtkWidget *pulldown_hbox;
   GtkWidget *scrolled_win;
+  GtkWidget *eventbox;
   GtkDialog *dialog;
   
   char *dir_title [2];
@@ -692,11 +695,14 @@ gtk_file_selection_init (GtkFileSelectio
   entry_vbox = gtk_vbox_new (FALSE, 2);
   gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 2);
   gtk_widget_show (entry_vbox);
-
+  
+  eventbox = gtk_event_box_new ();
   filesel->selection_text = label = gtk_label_new ("");
   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (eventbox), label);
+  gtk_box_pack_start (GTK_BOX (entry_vbox), eventbox, FALSE, FALSE, 0);
   gtk_widget_show (label);
+  gtk_widget_show (eventbox);
 
   filesel->selection_entry = gtk_entry_new ();
   gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event",
@@ -728,6 +734,172 @@ gtk_file_selection_init (GtkFileSelectio
   gtk_widget_grab_focus (filesel->selection_entry);
 }
 
+static gchar *
+uri_list_extract_first_uri (const gchar* uri_list)
+{
+  const gchar *p, *q;
+  gchar *retval;
+  
+  g_return_val_if_fail (uri_list != NULL, NULL);
+  
+  p = uri_list;
+  /* We don't actually try to validate the URI according to RFC
+   * 2396, or even check for allowed characters - we just ignore
+   * comments and trim whitespace off the ends.  We also
+   * allow LF delimination as well as the specified CRLF.
+   */
+  while (p)
+    {
+      if (*p != '#')
+	{
+	  while (isspace(*p))
+	    p++;
+	  
+	  q = p;
+	  while (*q && (*q != '\n') && (*q != '\r'))
+	    q++;
+	  
+	  if (q > p)
+	    {
+	      q--;
+	      while (q > p && isspace (*q))
+		q--;
+	      
+	      retval = g_malloc (q - p + 2);
+	      strncpy (retval, p, q - p + 1);
+	      retval[q - p + 1] = '\0';
+	      return retval;
+	    }
+	}
+      p = strchr (p, '\n');
+      if (p)
+	p++;
+    }
+  return NULL;
+}
+
+static gchar *
+uri_extract_filename (const gchar* uri)
+{
+  /* file uri with a hostname */
+  if (strncmp(uri, "file://", strlen("file://"))==0)
+    {
+      const char *hostname = &uri[strlen("file://")];
+      char *p = strchr (hostname,'/');
+      
+      /* if we can't find the '/' this uri is bad */
+      if(!p)
+	return NULL;
+      
+      return g_strdup (p);
+      
+      /* if the file doesn't have the //, we take it containing 
+	 a local path */
+    }
+  else if (strncmp (uri, "file:", strlen("file:"))==0)
+    {
+      const char *path = &uri[strlen("file:")];
+      /* if empty bad */
+      if (!*path)
+	return NULL;
+      return g_strdup (path);
+    }
+  return NULL;
+}
+
+
+static void
+filenames_dropped(GtkWidget        *widget,
+		  GdkDragContext   *context,
+		  gint              x,
+		  gint              y,
+		  GtkSelectionData *selection_data,
+		  guint             info,
+		  guint             time)
+{
+  char *uri = NULL;
+  char *filename = NULL;
+	
+  if (!selection_data->data)
+    return;
+
+  uri = uri_list_extract_first_uri ((char *)selection_data->data);
+  
+  if (!uri)
+    return;
+
+  filename = uri_extract_filename (uri);
+
+  g_free (uri);
+  
+  if (!filename)
+    return;
+  
+  gtk_file_selection_set_filename (GTK_FILE_SELECTION (widget),
+				   filename);
+  
+  g_free (filename);
+}
+
+static void
+filenames_drag_get (GtkWidget        *widget,
+		    GdkDragContext   *context,
+		    GtkSelectionData *selection_data,
+		    guint             info,
+		    guint             time,
+		    GtkFileSelection *filesel)
+{
+  gchar *file;
+  gchar *uri_list;
+
+  file = gtk_file_selection_get_filename (filesel);
+
+  if (file) /* ignore non-file-images for now */
+    {
+      uri_list = g_strconcat ("file:", file, NULL);
+      gtk_selection_data_set (selection_data,
+			      selection_data->target, 8,
+			      (void *)uri_list, strlen((char *)uri_list));
+      g_free (uri_list);
+    }
+  else
+    {
+      gtk_selection_data_set (selection_data,
+			      selection_data->target, 8,
+			      NULL, 0);
+    }
+}
+
+
+static void
+file_selection_setup_dnd (GtkFileSelection *filesel)
+{
+  GtkWidget *eventbox;
+  static GtkTargetEntry drag_types[] = {
+    { "text/uri-list", 0, 0 }
+  };
+  static gint n_drag_types = sizeof(drag_types)/sizeof(drag_types[0]);
+
+  gtk_drag_dest_set (GTK_WIDGET (filesel),
+		     GTK_DEST_DEFAULT_ALL,
+		     drag_types, n_drag_types,
+		     GDK_ACTION_COPY);
+
+  gtk_signal_connect (GTK_OBJECT(filesel), "drag_data_received",
+		      GTK_SIGNAL_FUNC(filenames_dropped), NULL);
+
+  eventbox = gtk_widget_get_parent (filesel->selection_text);
+  gtk_drag_source_set (eventbox,
+		       GDK_BUTTON1_MASK,
+		       drag_types, n_drag_types,
+		       GDK_ACTION_COPY);
+
+  gtk_signal_connect (GTK_OBJECT (eventbox),
+		      "drag_data_get",
+		      GTK_SIGNAL_FUNC (filenames_drag_get),
+		      filesel);
+}
+
 GtkWidget*
 gtk_file_selection_new (const gchar *title)
 {
@@ -737,6 +909,8 @@ gtk_file_selection_new (const gchar *tit
   gtk_window_set_title (GTK_WINDOW (filesel), title);
   gtk_dialog_set_has_separator (GTK_DIALOG (filesel), FALSE);
 
+  file_selection_setup_dnd (filesel);
+  
   return GTK_WIDGET (filesel);
 }
 





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