Fix #659: Option to change behaviour of mouse back button
authorColin Clark <colin.clark@cclark.uk>
Sun, 21 Jul 2019 09:58:25 +0000 (10:58 +0100)
committerColin Clark <colin.clark@cclark.uk>
Sun, 21 Jul 2019 09:58:25 +0000 (10:58 +0100)
https://github.com/BestImageViewer/geeqie/issues/659

Mouse buttons 8, 9 (Back, Forward) can be set to any menu item.
The defines are set in Edit/Preferences/Behavior

14 files changed:
doc/docbook/GuideOptionsBehavior.xml
src/layout.c
src/layout_image.c
src/options.c
src/options.h
src/pixbuf-renderer.c
src/preferences.c
src/rcfile.c
src/typedefs.h
src/ui_misc.c
src/ui_misc.h
src/view_dir.c
src/view_file/view_file_icon.c
src/view_file/view_file_list.c

index ad04f20..6db8c46 100644 (file)
           <para>If selected, mouse left-click on an image belonging to the video class will start a program chosen in a box below.</para>\r
         </listitem>\r
       </varlistentry>\r
+      <varlistentry>\r
+        <term>\r
+          <guilabel>Mouse button Back/Forward</guilabel>\r
+        </term>\r
+        <listitem>\r
+          <para>Some mice have additional buttons designated Back/Forward (mouse buttons 8 and 9). You may allocate any menu item to either of these buttons.</para>\r
+        </listitem>\r
+      </varlistentry>\r
     </variablelist>\r
   </section>\r
   <section id="Debugging">\r
index 979613f..2508496 100644 (file)
@@ -2406,6 +2406,11 @@ LayoutWindow *layout_new(FileData *dir_fd, LayoutOptions *lop)
        return layout_new_with_geometry(dir_fd, lop, NULL);
 }
 
+gboolean release_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+       return defined_mouse_buttons(widget, event, data);
+}
+
 LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
                                       const gchar *geometry)
 {
@@ -2454,6 +2459,8 @@ LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
        gtk_window_set_resizable(GTK_WINDOW(lw->window), TRUE);
        gtk_container_set_border_width(GTK_CONTAINER(lw->window), 0);
 
+       g_signal_connect(G_OBJECT(lw->window), "button_release_event", G_CALLBACK(release_cb), lw);
+
        if (options->save_window_positions)
                {
                hint_mask = GDK_HINT_USER_POS;
index b828aea..1a6cd59 100644 (file)
@@ -1766,16 +1766,6 @@ static void layout_image_button_cb(ImageWindow *imd, GdkEventButton *event, gpoi
                                }
                        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time);
                        break;
-               case MOUSE_BUTTON_BACK:
-                       dir_fd = file_data_new_dir(history_chain_back());
-                       layout_set_fd(lw, dir_fd);
-                       file_data_unref(dir_fd);
-                       break;
-               case MOUSE_BUTTON_FORWARD:
-                       dir_fd = file_data_new_dir(history_chain_forward());
-                       layout_set_fd(lw, dir_fd);
-                       file_data_unref(dir_fd);
-                       break;
                default:
                        break;
                }
index dd83f29..4da0f21 100644 (file)
@@ -207,6 +207,9 @@ ConfOptions *init_options(ConfOptions *options)
 
        options->disabled_plugins = NULL;
 
+       options->mouse_button_8 = g_strdup("Back");
+       options->mouse_button_9 = g_strdup("Forward");
+
        return options;
 }
 
index 722ff22..85b674e 100644 (file)
@@ -317,6 +317,10 @@ struct _ConfOptions
                gchar *template_string;
        } printer;
 
+       /* user-definable mouse buttons */
+       gchar *mouse_button_8;
+       gchar *mouse_button_9;
+
        gboolean read_metadata_in_idle;
 
        GList *disabled_plugins;
index aded467..a09692c 100644 (file)
@@ -2143,7 +2143,7 @@ static gboolean pr_mouse_release_cb(GtkWidget *widget, GdkEventButton *bevent, g
                        {
                        pr_scroller_start(pr, bevent->x, bevent->y);
                        }
-               else if (bevent->button == MOUSE_BUTTON_LEFT || bevent->button == MOUSE_BUTTON_MIDDLE || bevent->button == MOUSE_BUTTON_BACK || bevent->button == MOUSE_BUTTON_FORWARD)
+               else if (bevent->button == MOUSE_BUTTON_LEFT || bevent->button == MOUSE_BUTTON_MIDDLE)
                        {
                        pr_clicked_signal(pr, bevent);
                        }
index 3b33b57..4779eb9 100644 (file)
@@ -450,6 +450,9 @@ static void config_window_apply(void)
                }
 #endif
 
+       options->mouse_button_8 = c_options->mouse_button_8;
+       options->mouse_button_9 = c_options->mouse_button_9;
+
        config_tab_keywords_save();
 
        image_options_sync();
@@ -632,6 +635,143 @@ static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row
        gtk_widget_show(combo);
 }
 
+typedef struct _UseableMouseItems UseableMouseItems;
+struct _UseableMouseItems
+{
+       gchar *name; /* GtkActionEntry terminology */
+       gchar *label;
+       gchar *stock_id;
+};
+
+static const UseableMouseItems useable_mouse_items[] = {
+       {"", "", NULL},
+       {"FirstImage",  N_("First Image"), GTK_STOCK_GOTO_TOP},
+       {"PrevImage",   N_("Previous Image"), GTK_STOCK_GO_UP},
+       {"NextImage",   N_("Next Image"), GTK_STOCK_GO_DOWN},
+       {"LastImage",   N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
+       {"Back",        N_("Back"), GTK_STOCK_GO_BACK},
+       {"Forward",     N_("Forward"), GTK_STOCK_GO_FORWARD},
+       {"Home",        N_("Home"), GTK_STOCK_HOME},
+       {"Up",  N_("Up"), GTK_STOCK_GO_UP},
+       {"NewWindow",   N_("New _window"), GTK_STOCK_NEW},
+       {"NewCollection",       N_("New collection"), GTK_STOCK_INDEX},
+       {"OpenCollection",      N_("Open collection"), GTK_STOCK_OPEN},
+       {"Search",      N_("Search"), GTK_STOCK_FIND},
+       {"FindDupes",   N_("Find duplicates"), GTK_STOCK_FIND},
+       {"NewFolder",   N_("New folder"),GTK_STOCK_DIRECTORY},
+       {"Copy",        N_("Copy"), GTK_STOCK_COPY},
+       {"Move",        N_("Move"), PIXBUF_INLINE_ICON_MOVE},
+       {"Rename",      N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
+       {"Delete",      N_("Delete"), GTK_STOCK_DELETE},
+       {"CloseWindow", N_("Close Window"), GTK_STOCK_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"), GTK_STOCK_PRINT},
+       {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
+       {"LayoutConfig",        N_("Configure this window"), GTK_STOCK_PREFERENCES},
+       {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
+       {"RotateCW",    N_("Rotate clockwise"), PIXBUF_INLINE_ICON_CW},
+       {"RotateCCW",   N_("Rotate counterclockwise"), 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"), GTK_STOCK_ZOOM_IN},
+       {"ZoomOut",     N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
+       {"Zoom100",     N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
+       {"ZoomFit",     N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
+       {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
+       {"ZoomFillVert",        N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
+       {"Zoom200",     N_("Zoom 2:1"), GTK_STOCK_FILE},
+       {"Zoom300",     N_("Zoom 3:1"), GTK_STOCK_FILE},
+       {"Zoom400",     N_("Zoom 4:1"), GTK_STOCK_FILE},
+       {"Zoom50",      N_("Zoom 1:2"), GTK_STOCK_FILE},
+       {"Zoom33",      N_("Zoom1:3"), GTK_STOCK_FILE},
+       {"Zoom25",      N_("Zoom 1:4"), GTK_STOCK_FILE},
+       {"ConnectZoomIn",       N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
+       {"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"), GTK_STOCK_MEDIA_PAUSE},
+       {"SlideShowFaster",     N_("Slideshow Faster"), GTK_STOCK_FILE},
+       {"SlideShowSlower",     N_("Slideshow Slower"), GTK_STOCK_FILE},
+       {"Refresh",     N_("Refresh"), GTK_STOCK_REFRESH},
+       {"HelpContents",        N_("Help"), GTK_STOCK_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},
+       {"ImageGuidelines",     N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
+       {"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"), GTK_STOCK_QUIT},
+       {NULL,          NULL, NULL}
+};
+
+static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
+{
+       gchar **option = data;
+       gchar *label;
+
+       label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
+
+       const UseableMouseItems *list = useable_mouse_items;
+
+       while (list->name)
+               {
+               if (g_strcmp0(list->label, label) == 0)
+                       {
+                       break;
+                       }
+               list++;
+               }
+
+       g_free(*option);
+       *option = g_strdup(list->name);
+       g_free(label);
+}
+
+static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
+                            gchar *option, gchar **option_c)
+{
+       GtkWidget *combo;
+       gint current = 0;
+       gint i = 0;
+
+       *option_c = option;
+
+       pref_table_label(table, column, row, text, 0.0);
+
+       combo = gtk_combo_box_text_new();
+
+       const UseableMouseItems *list = useable_mouse_items;
+
+       while (list->name)
+               {
+               gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
+               if (g_strcmp0(list->name, option) == 0)
+                       {
+                       current = i;
+                       }
+               i++;
+               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);
+
+       gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
+                        GTK_EXPAND | GTK_FILL, 0, 0, 0);
+       gtk_widget_show(combo);
+}
+
 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
 {
        gint n;
@@ -3161,6 +3301,11 @@ static void config_tab_behavior(GtkWidget *notebook)
        table = pref_table_new(group, 2, 1, FALSE, FALSE);
        add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
 
+       table = pref_table_new(group, 2, 1, FALSE, FALSE);
+       table = pref_table_new(group, 2, 1, FALSE, FALSE);
+       add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
+       table = pref_table_new(group, 2, 1, FALSE, FALSE);
+       add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
 
 #ifdef DEBUG
        pref_spacer(group, PREF_PAD_GROUP);
index ae838a1..9e1119f 100644 (file)
@@ -510,6 +510,11 @@ static void write_global_attributes(GString *outstr, gint indent)
        WRITE_NL(); WRITE_BOOL(*options, printer.show_image_text);
        WRITE_NL(); WRITE_BOOL(*options, printer.show_page_text);
        WRITE_SEPARATOR();
+
+       /* user-definable mouse buttons */
+       WRITE_NL(); WRITE_CHAR(*options, mouse_button_8);
+       WRITE_NL(); WRITE_CHAR(*options, mouse_button_9);
+       WRITE_SEPARATOR();
 }
 
 static void write_color_profile(GString *outstr, gint indent)
@@ -893,6 +898,10 @@ static gboolean load_global_params(const gchar **attribute_names, const gchar **
                if (READ_BOOL(*options, printer.show_image_text)) continue;
                if (READ_BOOL(*options, printer.show_page_text)) continue;
 
+               /* user-definable mouse buttons */
+               if (READ_CHAR(*options, mouse_button_8)) continue;
+               if (READ_CHAR(*options, mouse_button_9)) continue;
+
                /* Dummy options */
                if (READ_DUMMY(*options, image.dither_quality, "deprecated since 2012-08-13")) continue;
 
index f9ada74..6136fbe 100644 (file)
@@ -39,8 +39,8 @@ typedef enum {
        MOUSE_BUTTON_RIGHT      = 3,
        MOUSE_BUTTON_WHEEL_UP   = 4,
        MOUSE_BUTTON_WHEEL_DOWN = 5,
-       MOUSE_BUTTON_BACK       = 8,
-       MOUSE_BUTTON_FORWARD    = 9
+       MOUSE_BUTTON_8  = 8,
+       MOUSE_BUTTON_9  = 9
 } MouseButton;
 
 typedef enum {
index 312d3aa..1c20037 100644 (file)
@@ -1759,7 +1759,43 @@ gchar *text_widget_text_pull_selected(GtkWidget *text_widget)
                {
                return NULL;
                }
+}
+
+gboolean defined_mouse_buttons(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+       LayoutWindow *lw = data;
+       GtkAction *action;
+       gboolean ret = FALSE;
+
+       switch (event->button)
+               {
+               case MOUSE_BUTTON_8:
+                       if (options->mouse_button_8)
+                               {
+                               action = gtk_action_group_get_action(lw->action_group, options->mouse_button_8);
+                               if (action)
+                                       {
+                                       gtk_action_activate(action);
+                                       }
+                               ret = TRUE;
+                               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)
+                                       {
+                                       gtk_action_activate(action);
+                                       }
+                               ret = TRUE;
+                               }
+                       break;
+               default:
+                       break;
+               }
 
+       return ret;
 }
 
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index 7f65770..b260e42 100644 (file)
@@ -201,5 +201,6 @@ 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);
 
+gboolean defined_mouse_buttons(GtkWidget *widget, GdkEventButton *event, gpointer data);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index 68381ed..09dee16 100644 (file)
@@ -31,6 +31,7 @@
 #include "ui_fileops.h"
 #include "ui_tree_edit.h"
 #include "ui_menu.h"
+#include "ui_misc.h"
 #include "utilops.h"
 #include "uri_utils.h"
 #include "view_dir_list.h"
@@ -1050,6 +1051,11 @@ gboolean vd_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
        GtkTreePath *tpath;
        FileData *fd = NULL;
 
+       if (defined_mouse_buttons(widget, bevent, vd->layout))
+               {
+               return TRUE;
+               }
+
        if (vd->type == DIRVIEW_LIST && !options->view_dir_list_single_click_enter)
                return FALSE;
 
index 866e342..ab4d5c8 100644 (file)
@@ -39,6 +39,7 @@
 #include "utilops.h"
 #include "ui_fileops.h"
 #include "ui_menu.h"
+#include "ui_misc.h"
 #include "ui_tree_edit.h"
 #include "uri_utils.h"
 #include "view_file.h"
@@ -1398,6 +1399,11 @@ gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer d
 
        tip_schedule(vf);
 
+       if (defined_mouse_buttons(widget, bevent, vf->layout))
+               {
+               return TRUE;
+               }
+
        if ((gint)bevent->x != 0 || (gint)bevent->y != 0)
                {
                fd = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
index b50abe7..418f25b 100644 (file)
@@ -36,6 +36,7 @@
 #include "utilops.h"
 #include "ui_fileops.h"
 #include "ui_menu.h"
+#include "ui_misc.h"
 #include "ui_tree_edit.h"
 #include "uri_utils.h"
 #include "view_file.h"
@@ -666,6 +667,11 @@ gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer d
        GtkTreeIter iter;
        FileData *fd = NULL;
 
+       if (defined_mouse_buttons(widget, bevent, vf->layout))
+               {
+               return TRUE;
+               }
+
        if (bevent->button == MOUSE_BUTTON_MIDDLE)
                {
                vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);