Bug fix: Pan view not displayed correctly
[geeqie.git] / src / layout-util.cc
index 235d3c0..b9edc6f 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "main.h"
 #include "layout-util.h"
 
+#include <dirent.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include <config.h>
+
 #include "advanced-exif.h"
+#include "bar-keywords.h"
 #include "bar-sort.h"
 #include "bar.h"
-#include "bar-keywords.h"
 #include "cache-maint.h"
-#include "collect.h"
-#include "collect-dlg.h"
 #include "collect-io.h"
+#include "collect.h"
 #include "color-man.h"
+#include "compat.h"
+#include "debug.h"
 #include "desktop-file.h"
 #include "dupe.h"
 #include "editors.h"
+#include "filedata.h"
 #include "fullscreen.h"
 #include "histogram.h"
 #include "history-list.h"
-#include "image.h"
 #include "image-overlay.h"
+#include "image.h"
 #include "img-view.h"
+#include "intl.h"
+#include "keymap-template.h"
 #include "layout-image.h"
+#include "layout.h"
 #include "logwindow.h"
+#include "main-defines.h"
+#include "main.h"
 #include "metadata.h"
 #include "misc.h"
+#include "options.h"
 #include "pan-view.h"
 #include "pixbuf-util.h"
 #include "preferences.h"
 #include "print.h"
 #include "rcfile.h"
-#include "search.h"
 #include "search-and-run.h"
+#include "search.h"
 #include "slideshow.h"
 #include "ui-fileops.h"
 #include "ui-menu.h"
 #include "ui-misc.h"
+#include "ui-utildlg.h"
 #include "utilops.h"
 #include "view-dir.h"
 #include "view-file.h"
 #include "window.h"
 
-#include <sys/wait.h>
-#include "keymap-template.h"
-
-#define MENU_EDIT_ACTION_OFFSET 16
-#define FILE_COLUMN_POINTER 0
+enum {
+       MENU_EDIT_ACTION_OFFSET = 16,
+       FILE_COLUMN_POINTER = 0
+};
 
 static gboolean layout_bar_enabled(LayoutWindow *lw);
 static gboolean layout_bar_sort_enabled(LayoutWindow *lw);
@@ -109,7 +128,7 @@ gboolean layout_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
                {
                if (event->keyval == GDK_KEY_Escape && lw->dir_fd)
                        {
-                       gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->dir_fd->path);
+                       gq_gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->dir_fd->path);
                        }
 
                /* the gtkaccelgroup of the window is stealing presses before they get to the entry (and more),
@@ -904,6 +923,95 @@ static void layout_menu_view_in_new_window_cb(GtkAction *, gpointer data)
        view_window_new(layout_image_get_fd(lw));
 }
 
+struct OpenWithData
+{
+       GAppInfo *application;
+       GList *g_file_list;
+       GtkWidget *app_chooser_dialog;
+};
+
+void open_with_response_cb(GtkDialog *, gint response_id, gpointer data)
+{
+       GError *error = nullptr;
+       auto open_with_data = static_cast<OpenWithData *>(data);
+
+       if (response_id == GTK_RESPONSE_OK)
+               {
+               g_app_info_launch(open_with_data->application, open_with_data->g_file_list, nullptr, &error);
+
+               if (error)
+                       {
+                       log_printf("Error launching app: %s\n", error->message);
+                       g_error_free(error);
+                       }
+               }
+
+       g_object_unref(open_with_data->application);
+       g_object_unref(g_list_first(open_with_data->g_file_list)->data);
+       g_list_free(open_with_data->g_file_list);
+       gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog));
+       g_free(open_with_data);
+}
+
+static void open_with_application_selected_cb(GtkAppChooserWidget *, GAppInfo *application, gpointer data)
+{
+       auto open_with_data = static_cast<OpenWithData *>(data);
+
+       g_object_unref(open_with_data->application);
+
+       open_with_data->application = g_app_info_dup(application);
+}
+
+static void open_with_application_activated_cb(GtkAppChooserWidget *, GAppInfo *application, gpointer data)
+{
+       GError *error = nullptr;
+       auto open_with_data = static_cast<OpenWithData *>(data);
+
+       g_app_info_launch(application, open_with_data->g_file_list, nullptr, &error);
+
+       if (error)
+               {
+               log_printf("Error launching app.: %s\n", error->message);
+               g_error_free(error);
+               }
+
+       g_object_unref(open_with_data->application);
+       g_object_unref(g_list_first(open_with_data->g_file_list)->data);
+       g_list_free(open_with_data->g_file_list);
+       gtk_widget_destroy(GTK_WIDGET(open_with_data->app_chooser_dialog));
+       g_free(open_with_data);
+}
+
+static void layout_menu_open_with_cb(GtkAction *, gpointer data)
+{
+       auto lw = static_cast<LayoutWindow *>(data);
+       FileData *fd;
+       GtkWidget *widget;
+       OpenWithData *open_with_data;
+
+       if (layout_selection_list(lw))
+               {
+               open_with_data = g_new(OpenWithData, 1);
+
+               fd = static_cast<FileData *>(g_list_first(layout_selection_list(lw))->data);
+
+               open_with_data->g_file_list = g_list_append(nullptr, g_file_new_for_path(fd->path));
+
+               open_with_data->app_chooser_dialog = gtk_app_chooser_dialog_new(nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, G_FILE(g_list_first(open_with_data->g_file_list)->data));
+
+               widget = gtk_app_chooser_dialog_get_widget(GTK_APP_CHOOSER_DIALOG(open_with_data->app_chooser_dialog));
+
+               open_with_data->application = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(open_with_data->app_chooser_dialog));
+
+               g_signal_connect(G_OBJECT(widget), "application-selected", G_CALLBACK(open_with_application_selected_cb), open_with_data);
+               g_signal_connect(G_OBJECT(widget), "application-activated", G_CALLBACK(open_with_application_activated_cb), open_with_data);
+               g_signal_connect(G_OBJECT(open_with_data->app_chooser_dialog), "response", G_CALLBACK(open_with_response_cb), open_with_data);
+               g_signal_connect(G_OBJECT(open_with_data->app_chooser_dialog), "close", G_CALLBACK(open_with_response_cb), open_with_data);
+
+               gtk_widget_show(open_with_data->app_chooser_dialog);
+               }
+}
+
 static void layout_menu_open_archive_cb(GtkAction *, gpointer data)
 {
        auto lw = static_cast<LayoutWindow *>(data);
@@ -1268,10 +1376,14 @@ static void layout_menu_foreach_func(
                                        GdkModifierType accel_mods,
                                        gboolean)
 {
-       gchar *path, *name;
-       gchar *key_name, *menu_name;
-       gchar **subset_lt_arr, **subset_gt_arr;
-       gchar *subset_lt, *converted_name;
+       gchar *path;
+       gchar *name;
+       gchar *key_name;
+       gchar *menu_name;
+       gchar **subset_lt_arr;
+       gchar **subset_gt_arr;
+       gchar *subset_lt;
+       gchar *converted_name;
        auto array = static_cast<GPtrArray *>(data);
 
        path = g_strescape(accel_path, nullptr);
@@ -1309,7 +1421,8 @@ static void layout_menu_kbd_map_cb(GtkAction *, gpointer)
        char * tmp_file;
        GError *error = nullptr;
        GIOChannel *channel;
-       char **pre_key, **post_key;
+       char **pre_key;
+       char **post_key;
        const char *key_name;
        char *converted_line;
        int keymap_index;
@@ -1821,7 +1934,7 @@ static void layout_menu_keyword_autocomplete_cb(GtkAction *, gpointer data)
  * color profile button (and menu)
  *-----------------------------------------------------------------------------
  */
-#ifdef HAVE_LCMS
+#if HAVE_LCMS
 static void layout_color_menu_enable_cb(GtkToggleAction *action, gpointer data)
 {
        auto lw = static_cast<LayoutWindow *>(data);
@@ -1838,7 +1951,7 @@ static void layout_color_menu_enable_cb()
 }
 #endif
 
-#ifdef HAVE_LCMS
+#if HAVE_LCMS
 static void layout_color_menu_use_image_cb(GtkToggleAction *action, gpointer data)
 {
        auto lw = static_cast<LayoutWindow *>(data);
@@ -1857,7 +1970,7 @@ static void layout_color_menu_use_image_cb()
 }
 #endif
 
-#ifdef HAVE_LCMS
+#if HAVE_LCMS
 static void layout_color_menu_input_cb(GtkRadioAction *action, GtkRadioAction *, gpointer data)
 {
        auto lw = static_cast<LayoutWindow *>(data);
@@ -1947,7 +2060,7 @@ static void layout_menu_collection_recent_update(LayoutWindow *lw)
                menu_item_add(menu, _("Empty"), nullptr, nullptr);
                }
 
-       recent = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/FileMenu/OpenRecent");
+       recent = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/FileMenu/OpenRecent" : "/MainMenu/FileMenu/OpenRecent");
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), menu);
        gtk_widget_set_sensitive(recent, (n != 0));
 }
@@ -2003,7 +2116,7 @@ static void layout_menu_collection_open_update(LayoutWindow *lw)
                menu_item_add(menu, _("Empty"), nullptr, nullptr);
                }
 
-       recent = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/FileMenu/OpenCollection");
+       recent = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/FileMenu/OpenCollection" : "/MainMenu/FileMenu/OpenCollection");
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), menu);
        gtk_widget_set_sensitive(recent, (n != 0));
 }
@@ -2152,7 +2265,8 @@ static void layout_menu_new_window_update(LayoutWindow *lw)
        GtkWidget *menu;
        GtkWidget *sub_menu;
        GtkWidget *item;
-       GList *children, *iter;
+       GList *children;
+       GList *iter;
        gint n;
        GList *list = nullptr;
        gint i = 0;
@@ -2162,7 +2276,7 @@ static void layout_menu_new_window_update(LayoutWindow *lw)
 
        list = layout_window_menu_list(list);
 
-       menu = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/WindowsMenu/NewWindow");
+       menu = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/WindowsMenu/NewWindow" : "/MainMenu/WindowsMenu/NewWindow");
        sub_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
 
        children = gtk_container_get_children(GTK_CONTAINER(sub_menu));
@@ -2170,7 +2284,7 @@ static void layout_menu_new_window_update(LayoutWindow *lw)
                {
                if (i >= 4) // separator, default, from current, separator
                        {
-                       gtk_widget_destroy(GTK_WIDGET(iter->data));
+                       gq_gtk_widget_destroy(GTK_WIDGET(iter->data));
                        }
                }
        g_list_free(children);
@@ -2208,7 +2322,7 @@ static void window_rename_ok(GenericDialog *, gpointer data)
        gchar *xml_name;
        gchar *new_id;
 
-       new_id = g_strdup(gtk_entry_get_text(GTK_ENTRY(rw->window_name_entry)));
+       new_id = g_strdup(gq_gtk_entry_get_text(GTK_ENTRY(rw->window_name_entry)));
 
        list = layout_window_menu_list(list);
        while (list)
@@ -2304,10 +2418,12 @@ static void layout_menu_windows_menu_cb(GtkWidget *, gpointer data)
        GtkWidget *menu;
        GtkWidget *sub_menu;
        gchar *menu_label;
-       GList *children, *iter;
+       GList *children;
+       GList *iter;
        gint i;
 
-       menu = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/WindowsMenu/");
+       menu = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/WindowsMenu/" : "/MainMenu/WindowsMenu/");
+
        sub_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
 
        /* disable Delete for temporary windows */
@@ -2334,11 +2450,12 @@ static void layout_menu_view_menu_cb(GtkWidget *, gpointer data)
        GtkWidget *menu;
        GtkWidget *sub_menu;
        gchar *menu_label;
-       GList *children, *iter;
+       GList *children;
+       GList *iter;
        gint i;
        FileData *fd;
 
-       menu = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/ViewMenu/");
+       menu = gtk_ui_manager_get_widget(lw->ui_manager, options->hamburger_menu ? "/MainMenu/OpenMenu/ViewMenu/" : "/MainMenu/ViewMenu/");
        sub_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu));
 
        fd = layout_image_get_fd(lw);
@@ -2480,8 +2597,8 @@ static void layout_menu_window_rename_cb(GtkWidget *, gpointer data)
        rw->window_name_entry = gtk_entry_new();
        gtk_widget_set_can_focus(rw->window_name_entry, TRUE);
        gtk_editable_set_editable(GTK_EDITABLE(rw->window_name_entry), TRUE);
-       gtk_entry_set_text(GTK_ENTRY(rw->window_name_entry), lw->options.id);
-       gtk_box_pack_start(GTK_BOX(hbox), rw->window_name_entry, TRUE, TRUE, 0);
+       gq_gtk_entry_set_text(GTK_ENTRY(rw->window_name_entry), lw->options.id);
+       gq_gtk_box_pack_start(GTK_BOX(hbox), rw->window_name_entry, TRUE, TRUE, 0);
        gtk_widget_grab_focus(GTK_WIDGET(rw->window_name_entry));
        gtk_widget_show(rw->window_name_entry);
        g_signal_connect(rw->window_name_entry, "activate", G_CALLBACK(window_rename_entry_activate_cb), rw);
@@ -2607,7 +2724,9 @@ static GtkActionEntry menu_entries[] = {
   { "NextPage",              GQ_ICON_FORWARD_PAGE,              N_("_Next Page"),                                       nullptr,               N_("Next Page of multi-page image"),                   CB(layout_menu_page_next_cb) },
   { "OpenArchive",           GQ_ICON_OPEN,                      N_("Open archive"),                                     nullptr,               N_("Open archive"),                                    CB(layout_menu_open_archive_cb) },
   { "OpenCollection",        GQ_ICON_OPEN,                      N_("_Open collection..."),                              "O",                   N_("Open collection..."),                              nullptr },
+  { "OpenMenu",              nullptr,                           N_("☰"),                                                nullptr,               nullptr,                                               nullptr },
   { "OpenRecent",            nullptr,                           N_("Open recen_t"),                                     nullptr,               N_("Open recent collection"),                          nullptr },
+  { "OpenWith",              GQ_ICON_OPEN_WITH,                 N_("Open With..."),                                     nullptr,               N_("Open With..."),                                    CB(layout_menu_open_with_cb) },
   { "OrientationMenu",       nullptr,                           N_("_Orientation"),                                     nullptr,               nullptr,                                               nullptr },
   { "OverlayMenu",           nullptr,                           N_("Image _Overlay"),                                   nullptr,               nullptr,                                               nullptr },
   { "PanView",               PIXBUF_INLINE_ICON_PANORAMA,       N_("Pa_n view"),                                        "<control>J",          N_("Pan view"),                                        CB(layout_menu_pan_cb) },
@@ -2749,292 +2868,8 @@ static GtkRadioActionEntry menu_stereo_mode_entries[] = {
   { "StereoOff",    nullptr,  N_("_Off"),           nullptr,  N_("Stereo Off"),           STEREO_PIXBUF_NONE },
   { "StereoSBS",    nullptr,  N_("_Side by Side"),  nullptr,  N_("Stereo Side by Side"),  STEREO_PIXBUF_SBS }
 };
-
-
 #undef CB
 
-static const gchar *menu_ui_description =
-"<ui>"
-"  <menubar name='MainMenu'>"
-"    <menu action='FileMenu'>"
-"      <menuitem action='NewCollection'/>"
-"      <menuitem action='OpenCollection'/>"
-"      <menuitem action='OpenRecent'/>"
-"      <placeholder name='OpenSection'/>"
-"      <separator/>"
-"      <menuitem action='Search'/>"
-"      <menuitem action='FindDupes'/>"
-"      <placeholder name='SearchSection'/>"
-"      <separator/>"
-"      <menuitem action='Print'/>"
-"      <placeholder name='PrintSection'/>"
-"      <separator/>"
-"      <menuitem action='NewFolder'/>"
-"      <menuitem action='Copy'/>"
-"      <menuitem action='Move'/>"
-"      <menuitem action='Rename'/>"
-"      <separator/>"
-"      <menuitem action='Delete'/>"
-"      <menuitem action='PermanentDelete'/>"
-"      <separator/>"
-"      <placeholder name='FileOpsSection'/>"
-"      <separator/>"
-"      <placeholder name='QuitSection'/>"
-"      <menuitem action='Quit'/>"
-"      <separator/>"
-"    </menu>"
-"    <menu action='GoMenu'>"
-"      <menuitem action='FirstImage'/>"
-"      <menuitem action='PrevImage'/>"
-"      <menuitem action='NextImage'/>"
-"      <menuitem action='LastImage'/>"
-"      <menuitem action='ImageBack'/>"
-"      <menuitem action='ImageForward'/>"
-"      <separator/>"
-"      <menuitem action='Back'/>"
-"      <menuitem action='Forward'/>"
-"      <menuitem action='Up'/>"
-"      <menuitem action='Home'/>"
-"      <separator/>"
-"      <menuitem action='FirstPage'/>"
-"      <menuitem action='LastPage'/>"
-"      <menuitem action='NextPage'/>"
-"      <menuitem action='PrevPage'/>"
-"    </menu>"
-"    <menu action='SelectMenu'>"
-"      <menuitem action='SelectAll'/>"
-"      <menuitem action='SelectNone'/>"
-"      <menuitem action='SelectInvert'/>"
-"      <menuitem action='RectangularSelection'/>"
-"      <menuitem action='ShowFileFilter'/>"
-"      <placeholder name='SelectSection'/>"
-"      <separator/>"
-"      <menuitem action='CopyPath'/>"
-"      <menuitem action='CopyPathUnquoted'/>"
-"      <placeholder name='ClipboardSection'/>"
-"      <separator/>"
-"      <menuitem action='ShowMarks'/>"
-"      <menuitem action='ClearMarks'/>"
-"      <placeholder name='MarksSection'/>"
-"      <separator/>"
-"    </menu>"
-"    <menu action='EditMenu'>"
-"      <placeholder name='EditSection'/>"
-"      <separator/>"
-"      <menu action='OrientationMenu'>"
-"        <menuitem action='RotateCW'/>"
-"        <menuitem action='RotateCCW'/>"
-"        <menuitem action='Rotate180'/>"
-"        <menuitem action='Mirror'/>"
-"        <menuitem action='Flip'/>"
-"        <menuitem action='AlterNone'/>"
-"        <separator/>"
-"        <menuitem action='ExifRotate'/>"
-"        <separator/>"
-"        <menuitem action='WriteRotation'/>"
-"        <menuitem action='WriteRotationKeepDate'/>"
-"        <separator/>"
-"      </menu>"
-"      <menu action='RatingMenu'>"
-"        <menuitem action='Rating0'/>"
-"        <menuitem action='Rating1'/>"
-"        <menuitem action='Rating2'/>"
-"        <menuitem action='Rating3'/>"
-"        <menuitem action='Rating4'/>"
-"        <menuitem action='Rating5'/>"
-"        <menuitem action='RatingM1'/>"
-"        <separator/>"
-"      </menu>"
-"      <menuitem action='SaveMetadata'/>"
-"      <menuitem action='KeywordAutocomplete'/>"
-"      <placeholder name='PropertiesSection'/>"
-"      <separator/>"
-"      <menuitem action='DrawRectangle'/>"
-"      <separator/>"
-"      <menuitem action='Preferences'/>"
-"      <menuitem action='Plugins'/>"
-"      <menuitem action='LayoutConfig'/>"
-"      <menuitem action='Maintenance'/>"
-"      <placeholder name='PreferencesSection'/>"
-"      <separator/>"
-"      <separator/>"
-"    </menu>"
-"    <menu action='PluginsMenu'>"
-"    </menu>"
-"    <menu action='ViewMenu'>"
-"      <menuitem action='ViewInNewWindow'/>"
-"      <menuitem action='PanView'/>"
-"      <menuitem action='ExifWin'/>"
-"      <menuitem action='OpenArchive'/>"
-"      <placeholder name='WindowSection'/>"
-"      <separator/>"
-"      <menu action='FileDirMenu'>"
-"        <menuitem action='FolderTree'/>"
-"        <placeholder name='FolderSection'/>"
-"        <separator/>"
-"        <menuitem action='ViewList'/>"
-"        <menuitem action='ViewIcons'/>"
-"        <menuitem action='Thumbnails'/>"
-"        <placeholder name='ListSection'/>"
-"        <separator/>"
-"        <menuitem action='FloatTools'/>"
-"        <menuitem action='HideTools'/>"
-"      </menu>"
-"      <placeholder name='DirSection'/>"
-"      <separator/>"
-"      <menu action='ZoomMenu'>"
-"        <menu action='ConnectZoomMenu'>"
-"          <menuitem action='ConnectZoomIn'/>"
-"          <menuitem action='ConnectZoomOut'/>"
-"          <menuitem action='ConnectZoomFit'/>"
-"          <menuitem action='ConnectZoomFillHor'/>"
-"          <menuitem action='ConnectZoomFillVert'/>"
-"          <menuitem action='ConnectZoom100'/>"
-"          <menuitem action='ConnectZoom200'/>"
-"          <menuitem action='ConnectZoom300'/>"
-"          <menuitem action='ConnectZoom400'/>"
-"          <menuitem action='ConnectZoom50'/>"
-"          <menuitem action='ConnectZoom33'/>"
-"          <menuitem action='ConnectZoom25'/>"
-"        </menu>"
-"        <menuitem action='ZoomIn'/>"
-"        <menuitem action='ZoomOut'/>"
-"        <menuitem action='ZoomFit'/>"
-"        <menuitem action='ZoomFillHor'/>"
-"        <menuitem action='ZoomFillVert'/>"
-"        <menuitem action='Zoom100'/>"
-"        <menuitem action='Zoom200'/>"
-"        <menuitem action='Zoom300'/>"
-"        <menuitem action='Zoom400'/>"
-"        <menuitem action='Zoom50'/>"
-"        <menuitem action='Zoom33'/>"
-"        <menuitem action='Zoom25'/>"
-"      </menu>"
-"      <menu action='SplitMenu'>"
-"        <menuitem action='SplitHorizontal'/>"
-"        <menuitem action='SplitVertical'/>"
-"        <menuitem action='SplitTriple'/>"
-"        <menuitem action='SplitQuad'/>"
-"        <menuitem action='SplitSingle'/>"
-"        <separator/>"
-"        <menuitem action='SplitNextPane'/>"
-"        <menuitem action='SplitPreviousPane'/>"
-"        <menuitem action='SplitUpPane'/>"
-"        <menuitem action='SplitDownPane'/>"
-"        <separator/>"
-"        <menuitem action='SplitPaneSync'/>"
-"      </menu>"
-"      <menu action='StereoMenu'>"
-"        <menuitem action='StereoAuto'/>"
-"        <menuitem action='StereoSBS'/>"
-"        <menuitem action='StereoCross'/>"
-"        <menuitem action='StereoOff'/>"
-"        <separator/>"
-"        <menuitem action='StereoCycle'/>"
-"      </menu>"
-"      <menu action='ColorMenu'>"
-"        <menuitem action='UseColorProfiles'/>"
-"        <menuitem action='UseImageProfile'/>"
-"        <menuitem action='ColorProfile0'/>"
-"        <menuitem action='ColorProfile1'/>"
-"        <menuitem action='ColorProfile2'/>"
-"        <menuitem action='ColorProfile3'/>"
-"        <menuitem action='ColorProfile4'/>"
-"        <menuitem action='ColorProfile5'/>"
-"        <separator/>"
-"        <menuitem action='Grayscale'/>"
-"      </menu>"
-"      <menu action='OverlayMenu'>"
-"        <menuitem action='ImageOverlay'/>"
-"        <menuitem action='ImageHistogram'/>"
-"        <menuitem action='ImageOverlayCycle'/>"
-"        <separator/>"
-"        <menuitem action='HistogramChanR'/>"
-"        <menuitem action='HistogramChanG'/>"
-"        <menuitem action='HistogramChanB'/>"
-"        <menuitem action='HistogramChanRGB'/>"
-"        <menuitem action='HistogramChanV'/>"
-"        <menuitem action='HistogramChanCycle'/>"
-"        <separator/>"
-"        <menuitem action='HistogramModeLin'/>"
-"        <menuitem action='HistogramModeLog'/>"
-"        <menuitem action='HistogramModeCycle'/>"
-"      </menu>"
-"      <menuitem action='OverUnderExposed'/>"
-"      <menuitem action='FullScreen'/>"
-"      <placeholder name='ViewSection'/>"
-"      <separator/>"
-"      <menuitem action='SBar'/>"
-"      <menuitem action='SBarSort'/>"
-"      <menuitem action='HideBars'/>"
-"      <menuitem action='HideSelectableToolbars'/>"
-"      <menuitem action='ShowInfoPixel'/>"
-"      <menuitem action='IgnoreAlpha'/>"
-"      <placeholder name='ToolsSection'/>"
-"      <separator/>"
-"      <menuitem action='Animate'/>"
-"      <menuitem action='SlideShow'/>"
-"      <menuitem action='SlideShowPause'/>"
-"      <menuitem action='SlideShowFaster'/>"
-"      <menuitem action='SlideShowSlower'/>"
-"      <separator/>"
-"      <menuitem action='Refresh'/>"
-"      <placeholder name='SlideShowSection'/>"
-"      <separator/>"
-"    </menu>"
-"    <menu action='WindowsMenu'>"
-"      <menu action='NewWindow'>"
-"        <menuitem action='NewWindowDefault'/>"
-"        <menuitem action='NewWindowFromCurrent'/>"
-"        <separator/>"
-"       </menu>"
-"      <menuitem action='RenameWindow'/>"
-"      <menuitem action='DeleteWindow'/>"
-"      <menuitem action='CloseWindow'/>"
-"    </menu>"
-"    <menu action='HelpMenu'>"
-"      <separator/>"
-"      <menuitem action='HelpContents'/>"
-"      <menuitem action='SearchAndRunCommand'/>"
-"      <menuitem action='HelpSearch'/>"
-"      <menuitem action='HelpShortcuts'/>"
-"      <menuitem action='HelpKbd'/>"
-"      <menuitem action='HelpNotes'/>"
-"      <menuitem action='HelpChangeLog'/>"
-"      <placeholder name='HelpSection'/>"
-"      <separator/>"
-"      <menuitem action='About'/>"
-"      <separator/>"
-"      <menuitem action='LogWindow'/>"
-"      <separator/>"
-"    </menu>"
-"  </menubar>"
-"  <toolbar name='ToolBar'>"
-"  </toolbar>"
-"  <toolbar name='StatusBar'>"
-"  </toolbar>"
-"<accelerator action='PrevImageAlt1'/>"
-"<accelerator action='PrevImageAlt2'/>"
-"<accelerator action='NextImageAlt1'/>"
-"<accelerator action='NextImageAlt2'/>"
-"<accelerator action='DeleteAlt1'/>"
-"<accelerator action='DeleteAlt2'/>"
-"<accelerator action='FullScreenAlt1'/>"
-"<accelerator action='FullScreenAlt2'/>"
-"<accelerator action='Escape'/>"
-"<accelerator action='EscapeAlt1'/>"
-
-"<accelerator action='ZoomInAlt1'/>"
-"<accelerator action='ZoomOutAlt1'/>"
-"<accelerator action='Zoom100Alt1'/>"
-"<accelerator action='ZoomFitAlt1'/>"
-
-"<accelerator action='ConnectZoomInAlt1'/>"
-"<accelerator action='ConnectZoomOutAlt1'/>"
-"<accelerator action='ConnectZoom100Alt1'/>"
-"<accelerator action='ConnectZoomFitAlt1'/>"
-"</ui>";
-
 static gchar *menu_translate(const gchar *path, gpointer)
 {
        return static_cast<gchar *>(_(path));
@@ -3074,8 +2909,13 @@ static void layout_actions_setup_marks(LayoutWindow *lw)
        GError *error;
        GString *desc = g_string_new(
                                "<ui>"
-                               "  <menubar name='MainMenu'>"
-                               "    <menu action='SelectMenu'>");
+                               "  <menubar name='MainMenu'>");
+
+       if (options->hamburger_menu)
+               {
+               g_string_append(desc, "    <menu action='OpenMenu'>");
+               }
+       g_string_append(desc, "      <menu action='SelectMenu'>");
 
        for (mark = 1; mark <= FILEDATA_MARKS_SIZE; mark++)
                {
@@ -3110,8 +2950,13 @@ static void layout_actions_setup_marks(LayoutWindow *lw)
                }
 
        g_string_append(desc,
-                               "    </menu>"
-                               "  </menubar>");
+                               "      </menu>");
+       if (options->hamburger_menu)
+               {
+               g_string_append(desc, "    </menu>");
+               }
+       g_string_append(desc, "  </menubar>");
+
        for (mark = 1; mark <= FILEDATA_MARKS_SIZE; mark++)
                {
                gint i = (mark < 10 ? mark : 0);
@@ -3160,7 +3005,9 @@ static GList *layout_actions_editor_menu_path(EditorDescription *editor)
 
 static void layout_actions_editor_add(GString *desc, GList *path, GList *old_path)
 {
-       gint to_open, to_close, i;
+       gint to_open;
+       gint to_close;
+       gint i;
        while (path && old_path && strcmp(static_cast<gchar *>(path->data), static_cast<gchar *>(old_path->data)) == 0)
                {
                path = path->next;
@@ -3241,6 +3088,11 @@ static void layout_actions_setup_editors(LayoutWindow *lw)
                                "<ui>"
                                "  <menubar name='MainMenu'>");
 
+       if (options->hamburger_menu)
+               {
+               g_string_append(desc, "    <menu action='OpenMenu'>");
+               }
+
        editors_list = editor_list_get();
 
        old_path = nullptr;
@@ -3273,7 +3125,12 @@ static void layout_actions_setup_editors(LayoutWindow *lw)
        layout_actions_editor_add(desc, nullptr, old_path);
        g_list_free_full(old_path, g_free);
 
-       g_string_append(desc,   "  </menubar>"
+       if (options->hamburger_menu)
+               {
+               g_string_append(desc, "</menu>");
+               }
+
+       g_string_append(desc,"  </menubar>"
                                "</ui>" );
 
        error = nullptr;
@@ -3333,7 +3190,8 @@ void layout_actions_setup(LayoutWindow *lw)
 
        DEBUG_1("%s layout_actions_setup: add menu", get_exec_time());
        error = nullptr;
-       if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, menu_ui_description, -1, &error))
+
+       if (!gtk_ui_manager_add_ui_from_resource(lw->ui_manager, options->hamburger_menu ? GQ_RESOURCE_PATH_UI "/menu-hamburger.ui" : GQ_RESOURCE_PATH_UI "/menu-classic.ui" , &error))
                {
                g_message("building menus failed: %s", error->message);
                g_error_free(error);
@@ -3452,20 +3310,10 @@ GtkWidget *layout_actions_menu_bar(LayoutWindow *lw)
 GtkWidget *layout_actions_toolbar(LayoutWindow *lw, ToolbarType type)
 {
        if (lw->toolbar[type]) return lw->toolbar[type];
-       switch (type)
-               {
-               case TOOLBAR_MAIN:
-                       lw->toolbar[type] = gtk_ui_manager_get_widget(lw->ui_manager, "/ToolBar");
-                       gtk_toolbar_set_style(GTK_TOOLBAR(lw->toolbar[type]), GTK_TOOLBAR_ICONS);
-                       break;
-               case TOOLBAR_STATUS:
-                       lw->toolbar[type] = gtk_ui_manager_get_widget(lw->ui_manager, "/StatusBar");
-                       gtk_toolbar_set_style(GTK_TOOLBAR(lw->toolbar[type]), GTK_TOOLBAR_ICONS);
-                       gtk_toolbar_set_show_arrow(GTK_TOOLBAR(lw->toolbar[type]), FALSE);
-                       break;
-               default:
-                       break;
-               }
+
+       lw->toolbar[type] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+
+       gtk_widget_show(lw->toolbar[type]);
        g_object_ref(lw->toolbar[type]);
        return lw->toolbar[type];
 }
@@ -3477,19 +3325,38 @@ GtkWidget *layout_actions_menu_tool_bar(LayoutWindow *lw)
 
        if (lw->menu_tool_bar) return lw->menu_tool_bar;
 
-       menu_bar = layout_actions_menu_bar(lw);
-       DEBUG_NAME(menu_bar);
        toolbar = layout_actions_toolbar(lw, TOOLBAR_MAIN);
        DEBUG_NAME(toolbar);
        lw->menu_tool_bar = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
 
-       gtk_box_pack_start(GTK_BOX(lw->menu_tool_bar), menu_bar, FALSE, FALSE, 0);
-       gtk_box_pack_start(GTK_BOX(lw->menu_tool_bar), toolbar, FALSE, FALSE, 0);
+       if (!options->hamburger_menu)
+               {
+               menu_bar = layout_actions_menu_bar(lw);
+               DEBUG_NAME(menu_bar);
+               gq_gtk_box_pack_start(GTK_BOX(lw->menu_tool_bar), menu_bar, FALSE, FALSE, 0);
+               }
+
+       gq_gtk_box_pack_start(GTK_BOX(lw->menu_tool_bar), toolbar, FALSE, FALSE, 0);
 
        g_object_ref(lw->menu_tool_bar);
        return lw->menu_tool_bar;
 }
 
+void toolbar_clear_cb(GtkWidget *widget, gpointer)
+{
+       GtkAction *action;
+
+       if (GTK_IS_BUTTON(widget))
+               {
+               action = static_cast<GtkAction *>(g_object_get_data(G_OBJECT(widget), "action"));
+               if (g_object_get_data(G_OBJECT(widget), "id") )
+                       {
+                       g_signal_handler_disconnect(action, GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "id")));
+                       }
+               }
+       gtk_widget_destroy(widget);
+}
+
 void layout_toolbar_clear(LayoutWindow *lw, ToolbarType type)
 {
        if (lw->toolbar_merge_id[type])
@@ -3501,15 +3368,59 @@ void layout_toolbar_clear(LayoutWindow *lw, ToolbarType type)
        lw->toolbar_actions[type] = nullptr;
 
        lw->toolbar_merge_id[type] = gtk_ui_manager_new_merge_id(lw->ui_manager);
+
+       if (lw->toolbar[type])
+               {
+               gtk_container_foreach(GTK_CONTAINER(lw->toolbar[type]), (GtkCallback)G_CALLBACK(toolbar_clear_cb), nullptr);
+               }
+}
+
+void action_radio_changed_cb(GtkAction *action, GtkAction *current, gpointer data)
+{
+       auto button = static_cast<GtkToggleButton *>(data);
+
+       if (action == current )
+               {
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
+               }
+       else
+               {
+               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
+               }
+}
+
+void action_toggle_activate_cb(GtkAction* self, gpointer data)
+{
+       auto button = static_cast<GtkToggleButton *>(data);
+
+       if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(self)) != gtk_toggle_button_get_active(button))
+               {
+               gtk_toggle_button_set_active(button, gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(self)));
+               }
+}
+
+gboolean toolbar_button_press_event_cb(GtkWidget *, GdkEvent *, gpointer data)
+{
+       gtk_action_activate(GTK_ACTION(data));
+
+       return TRUE;
 }
 
-void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action)
+void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action_name)
 {
        const gchar *path = nullptr;
+       const gchar *tooltip_text = nullptr;
+       GtkAction *action;
+       GtkWidget *action_icon = nullptr;
+       GtkWidget *button;
+       gulong id;
 
-       if (!action || !lw->ui_manager) return;
+       if (!action_name || !lw->ui_manager) return;
 
-       if (g_list_find_custom(lw->toolbar_actions[type], action, reinterpret_cast<GCompareFunc>(strcmp))) return;
+       if (!lw->toolbar[type])
+               {
+               return;
+               }
 
        switch (type)
                {
@@ -3523,8 +3434,7 @@ void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action)
                        break;
                }
 
-
-       if (g_str_has_suffix(action, ".desktop"))
+       if (g_str_has_suffix(action_name, ".desktop"))
                {
                /* this may be called before the external editors are read
                   create a dummy action for now */
@@ -3533,22 +3443,79 @@ void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action)
                        lw->action_group_editors = gtk_action_group_new("MenuActionsExternal");
                        gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_editors, 1);
                        }
-               if (!gtk_action_group_get_action(lw->action_group_editors, action))
+               if (!gtk_action_group_get_action(lw->action_group_editors, action_name))
                        {
-                       GtkActionEntry entry = { action,
+                       GtkActionEntry entry = { action_name,
                                                 GQ_ICON_MISSING_IMAGE,
-                                                action,
+                                                action_name,
                                                 nullptr,
                                                 nullptr,
-                                                nullptr };
-                       DEBUG_1("Creating temporary action %s", action);
+                                                nullptr
+                                              };
+                       DEBUG_1("Creating temporary action %s", action_name);
                        gtk_action_group_add_actions(lw->action_group_editors, &entry, 1, lw);
                        }
                }
-       gtk_ui_manager_add_ui(lw->ui_manager, lw->toolbar_merge_id[type], path, action, action, GTK_UI_MANAGER_TOOLITEM, FALSE);
-       lw->toolbar_actions[type] = g_list_append(lw->toolbar_actions[type], g_strdup(action));
-}
 
+       if (g_strcmp0(action_name, "Separator") == 0)
+               {
+               button = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
+               }
+       else
+               {
+               action = gtk_action_group_get_action(lw->action_group, action_name);
+
+               action_icon = gtk_action_create_icon(action, GTK_ICON_SIZE_SMALL_TOOLBAR);
+               tooltip_text = gtk_action_get_tooltip(action);
+
+               gtk_ui_manager_add_ui(lw->ui_manager, lw->toolbar_merge_id[type], path, action_name, action_name, GTK_UI_MANAGER_TOOLITEM, FALSE);
+
+               if (GTK_IS_RADIO_ACTION(action) || GTK_IS_TOGGLE_ACTION(action))
+                       {
+                       button = gtk_toggle_button_new();
+                       }
+               else
+                       {
+                       button = gtk_button_new();
+                       }
+
+               if (GTK_IS_TOGGLE_ACTION(action) || GTK_IS_RADIO_ACTION(action))
+                       {
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)));
+                       }
+
+               if (action_icon)
+                       {
+                       gtk_button_set_image(GTK_BUTTON(button), action_icon);
+                       }
+               else
+                       {
+                       gtk_button_set_label(GTK_BUTTON(button), action_name);
+                       }
+
+               gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
+               gtk_widget_set_tooltip_text(button, tooltip_text);
+
+               if (GTK_IS_RADIO_ACTION(action))
+                       {
+                       id = g_signal_connect(G_OBJECT(action), "changed", G_CALLBACK(action_radio_changed_cb), button);
+                       g_object_set_data(G_OBJECT(button), "id", GUINT_TO_POINTER(id));
+                       }
+               else if (GTK_IS_TOGGLE_ACTION(action))
+                       {
+                       id = g_signal_connect(G_OBJECT(action), "activate", G_CALLBACK(action_toggle_activate_cb), button);
+                       g_object_set_data(G_OBJECT(button), "id", GUINT_TO_POINTER(id));
+                       }
+
+               g_signal_connect(G_OBJECT(button), "button_press_event", G_CALLBACK(toolbar_button_press_event_cb), action);
+               g_object_set_data(G_OBJECT(button), "action", action);
+               }
+
+       gq_gtk_container_add(GTK_WIDGET(lw->toolbar[type]), GTK_WIDGET(button));
+       gtk_widget_show(GTK_WIDGET(button));
+
+       lw->toolbar_actions[type] = g_list_append(lw->toolbar_actions[type], g_strdup(action_name));
+}
 
 void layout_toolbar_add_default(LayoutWindow *lw, ToolbarType type)
 {
@@ -3742,7 +3709,7 @@ void layout_util_sync_color(LayoutWindow *lw)
        gboolean use_image = FALSE;
        gint i;
        gchar action_name[15];
-#ifdef HAVE_LCMS
+#if HAVE_LCMS
        gchar *image_profile;
        gchar *screen_profile;
 #endif
@@ -3753,7 +3720,7 @@ void layout_util_sync_color(LayoutWindow *lw)
        use_color = layout_image_color_profile_get_use(lw);
 
        action = gtk_action_group_get_action(lw->action_group, "UseColorProfiles");
-#ifdef HAVE_LCMS
+#if HAVE_LCMS
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_color);
        if (layout_image_color_profile_get_status(lw, &image_profile, &screen_profile))
                {
@@ -4131,7 +4098,7 @@ void layout_bar_sort_set(LayoutWindow *lw, GtkWidget *bar)
        g_signal_connect(G_OBJECT(lw->bar_sort), "destroy",
                         G_CALLBACK(layout_bar_sort_destroyed), lw);
 
-       gtk_box_pack_end(GTK_BOX(lw->utility_box), lw->bar_sort, FALSE, FALSE, 0);
+       gq_gtk_box_pack_end(GTK_BOX(lw->utility_box), lw->bar_sort, FALSE, FALSE, 0);
 }
 
 void layout_bar_sort_toggle(LayoutWindow *lw)
@@ -4217,7 +4184,7 @@ GtkWidget *layout_bars_prepare(LayoutWindow *lw, GtkWidget *image)
        lw->utility_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
        lw->utility_paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
        DEBUG_NAME(lw->utility_paned);
-       gtk_box_pack_start(GTK_BOX(lw->utility_box), lw->utility_paned, TRUE, TRUE, 0);
+       gq_gtk_box_pack_start(GTK_BOX(lw->utility_box), lw->utility_paned, TRUE, TRUE, 0);
 
        gtk_paned_pack1(GTK_PANED(lw->utility_paned), image, TRUE, FALSE);
        gtk_widget_show(lw->utility_paned);