Re: [Nautilus-list] [patch] - hierarchical script menus - done?
- From: David Watson <dwatson cs ucr edu>
- To: <darin bentspoon com>
- Cc: <nautilus-list lists eazel com>, <dwatson cs ucr edu>
- Subject: Re: [Nautilus-list] [patch] - hierarchical script menus - done?
- Date: Sun, 3 Jun 2001 01:18:07 -0700 (PDT)
I fixed a bug in add_directory_to_scripts_directory_list () where I was
indexing into a string of unknown size.
Hopefully this is the last time I need to send this patch, tonight
anyway... :)
--
The theory of groups is a branch of Mathematics in which one does
something to something and then compares the result with the result
obtained from doing the same thing to something else, or something else to
the same thing.
J. R. Newman
--- ./nautilus-1.0.3-orig/src/file-manager/fm-directory-view.c Sat May 26 11:02:20 2001
+++ ./nautilus-1.0.3/src/file-manager/fm-directory-view.c Sun Jun 3 01:10:49 2001
@@ -22,8 +22,9 @@
*
* Authors: Ettore Perazzoli,
* John Sullivan <sullivan eazel com>,
- * Darin Adler <darin eazel com>
- * Pavel Cisler <pavel eazel com>
+ * Darin Adler <darin eazel com>,
+ * Pavel Cisler <pavel eazel com>,
+ * David Emory Watson <dwatson cs ucr edu>
*/
#include <config.h>
@@ -135,6 +136,8 @@
#define FM_DIRECTORY_VIEW_POPUP_PATH_OPEN_WITH "/popups/selection/Open Placeholder/Open With"
#define FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS "/popups/selection/Open Placeholder/Scripts"
+#define MAX_MENU_LEVELS 5
+
enum {
ADD_FILE,
BEGIN_ADDING_FILES,
@@ -166,9 +169,16 @@ struct FMDirectoryViewDetails
NautilusFile *directory_as_file;
BonoboUIComponent *ui;
- NautilusDirectory *scripts_directory;
- guint scripts_added_handler_id;
- guint scripts_changed_handler_id;
+ /* The first link in this list is reserved for the top level scripts
+ * directory. This means that new links are always appended to the
+ * list. In addition, lower level script directories must always occur
+ * after higher level ones so if you remove a directory, you must remove
+ * its subdirectories as well. This is done to preserve the ordering of
+ * the callbacks when we rebuild the script menus.
+ */
+ GList *scripts_directory_list;
+ GList *scripts_uri_list;
+ guint scripts_directory_length;
guint display_selection_idle_id;
guint update_menus_timeout_id;
@@ -287,7 +297,9 @@ static void schedule_timeout_d
static void unschedule_timeout_display_of_pending_files (FMDirectoryView *view);
static void unschedule_display_of_pending_files (FMDirectoryView *view);
static void disconnect_model_handlers (FMDirectoryView *view);
-static void disconnect_script_handlers (FMDirectoryView *view);
+static void disconnect_scripts_directory_list (FMDirectoryView *view);
+static void disconnect_scripts_directory (FMDirectoryView *view,
+ NautilusDirectory *directory);
static void filtering_changed_callback (gpointer callback_data);
static void metadata_for_directory_as_file_ready_callback (NautilusFile *file,
gpointer callback_data);
@@ -1138,46 +1150,45 @@ get_scripts_directory (void)
static void
scripts_added_or_changed_callback (NautilusDirectory *directory,
- GList *files,
- gpointer callback_data)
+ GList *files,
+ gpointer callback_data)
{
FMDirectoryView *view;
view = FM_DIRECTORY_VIEW (callback_data);
- g_assert (directory == view->details->scripts_directory);
+ g_assert (g_list_find (view->details->scripts_directory_list, directory) != NULL);
view->details->scripts_invalid = TRUE;
schedule_update_menus (view);
}
static void
-connect_script_handlers (FMDirectoryView *view)
+connect_script_handlers (FMDirectoryView *view,
+ NautilusDirectory *directory)
{
- if (view->details->scripts_directory == NULL) {
- return;
- }
+ g_assert(directory != NULL);
- nautilus_directory_file_monitor_add (view->details->scripts_directory,
- &view->details->scripts_directory,
+ nautilus_directory_file_monitor_add (directory, &view->details->scripts_directory_list,
FALSE, FALSE, NULL);
- view->details->scripts_added_handler_id = gtk_signal_connect
- (GTK_OBJECT (view->details->scripts_directory),
- "files_added",
- scripts_added_or_changed_callback,
- view);
+ gtk_signal_connect (GTK_OBJECT (directory),
+ "files_added",
+ scripts_added_or_changed_callback,
+ view);
- view->details->scripts_changed_handler_id = gtk_signal_connect
- (GTK_OBJECT (view->details->scripts_directory),
- "files_changed",
- scripts_added_or_changed_callback,
- view);
+ gtk_signal_connect (GTK_OBJECT (directory),
+ "files_changed",
+ scripts_added_or_changed_callback,
+ view);
}
static void
fm_directory_view_initialize (FMDirectoryView *view)
{
+ NautilusDirectory *scripts_directory;
+ char *scripts_directory_uri;
+
view->details = g_new0 (FMDirectoryViewDetails, 1);
/* We need to have our own X window so that cut, copy, and
@@ -1196,8 +1207,19 @@ fm_directory_view_initialize (FMDirector
view->details->nautilus_view = nautilus_view_new (GTK_WIDGET (view));
- view->details->scripts_directory = get_scripts_directory ();
- connect_script_handlers (view);
+ scripts_directory = get_scripts_directory ();
+
+ if (scripts_directory != NULL) {
+ view->details->scripts_directory_list = g_list_append (view->details->scripts_directory_list,
+ scripts_directory);
+
+ scripts_directory_uri = nautilus_directory_get_uri (scripts_directory);
+ view->details->scripts_uri_list = g_list_append (view->details->scripts_uri_list,
+ scripts_directory_uri);
+ view->details->scripts_directory_length = strlen (scripts_directory_uri);
+
+ connect_script_handlers (view, scripts_directory);
+ }
view->details->zoomable = bonobo_zoomable_new ();
bonobo_zoomable_set_parameters_full (view->details->zoomable,
@@ -1297,6 +1319,7 @@ static void
fm_directory_view_destroy (GtkObject *object)
{
FMDirectoryView *view;
+ GList *node1, *node2;
view = FM_DIRECTORY_VIEW (object);
@@ -1314,8 +1337,17 @@ fm_directory_view_destroy (GtkObject *ob
fm_directory_view_stop (view);
fm_directory_view_clear (view);
- disconnect_script_handlers (view);
- nautilus_directory_unref (view->details->scripts_directory);
+ disconnect_scripts_directory_list (view);
+
+ for (node1 = view->details->scripts_directory_list, node2 = view->details->scripts_uri_list;
+ node1 != NULL;
+ node1 = node1->next, node2 = node2->next) {
+ nautilus_directory_unref (node1->data);
+ g_free (node2->data);
+ }
+
+ g_list_free (view->details->scripts_directory_list);
+ g_list_free (view->details->scripts_uri_list);
disconnect_model_handlers (view);
nautilus_directory_unref (view->details->model);
@@ -3176,7 +3208,24 @@ add_numbered_menu_item (BonoboUIComponen
(ui, parent_path, index);
bonobo_ui_component_add_verb_full (ui, verb_name, callback, callback_data, destroy_notify);
g_free (verb_name);
-}
+}
+
+/* FIXME: Allow the icon to be set. */
+static void
+add_menu (BonoboUIComponent *ui,
+ const char *parent_path,
+ const char *label)
+{
+ char *escaped_label;
+
+ escaped_label = eel_str_double_underscores (label);
+
+ nautilus_bonobo_add_submenu (ui,
+ parent_path,
+ escaped_label);
+
+ g_free (escaped_label);
+}
static void
add_application_to_bonobo_menu (FMDirectoryView *directory_view,
@@ -3521,12 +3570,14 @@ run_script_callback (BonoboUIComponent *
chdir (old_working_dir);
g_free (old_working_dir);
g_free (quoted_path);
-}
+}
static void
-add_script_to_menus (FMDirectoryView *directory_view,
- NautilusFile *file,
- int index)
+add_script_to_script_menus (FMDirectoryView *directory_view,
+ NautilusFile *file,
+ int index,
+ const char *menu_path,
+ const char *popup_path)
{
ScriptLaunchParameters *launch_parameters;
char *tip;
@@ -3535,13 +3586,13 @@ add_script_to_menus (FMDirectoryView *di
name = nautilus_file_get_name (file);
tip = g_strdup_printf (_("Run \"%s\" on any selected items"), name);
-
+
launch_parameters = script_launch_parameters_new (file, directory_view);
pixbuf = nautilus_icon_factory_get_pixbuf_for_file
(file, NULL, NAUTILUS_ICON_SIZE_FOR_MENUS, TRUE);
- add_numbered_menu_item (directory_view->details->ui,
- FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER,
+ add_numbered_menu_item (directory_view->details->ui,
+ menu_path,
name,
tip,
index,
@@ -3553,8 +3604,8 @@ add_script_to_menus (FMDirectoryView *di
/* Use same launch parameters and no DestroyNotify for popup item, which has same
* lifetime as the item in the File menu in the menu bar.
*/
- add_numbered_menu_item (directory_view->details->ui,
- FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER,
+ add_numbered_menu_item (directory_view->details->ui,
+ popup_path,
name,
tip,
index,
@@ -3569,17 +3620,158 @@ add_script_to_menus (FMDirectoryView *di
}
static void
+add_menu_to_script_menus (FMDirectoryView *directory_view,
+ NautilusFile *file,
+ const char *menu_path,
+ const char *popup_path)
+{
+ ScriptLaunchParameters *launch_parameters;
+ char *tip;
+ char *name;
+ GdkPixbuf *pixbuf;
+
+ name = nautilus_file_get_name (file);
+ tip = g_strdup_printf (_("Run \"%s\" on any selected items"), name);
+
+ launch_parameters = script_launch_parameters_new (file, directory_view);
+ pixbuf = nautilus_icon_factory_get_pixbuf_for_file
+ (file, NULL, NAUTILUS_ICON_SIZE_FOR_MENUS, TRUE);
+
+ add_menu (directory_view->details->ui,
+ menu_path,
+ name);
+
+ add_menu (directory_view->details->ui,
+ popup_path,
+ name);
+
+ gdk_pixbuf_unref (pixbuf);
+ g_free (name);
+ g_free (tip);
+}
+
+static gboolean
+add_directory_to_scripts_directory_list (FMDirectoryView *view, NautilusFile *file)
+{
+ char *uri;
+ NautilusDirectory *directory;
+ int num_levels;
+ int i;
+
+ uri = nautilus_file_get_uri (file);
+
+ if (strlen (uri) < view->details->scripts_directory_length) {
+ g_free (uri);
+ return FALSE;
+ }
+
+ num_levels = 0;
+ for (i = view->details->scripts_directory_length; uri[i] != '\0'; i++) {
+ if (uri[i] == '/') {
+ num_levels++;
+ }
+ }
+
+ if (num_levels > MAX_MENU_LEVELS) {
+ g_free (uri);
+ return FALSE;
+ }
+
+ directory = nautilus_directory_get (uri);
+
+ if (g_list_find (view->details->scripts_directory_list, directory) == NULL) {
+ connect_script_handlers (view, directory);
+
+ view->details->scripts_directory_list = g_list_append (view->details->scripts_directory_list,
+ directory);
+ view->details->scripts_uri_list = g_list_append (view->details->scripts_uri_list,
+ uri);
+ } else {
+ nautilus_directory_unref (directory);
+ g_free (uri);
+ }
+
+ return TRUE;
+}
+
+/**
+ * clean_scripts_directory_list
+ *
+ * Verify that a given directory has not changed. If it has, remove references to
+ * it from both scripts_directory_list and scripts_uri_list.
+ * @view: FMDirectoryView of interest.
+ * @directory: The directory that we are verifying.
+ *
+ * Return value: True if the directory was removed, false otherwise.
+ *
+ **/
+static gboolean
+clean_scripts_directory_list (FMDirectoryView *view, NautilusDirectory *directory)
+{
+ GList *node1, *node2;
+ char *uri;
+
+ uri = nautilus_directory_get_uri (directory);
+
+ for (node1 = view->details->scripts_directory_list, node2 = view->details->scripts_uri_list;
+ node1 != NULL;
+ node1 = node1->next, node2 = node2->next) {
+ if (directory == node1->data) {
+ if (strcmp (uri, node2->data) == 0) {
+ g_free (uri);
+ return FALSE;
+ } else {
+ view->details->scripts_directory_list = g_list_remove_link (view->details->scripts_directory_list, node1);
+ view->details->scripts_uri_list = g_list_remove_link (view->details->scripts_uri_list, node2);
+
+ disconnect_scripts_directory (view, node1->data);
+ nautilus_directory_unref (node1->data);
+ g_free (node2->data);
+
+ g_list_free (node1);
+ g_list_free (node2);
+
+ g_free (uri);
+ return TRUE;
+ }
+ }
+ }
+
+ /* This should never happen. */
+ g_free (uri);
+ return TRUE;
+}
+
+static void
reset_scripts_menu (FMDirectoryView *view, GList *all_files)
{
GList *node;
NautilusFile *file;
int index;
gboolean any_scripts;
-
- nautilus_bonobo_remove_menu_items_and_commands
- (view->details->ui, FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER);
- nautilus_bonobo_remove_menu_items_and_commands
- (view->details->ui, FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER);
+ char *parent_path;
+ char *menu_path, *popup_path;
+
+ if (all_files == NULL) {
+ view->details->scripts_invalid = FALSE;
+ return;
+ }
+
+ parent_path = nautilus_file_get_parent_uri (all_files->data);
+
+ menu_path = g_strdup_printf ("%s%s", FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER,
+ parent_path + view->details->scripts_directory_length);
+ popup_path = g_strdup_printf ("%s%s", FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER,
+ parent_path + view->details->scripts_directory_length);
+
+ /* We rebuild the entire scripts menu each time so we only need to remove the
+ top level menu since it contains all other menus and is rebuilt first. */
+ if (strcmp(parent_path, view->details->scripts_uri_list->data) == 0) {
+ nautilus_bonobo_remove_menu_items_and_commands (view->details->ui, menu_path);
+ nautilus_bonobo_remove_menu_items_and_commands (view->details->ui, popup_path);
+ }
+
+ g_free (parent_path);
all_files = nautilus_file_list_sort_by_name (all_files);
@@ -3588,11 +3780,19 @@ reset_scripts_menu (FMDirectoryView *vie
file = node->data;
if (file_is_launchable (file)) {
- add_script_to_menus (view, file, index);
+ add_script_to_script_menus (view, file, index, menu_path, popup_path);
any_scripts = TRUE;
+ } else if (nautilus_file_is_directory (file)) {
+ if (add_directory_to_scripts_directory_list (view, file)) {
+ add_menu_to_script_menus (view, file, menu_path, popup_path);
+ any_scripts = TRUE;
+ }
}
}
+ g_free (popup_path);
+ g_free (menu_path);
+
nautilus_bonobo_set_hidden (view->details->ui,
FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_SEPARATOR,
!any_scripts);
@@ -3613,7 +3813,7 @@ reset_scripts_menu_callback (NautilusDir
view = callback_data;
g_assert (FM_IS_DIRECTORY_VIEW (view));
- g_assert (view->details->scripts_directory == directory);
+ g_assert (g_list_find (view->details->scripts_directory_list, directory) != NULL);
reset_scripts_menu (view, files);
}
@@ -3623,23 +3823,40 @@ call_when_ready_on_scripts_directory (FM
NautilusDirectoryCallback scripts_directory_callback)
{
GList *attributes;
+ GList *node, *next_node;
- if (view->details->scripts_directory == NULL) {
+ if (view->details->scripts_directory_list == NULL) {
return;
}
- nautilus_directory_cancel_callback (view->details->scripts_directory,
- scripts_directory_callback,
- view);
+ for (node = view->details->scripts_directory_list; node != NULL; node = node->next) {
+ nautilus_directory_cancel_callback (node->data,
+ scripts_directory_callback,
+ view);
+ }
/* Later we may want to add more attributes here to get icon, etc. */
attributes = nautilus_icon_factory_get_required_file_attributes ();
attributes = g_list_prepend (attributes, NAUTILUS_FILE_ATTRIBUTE_CAPABILITIES);
attributes = g_list_prepend (attributes, NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT);
- nautilus_directory_call_when_ready (view->details->scripts_directory,
- attributes,
- scripts_directory_callback,
- view);
+
+ node = view->details->scripts_directory_list;
+ while (node != NULL) {
+
+ /* It is important that we remember the next link in the list because
+ clean_scripts_directory_list() may remove links from underneath us. */
+ next_node = node->next;
+
+ if (!clean_scripts_directory_list (view, node->data)) {
+ nautilus_directory_call_when_ready (node->data,
+ attributes,
+ scripts_directory_callback,
+ view);
+ }
+
+ node = next_node;
+ }
+
g_list_free (attributes);
}
@@ -3659,8 +3876,8 @@ open_scripts_folder_callback (BonoboUICo
view = FM_DIRECTORY_VIEW (callback_data);
- if (view->details->scripts_directory != NULL) {
- uri = nautilus_directory_get_uri (view->details->scripts_directory);
+ if (view->details->scripts_directory_list != NULL) {
+ uri = nautilus_directory_get_uri (view->details->scripts_directory_list->data);
open_location (view, uri, RESPECT_PREFERENCE);
g_free (uri);
@@ -4892,9 +5109,17 @@ disconnect_directory_handler (FMDirector
}
static void
-disconnect_scripts_directory_handler (FMDirectoryView *view, int *id)
+disconnect_scripts_directory (FMDirectoryView *view, NautilusDirectory *directory)
{
- disconnect_handler (GTK_OBJECT (view->details->scripts_directory), id);
+ gtk_signal_disconnect_by_func (GTK_OBJECT (directory),
+ scripts_added_or_changed_callback,
+ view);
+
+ nautilus_directory_file_monitor_remove (directory, &view->details->scripts_directory_list);
+
+ nautilus_directory_cancel_callback (directory,
+ reset_scripts_menu_callback,
+ view);
}
static void
@@ -4927,21 +5152,13 @@ disconnect_model_handlers (FMDirectoryVi
}
static void
-disconnect_script_handlers (FMDirectoryView *view)
+disconnect_scripts_directory_list (FMDirectoryView *view)
{
- if (view->details->scripts_directory == NULL) {
- return;
- }
-
- disconnect_scripts_directory_handler (view, &view->details->scripts_added_handler_id);
- disconnect_scripts_directory_handler (view, &view->details->scripts_changed_handler_id);
-
- nautilus_directory_file_monitor_remove (view->details->scripts_directory,
- &view->details->scripts_directory);
+ GList *node;
- nautilus_directory_cancel_callback (view->details->scripts_directory,
- reset_scripts_menu_callback,
- view);
+ for (node = view->details->scripts_directory_list; node != NULL; node = node->next) {
+ disconnect_scripts_directory (view, node->data);
+ }
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]