summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorAndre Miranda <andreldm@xfce.org>2018-02-12 18:37:55 -0300
committerAndre Miranda <andreldm@xfce.org>2018-03-22 23:16:51 -0300
commitab5daf33fa4845ecf2fa795a75a10fad1642d047 (patch)
tree56d00dc6a44e7cb3574fdfd67c324b239271f630 /plugins
parent3baffcbac309f16a9da43027b0c404a6241a9ae6 (diff)
downloadthunar-ab5daf33fa4845ecf2fa795a75a10fad1642d047.tar.gz
Make it possible to assign accelerators to custom actions
Diffstat (limited to 'plugins')
-rw-r--r--plugins/thunar-uca/Makefile.am4
-rw-r--r--plugins/thunar-uca/thunar-uca-editor.c192
-rw-r--r--plugins/thunar-uca/thunar-uca-editor.ui79
-rw-r--r--plugins/thunar-uca/thunar-uca-model.c16
-rw-r--r--plugins/thunar-uca/thunar-uca-model.h4
-rw-r--r--plugins/thunar-uca/thunar-uca-provider.c4
6 files changed, 275 insertions, 24 deletions
diff --git a/plugins/thunar-uca/Makefile.am b/plugins/thunar-uca/Makefile.am
index c7e2a1a5..c1944691 100644
--- a/plugins/thunar-uca/Makefile.am
+++ b/plugins/thunar-uca/Makefile.am
@@ -33,6 +33,7 @@ thunar_uca_la_CFLAGS = \
$(EXO_CFLAGS) \
$(LIBXFCE4UTIL_CFLAGS) \
$(LIBXFCE4UI_CFLAGS) \
+ $(LIBXFCE4KBD_PRIVATE_CFLAGS) \
$(PLATFORM_CFLAGS)
thunar_uca_la_LDFLAGS = \
@@ -47,7 +48,8 @@ thunar_uca_la_LIBADD = \
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la \
$(EXO_LIBS) \
$(LIBXFCE4UTIL_LIBS) \
- $(LIBXFCE4UI_LIBS)
+ $(LIBXFCE4UI_LIBS) \
+ $(LIBXFCE4KBD_PRIVATE_LIBS)
thunar_uca_la_DEPENDENCIES = \
$(top_builddir)/thunarx/libthunarx-$(THUNARX_VERSION_API).la
diff --git a/plugins/thunar-uca/thunar-uca-editor.c b/plugins/thunar-uca/thunar-uca-editor.c
index 13717c0b..42e93498 100644
--- a/plugins/thunar-uca/thunar-uca-editor.c
+++ b/plugins/thunar-uca/thunar-uca-editor.c
@@ -31,20 +31,24 @@
#endif
#include <exo/exo.h>
+#include <libxfce4kbd-private/xfce-shortcut-dialog.h>
+#include <libxfce4ui/libxfce4ui.h>
#include <thunar-uca/thunar-uca-editor.h>
-static const gchar *thunar_uca_editor_get_icon_name (const ThunarUcaEditor *uca_editor);
-static void thunar_uca_editor_set_icon_name (ThunarUcaEditor *uca_editor,
- const gchar *icon_name);
-static ThunarUcaTypes thunar_uca_editor_get_types (const ThunarUcaEditor *uca_editor);
-static void thunar_uca_editor_set_types (ThunarUcaEditor *uca_editor,
- ThunarUcaTypes types);
-static void thunar_uca_editor_command_clicked (ThunarUcaEditor *uca_editor);
-static void thunar_uca_editor_icon_clicked (ThunarUcaEditor *uca_editor);
-static void thunar_uca_editor_constructed (GObject *object);
+static const gchar *thunar_uca_editor_get_icon_name (const ThunarUcaEditor *uca_editor);
+static void thunar_uca_editor_set_icon_name (ThunarUcaEditor *uca_editor,
+ const gchar *icon_name);
+static ThunarUcaTypes thunar_uca_editor_get_types (const ThunarUcaEditor *uca_editor);
+static void thunar_uca_editor_set_types (ThunarUcaEditor *uca_editor,
+ ThunarUcaTypes types);
+static void thunar_uca_editor_command_clicked (ThunarUcaEditor *uca_editor);
+static void thunar_uca_editor_shortcut_clicked (ThunarUcaEditor *uca_editor);
+static void thunar_uca_editor_shortcut_clear_clicked (ThunarUcaEditor *uca_editor);
+static void thunar_uca_editor_icon_clicked (ThunarUcaEditor *uca_editor);
+static void thunar_uca_editor_constructed (GObject *object);
@@ -62,6 +66,7 @@ struct _ThunarUcaEditor
GtkWidget *description_entry;
GtkWidget *icon_button;
GtkWidget *command_entry;
+ GtkWidget *shortcut_button;
GtkWidget *sn_button;
GtkWidget *patterns_entry;
GtkWidget *directories_button;
@@ -70,8 +75,20 @@ struct _ThunarUcaEditor
GtkWidget *text_files_button;
GtkWidget *video_files_button;
GtkWidget *other_files_button;
+
+ gchar *accel_path;
+ GdkModifierType accel_mods;
+ guint accel_key;
};
+typedef struct {
+ gboolean in_use;
+ GdkModifierType mods;
+ guint key;
+ gchar *current_path;
+ gchar *other_path;
+} ShortcutInfo;
+
THUNARX_DEFINE_TYPE (ThunarUcaEditor, thunar_uca_editor, GTK_TYPE_DIALOG);
@@ -96,6 +113,7 @@ thunar_uca_editor_class_init (ThunarUcaEditorClass *klass)
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, description_entry);
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, icon_button);
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, command_entry);
+ gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, shortcut_button);
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, sn_button);
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, patterns_entry);
gtk_widget_class_bind_template_child (widget_class, ThunarUcaEditor, directories_button);
@@ -107,6 +125,8 @@ thunar_uca_editor_class_init (ThunarUcaEditorClass *klass)
gtk_widget_class_bind_template_callback(widget_class, thunar_uca_editor_icon_clicked);
gtk_widget_class_bind_template_callback(widget_class, thunar_uca_editor_command_clicked);
+ gtk_widget_class_bind_template_callback(widget_class, thunar_uca_editor_shortcut_clicked);
+ gtk_widget_class_bind_template_callback(widget_class, thunar_uca_editor_shortcut_clear_clicked);
}
@@ -272,6 +292,129 @@ thunar_uca_editor_command_clicked (ThunarUcaEditor *uca_editor)
static void
+thunar_uca_editor_shortcut_check (gpointer data,
+ const gchar *path,
+ guint key,
+ GdkModifierType mods,
+ gboolean changed)
+{
+ ShortcutInfo *info = (ShortcutInfo*) data;
+ if (info->in_use)
+ return;
+
+ info->in_use = info->mods == mods &&
+ info->key == key &&
+ g_strcmp0 (info->current_path, path) != 0;
+
+ if (info->in_use)
+ info->other_path = g_strdup (path);
+}
+
+
+
+static gboolean
+thunar_uca_editor_validate_shortcut (XfceShortcutDialog *dialog,
+ const gchar *shortcut,
+ ThunarUcaEditor *uca_editor)
+{
+ GdkModifierType accel_mods;
+ guint accel_key;
+ ShortcutInfo info;
+ gchar *command, *message;
+
+ g_return_val_if_fail (XFCE_IS_SHORTCUT_DIALOG (dialog), FALSE);
+ g_return_val_if_fail (shortcut != NULL, FALSE);
+
+ /* Ignore empty shortcuts */
+ if (G_UNLIKELY (g_utf8_strlen (shortcut, -1) == 0))
+ return FALSE;
+
+ /* Ignore raw 'Return' and 'space' since that may have been used to activate the shortcut row */
+ if (G_UNLIKELY (g_utf8_collate (shortcut, "Return") == 0 ||
+ g_utf8_collate (shortcut, "space") == 0))
+ return FALSE;
+
+ gtk_accelerator_parse (shortcut, &accel_key, &accel_mods);
+
+ info.in_use = FALSE;
+ info.mods = accel_mods;
+ info.key = accel_key;
+ info.current_path = uca_editor->accel_path;
+ info.other_path = NULL;
+
+ gtk_accel_map_foreach_unfiltered (&info, thunar_uca_editor_shortcut_check);
+
+ if (info.in_use)
+ {
+ command = g_strrstr (info.other_path, "/");
+ command = command == NULL ?
+ info.other_path :
+ command + 1; /* skip leading slash */
+
+ message = g_strdup_printf (_("This shorcut is currently used by: '%s'"),
+ command);
+ xfce_dialog_show_warning (GTK_WINDOW (dialog), message,
+ _("Keyboard shorcut already in use"));
+ g_free (message);
+ }
+
+ g_free (info.other_path);
+
+ return !info.in_use;
+}
+
+
+
+static void
+thunar_uca_editor_shortcut_clicked (ThunarUcaEditor *uca_editor)
+{
+ GtkWidget *dialog;
+ gint response;
+ const gchar *shortcut;
+ GdkModifierType accel_mods;
+ guint accel_key;
+ gchar *label;
+
+ dialog = xfce_shortcut_dialog_new ("thunar",
+ gtk_entry_get_text (GTK_ENTRY (uca_editor->name_entry)), "");
+
+ g_signal_connect (dialog, "validate-shortcut",
+ G_CALLBACK (thunar_uca_editor_validate_shortcut),
+ uca_editor);
+
+ response = xfce_shortcut_dialog_run (XFCE_SHORTCUT_DIALOG (dialog),
+ gtk_widget_get_toplevel (uca_editor->shortcut_button));
+
+ if (G_LIKELY (response == GTK_RESPONSE_OK))
+ {
+ shortcut = xfce_shortcut_dialog_get_shortcut (XFCE_SHORTCUT_DIALOG (dialog));
+ gtk_accelerator_parse (shortcut, &accel_key, &accel_mods);
+
+ label = gtk_accelerator_get_label (accel_key, accel_mods);
+ gtk_button_set_label (GTK_BUTTON (uca_editor->shortcut_button), label);
+
+ uca_editor->accel_key = accel_key;
+ uca_editor->accel_mods = accel_mods;
+
+ g_free (label);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+
+
+static void
+thunar_uca_editor_shortcut_clear_clicked (ThunarUcaEditor *uca_editor)
+{
+ uca_editor->accel_key = 0;
+ uca_editor->accel_mods = 0;
+ gtk_button_set_label (GTK_BUTTON (uca_editor->shortcut_button), _("None"));
+}
+
+
+
+static void
thunar_uca_editor_icon_clicked (ThunarUcaEditor *uca_editor)
{
const gchar *name;
@@ -431,7 +574,10 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor,
gchar *command;
gchar *icon_name;
gchar *name;
+ gchar *unique_id;
+ gchar *accel_label = NULL;
gboolean startup_notify;
+ GtkAccelKey key;
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
g_return_if_fail (THUNAR_UCA_IS_MODEL (uca_model));
@@ -446,6 +592,7 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor,
THUNAR_UCA_MODEL_COLUMN_ICON_NAME, &icon_name,
THUNAR_UCA_MODEL_COLUMN_NAME, &name,
THUNAR_UCA_MODEL_COLUMN_STARTUP_NOTIFY, &startup_notify,
+ THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id,
-1);
/* setup the new selection */
@@ -454,11 +601,17 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor,
/* setup the new icon */
thunar_uca_editor_set_icon_name (uca_editor, icon_name);
+ /* Resolve shortcut from accelerator */
+ uca_editor->accel_path = g_strdup_printf ("<Actions>/ThunarActions/uca-action-%s", unique_id);
+ if (gtk_accel_map_lookup_entry (uca_editor->accel_path, &key) && key.accel_key != 0)
+ accel_label = gtk_accelerator_get_label (key.accel_key, key.accel_mods);
+
/* apply the new values */
gtk_entry_set_text (GTK_ENTRY (uca_editor->description_entry), (description != NULL) ? description : "");
gtk_entry_set_text (GTK_ENTRY (uca_editor->patterns_entry), (patterns != NULL) ? patterns : "");
gtk_entry_set_text (GTK_ENTRY (uca_editor->command_entry), (command != NULL) ? command : "");
gtk_entry_set_text (GTK_ENTRY (uca_editor->name_entry), (name != NULL) ? name : "");
+ gtk_button_set_label (GTK_BUTTON (uca_editor->shortcut_button), (accel_label != NULL) ? accel_label : _("None"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (uca_editor->sn_button), startup_notify);
/* cleanup */
@@ -467,6 +620,8 @@ thunar_uca_editor_load (ThunarUcaEditor *uca_editor,
g_free (command);
g_free (icon_name);
g_free (name);
+ g_free (unique_id);
+ g_free (accel_label);
}
@@ -485,19 +640,34 @@ thunar_uca_editor_save (ThunarUcaEditor *uca_editor,
ThunarUcaModel *uca_model,
GtkTreeIter *iter)
{
+ gchar *unique_id;
+ GtkAccelKey key;
+
g_return_if_fail (THUNAR_UCA_IS_EDITOR (uca_editor));
g_return_if_fail (THUNAR_UCA_IS_MODEL (uca_model));
g_return_if_fail (iter != NULL);
+ gtk_tree_model_get (GTK_TREE_MODEL (uca_model), iter,
+ THUNAR_UCA_MODEL_COLUMN_UNIQUE_ID, &unique_id,
+ -1);
+
+ /* always clear the accelerator, it'll be updated in thunar_uca_model_update */
+ if (gtk_accel_map_lookup_entry (uca_editor->accel_path, &key) && key.accel_key != 0)
+ gtk_accel_map_change_entry (uca_editor->accel_path, 0, 0, TRUE);
+
thunar_uca_model_update (uca_model, iter,
gtk_entry_get_text (GTK_ENTRY (uca_editor->name_entry)),
- NULL, /* don't touch the unique id */
+ 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)),
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (uca_editor->sn_button)),
gtk_entry_get_text (GTK_ENTRY (uca_editor->patterns_entry)),
- thunar_uca_editor_get_types (uca_editor));
+ thunar_uca_editor_get_types (uca_editor),
+ uca_editor->accel_key,
+ uca_editor->accel_mods);
+
+ g_free (unique_id);
}
diff --git a/plugins/thunar-uca/thunar-uca-editor.ui b/plugins/thunar-uca/thunar-uca-editor.ui
index 65df4688..1a5907d1 100644
--- a/plugins/thunar-uca/thunar-uca-editor.ui
+++ b/plugins/thunar-uca/thunar-uca-editor.ui
@@ -155,6 +155,67 @@
</packing>
</child>
<child>
+ <object class="GtkLabel" id="shortcut_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Shortcut:</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="shortcut_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">The shortcut for the action.</property>
+ <property name="hexpand">True</property>
+ <signal name="clicked" handler="thunar_uca_editor_shortcut_clicked" swapped="yes"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="shortcut_clear_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Clear the shortcut for this action.</property>
+ <signal name="clicked" handler="thunar_uca_editor_shortcut_clear_clicked" swapped="yes"/>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">edit-clear</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <style>
+ <class name="linked"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkCheckButton" id="sn_button">
<property name="label" translatable="yes">Use Startup Notification</property>
<property name="visible">True</property>
@@ -165,7 +226,7 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">3</property>
+ <property name="top_attach">4</property>
</packing>
</child>
<child>
@@ -183,7 +244,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">4</property>
+ <property name="top_attach">5</property>
</packing>
</child>
<child>
@@ -198,11 +259,11 @@
</object>
<packing>
<property name="left_attach">1</property>
- <property name="top_attach">4</property>
+ <property name="top_attach">5</property>
</packing>
</child>
<child>
- <object class="GtkBox" id="box2">
+ <object class="GtkBox" id="box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
@@ -214,7 +275,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">5</property>
+ <property name="top_attach">6</property>
<property name="width">2</property>
</packing>
</child>
@@ -226,7 +287,7 @@
<property name="column_spacing">6</property>
<property name="valign">start</property>
<child>
- <object class="GtkImage" id="image2">
+ <object class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">dialog-information</property>
@@ -441,7 +502,7 @@
</object>
<packing>
<property name="left_attach">0</property>
- <property name="top_attach">6</property>
+ <property name="top_attach">7</property>
<property name="width">2</property>
</packing>
</child>
@@ -615,12 +676,12 @@
</packing>
</child>
<child>
- <object class="GtkBox" id="box3">
+ <object class="GtkBox" id="box4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">12</property>
<child>
- <object class="GtkImage" id="image3">
+ <object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
diff --git a/plugins/thunar-uca/thunar-uca-model.c b/plugins/thunar-uca/thunar-uca-model.c
index d8ac6b58..edee3e40 100644
--- a/plugins/thunar-uca/thunar-uca-model.c
+++ b/plugins/thunar-uca/thunar-uca-model.c
@@ -838,7 +838,8 @@ end_element_handler (GMarkupParseContext *context,
parser->command->str,
parser->startup_notify,
parser->patterns->str,
- parser->types);
+ parser->types,
+ 0, 0);
/* check if a new id should've been generated */
if (exo_str_is_empty (parser->unique_id->str))
@@ -1307,11 +1308,14 @@ thunar_uca_model_update (ThunarUcaModel *uca_model,
const gchar *command,
gboolean startup_notify,
const gchar *patterns,
- ThunarUcaTypes types)
+ ThunarUcaTypes types,
+ guint accel_key,
+ GdkModifierType accel_mods)
{
ThunarUcaModelItem *item;
GtkTreePath *path;
guint n, m;
+ gchar *accel_path;
g_return_if_fail (THUNAR_UCA_IS_MODEL (uca_model));
g_return_if_fail (iter->stamp == uca_model->stamp);
@@ -1362,6 +1366,14 @@ thunar_uca_model_update (ThunarUcaModel *uca_model,
path = gtk_tree_model_get_path (GTK_TREE_MODEL (uca_model), iter);
gtk_tree_model_row_changed (GTK_TREE_MODEL (uca_model), path, iter);
gtk_tree_path_free (path);
+
+ /* update accelerator */
+ if (accel_key > 0)
+ {
+ accel_path = g_strdup_printf ("<Actions>/ThunarActions/uca-action-%s", item->unique_id);
+ gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, TRUE);
+ g_free (accel_path);
+ }
}
diff --git a/plugins/thunar-uca/thunar-uca-model.h b/plugins/thunar-uca/thunar-uca-model.h
index 2b4272bc..e662b2f2 100644
--- a/plugins/thunar-uca/thunar-uca-model.h
+++ b/plugins/thunar-uca/thunar-uca-model.h
@@ -96,7 +96,9 @@ void thunar_uca_model_update (ThunarUcaModel *uca_mod
const gchar *command,
gboolean startup_notify,
const gchar *patterns,
- ThunarUcaTypes types);
+ ThunarUcaTypes types,
+ guint accel_key,
+ GdkModifierType accel_mods);
gboolean thunar_uca_model_save (ThunarUcaModel *uca_model,
GError **error);
diff --git a/plugins/thunar-uca/thunar-uca-provider.c b/plugins/thunar-uca/thunar-uca-provider.c
index 1c93c3fd..a1b878b2 100644
--- a/plugins/thunar-uca/thunar-uca-provider.c
+++ b/plugins/thunar-uca/thunar-uca-provider.c
@@ -248,6 +248,10 @@ thunar_uca_provider_get_file_menu_items (ThunarxMenuProvider *menu_provider,
g_object_ref (G_OBJECT (uca_provider)), (GClosureNotify) g_object_unref,
G_CONNECT_SWAPPED);
+ /* set the action path */
+ g_object_set_data (G_OBJECT (item), "action_path",
+ g_strconcat ("<Actions>/ThunarActions/", name, NULL));
+
/* add the menu item to the return list */
items = g_list_prepend (items, item);