Index: panel-run-dialog.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/gnome-panel/panel-run-dialog.c,v
retrieving revision 1.23
diff -u -r1.23 panel-run-dialog.c
--- panel-run-dialog.c	12 Feb 2004 09:40:00 -0000	1.23
+++ panel-run-dialog.c	5 Mar 2004 00:45:22 -0000
@@ -75,7 +75,8 @@
 	
 	GtkListStore     *program_list_store;
 
-	GList            *executables;
+	GList            *files_in_path;	/* Initially stores all files in the user's path. */
+	GList            *executables;		/* Pointer into files_in_path were valid executables begin. */
 	GCompletion      *completion;
 	
 	GSList           *add_icon_paths;
@@ -133,11 +134,13 @@
 					    dialog->content_notify_id);
 	dialog->content_notify_id = 0;
 
-	for (l = dialog->executables; l; l = l->next)
+	for (l = dialog->files_in_path; l; l = l->next)
 		g_free (l->data);
-	g_list_free (dialog->executables);
+	g_list_free (dialog->files_in_path);
+	dialog->files_in_path = NULL;
 	dialog->executables = NULL;
 
+
 	if (dialog->completion)
 		g_completion_free (dialog->completion);
 	dialog->completion = NULL;
@@ -1075,7 +1078,6 @@
 	struct dirent *dent;
 	DIR           *dir;
 	char          *file;
-	struct stat    file_stat;
 
 	dir = opendir (dirname);
 
@@ -1085,10 +1087,8 @@
 	while ((dent = readdir (dir))) {
 		file = g_build_filename (dirname, dent->d_name, NULL);
 
-		if (!access (file, X_OK) &&
-		    !stat (file, &file_stat) && !S_ISDIR (file_stat.st_mode))
-			dialog->executables = g_list_prepend (dialog->executables,
-							      g_strdup (dent->d_name));
+		dialog->files_in_path = g_list_prepend (dialog->files_in_path,
+							g_strdup (file));
 		
 		g_free (file);
 	}
@@ -1112,18 +1112,62 @@
 
 	for (i = 0; pathv [i]; i++)
 		panel_run_dialog_fill_executables_from (dialog, pathv[i]);
-	
+
 	g_strfreev (pathv);
 }
 
+static gboolean
+panel_run_dialog_ensure_completion_idle_handler (PanelRunDialog *dialog)
+{
+	int	i;
+	char *file = NULL;
+	GList *l = NULL;
+	struct stat file_stat;
+
+	/* dialog->executables is our pointer into the list of files in the path were valid executables
+	 * start. If this is NULL, then start from the end of the files_in_path list.
+	 * Else, just start from the file in path that's before the first valid executable (executables->prev).
+	 */
+	l = (dialog->executables) ? dialog->executables->prev : g_list_last (dialog->files_in_path);
+	
+	/* Work backwords in 100 file batches to prevent blocking the UI.
+	 * If it's a valid executable, then change the list link's data to be the basename
+	 * and change the executables pointer to point to the new valid entry.
+	 * Else, delete the link from the list.
+	 */
+	for (i = 0, l; i < 100 && l; i++, l = l->prev)
+	{
+		file = l->data;
+		if (!access (file, X_OK) &&
+		    !stat (file, &file_stat) && !S_ISDIR (file_stat.st_mode))
+		{
+			l->data = g_path_get_basename (file);
+			dialog->executables = l;
+		}
+		else
+			dialog->files_in_path = g_list_delete_link (dialog->files_in_path, l);
+	}
+	
+	/* Give GCompletion what we've got so far. */
+	if (dialog->executables)
+		g_completion_add_items (dialog->completion, dialog->executables);
+
+	/* We're at the end when our valid executables pointer is at the same spot as the files_in_path pointer. */
+	if (dialog->executables == dialog->files_in_path)
+		return FALSE;
+	
+	/* More batches, repeat next idle iteration. */
+	return TRUE;
+}
+
 static void
 panel_run_dialog_ensure_completion (PanelRunDialog *dialog)
 {
 	if (!dialog->completion) {
 		dialog->completion = g_completion_new (NULL);
 		panel_run_dialog_fill_executables (dialog);
-
-		g_completion_add_items (dialog->completion, dialog->executables);
+		
+		g_idle_add ((GSourceFunc) panel_run_dialog_ensure_completion_idle_handler, dialog);
 	}
 }
 
@@ -1454,7 +1498,7 @@
 
 	gtk_widget_grab_focus (dialog->gtk_entry);
 	gtk_widget_show (dialog->run_dialog);
-	
+
 	return dialog;
 }
 
