PATCH: even better run dialog



Hi,

since gnome-terminal was broken in the Ximian snapshots I find myself
using xterm quite a bit. It's really quite annoying to use the run
dialog everytime, if you just want a new terminal. Wouldn't it be great
if you could just drag the icon that appears on the run dialog and drop
it on the desktop or the panel to make a new launcher? Well, now you
can! :)

While working on that I also noticed that a lot of the code in the run
dialog was pretty crappy. So I rewrote a bunch of stuff with the
following results:

1. You can now drag the icon to make launchers.

2. The run dialog uses gnome_url_show to properly display urls.

3. A new function show_document() correctly displays documents in the
default application. It takes care of all the exec field expansion and
honors the GnomeVfsMimeApplication settings. Something like this should
probably go into libgnome as gnome_url_document_show() vs.
gnome_url_show().

4. Remove deprecated gnome_config_ stuff.

5. Autocompletion works better and you don't have to press CTRL-TAB to
use it. Works kinda like the Nautilus location bar.

6. While doing this I also removed one feature that was kind of a hassle
-- defining additional environment variables in the command line. I hope
nobody minds that, I figure if you really want to do that you might as
well use the terminal.

7. Another problem is that (on my system at least) there is no url
handler defined for file:// urls and as a result the default handler is
used with gnome_url_show. On my system that was Galeon which is
obviously not appropriate. There really should be a file:// handler that
defaults to Nautilus, or the Unknown handler should be Nautilus.
Otherwise the run dialog will open directories in Galeon!!


So yeah, I am pretty happy about this. The run dialog is my little baby
afterall. :)

Patch is attached. Quite a few string changes, is it still ok for 2.0.1?

- Frank
Index: gnome-run.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/gnome-run.c,v
retrieving revision 1.109
diff -u -p -r1.109 gnome-run.c
--- gnome-run.c	15 Jul 2002 00:20:01 -0000	1.109
+++ gnome-run.c	20 Jul 2002 02:39:41 -0000
@@ -27,6 +27,7 @@
 #include <dirent.h>
 #include <string.h>
 
+#include <gdk/gdkkeysyms.h>
 #include <libgnome/libgnome.h>
 #include <libgnomeui/libgnomeui.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
@@ -97,11 +98,13 @@ fill_executables_from (const char *dirna
 		return;
 
 	while ( (dent = readdir (dir)) != NULL) {
-		char *file = g_strconcat (dirname, "/", dent->d_name, NULL);
+		char *file = g_build_filename (dirname, dent->d_name, NULL);
 
 		if (access (file, X_OK) == 0)
 			executables = g_list_prepend (executables,
 						      g_strdup (dent->d_name));
+						      
+		g_free (file);
 	}
 
 	closedir (dir);
@@ -135,9 +138,8 @@ static void
 ensure_completion (void)
 {
 	if (exe_completion == NULL) {
+		if (executables == NULL) fill_executables ();
 		exe_completion = g_completion_new (NULL);
-		fill_executables ();
-
 		g_completion_add_items (exe_completion, executables);
 	}
 }
@@ -156,53 +158,230 @@ kill_completion (void)
 	}
 }
 
-static void
-get_environment (int *argc, char ***argv, int *envc, char ***envv)
+static char *
+get_uri_from_command (const char *command)
 {
-	GList *envar = NULL, *li;
-	int i, moveby;
+	char *uri = NULL;
+	char *path = NULL;
+	char **tokens;
+	
+	if (string_empty (command))
+		return NULL;
 
-	*envv = NULL;
-	*envc = 0;
+	tokens = g_strsplit (command, " ", -1);
 
-	moveby = 0;
-	for (i = 0; i < *argc; i++) {
-		if (strchr ((*argv)[i], '=') == NULL) {
-			break;
+	if (strchr (tokens[0], ':') == NULL) {
+		if (!g_file_test (tokens[0], G_FILE_TEST_EXISTS)) {
+			path = g_build_filename (g_get_home_dir (), tokens[0], NULL);
+			if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
+				g_strfreev (tokens);
+				g_free (path);
+				return NULL;
+			}
 		}
-		envar = g_list_append (envar, g_strdup ((*argv)[i]));
-		moveby ++;
+	} else {
+			path = g_strdup (command);
+	}
+		
+	if (path) {
+		uri = g_strconcat ("file://", path, NULL);
+		g_free (path);
+	} else {
+		uri = gnome_vfs_make_uri_canonical (tokens[0]);
 	}
 
-	if (moveby == *argc) {
-		panel_g_list_deep_free (envar);
-		return;
+	g_strfreev (tokens);
+
+	return uri;
+}
+
+static gboolean
+command_is_executable (const char *command)
+{
+	char *uri, *path;
+	char **tokens;
+	GList *item;
+	
+	if (string_empty (command))
+		return FALSE;
+	
+	/* check if the command is a simple executable */
+	tokens = g_strsplit (command, " ", -1);
+
+	if (executables == NULL) fill_executables ();
+	for (item = executables; item != NULL; item = item->next) {
+		if (!strcmp (tokens[0], item->data))
+			break;
 	}
 
-	if (envar == NULL)
-		return;
+	g_strfreev (tokens);
+	
+	if (item != NULL) return TRUE;
+	
+	/* check absolute path */
+	uri = get_uri_from_command (command);
+	if (uri == NULL) return FALSE;
+	
+	path = gnome_vfs_get_local_path_from_uri (uri);
+	g_free (uri);
+	
+	if (path == NULL || 
+	    !g_file_test (path, G_FILE_TEST_IS_EXECUTABLE) ||
+	    !g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
+	    	g_free (path);
+		return FALSE;
+	}
+	
+	g_free (path);
+	return TRUE;
+}
 
-	for (i = 0; i < *argc; i++) {
-		g_free ((*argv)[i]);
-		if (i + moveby < *argc) {
-			(*argv)[i] = (*argv)[i+moveby];
-			(*argv)[i+moveby] = NULL;
-		} else {
-			(*argv)[i] = NULL;
+
+static gboolean
+show_document (const char *url)
+{
+	GnomeDesktopItem *ditem;
+	GnomeVFSFileInfo *info;
+	GnomeVFSURI *uri;
+	GnomeVFSResult result;
+	GError *error = NULL;
+	GList *item;
+	GList params;
+	char *scheme;
+	int pid;
+
+
+	uri = gnome_vfs_uri_new (url);
+	scheme = g_strdup (gnome_vfs_uri_get_scheme (uri));
+	gnome_vfs_uri_unref (uri);
+
+	/* always launch http uris in the browser */
+	if (!strcmp ("http", scheme)) {
+		if (!gnome_url_show (url, &error)) {
+			panel_error_dialog ("run_error",
+					     _("<b>Error displaying document:</b> '%s'\n\nDetails: %s"),
+					     url, error->message);
+			g_error_free (error);
 		}
+		g_free (scheme);
+		return FALSE;
 	}
-	*argc -= moveby;
+	
+	info = gnome_vfs_file_info_new ();
+	result = gnome_vfs_get_file_info (url, info, 0);
+	
+	if (result != GNOME_VFS_OK) {
+		panel_error_dialog ("run_error",
+				    _("<b>Error displaying document:</b> '%s'\n\n"
+				      "Details: error reading file"),
+				       url);
+
+		gnome_vfs_file_info_unref (info);
+		g_free (scheme);
+		return FALSE;
+	}
+	
+	if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE)
+	    && info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
+	    
+		char *mime_info;
+		GnomeVFSMimeApplication *app;
+		GnomeDesktopItemLaunchFlags flags;
+		
+		mime_info = gnome_vfs_get_mime_type (url);
+		app = gnome_vfs_mime_get_default_application (mime_info);
+		g_free (mime_info);
+				
+		if (app == NULL) {
+			panel_error_dialog ("run_error",
+					    _("<b>Error displaying document:</b> '%s'\n\n"
+					      "Details: no default application available"),
+					       url);
+					       
+			gnome_vfs_file_info_unref (info);
+			g_free (scheme);
+			return FALSE;			
+		}
+				
+		for (item = app->supported_uri_schemes; item != NULL; item = item->next)
+		{
+			if (!strcmp (item->data, scheme)) {
+				break;
+			}
+		}
+		
+		if (item == NULL && app->supported_uri_schemes != NULL) {
+			panel_error_dialog ("run_error",
+					    _("<b>Error displaying document:</b> '%s'\n\n"
+					      "Details: scheme not supported by default application"),
+					       url);
+					       
+			gnome_vfs_mime_application_free (app);
+			gnome_vfs_file_info_unref (info);
+			g_free (scheme);
+			return FALSE;
+		}			
+					
+		/* let gnome-desktop-item do the command expansion for us */
+		ditem = gnome_desktop_item_new ();
+		gnome_desktop_item_set_entry_type (ditem, GNOME_DESKTOP_ITEM_TYPE_APPLICATION);
+		gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_EXEC, app->command);
+		gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_NAME, app->name);
+		gnome_desktop_item_set_boolean (ditem, GNOME_DESKTOP_ITEM_TERMINAL, app->requires_terminal);
+		
+		params.prev = NULL;
+		params.data = (gpointer) url;
+		params.next = NULL;
+		
+		if (app->expects_uris == GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS) {
+			flags = GNOME_DESKTOP_ITEM_LAUNCH_APPEND_URIS;
+		} else {
+			flags = GNOME_DESKTOP_ITEM_LAUNCH_APPEND_PATHS;
+		}
+		
+		pid = gnome_desktop_item_launch (ditem, &params, flags, &error);
+		
+		if (pid == -1)
+		{
+			panel_error_dialog ("run_error",
+					    _("<b>Error displaying document:</b> '%s'\n\n"
+					      "Details: %s"),
+					      url, error->message);
+			g_error_free (error);
+		}
 
-	*envc = g_list_length (envar);
-	*envv = g_new0 (char *, *envc + 1);
-	for (i = 0, li = envar; li != NULL; li = li->next, i++) {
-		(*envv)[i] = li->data;
-		li->data = NULL;
-	}	
-	(*envv)[i] = NULL;
-	g_list_free (envar);
+		gnome_vfs_mime_application_free (app);
+		gnome_desktop_item_unref (ditem);
+		g_free (scheme);
+		
+		return (pid != -1);
+		
+	} else if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE)
+		    && info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
+
+		if (!gnome_url_show (url, &error)) {
+			panel_error_dialog ("run_error",
+					    _("<b>Error displaying document:</b> '%s'\n\n"
+					      "Details: %s"),
+					     url, error->message);
+			g_free (scheme);
+			g_error_free (error);
+			return FALSE;
+		}
+		
+		g_free (scheme);
+		return TRUE;
+	}
+	
+	panel_error_dialog ("run_error",
+			    _("<b>Error displaying document:</b> '%s'\n\n"
+			      "Details: file type not supported"), 
+			       url);
+	g_free (scheme);
+	return FALSE;
 }
 
+
 static void
 launch_selected (GtkTreeModel *model,
 		 GtkTreeIter  *iter,
@@ -231,12 +410,11 @@ launch_selected (GtkTreeModel *model,
 				    _("<b>Failed to run this program</b>\n\n"
 				      "Details: %s"),
 				    error->message);
-		g_clear_error (&error);
+		g_error_free (error);
 		return;
 	}
 
-        terminal = GTK_TOGGLE_BUTTON (
-			g_object_get_data (G_OBJECT (dialog), "terminal"));
+        terminal = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (dialog), "terminal"));
 
 	/* Honor "run in terminal" button */
 	gnome_desktop_item_set_boolean (ditem,
@@ -248,7 +426,9 @@ launch_selected (GtkTreeModel *model,
 				    _("<b>Failed to run this program</b>\n\n"
 				      "Details: %s"),
 				    error->message);
-		g_clear_error (&error);
+		g_error_free (error);
+		gnome_desktop_item_unref (ditem);
+		return;
 	}
 
 	/* save command history */
@@ -258,28 +438,23 @@ launch_selected (GtkTreeModel *model,
 	gnome_entry_prepend_history (gnome_entry, TRUE, command);
 	g_free (command);
 	
+	g_error_free (error);
 	gnome_desktop_item_unref (ditem);
 }
 
 static void 
 run_dialog_response (GtkWidget *w, int response, gpointer data)
 {
-	GtkWidget *entry;
-        GtkWidget *list;
-	GnomeEntry *gnome_entry;
+	int argc;
 	char **argv = NULL;
-	char **temp_argv = NULL;
-	int argc, temp_argc;
-	char *s = NULL;
+	char *command = NULL;
 	char *escaped = NULL;
-	char **envv = NULL;
-	int envc;
+	char *uri     = NULL;
 	GError *error = NULL;
 
 	if (response == GTK_RESPONSE_HELP) {
 		panel_show_help ("wgoseditmainmenu.xml", "gospanel-23");
-		/* just return as we don't want to close */
-		return;
+		goto return_only;
 	} else if (response != PANEL_RESPONSE_RUN) {
 		goto return_and_close;
 	}
@@ -288,38 +463,39 @@ run_dialog_response (GtkWidget *w, int r
 		GtkTreeSelection *selection;
 		GtkTreeModel *model;
 		GtkTreeIter iter;
-
+	        GtkWidget *list;
+		
 	        list = g_object_get_data (G_OBJECT (run_dialog), "program_list");
 		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
 
 		/* just return if nothing selected */
-		if ( ! gtk_tree_selection_get_selected (selection, 
-							&model, &iter))
-			return;
+		if (!gtk_tree_selection_get_selected (selection, 
+						      &model, &iter)) {
+			goto return_only;
+		}
 
 		launch_selected (model, &iter, w);
+		
         } else {
-	
+
+		GtkWidget *entry;
+		GnomeEntry *gnome_entry;
 		GtkToggleButton *terminal;
 
                 entry = g_object_get_data (G_OBJECT (w), "entry");
+                command = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+		escaped = g_markup_escape_text (command, -1);
 
-                s = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
-		escaped = g_markup_escape_text (s, -1);
-
-                if (string_empty (s))
-                        goto return_and_close;
-
-		/* save command in history */
-		gnome_entry = g_object_get_data (G_OBJECT (w), "gnome_entry");
-		gnome_entry_prepend_history (gnome_entry, TRUE, s);
+                if (string_empty (command)) {
+			goto return_only;
+		}
 
                 /* evil eggies, do not translate! */
-                if (strcmp (s, "you shall bring us a shrubbery") == 0) {
+                if (strcmp (command, "you shall bring us a shrubbery") == 0) {
                         panel_info_dialog ("ni_ni_ni_ni",
 					   "NI! NI! NI! NI! NI! NI!");
                         goto return_and_close;
-                } else if (strcmp (s, "supreme executive power") == 0) {
+                } else if (strcmp (command, "supreme executive power") == 0) {
                         panel_info_dialog ("evil",
 					   "Listen -- strange women lying in\n"
 					   "ponds distributing swords is no\n"
@@ -328,156 +504,80 @@ run_dialog_response (GtkWidget *w, int r
 					   "a mandate from the masses, not from\n"
 					   "some farcical aquatic ceremony!");
                         goto return_and_close;
-                } else if (strcmp (s, "free the fish") == 0) {
+                } else if (strcmp (command, "free the fish") == 0) {
 			start_screen_check ();
                         goto return_and_close;
-		} else if (strcmp (s, "gegls from outer space") == 0) {
+		} else if (strcmp (command, "gegls from outer space") == 0) {
 			start_geginv ();
                         goto return_and_close;
-		} else if (strcmp (s, "End world hunger") == 0) {
+		} else if (strcmp (command, "End world hunger") == 0) {
 			gnome_url_show ("http://www.wfp.org";, NULL);
                         goto return_and_close;
 		}
 
-                /* Somewhat of a hack I suppose */
-                if (panel_is_url (s)) {
-                        gnome_url_show (s, NULL);
-                        goto return_and_close;
-                }
-
-                if ( ! g_shell_parse_argv (s, &temp_argc, &temp_argv, &error)) {
-			panel_error_dialog ("run_error",
-					    _("<b>Failed to execute command:</b> '%s'\n\nDetails: %s"),
-					    escaped, error->message);
-			g_clear_error (&error);
-                        goto return_and_close;
-                }
+		gnome_entry = g_object_get_data (G_OBJECT (w), "gnome_entry");
+		gnome_entry_prepend_history (gnome_entry, TRUE, command);
 
-                get_environment (&temp_argc, &temp_argv, &envc, &envv);
+		if (command_is_executable (command)) {
 
-		terminal = GTK_TOGGLE_BUTTON (
-				g_object_get_data (G_OBJECT (w), "terminal"));
+	                if (! g_shell_parse_argv (command, &argc, &argv, &error)) {
+				panel_error_dialog ("run_error",
+						    _("<b>Failed to execute command:</b> '%s'\n\n"
+						      "Details: %s"),
+						    escaped, error->message);
+				goto return_only;
+	                }
 
-                if (terminal->active) {
-                        char **term_argv;
-                        int term_argc;
-                        gnome_config_get_vector ("/Gnome/Applications/Terminal",
-                                                 &term_argc, &term_argv);
-                        if (term_argv) {
-                                int i;
-                                argv = g_new(char *, term_argc + temp_argc + 1);
-                                argc = term_argc + temp_argc;
-                                for(i = 0; i < term_argc; i++) {
-                                        argv[i] = term_argv[i];
-                                        term_argv[i] = NULL;
-                                }
-                                for(i = term_argc; i < term_argc+temp_argc; i++) {
-                                        argv[i] = temp_argv[i-term_argc];
-                                        temp_argv[i-term_argc] = NULL;
-				}
-                                argv[i] = NULL;
-				g_free (term_argv);
-                        } else {
-                                char *check;
-                                int i;
-                                check = g_find_program_in_path ("gnome-terminal");
-                                argv = g_new(char *, 2 + temp_argc + 1);
-                                argc = 2 + temp_argc;
-                                if(!check) {
-                                        argv[0] = g_strdup ("xterm");
-                                        argv[1] = g_strdup ("-e");
-                                } else {
-                                        argv[0] = check;
-                                        argv[1] = g_strdup ("-x");
-                                }
-                                for(i = 2; i < 2+temp_argc; i++) {
-                                        argv[i] = temp_argv[i-2];
-                                        temp_argv[i-2] = NULL;
-				}
-                                argv[i] = NULL;
-                        }
-                } else {
-                        argv = temp_argv;
-                        temp_argv = NULL;
-                        argc = temp_argc;
-                }
+			terminal = GTK_TOGGLE_BUTTON (
+					g_object_get_data (G_OBJECT (w), "terminal"));
 
-                if (gnome_execute_async_with_env (g_get_home_dir (),
-                                                  argc, argv,
-                                                  envc, envv) < 0) {
-
-			/* if all else fails we try to open the file with an app */
-			char *path;
-			char *command = NULL;
-			GError *error = NULL;
-			GnomeVFSFileInfo *info = NULL;
+                	if (terminal->active) {
+				gnome_prepend_terminal_to_vector (&argc, &argv);
+			}
 
-			if (!g_path_is_absolute (s)) {
-				path = g_strconcat (g_get_home_dir (), "/", s, NULL);
-			} else {
-				path = g_strdup (s);
+			if (gnome_execute_async (g_get_home_dir (),
+						 argc, argv) == -1) {
+				panel_error_dialog ("run_error",
+						     _("<b>Failed to execute command:</b> '%s'"),
+						     escaped);
+				goto return_only;
 			}
 			
-			info = gnome_vfs_file_info_new ();
-			if (gnome_vfs_get_file_info (path, info, 0) != GNOME_VFS_OK) {
-				panel_error_dialog("run_error",
-						   _("<b>Failed to execute command:</b> '%s'\n\nDetails: %s"),
-                	                           escaped, g_strerror (errno));
-				g_free (path);
-				gnome_vfs_file_info_unref (info);
-				goto return_and_close;
-			}
+		} else {
+			/* The command is not an executable so try and convert it
+			 * into a URL and try to display it.
+			 */
+			uri = get_uri_from_command (command);
 			
-			if (info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
-				char *mime_info;
-				GnomeVFSMimeApplication *app;				
-				
-				mime_info = gnome_vfs_get_mime_type (path);
-				app = gnome_vfs_mime_get_default_application (mime_info);
-						
-				if (app != NULL) {
-					command = g_strconcat (app->command, " ", path, NULL);
+			if (uri != NULL) {
+				if (!show_document (uri)) {
+					goto return_only;
 				}
-				
-				gnome_vfs_mime_application_free (app);
-				g_free (mime_info);				
-				
-				if (command == NULL) {
-					panel_error_dialog ("run_error",
-							    _("<b>Failed to open file:</b> '%s'\n\nDetails: no application available to open file"),
-							    escaped);
-
-					gnome_vfs_file_info_unref (info);
-					g_free (path);
-					goto return_and_close;
-				}
-
-			} else if (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
-				command = g_strconcat ("nautilus ", path, NULL);
-			}
-			
-			if (!g_spawn_command_line_async (command, &error)) {
+			} else {
 				panel_error_dialog ("run_error",
-						    _("<b>Failed to open file:</b> '%s'\n\nDetails: %s"),
-						    escaped, error->message);
-				g_clear_error (&error);
+						    _("<b>Error displaying document:</b> '%s'\n\n"
+						      "Details: unable to convert to proper URL"),
+						    command);
+				goto return_only;
 			}
-	
-			gnome_vfs_file_info_unref (info);
-			g_free (path);
-			g_free (command);
-                }
+		}
         }
         
 return_and_close:
 	g_strfreev (argv);
-	g_strfreev (temp_argv);
-	g_strfreev (envv);
-	g_free (s);
+	g_free (command);
 	g_free (escaped);
-
+	g_free (uri);
+	if (error) g_error_free (error);
 	gtk_widget_destroy (w);
-        
+	return;
+
+return_only:
+	g_strfreev (argv);
+	g_free (command);
+	g_free (escaped);
+	g_free (uri);
+	if (error) g_error_free (error);
 }
 
 static char *
@@ -564,39 +664,38 @@ browse (GtkWidget *w, GtkWidget *entry)
 static gboolean
 entry_event (GtkEntry * entry, GdkEventKey * event, gpointer data)
 {
-	if (event->type != GDK_KEY_PRESS)
-		return FALSE;
-
-	/* completion */
-	if ((event->keyval == GDK_Tab) &&
-	    (event->state & GDK_CONTROL_MASK)) {
-		gchar* prefix;
-		gchar* nprefix = NULL;
-		gint pos;
-
+	gchar* prefix;
+	gchar* nprefix = NULL;
+	gint pos;
+
+	if (event->type == GDK_KEY_PRESS &&
+	    event->keyval != GDK_BackSpace &&
+	    event->keyval != GDK_Delete &&
+	    event->keyval != GDK_space &&
+	    event->length > 0) {
+	
 		ensure_completion ();
 
-		pos = gtk_editable_get_position (GTK_EDITABLE (entry));
-		prefix = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, pos);
+		prefix = g_strconcat (gtk_entry_get_text (GTK_ENTRY (entry)), event->string, NULL);
+		pos = strlen (prefix);
 
 		g_completion_complete (exe_completion, prefix, &nprefix);
-
+	
 		if (nprefix != NULL &&
 		    strlen (nprefix) > strlen (prefix)) {
-			gtk_editable_insert_text (GTK_EDITABLE (entry),
-						  nprefix + pos, 
-						  strlen (nprefix) -
-						    strlen (prefix),
-						  &pos);
+		    
+			gtk_entry_set_text (GTK_ENTRY (entry), nprefix);
 			gtk_editable_set_position (GTK_EDITABLE (entry), pos);
-		} else {
-                        gdk_beep ();
-                }
+			gtk_editable_select_region (GTK_EDITABLE (entry), pos, -1);
+		
+			g_free (nprefix);
+			g_free (prefix);
+
+			return TRUE;
+		}
 
 		g_free (nprefix);
 		g_free (prefix);
-
-		return TRUE;
 	}
 
 	return FALSE;
@@ -750,20 +849,28 @@ create_disclosure_widget (void)
         return disclosure;
 }
 
+#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
+
 static void
 entry_changed (GtkWidget *entry,
                gpointer   data)
 {
+	static GtkTargetEntry dnd_types[] = { { "text/uri-list", 0, 0 } };
 	GtkWidget *button;
 	char *text;
-	
+		
 	/* desensitize run button if no text entered */
 	text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
 	button = g_object_get_data (G_OBJECT (run_dialog), "run_button");
 	if (strlen (text) == 0) {
 		gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
+		gtk_drag_source_unset (run_dialog);
 	} else {
 		gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
+		gtk_drag_source_set (run_dialog,
+				     GDK_BUTTON1_MASK,
+				     dnd_types, ELEMENTS (dnd_types),
+				     GDK_ACTION_COPY);
 	}
 	g_free (text);
 
@@ -816,7 +923,144 @@ drag_data_received (GtkWidget        *wi
 	gtk_drag_finish (context, TRUE, FALSE, time);
 }
 
-#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
+
+static char *
+ditem_get_unique_uri (void)
+{
+	int rnd, word;
+	char *uri;
+#define NUM_OF_WORDS 12
+	char *words[] = {
+		"foo",
+		"bar",
+		"blah",
+		"gegl",
+		"frobate",
+		"hadjaha",
+		"greasy",
+		"hammer",
+		"eek",
+		"larry",
+		"curly",
+		"moe",
+		NULL};
+	char *fname, *full;
+
+	for (;;) {
+		rnd = rand ();
+		word = rand () % NUM_OF_WORDS;
+		fname = g_strdup_printf ("%s-%010x.desktop",
+					 words[word],
+					 (guint)rnd);
+		full = g_build_filename (g_get_tmp_dir (), fname, NULL);
+		g_free (fname);
+
+		if ( ! g_file_test (full, G_FILE_TEST_EXISTS)) {
+			uri = gnome_vfs_get_uri_from_local_path (full);
+			g_free (full);
+			return uri;
+		}
+		
+		g_free (full);
+	}
+
+	g_assert_not_reached ();
+	return NULL;
+}
+
+
+static void  
+drag_data_get (GtkWidget          *dialog,
+	  	GdkDragContext     *context,
+	  	GtkSelectionData   *selection_data,
+		guint               info,
+		guint               time,
+		GtkWidget	     *widget)
+{
+	GnomeDesktopItem *ditem;
+	GtkToggleButton  *terminal;
+	char             *name, *file, *uri;
+	const char 	 *location;
+
+        terminal = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (dialog), "terminal"));
+	
+	if (g_object_get_data (G_OBJECT (dialog), "use_list")) {
+		GtkWidget 	 *list;
+		GtkTreeSelection *selection;
+		GtkTreeModel 	 *model;
+		GtkTreeIter 	  iter;
+
+	        list = g_object_get_data (G_OBJECT (run_dialog), "program_list");
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
+
+		if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+			return;
+		}
+
+		gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1);
+
+		if (!name) return;
+		g_free (name);
+		                        
+		ditem = gnome_desktop_item_new_from_uri (name,
+							 GNOME_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS,
+							 NULL);
+		if (!ditem) return;
+		
+		/* Honor "run in terminal" button */		
+		gnome_desktop_item_set_boolean (ditem,
+						GNOME_DESKTOP_ITEM_TERMINAL,
+						terminal->active);
+		
+		location = gnome_desktop_item_get_location (ditem);
+		
+		gtk_selection_data_set (selection_data,
+					selection_data->target, 8,
+					location, strlen (location));		
+	
+	} else {
+		GtkEntry *entry;
+		entry = g_object_get_data (G_OBJECT (dialog), "entry");
+		
+		if (strlen (gtk_entry_get_text (entry)) == 0) return;
+		
+		ditem = gnome_desktop_item_new ();
+
+		if (command_is_executable (gtk_entry_get_text (entry))) {
+			gnome_desktop_item_set_entry_type (ditem, GNOME_DESKTOP_ITEM_TYPE_APPLICATION);
+			gnome_desktop_item_set_string (ditem, "Exec", gtk_entry_get_text (entry));
+		} else {
+			uri = get_uri_from_command (gtk_entry_get_text (entry));
+			gnome_desktop_item_set_entry_type (ditem, GNOME_DESKTOP_ITEM_TYPE_LINK);
+			gnome_desktop_item_set_string (ditem, "Exec", uri);
+			g_free (uri);
+		}
+				
+		gnome_desktop_item_set_string (ditem, "Name", gtk_entry_get_text (entry));
+
+		gnome_desktop_item_set_boolean (ditem,
+						GNOME_DESKTOP_ITEM_TERMINAL,
+						terminal->active);
+
+		file = g_object_get_data (G_OBJECT (dialog), "pixmap_file");
+		gnome_desktop_item_set_string (ditem, "Icon", file);
+		
+		file = ditem_get_unique_uri ();
+		gnome_desktop_item_set_location (ditem, file);
+		
+		if (!gnome_desktop_item_save (ditem, NULL, FALSE, NULL)) {
+			gnome_desktop_item_unref (ditem);
+			return;
+		}
+		
+		gnome_desktop_item_unref (ditem);
+		
+		gtk_selection_data_set (selection_data,
+					selection_data->target, 8,
+					file, strlen (file));
+	}
+}
+
 
 static GtkWidget*
 create_simple_contents (void)
@@ -831,7 +1075,7 @@ create_simple_contents (void)
         GtkWidget *w;
 	const char *key;
 	gboolean enable_program_list;
-	static GtkTargetEntry drop_types[] = { { "text/uri-list", 0, 0 } };
+	static GtkTargetEntry dnd_types[] = { { "text/uri-list", 0, 0 } };
         
         vbox = gtk_vbox_new (FALSE, 0);
 
@@ -847,6 +1091,9 @@ create_simple_contents (void)
 			    FALSE, FALSE, 10);
         unset_pixmap (pixmap);
 	
+	g_signal_connect (run_dialog, "drag_data_get",
+			  G_CALLBACK (drag_data_get), NULL);
+	
 	vbox2 = gtk_vbox_new (FALSE, 0);
 	gtk_box_pack_start (GTK_BOX (hbox), vbox2,
 			    TRUE, TRUE, GNOME_PAD_SMALL);
@@ -883,7 +1130,7 @@ create_simple_contents (void)
 	gtk_drag_dest_unset (entry);
 	gtk_drag_dest_set (gentry,
 			   GTK_DEST_DEFAULT_ALL,
-			   drop_types, ELEMENTS (drop_types), GDK_ACTION_COPY);
+			   dnd_types, ELEMENTS (dnd_types), GDK_ACTION_COPY);
 
 	g_signal_connect (gentry, "drag_data_received",
 			  G_CALLBACK (drag_data_received),
@@ -1008,7 +1255,7 @@ find_icon_timeout (gpointer data)
 	GtkTreePath *path;
 	GtkWidget *pixmap;
 	GValue value = {0};
-	char *exec, *icon;
+	char *exec, *icon, *old_icon;
 	char *found_icon = NULL;
 
 	pixmap = g_object_get_data (G_OBJECT (run_dialog), "pixmap");
@@ -1077,9 +1324,16 @@ find_icon_timeout (gpointer data)
 		if (icon != NULL) {
 			pixbuf = gdk_pixbuf_new_from_file (icon, NULL);
 			g_free (icon);
-			if (pixbuf != NULL)
+			if (pixbuf != NULL) {
 				gtk_image_set_from_pixbuf (GTK_IMAGE (pixmap),
 							   pixbuf);
+							   
+				old_icon = g_object_get_data (G_OBJECT (run_dialog),
+							      "pixmap_file");
+				g_object_set_data (G_OBJECT (run_dialog),
+						   "pixmap_file", icon);
+				g_free (old_icon);
+			}
 		}
 		g_free (found_icon);
 	}
@@ -1231,13 +1485,14 @@ fill_list (GtkWidget *list)
 					 store, NULL);
 }
 
+
 #define DEFAULT_ICON "document-icons/i-executable.png"
 #define FALLBACK_DEFAULT_ICON "gnome-logo-icon-transparent.png"
 
 static void
 unset_pixmap (GtkWidget *gpixmap)
 {
-        gchar *file;
+        gchar *file, *old_file;
 
         file = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_PIXMAP, 
 					  DEFAULT_ICON, TRUE, NULL);
@@ -1254,7 +1509,9 @@ unset_pixmap (GtkWidget *gpixmap)
         
 	gtk_image_set_from_file (GTK_IMAGE (gpixmap), file);
 
-	g_free (file);
+	old_file = g_object_get_data (G_OBJECT (run_dialog), "pixmap_file");
+	g_object_set_data (G_OBJECT (run_dialog), "pixmap_file", file);
+	g_free (old_file);
 }
 
 static void


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