[Xfce4-commits] <thunar:master> Allow keyboard shortcuts for user customizable actions (bug #1941).
Nick Schermer
noreply at xfce.org
Tue Jan 15 20:40:01 CET 2013
Updating branch refs/heads/master
to dae9c330340b7fecf0986734956b794251128831 (commit)
from 2d40555ffa59671c1bddb15696627023a7f92937 (commit)
commit dae9c330340b7fecf0986734956b794251128831
Author: Jannis Pohlmann <jannis at 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 <benny at xfce.org>
+ * Copyright (c) 2011 Jannis Pohlmann <jannis at 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 <benny at xfce.org>
- * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2009-2012 Jannis Pohlmann <jannis at 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)
More information about the Xfce4-commits
mailing list