Allow .desktop files to be linked to programmable mouse buttons
authorColin Clark <colin.clark@cclark.uk>
Sat, 12 Aug 2023 14:37:41 +0000 (15:37 +0100)
committerColin Clark <colin.clark@cclark.uk>
Sat, 12 Aug 2023 14:37:41 +0000 (15:37 +0100)
Desktop files can be linked to mouse buttons 8 and 9 on
Edit/Preferences/Behavior

src/preferences.cc
src/remote.cc
src/typedefs.h
src/ui-misc.cc
src/ui-misc.h

index 390bbea..30220f9 100644 (file)
@@ -763,116 +763,43 @@ static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint ro
        gtk_widget_show(combo);
 }
 
-struct UseableMouseItems
-{
-       const gchar *name; /* GtkActionEntry terminology */
-       const gchar *label;
-       const gchar *icon_name;
-};
-
-static const UseableMouseItems useable_mouse_items[] = {
-       {"", "", nullptr},
-       {"FirstImage",  N_("First Image"), GQ_ICON_GO_TOP},
-       {"PrevImage",   N_("Previous Image"), GQ_ICON_GO_UP},
-       {"NextImage",   N_("Next Image"), GQ_ICON_GO_DOWN},
-       {"LastImage",   N_("Last Image"), GQ_ICON_GO_BOTTOM},
-       {"Back",        N_("Back"), GQ_ICON_GO_PREV},
-       {"Forward",     N_("Forward"), GQ_ICON_GO_NEXT},
-       {"Home",        N_("Home"), GQ_ICON_HOME},
-       {"Up",  N_("Up"), GQ_ICON_GO_UP},
-       {"FirstPage",   N_("First page"), GQ_ICON_PREV_PAGE},
-       {"LastPage",    N_("Last Page"), GQ_ICON_NEXT_PAGE},
-       {"NextPage",    N_("Next page"), GQ_ICON_FORWARD_PAGE},
-       {"PrevPage",    N_("Previous Page"), GQ_ICON_BACK_PAGE},
-       {"NewWindow",   N_("New _window"), GQ_ICON_NEW},
-       {"NewCollection",       N_("New collection"), GQ_ICON_COLLECTION},
-       {"OpenCollection",      N_("Open collection"), GQ_ICON_OPEN},
-       {"Search",      N_("Search"), GQ_ICON_FIND},
-       {"FindDupes",   N_("Find duplicates"), GQ_ICON_FIND},
-       {"NewFolder",   N_("New folder"),GQ_ICON_DIRECTORY},
-       {"Copy",        N_("Copy"), GQ_ICON_COPY},
-       {"Move",        N_("Move"), PIXBUF_INLINE_ICON_MOVE},
-       {"Rename",      N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
-       {"Delete",      N_("Delete"), GQ_ICON_DELETE},
-       {"CloseWindow", N_("Close Window"), GQ_ICON_CLOSE},
-       {"PanView",     N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
-       {"SelectAll",   N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
-       {"SelectNone",  N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
-       {"SelectInvert",        N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
-       {"ShowFileFilter",      N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
-       {"RectangularSelection",        N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
-       {"Print",       N_("Print"), GQ_ICON_PRINT},
-       {"Preferences", N_("Preferences"), GQ_ICON_PREFERENCES},
-       {"LayoutConfig",        N_("Configure this window"), GQ_ICON_PREFERENCES},
-       {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
-       {"RotateCW",    N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
-       {"RotateCCW",   N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
-       {"Rotate180",   N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
-       {"Mirror",      N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
-       {"Flip",        N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
-       {"AlterNone",   N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
-       {"ZoomIn",      N_("Zoom in"), GQ_ICON_ZOOM_IN},
-       {"ZoomOut",     N_("Zoom out"), GQ_ICON_ZOOM_OUT},
-       {"Zoom100",     N_("Zoom 1:1"), GQ_ICON_ZOOM_100},
-       {"ZoomFit",     N_("Zoom to fit"), GQ_ICON_ZOOM_FIT},
-       {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
-       {"ZoomFillVert",        N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
-       {"Zoom200",     N_("Zoom 2:1"), GQ_ICON_GENERIC},
-       {"Zoom300",     N_("Zoom 3:1"), GQ_ICON_GENERIC},
-       {"Zoom400",     N_("Zoom 4:1"), GQ_ICON_GENERIC},
-       {"Zoom50",      N_("Zoom 1:2"), GQ_ICON_GENERIC},
-       {"Zoom33",      N_("Zoom 1:3"), GQ_ICON_GENERIC},
-       {"Zoom25",      N_("Zoom 1:4"), GQ_ICON_GENERIC},
-       {"ConnectZoomIn",       N_("Connected Zoom in"), GQ_ICON_ZOOM_IN},
-       {"SplitPaneSync",       N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
-       {"Grayscale",   N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
-       {"OverUnderExposed",    N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
-       {"HideTools",   N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
-       {"SlideShowPause",      N_("Pause slideshow"), GQ_ICON_PAUSE},
-       {"SlideShowFaster",     N_("Slideshow Faster"), GQ_ICON_GENERIC},
-       {"SlideShowSlower",     N_("Slideshow Slower"), GQ_ICON_GENERIC},
-       {"Refresh",     N_("Refresh"), GQ_ICON_REFRESH},
-       {"HelpContents",        N_("Help"), GQ_ICON_HELP},
-       {"ExifWin",     N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
-       {"Thumbnails",  N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
-       {"ShowMarks",   N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
-       {"DrawRectangle",       N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
-       {"FloatTools",  N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
-       {"SBar",        N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
-       {"SBarSort",    N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
-       {"Quit",        N_("Quit"), GQ_ICON_QUIT},
-       {nullptr,               nullptr, nullptr}
-};
-
 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
 {
+       ActionItem *action_item = nullptr;
        auto option = static_cast<gchar **>(data);
        gchar *label;
+       GList *list;
+       GList *work;
 
        label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
 
-       const UseableMouseItems *list = useable_mouse_items;
+       list = get_action_items();
+       work = list;
 
-       while (list->name)
+       while (work)
                {
-               if (g_strcmp0(list->label, label) == 0)
+               action_item = static_cast<ActionItem *>(work->data);
+               if (g_strcmp0(action_item->label, label) == 0)
                        {
                        break;
                        }
-               list++;
+               work=work->next;
                }
 
        g_free(*option);
-       *option = g_strdup(list->name);
+       *option = g_strdup(action_item->name);
        g_free(label);
+       action_items_free(list);
 }
 
-static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
-                            gchar *option, gchar **option_c)
+static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, gchar *option, gchar **option_c)
 {
-       GtkWidget *combo;
+       ActionItem *action_item;
        gint current = 0;
        gint i = 0;
+       GList *list;
+       GList *work;
+       GtkWidget *combo;
 
        *option_c = option;
 
@@ -880,23 +807,26 @@ static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, co
 
        combo = gtk_combo_box_text_new();
 
-       const UseableMouseItems *list = useable_mouse_items;
-
-       while (list->name)
+       list = get_action_items();
+       work = list;
+       while (work)
                {
-               gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
-               if (g_strcmp0(list->name, option) == 0)
+               action_item = static_cast<ActionItem *>(work->data);
+               gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), action_item->label);
+
+               if (g_strcmp0(action_item->name, option) == 0)
                        {
                        current = i;
                        }
                i++;
-               list++;
+               work = work->next;
                }
 
+       action_items_free(list);
+
        gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
 
-       g_signal_connect(G_OBJECT(combo), "changed",
-                        G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
+       g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
 
        gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
        gtk_widget_show(combo);
index 70a6561..c274de0 100644 (file)
@@ -36,6 +36,7 @@
 #include "pixbuf-renderer.h"
 #include "slideshow.h"
 #include "ui-fileops.h"
+#include "ui-misc.h"
 #include "utilops.h"
 #include "rcfile.h"
 #include "view-file.h"
@@ -1556,103 +1557,53 @@ static void gr_action(const gchar *text, GIOChannel *, gpointer)
                }
 }
 
-static gint simple_sort(gconstpointer a, gconstpointer b)
-{
-       return g_strcmp0((gchar *)a, (gchar *)b);
-}
-
 static void gr_action_list(const gchar *, GIOChannel *channel, gpointer)
 {
-       const gchar *accel_path;
+       ActionItem *action_item;
        gchar *action_list;
-       gchar *action_name;
-       gchar *comment_list;
-       gchar *label;
-       gchar *tooltip;
        gint max_length = 0;
-       GList *actions;
-       GList *groups;
        GList *list_final = nullptr;
        GList *list = nullptr;
        GList *work;
        GString *out_string = g_string_new(nullptr);
-       GtkAction *action;
 
        if (!layout_valid(&lw_id))
                {
                return;
                }
 
-       groups = gtk_ui_manager_get_action_groups(lw_id->ui_manager);
-       while (groups)
+       list = get_action_items();
+       work = list;
+
+       /* Get the length required for padding */
+       while (work)
                {
-               actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
-               while (actions)
+               action_item = static_cast<ActionItem *>(work->data);
+               if (g_utf8_strlen(action_item->name, -1) > max_length)
                        {
-                       action = GTK_ACTION(actions->data);
-                       accel_path = gtk_action_get_accel_path(action);
-
-                               if (accel_path && gtk_accel_map_lookup_entry(accel_path, nullptr))
-                                       {
-                                       g_object_get(action, "tooltip", &tooltip, "label", &label, NULL);
-
-                                       action_name = g_path_get_basename(accel_path);
-
-                                       /* Used for output column padding */
-                                       if (g_utf8_strlen(action_name, -1) > max_length)
-                                               {
-                                               max_length = g_utf8_strlen(action_name, -1);
-                                               }
-
-                                       /* Tooltips with newlines affect output format */
-                                       if (tooltip && (g_strstr_len(tooltip, -1, "\n") == nullptr) )
-                                               {
-                                               list = g_list_prepend(list, g_strdup(tooltip));
-                                               }
-                                       else
-                                               {
-                                               list = g_list_prepend(list, g_strdup(label));
-                                               }
-
-                                       list = g_list_prepend(list, g_strdup(action_name));
-
-                                       g_free(action_name);
-                                       g_free(label);
-                                       g_free(tooltip);
-                                       }
-
-                       actions = actions->next;
+                       max_length = g_utf8_strlen(action_item->name, -1);
                        }
 
-               groups = groups->next;
+               work = work->next;
                }
 
-       /* Pad the action names to the same column for readable output */
        work = list;
+
+       /* Pad the action names to the same column for readable output */
        while (work)
                {
-               /* Menu actions are irrelevant */
-               if (g_strstr_len(static_cast<gchar *>(work->data), -1, "Menu") == nullptr)
-                       {
-                       action_list = g_strdup_printf("%-*s", max_length + 4, static_cast<gchar *>(work->data));
+               action_item = static_cast<ActionItem *>(work->data);
 
-                       work=work->next;
+               action_list = g_strdup_printf("%-*s", max_length + 4, action_item->name);
+               list_final = g_list_prepend(list_final, g_strconcat(action_list, action_item->label, nullptr));
 
-                       comment_list = static_cast<gchar *>(work->data);
-                       list_final = g_list_prepend(list_final, g_strconcat(action_list, comment_list, nullptr));
-
-                       g_free(action_list);
-                       }
-               else
-                       {
-                       work = work->next;
-                       }
+               g_free(action_list);
                work = work->next;
                }
 
-       string_list_free(list);
+       action_items_free(list);
 
-       list_final = g_list_sort(list_final, simple_sort);
+       list_final = g_list_reverse(list_final);
 
        work = list_final;
        while (work)
index 55c303d..3af878e 100644 (file)
@@ -404,6 +404,13 @@ struct ThumbLoader
        guint idle_done_id; /**< event source id */
 };
 
+struct ActionItem
+{
+       const gchar *name; /* GtkActionEntry terminology */
+       const gchar *label;
+       const gchar *icon_name;
+};
+
 struct AnimationData
 {
        ImageWindow *iw;
index 133996c..52abb36 100644 (file)
 #include <cstring>
 
 #include "main.h"
-#include "ui-misc.h"
-
 #include "history-list.h"
+#include "layout.h"
+#include "ui-misc.h"
+#include "utilops.h"
 
 #include <langinfo.h>
 
@@ -1379,6 +1380,142 @@ gchar *text_widget_text_pull_selected(GtkWidget *text_widget)
                }
 }
 
+static gint simple_sort_cb(gconstpointer a, gconstpointer b)
+{
+       const ActionItem *a_action;
+       const ActionItem *b_action;
+
+       a_action = static_cast<const ActionItem *>(a);
+       b_action = static_cast<const ActionItem *>(b);
+
+       return g_strcmp0(a_action->name, b_action->name);
+}
+
+void free_action_items_cb(gpointer data)
+{
+       ActionItem *action_item;
+
+       action_item = static_cast<ActionItem *>(data);
+       g_free((gchar *)action_item->name);
+       g_free((gchar *)action_item->label);
+       g_free(action_item);
+}
+
+void action_items_free(GList *list)
+{
+       g_list_free_full(list, free_action_items_cb);
+}
+
+/**
+ * @brief Get a list of menu actions
+ * @param
+ * @returns GList ActionItem
+ *
+ * Free returned list with action_items_free(list)
+ *
+ * The list generated is used in the --remote --action-list command and
+ * programmable mouse buttons 8 and 9.
+ */
+GList* get_action_items()
+{
+       ActionItem *action_item;
+       const gchar *accel_path;
+       gboolean duplicate;
+       gchar *action_name;
+       gchar *label;
+       gchar *tooltip;
+       GList *actions;
+       GList *groups;
+       GList *list = nullptr;
+       GList *work;
+       GtkAction *action;
+       LayoutWindow *lw = nullptr;
+
+       if (!layout_valid(&lw))
+               {
+               return nullptr;
+               }
+
+       groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
+       while (groups)
+               {
+               actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
+               while (actions)
+                       {
+                       action = GTK_ACTION(actions->data);
+                       accel_path = gtk_action_get_accel_path(action);
+
+                       if (accel_path && gtk_accel_map_lookup_entry(accel_path, nullptr))
+                               {
+                               g_object_get(action, "tooltip", &tooltip, "label", &label, NULL);
+
+                               action_name = g_path_get_basename(accel_path);
+
+                               /* Menu actions are irrelevant */
+                               if (g_strstr_len(action_name, -1, "Menu") == nullptr)
+                                       {
+                                       action_item = g_new0(ActionItem, 1);
+
+                                       /* .desktop items need the program name, Geeqie menu items need the tooltip */
+                                       if (g_strstr_len(action_name, -1, ".desktop") == nullptr)
+                                               {
+
+                                               /* Tooltips with newlines affect output format */
+                                               if (tooltip && (g_strstr_len(tooltip, -1, "\n") == nullptr) )
+                                                       {
+                                                       action_item->label = g_strdup(tooltip);
+                                                       }
+                                               else
+                                                       {
+                                                       action_item->label = g_strdup(label);
+                                                       }
+                                               }
+                                       else
+                                               {
+                                               action_item->label = g_strdup(label);
+                                               }
+
+                                       action_item->name = g_strdup(action_name);
+
+                                       /* Ignore duplicate entries */
+                                       work = list;
+                                       duplicate = FALSE;
+                                       while (work)
+                                               {
+                                               if (g_strcmp0(tooltip, static_cast<ActionItem *>(work->data)->label) == 0)
+                                                       {
+                                                       duplicate = TRUE;
+                                                       break;
+                                                       }
+                                               work = work->next;
+                                               }
+
+                                       if (duplicate)
+                                               {
+                                               g_free((gchar *)action_item->name);
+                                               g_free((gchar *)action_item->label);
+                                               g_free(action_item);
+                                               }
+                                       else
+                                               {
+                                               list = g_list_prepend(list, action_item);
+                                               }
+                                       g_free(action_name);
+                                       g_free(label);
+                                       g_free(tooltip);
+                                       }
+                               }
+                       actions = actions->next;
+                       }
+
+               groups = groups->next;
+               }
+
+       list = g_list_sort(list, simple_sort_cb);
+
+       return list;
+}
+
 gboolean defined_mouse_buttons(GtkWidget *, GdkEventButton *event, gpointer data)
 {
        auto lw = static_cast<LayoutWindow *>(data);
@@ -1390,23 +1527,39 @@ gboolean defined_mouse_buttons(GtkWidget *, GdkEventButton *event, gpointer data
                case MOUSE_BUTTON_8:
                        if (options->mouse_button_8)
                                {
-                               action = gtk_action_group_get_action(lw->action_group, options->mouse_button_8);
-                               if (action)
+                               if (g_strstr_len(options->mouse_button_8, -1, ".desktop") != nullptr)
                                        {
-                                       gtk_action_activate(action);
+                                       file_util_start_editor_from_filelist(options->mouse_button_8, layout_selection_list(lw), layout_get_path(lw), lw->window);
+                                       ret = TRUE;
+                                       }
+                               else
+                                       {
+                                       action = gtk_action_group_get_action(lw->action_group, options->mouse_button_8);
+                                       if (action)
+                                               {
+                                               gtk_action_activate(action);
+                                               }
+                                       ret = TRUE;
                                        }
-                               ret = TRUE;
                                }
-                               break;
+                       break;
                case MOUSE_BUTTON_9:
                        if (options->mouse_button_9)
                                {
-                               action = gtk_action_group_get_action(lw->action_group, options->mouse_button_9);
-                               if (action)
+                               if (g_strstr_len(options->mouse_button_9, -1, ".desktop") != nullptr)
+                                       {
+                                       file_util_start_editor_from_filelist(options->mouse_button_9, layout_selection_list(lw), layout_get_path(lw), lw->window);
+                                       }
+                               else
                                        {
-                                       gtk_action_activate(action);
+                                       action = gtk_action_group_get_action(lw->action_group, options->mouse_button_9);
+                                       ret = TRUE;
+                                       if (action)
+                                               {
+                                               gtk_action_activate(action);
+                                               }
+                                       ret = TRUE;
                                        }
-                               ret = TRUE;
                                }
                        break;
                default:
index b74ba2d..ad8d9a1 100644 (file)
@@ -228,6 +228,9 @@ GtkWidget *pref_color_button_new(GtkWidget *parent_box,
 gchar *text_widget_text_pull(GtkWidget *text_widget);
 gchar *text_widget_text_pull_selected(GtkWidget *text_widget);
 
+GList* get_action_items();
+void action_items_free(GList *list);
+
 gboolean defined_mouse_buttons(GtkWidget *widget, GdkEventButton *event, gpointer data);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */