Updating branch refs/heads/master to dae9c330340b7fecf0986734956b794251128831 (commit) from 2d40555ffa59671c1bddb15696627023a7f92937 (commit)
commit dae9c330340b7fecf0986734956b794251128831 Author: Jannis Pohlmann <jan...@xfce.org> Date: Tue Jan 15 20:36:15 2013 +0100 Allow keyboard shortcuts for user customizable actions (bug #1941). Generate and store unique ids for the uca actions. Should work for all plugins as long they produce unique ids that are the same each startup. plugins/thunar-uca/thunar-uca-editor.c | 2 + plugins/thunar-uca/thunar-uca-model.c | 71 +++++++++++++++++- plugins/thunar-uca/thunar-uca-model.h | 2 + plugins/thunar-uca/thunar-uca-provider.c | 5 +- plugins/thunar-uca/uca.xml.in | 4 +- thunar/thunar-window-ui.xml | 2 + thunar/thunar-window.c | 120 ++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+), 4 deletions(-) diff --git a/plugins/thunar-uca/thunar-uca-editor.c b/plugins/thunar-uca/thunar-uca-editor.c index 31ddca2..ea32a46 100644 --- a/plugins/thunar-uca/thunar-uca-editor.c +++ b/plugins/thunar-uca/thunar-uca-editor.c @@ -1,6 +1,7 @@ /* $Id$ */ /*- * Copyright (c) 2005-2007 Benedikt Meurer <be...@xfce.org> + * Copyright (c) 2011 Jannis Pohlmann <jan...@xfce.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -809,6 +810,7 @@ thunar_uca_editor_save (ThunarUcaEditor *uca_editor, thunar_uca_model_update (uca_model, iter, gtk_entry_get_text (GTK_ENTRY (uca_editor->name_entry)), + NULL, /* don't touch the unique id */ gtk_entry_get_text (GTK_ENTRY (uca_editor->description_entry)), thunar_uca_editor_get_icon_name (uca_editor), gtk_entry_get_text (GTK_ENTRY (uca_editor->command_entry)), diff --git a/plugins/thunar-uca/thunar-uca-model.c b/plugins/thunar-uca/thunar-uca-model.c index 3f7a5b6..642a344 100644 --- a/plugins/thunar-uca/thunar-uca-model.c +++ b/plugins/thunar-uca/thunar-uca-model.c @@ -1,7 +1,7 @@ /* $Id$ */ /*- * Copyright (c) 2005-2006 Benedikt Meurer <be...@xfce.org> - * Copyright (c) 2009 Jannis Pohlmann <jan...@xfce.org> + * Copyright (c) 2009-2012 Jannis Pohlmann <jan...@xfce.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -75,6 +75,7 @@ typedef enum PARSER_ACTION, PARSER_ICON, PARSER_NAME, + PARSER_UNIQUE_ID, PARSER_COMMAND, PARSER_STARTUP_NOTIFY, PARSER_PATTERNS, @@ -162,6 +163,7 @@ struct _ThunarUcaModelItem { gchar *name; gchar *description; + gchar *unique_id; gchar *icon_name; GIcon *gicon; gchar *command; @@ -170,7 +172,7 @@ struct _ThunarUcaModelItem ThunarUcaTypes types; /* derived attributes */ - gboolean multiple_selection : 1; + guint multiple_selection : 1; }; typedef XFCE_GENERIC_STACK(ParserState) ParserStack; @@ -183,6 +185,7 @@ typedef struct GString *name; gboolean name_use; guint name_match; + GString *unique_id; GString *icon_name; GString *command; GString *patterns; @@ -190,6 +193,7 @@ typedef struct gboolean startup_notify; gboolean description_use; guint description_match; + gboolean unique_id_generated; ThunarUcaTypes types; } Parser; @@ -319,6 +323,9 @@ thunar_uca_model_get_column_type (GtkTreeModel *tree_model, case THUNAR_UCA_MODEL_COLUMN_NAME: return G_TYPE_STRING; + case THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID: + return G_TYPE_STRING; + case THUNAR_UCA_MODEL_COLUMN_DESCRIPTION: return G_TYPE_STRING; @@ -429,6 +436,10 @@ thunar_uca_model_get_value (GtkTreeModel *tree_model, g_value_set_static_string (value, item->icon_name); break; + case THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID: + g_value_set_static_string (value, item->unique_id); + break; + case THUNAR_UCA_MODEL_COLUMN_COMMAND: g_value_set_static_string (value, item->command); break; @@ -570,11 +581,13 @@ thunar_uca_model_load_from_file (ThunarUcaModel *uca_model, parser.model = uca_model; parser.locale = g_strdup (setlocale (LC_MESSAGES, NULL)); parser.name = g_string_new (NULL); + parser.unique_id = g_string_new (NULL); parser.icon_name = g_string_new (NULL); parser.command = g_string_new (NULL); parser.patterns = g_string_new (NULL); parser.description = g_string_new (NULL); parser.startup_notify = FALSE; + parser.unique_id_generated = FALSE; xfce_stack_push (parser.stack, PARSER_START); /* parse the file */ @@ -588,11 +601,17 @@ thunar_uca_model_load_from_file (ThunarUcaModel *uca_model, g_string_free (parser.patterns, TRUE); g_string_free (parser.command, TRUE); g_string_free (parser.icon_name, TRUE); + g_string_free (parser.unique_id, TRUE); g_string_free (parser.name, TRUE); g_free (parser.locale); xfce_stack_free (parser.stack); g_free (content); + /* save model to store new ids */ + if (succeed + && parser.unique_id_generated) + succeed = thunar_uca_model_save (uca_model, error); + return succeed; } @@ -606,6 +625,7 @@ thunar_uca_model_item_reset (ThunarUcaModelItem *item) g_free (item->description); g_free (item->command); g_free (item->name); + g_free (item->unique_id); g_free (item->icon_name); if (item->gicon != NULL) @@ -656,6 +676,7 @@ start_element_handler (GMarkupParseContext *context, parser->startup_notify = FALSE; g_string_truncate (parser->icon_name, 0); g_string_truncate (parser->name, 0); + g_string_truncate (parser->unique_id, 0); g_string_truncate (parser->command, 0); g_string_truncate (parser->patterns, 0); g_string_truncate (parser->description, 0); @@ -695,6 +716,11 @@ start_element_handler (GMarkupParseContext *context, xfce_stack_push (parser->stack, PARSER_NAME); } + else if (strcmp (element_name, "unique-id") == 0) + { + g_string_truncate (parser->unique_id, 0); + xfce_stack_push (parser->stack, PARSER_UNIQUE_ID); + } else if (strcmp (element_name, "icon") == 0) { g_string_truncate (parser->icon_name, 0); @@ -818,12 +844,17 @@ end_element_handler (GMarkupParseContext *context, thunar_uca_model_append (parser->model, &iter); thunar_uca_model_update (parser->model, &iter, parser->name->str, + parser->unique_id->str, parser->description->str, parser->icon_name->str, parser->command->str, parser->startup_notify, parser->patterns->str, parser->types); + + /* check if a new id should've been generated */ + if (exo_str_is_empty (parser->unique_id->str)) + parser->unique_id_generated = TRUE; } else goto unknown_element; @@ -834,6 +865,11 @@ end_element_handler (GMarkupParseContext *context, goto unknown_element; break; + case PARSER_UNIQUE_ID: + if (strcmp (element_name, "unique-id") != 0) + goto unknown_element; + break; + case PARSER_ICON: if (strcmp (element_name, "icon") != 0) goto unknown_element; @@ -919,6 +955,10 @@ text_handler (GMarkupParseContext *context, g_string_append_len (parser->name, text, text_len); break; + case PARSER_UNIQUE_ID: + g_string_append_len (parser->unique_id, text, text_len); + break; + case PARSER_ICON: g_string_append_len (parser->icon_name, text, text_len); break; @@ -943,6 +983,19 @@ text_handler (GMarkupParseContext *context, +static gchar * +thunar_uca_model_get_unique_id (void) +{ + static guint counter = 0; + + /* produce a "<timestamp>-<counter>" string */ + return g_strdup_printf ("%" G_GINT64_FORMAT "-%d", + g_get_real_time (), + ++counter); +} + + + /** * thunar_uca_model_get_default: * @@ -1048,6 +1101,7 @@ thunar_uca_model_match (ThunarUcaModel *uca_model, gint i, m, n; g_return_val_if_fail (THUNAR_UCA_IS_MODEL (uca_model), NULL); + g_return_val_if_fail (file_infos != NULL, NULL); /* special case to avoid overhead */ if (G_UNLIKELY (uca_model->items == NULL)) @@ -1243,6 +1297,7 @@ thunar_uca_model_remove (ThunarUcaModel *uca_model, * @uca_model : a #ThunarUcaModel. * @iter : the #GtkTreeIter of the item to update. * @name : the name of the item. + * @unique_id : a unique ID for the item. * @description : the description of the item. * @icon : the icon for the item. * @command : the command of the item. @@ -1255,6 +1310,7 @@ void thunar_uca_model_update (ThunarUcaModel *uca_model, GtkTreeIter *iter, const gchar *name, + const gchar *unique_id, const gchar *description, const gchar *icon, const gchar *command, @@ -1285,6 +1341,15 @@ thunar_uca_model_update (ThunarUcaModel *uca_model, item->types = types; item->startup_notify = startup_notify; + /* set the unique id once */ + if (item->unique_id == NULL) + { + if (G_LIKELY (unique_id != NULL && *unique_id != '\0')) + item->unique_id = g_strdup (unique_id); + else + item->unique_id = thunar_uca_model_get_unique_id (); + } + /* setup the patterns */ item->patterns = g_strsplit ((patterns != NULL && *patterns != '\0') ? patterns : "*", ";", -1); for (m = n = 0; item->patterns[m] != NULL; ++m) @@ -1368,11 +1433,13 @@ thunar_uca_model_save (ThunarUcaModel *uca_model, patterns = g_strjoinv (";", item->patterns); escaped = g_markup_printf_escaped ("\t<icon>%s</icon>\n" "\t<name>%s</name>\n" + "\t<unique-id>%s</unique-id>\n" "\t<command>%s</command>\n" "\t<description>%s</description>\n" "\t<patterns>%s</patterns>\n", (item->icon_name != NULL) ? item->icon_name : "", (item->name != NULL) ? item->name : "", + (item->unique_id != NULL) ? item->unique_id : "", (item->command != NULL) ? item->command : "", (item->description != NULL) ? item->description : "", patterns); diff --git a/plugins/thunar-uca/thunar-uca-model.h b/plugins/thunar-uca/thunar-uca-model.h index 46b3c37..fd128ff 100644 --- a/plugins/thunar-uca/thunar-uca-model.h +++ b/plugins/thunar-uca/thunar-uca-model.h @@ -41,6 +41,7 @@ typedef enum THUNAR_UCA_MODEL_COLUMN_DESCRIPTION, THUNAR_UCA_MODEL_COLUMN_GICON, THUNAR_UCA_MODEL_COLUMN_ICON_NAME, + THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, THUNAR_UCA_MODEL_COLUMN_COMMAND, THUNAR_UCA_MODEL_COLUMN_STARTUP_NOTIFY, THUNAR_UCA_MODEL_COLUMN_PATTERNS, @@ -89,6 +90,7 @@ void thunar_uca_model_remove (ThunarUcaModel *uca_mod void thunar_uca_model_update (ThunarUcaModel *uca_model, GtkTreeIter *iter, const gchar *name, + const gchar *unique_id, const gchar *description, const gchar *icon, const gchar *command, diff --git a/plugins/thunar-uca/thunar-uca-provider.c b/plugins/thunar-uca/thunar-uca-provider.c index 8072c1f..b24952e 100644 --- a/plugins/thunar-uca/thunar-uca-provider.c +++ b/plugins/thunar-uca/thunar-uca-provider.c @@ -199,6 +199,7 @@ thunar_uca_provider_get_file_actions (ThunarxMenuProvider *menu_provider, GList *lp; gchar *tooltip; gchar *label; + gchar *unique_id; gchar *name; GIcon *gicon; @@ -213,10 +214,11 @@ thunar_uca_provider_get_file_actions (ThunarxMenuProvider *menu_provider, THUNAR_UCA_MODEL_COLUMN_NAME, &label, THUNAR_UCA_MODEL_COLUMN_GICON, &gicon, THUNAR_UCA_MODEL_COLUMN_DESCRIPTION, &tooltip, + THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id, -1); /* generate a unique action name */ - name = g_strdup_printf ("ThunarUca::action-%d", ++uca_provider->last_action_id); + name = g_strdup_printf ("uca-action-%s", unique_id); /* create the new action with the given parameters */ action = gtk_action_new (name, label, tooltip, NULL); @@ -246,6 +248,7 @@ thunar_uca_provider_get_file_actions (ThunarxMenuProvider *menu_provider, g_free (tooltip); g_free (label); g_free (name); + g_free (unique_id); if (gicon != NULL) g_object_unref (G_OBJECT (gicon)); diff --git a/plugins/thunar-uca/uca.xml.in b/plugins/thunar-uca/uca.xml.in index c72a40c..65efa38 100644 --- a/plugins/thunar-uca/uca.xml.in +++ b/plugins/thunar-uca/uca.xml.in @@ -2,7 +2,7 @@ <!DOCTYPE actions [ <!ELEMENT actions (action)+> - <!ELEMENT action (icon|patterns|name|command|description|directories|audio-files|image-files|other-files|text-files|video-files)*> + <!ELEMENT action (icon|patterns|name|unique-id|command|description|directories|audio-files|image-files|other-files|text-files|video-files)*> <!ELEMENT icon (#PCDATA)> <!ELEMENT command (#PCDATA)> @@ -11,6 +11,8 @@ <!ELEMENT name (#PCDATA)> <!ATTLIST name xml:lang CDATA #IMPLIED> + <!ELEMENT unique-id (#PCDATA)> + <!ELEMENT description (#PCDATA)> <!ATTLIST description xml:lang CDATA #IMPLIED> diff --git a/thunar/thunar-window-ui.xml b/thunar/thunar-window-ui.xml index 1e026c7..df6b505 100644 --- a/thunar/thunar-window-ui.xml +++ b/thunar/thunar-window-ui.xml @@ -24,6 +24,8 @@ <placeholder name="placeholder-sendto-actions" /> </menu> <separator /> + <placeholder name="placeholder-custom-actions" /> + <separator /> <placeholder name="placeholder-file-properties" /> <separator /> <menuitem action="empty-trash" /> diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c index 078df53..7f482e1 100644 --- a/thunar/thunar-window.c +++ b/thunar/thunar-window.c @@ -227,6 +227,9 @@ static void thunar_window_menu_item_selected (GtkWidget ThunarWindow *window); static void thunar_window_menu_item_deselected (GtkWidget *menu_item, ThunarWindow *window); +static void thunar_window_update_custom_actions (ThunarView *view, + GParamSpec *pspec, + ThunarWindow *window); static void thunar_window_notify_loading (ThunarView *view, GParamSpec *pspec, ThunarWindow *window); @@ -297,6 +300,10 @@ struct _ThunarWindow GClosure *menu_item_selected_closure; GClosure *menu_item_deselected_closure; + /* custom menu actions for the file menu */ + GtkActionGroup *custom_actions; + guint custom_merge_id; + GtkWidget *table; GtkWidget *menubar; GtkWidget *spinner; @@ -984,6 +991,10 @@ thunar_window_finalize (GObject *object) g_signal_handlers_disconnect_matched (window->ui_manager, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window); g_object_unref (window->ui_manager); + /* release the custom actions */ + if (window->custom_actions != NULL) + g_object_unref (window->custom_actions); + g_object_unref (window->action_group); g_object_unref (window->icon_factory); g_object_unref (window->launcher); @@ -1502,6 +1513,7 @@ thunar_window_notebook_page_added (GtkWidget *notebook, /* connect signals */ g_signal_connect (G_OBJECT (page), "notify::loading", G_CALLBACK (thunar_window_notify_loading), window); + g_signal_connect (G_OBJECT (page), "notify::selected-files", G_CALLBACK (thunar_window_update_custom_actions), window); g_signal_connect_swapped (G_OBJECT (page), "start-open-location", G_CALLBACK (thunar_window_start_open_location), window); g_signal_connect_swapped (G_OBJECT (page), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window); g_signal_connect_swapped (G_OBJECT (page), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window); @@ -3308,6 +3320,114 @@ thunar_window_menu_item_deselected (GtkWidget *menu_item, static void +thunar_window_update_custom_actions (ThunarView *view, + GParamSpec *pspec, + ThunarWindow *window) +{ + ThunarFile *folder; + GList *selected_files; + GList *actions = NULL; + GList *lp; + GList *providers; + GList *tmp; + + _thunar_return_if_fail (THUNAR_IS_VIEW (view)); + _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); + + /* leave if the signal is emitted from a non-active tab */ + if (!gtk_widget_get_realized (GTK_WIDGET (window)) + || window->view != GTK_WIDGET (view)) + return; + + /* load the menu provides from the provider factory */ + providers = thunarx_provider_factory_list_providers (window->provider_factory, + THUNARX_TYPE_MENU_PROVIDER); + if (G_LIKELY (providers != NULL)) + { + /* grab a reference to the current directory of the window */ + folder = thunar_window_get_current_directory (window); + + /* get a list of selected files */ + selected_files = thunar_component_get_selected_files (THUNAR_COMPONENT (view)); + + /* load the actions offered by the menu providers */ + for (lp = providers; lp != NULL; lp = lp->next) + { + if (G_LIKELY (selected_files != NULL)) + { + tmp = thunarx_menu_provider_get_file_actions (lp->data, + GTK_WIDGET (window), + selected_files); + } + else if (G_LIKELY (folder != NULL)) + { + tmp = thunarx_menu_provider_get_folder_actions (lp->data, + GTK_WIDGET (window), + THUNARX_FILE_INFO (folder)); + } + else + { + tmp = NULL; + } + + actions = g_list_concat (actions, tmp); + g_object_unref (G_OBJECT (lp->data)); + } + g_list_free (providers); + } + + /* remove previously inserted menu actions from the UI manager */ + if (window->custom_merge_id != 0) + { + gtk_ui_manager_remove_ui (window->ui_manager, window->custom_merge_id); + gtk_ui_manager_ensure_update (window->ui_manager); + window->custom_merge_id = 0; + } + + /* drop any previous custom action group */ + if (window->custom_actions != NULL) + { + gtk_ui_manager_remove_action_group (window->ui_manager, window->custom_actions); + g_object_unref (window->custom_actions); + window->custom_actions = NULL; + } + + /* add the actions specified by the menu providers */ + if (G_LIKELY (actions != NULL)) + { + /* allocate the action group and the merge id for the custom actions */ + window->custom_actions = gtk_action_group_new ("ThunarActions"); + window->custom_merge_id = gtk_ui_manager_new_merge_id (window->ui_manager); + gtk_ui_manager_insert_action_group (window->ui_manager, window->custom_actions, -1); + + /* add the actions to the UI manager */ + for (lp = actions; lp != NULL; lp = lp->next) + { + /* add the action to the action group */ + gtk_action_group_add_action_with_accel (window->custom_actions, + GTK_ACTION (lp->data), + NULL); + + /* add to the file context menu */ + gtk_ui_manager_add_ui (window->ui_manager, + window->custom_merge_id, + "/main-menu/file-menu/placeholder-custom-actions", + gtk_action_get_name (GTK_ACTION (lp->data)), + gtk_action_get_name (GTK_ACTION (lp->data)), + GTK_UI_MANAGER_MENUITEM, FALSE); + + /* release the reference on the action */ + g_object_unref (G_OBJECT (lp->data)); + } + + /* cleanup */ + g_list_free (actions); + } +} + + + +static void thunar_window_notify_loading (ThunarView *view, GParamSpec *pspec, ThunarWindow *window) _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org https://mail.xfce.org/mailman/listinfo/xfce4-commits