Fix #872: Geometry of Icon pane not being saved
authorColin Clark <colin.clark@cclark.uk>
Wed, 4 Aug 2021 15:11:38 +0000 (16:11 +0100)
committerColin Clark <colin.clark@cclark.uk>
Wed, 4 Aug 2021 15:11:38 +0000 (16:11 +0100)
https://github.com/BestImageViewer/geeqie/issues/872

Permit the user to save the current window layout as the default for all
new windows.

doc/docbook/GuideOptionsWindow.xml
src/layout.c
src/layout.h
src/layout_util.c
src/layout_util.h
src/main.c
src/main.h
src/preferences.c
src/rcfile.c
src/rcfile.h
src/remote.c

index 04c4708..62ca439 100644 (file)
@@ -7,7 +7,7 @@
     <variablelist>\r
       <varlistentry>\r
         <term>\r
-          <guilabel>Remember window positions</guilabel>\r
+          <guilabel>Remember session</guilabel>\r
         </term>\r
         <listitem>\r
           <para>This will maintain windows size and position between Geeqie sessions.</para>\r
         </listitem>\r
       </varlistentry>\r
     </variablelist>\r
+    <variablelist>\r
+      <varlistentry>\r
+        <term>\r
+          <guilabel>Use current layout for default</guilabel>\r
+        </term>\r
+        <listitem>\r
+          <para>\r
+            Press the <code>Set</code> button to store the current window layout for use as the default for all new windows.\r
+          </para>\r
+        </listitem>\r
+      </varlistentry>\r
+    </variablelist>\r
   </section>\r
   <section id="Size">\r
     <title>Size</title>\r
index 37fe728..fae646b 100644 (file)
@@ -2598,6 +2598,7 @@ LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
        GdkGeometry hint;
        GdkWindowHints hint_mask;
        Histogram *histogram;
+       gchar *default_path;
 
        DEBUG_1("%s layout_new: start", get_exec_time());
        lw = g_new0(LayoutWindow, 1);
@@ -2625,11 +2626,16 @@ LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
 
        /* divider positions */
 
+       default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
+
        if (!options->save_window_positions)
                {
-               lw->options.main_window.hdivider_pos = MAIN_WINDOW_DIV_HPOS;
-               lw->options.main_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
-               lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
+               if (!isfile(default_path))
+                       {
+                       lw->options.main_window.hdivider_pos = MAIN_WINDOW_DIV_HPOS;
+                       lw->options.main_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
+                       lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
+                       }
                }
 
        /* window */
@@ -2657,7 +2663,7 @@ LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
        gtk_window_set_geometry_hints(GTK_WINDOW(lw->window), NULL, &hint,
                                      GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hint_mask);
 
-       if (options->save_window_positions)
+       if (options->save_window_positions || isfile(default_path))
                {
                gtk_window_set_default_size(GTK_WINDOW(lw->window), lw->options.main_window.w, lw->options.main_window.h);
 //             if (!layout_window_list)
@@ -2673,6 +2679,7 @@ LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
                gtk_window_set_default_size(GTK_WINDOW(lw->window), MAINWINDOW_DEF_WIDTH, MAINWINDOW_DEF_HEIGHT);
                }
 
+       g_free(default_path);
        g_signal_connect(G_OBJECT(lw->window), "delete_event",
                         G_CALLBACK(layout_delete_cb), lw);
 
@@ -3041,5 +3048,31 @@ void layout_update_from_config(LayoutWindow *lw, const gchar **attribute_names,
        free_layout_options_content(&lop);
 }
 
+LayoutWindow *layout_new_from_default()
+{
+       LayoutWindow *lw;
+       gchar *path = NULL;
+       GList *work;
+       gboolean success;
+       gchar *default_path;
+
+       default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
+       success = load_config_from_file(default_path, TRUE);
+       g_free(default_path);
+
+       if (success)
+               {
+               work = g_list_last(layout_window_list);
+               lw = work->data;
+               g_free(lw->options.id);
+               lw->options.id = g_strdup(layout_get_unique_id());
+               }
+       else
+               {
+               layout_new_from_config(NULL, NULL, TRUE);
+               }
+       return lw;
+}
+
 
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index ddb0d89..cf1441c 100644 (file)
@@ -32,6 +32,7 @@ LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
                                       const gchar *geometry);
 LayoutWindow *layout_new_from_config(const gchar **attribute_names, const gchar **attribute_values, gboolean use_commandline);
 void layout_update_from_config(LayoutWindow *lw, const gchar **attribute_names, const gchar **attribute_values);
+LayoutWindow *layout_new_from_default();
 
 void layout_close(LayoutWindow *lw);
 void layout_free(LayoutWindow *lw);
index a9c7da7..9a2cb59 100644 (file)
@@ -221,31 +221,6 @@ static void layout_exit_fullscreen(LayoutWindow *lw)
        layout_image_full_screen_stop(lw);
 }
 
-LayoutWindow *layout_menu_new_window(GtkAction *action, gpointer data)
-{
-       LayoutWindow *lw = data;
-       LayoutWindow *nw;
-       LayoutOptions lop;
-       gboolean tmp = options->save_window_positions;
-
-       if (!options->use_saved_window_positions_for_new_windows)
-               options->save_window_positions = FALSE; /* let the windowmanager decide for the first time */
-
-       layout_exit_fullscreen(lw);
-
-       layout_sync_options_with_current_state(lw);
-       lop = lw->options; /* we can copy it directly, no strings are modified */
-
-       lop.id = NULL; /* get a new id */
-       nw = layout_new(NULL, &lop);
-       layout_sort_set(nw, options->file_sort.method, options->file_sort.ascending);
-       layout_set_fd(nw, lw->dir_fd);
-       options->save_window_positions = tmp;
-
-       return nw;
-}
-
-
 static void clear_marks_cancel_cb(GenericDialog *gd, gpointer data)
 {
        generic_dialog_close(gd);
@@ -2233,7 +2208,7 @@ static void window_delete_ok_cb(GenericDialog *gd, gpointer data)
 
 static void layout_menu_window_default_cb(GtkWidget *widget, gpointer data)
 {
-       layout_new_from_config(NULL, NULL, TRUE);
+       layout_new_from_default();
 }
 
 static void layout_menu_windows_menu_cb(GtkWidget *widget, gpointer data)
index c2a4d3a..5b15aa3 100644 (file)
@@ -73,7 +73,6 @@ void layout_bars_close(LayoutWindow *lw);
 void layout_exif_window_new(LayoutWindow *lw);
 
 gboolean is_help_key(GdkEventKey *event);
-LayoutWindow *layout_menu_new_window(GtkAction *action, gpointer data);
 void layout_menu_close_cb(GtkAction *action, gpointer data);
 GtkWidget *layout_actions_menu_tool_bar(LayoutWindow *lw);
 #endif
index fd3343e..ee4de76 100644 (file)
@@ -44,6 +44,7 @@
 #include "layout_util.h"
 #include "misc.h"
 #include "options.h"
+#include "rcfile.h"
 #include "remote.h"
 #include "secure_save.h"
 #include "similar.h"
 #include <X11/Xlib.h>
 #endif
 
+/**
+ * @page diagrams Diagrams
+ * @section options_overview Options Overview
+ * 
+ * #_ConfOptions  #_LayoutOptions
+ * 
+ * @startuml
+ * 
+ * object options.h
+ * object typedefs.h
+ * 
+ * options.h : ConfOptions
+ * options.h : \n
+ * options.h : Options applicable to **all** Layout Windows
+ * options.h : These are in the <global> section of geeqierc.xml
+ * options.h : Available to all modules via the global variable **options**
+ * typedefs.h : LayoutOptions
+ * typedefs.h : \n
+ * typedefs.h : Options applicable to **each** Layout Window
+ * typedefs.h : These are in the <layout> section of geeqierc.xml
+ * typedefs.h : There is one <layout> section for each Layout Window displayed
+ * typedefs.h : Available via **<layout_window>->options**
+ * 
+ * @enduml
+ */
+
+/**
+ * @page diagrams Diagrams
+ * @section options_diagrams_main Options - New Window From Main
+ * #main  
+ * #init_options  
+ * #layout_new_from_default  
+ * #load_config_from_file  
+ * #load_options  
+ * #setup_default_options
+ * 
+ * @startuml
+ * group main.c
+ * start
+ * group options.c
+ * : **init_options()**
+ * 
+ * Set **options** = ConfOptions from hard-coded init values;
+ * end group
+ * 
+ * group options.c
+ * : **setup_default_options()**
+ * 
+ * set hard-coded ConfOptions:
+ * 
+ * bookmarks:
+ * * dot dir
+ * * Home
+ * * Desktop
+ * * Collections
+ * safe delete path
+ * OSD template string
+ * sidecar extensions
+ * shell path and options
+ * marks tooltips
+ * help search engine;
+ * end group
+ * 
+ * if (first entry
+ * or
+ * --new-instance) then (yes)
+ * group options.c
+ * : **load_options()**
+ * ;
+ * 
+ * split
+ * : GQ_SYSTEM_WIDE_DIR
+ * /geeqierc.xml;
+ * split again
+ * : XDG_CONFIG_HOME
+ * /geeqierc.xml;
+ * split again
+ * : HOME
+ * /.geeqie/geeqierc.xml;
+ * end split
+ * 
+ * group rcfile.c
+ * : **load_config_from_file()**
+ * 
+ * set  **options** from file
+ * and all <layout window>->options  in file;
+ * end group
+ * 
+ * end group
+ * 
+ * if (broken config. file
+ * or no config file
+ * or no layout section loaded
+ * (i.e. session not saved)) then (yes)
+ * group layout.c
+ * : **layout_new_from_default()**;
+ * if (default.xml exists) then (yes)
+ * : Load user-saved
+ *  layout_window default options
+ *  from default.xml file;
+ * else (no)
+ * : Load hard-coded
+ *  layout_window default options;
+ * endif
+ * end group
+ * endif
+ * 
+ * else (no)
+ * : Send --new-window request to remote
+ *  No return to this point
+ *  This instance terminates;
+ * stop
+ * endif
+ * 
+ * : Enter gtk main loop;
+ * 
+ * end group
+ * @enduml
+ */
+
+/**
+ * @page diagrams Diagrams
+ * @section options_diagrams_remote Options - New Window From Remote
+ * #layout_new_from_default  
+ * @startuml
+ * 
+ * group remote.c
+ * start
+ * group layout.c
+ * : **layout_new_from_default()**;
+ * if (default.xml exists) then (yes)
+ * : Load user-saved
+ *  layout_window default options
+ *  from default.xml file;
+ * else (no)
+ * : Load hard-coded
+ *  layout_window default options;
+ * endif
+ * end group
+ * : set path from PWD;
+ * @enduml
+ */
+
+/**
+ * @page diagrams Diagrams
+ * @section options_diagrams_menu Options - New Window From Menu
+ * #layout_menu_new_window_cb  
+ * #layout_menu_window_from_current_cb  
+ * #layout_new_from_default  
+ * @startuml
+ * 
+ * group layout_util.c
+ * start
+ * 
+ * split
+ * : default;
+ * group layout.c
+ * : **layout_new_from_default()**;
+ * if (default.xml exists) then (yes)
+ * : Load user-saved
+ *  layout_window default options
+ *  from default.xml file;
+ * else (no)
+ * : Load hard-coded
+ *  layout_window default options;
+ * endif
+ * end group
+ * 
+ * split again
+ * : from current
+ * 
+ * **layout_menu_window_from_current_cb()**
+ * copy layout_window options
+ * from current window;
+ * 
+ * split again
+ * : named
+ * 
+ * **layout_menu_new_window_cb()**
+ * load layout_window options
+ * from saved xml file list;
+ * end split
+ * 
+ * end group
+ * @enduml
+ */
+  /**
+  * @file
+  * @ref options_overview Options Overview
+  */
+
+
 gboolean thumb_format_changed = FALSE;
 static RemoteConnection *remote_connection = NULL;
 
@@ -1112,8 +1305,8 @@ gint main(gint argc, gchar *argv[])
        /* handle missing config file and commandline additions*/
        if (!layout_window_list)
                {
-               /* broken or no config file */
-               layout_new_from_config(NULL, NULL, TRUE);
+               /* broken or no config file or no <layout> section */
+               layout_new_from_default();
                }
 
        layout_editors_reload_start();
index 61cc21d..87aa96e 100644 (file)
@@ -88,6 +88,7 @@
 #define GQ_SYSTEM_WIDE_DIR    "/etc/" GQ_APPNAME_LC
 
 #define RC_FILE_NAME GQ_APPNAME_LC "rc.xml"
+#define DEFAULT_WINDOW_LAYOUT "default_window_layout.xml"
 
 #define GQ_COLLECTION_EXT ".gqv"
 
index d0d34a2..476b481 100644 (file)
@@ -41,6 +41,7 @@
 #include "metadata.h"
 #include "osd.h"
 #include "pixbuf_util.h"
+#include "rcfile.h"
 #include "slideshow.h"
 #include "toolbar.h"
 #include "trash.h"
@@ -2311,11 +2312,32 @@ static void config_tab_image(GtkWidget *notebook)
 }
 
 /* windows tab */
+
+static void save_default_window_layout_cb(GtkWidget *widget, gpointer data)
+{
+       LayoutWindow *lw = NULL;
+       gchar *default_path;
+       gchar *tmp_id;
+
+       /* Get current lw */
+       layout_valid(&lw);
+
+       tmp_id = lw->options.id;
+       lw->options.id = g_strdup("lw_default");
+
+       default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
+       save_default_layout_options_to_file(default_path, options, lw);
+       g_free(lw->options.id);
+       lw->options.id = tmp_id;
+       g_free(default_path);
+}
+
 static void config_tab_windows(GtkWidget *notebook)
 {
        GtkWidget *hbox;
        GtkWidget *vbox;
        GtkWidget *group;
+       GtkWidget *subgroup;
        GtkWidget *button;
        GtkWidget *ct_button;
        GtkWidget *spin;
@@ -2324,7 +2346,7 @@ static void config_tab_windows(GtkWidget *notebook)
 
        group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
 
-       ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
+       ct_button = pref_checkbox_new_int(group, _("Remember session"),
                                          options->save_window_positions, &c_options->save_window_positions);
 
        button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
@@ -2344,6 +2366,10 @@ static void config_tab_windows(GtkWidget *notebook)
        pref_checkbox_new_int(group, _("Show window IDs"),
                              options->show_window_ids, &c_options->show_window_ids);
 
+       subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
+       pref_label_new(subgroup, _("Use current layout for default: "));
+       button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
+
        group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
 
        pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
index 7f3d384..8c90aec 100644 (file)
@@ -699,12 +699,16 @@ gboolean save_config_to_file(const gchar *utf8_path, ConfOptions *options, Layou
        /* Layout Options */
        if (!lw)
                {
-               work = layout_window_list;
-               while (work)
+               /* If not save_window_positions, do not include a <layout> section */
+               if (options->save_window_positions)
                        {
-                       LayoutWindow *lw = work->data;
-                       layout_write_config(lw, outstr, indent);
-                       work = work->next;
+                       work = layout_window_list;
+                       while (work)
+                               {
+                               LayoutWindow *lw = work->data;
+                               layout_write_config(lw, outstr, indent);
+                               work = work->next;
+                               }
                        }
                }
        else
@@ -729,6 +733,57 @@ gboolean save_config_to_file(const gchar *utf8_path, ConfOptions *options, Layou
        return TRUE;
 }
 
+gboolean save_default_layout_options_to_file(const gchar *utf8_path, ConfOptions *options, LayoutWindow *lw)
+{
+       SecureSaveInfo *ssi;
+       gchar *rc_pathl;
+       GString *outstr;
+       gint indent = 0;
+
+       rc_pathl = path_from_utf8(utf8_path);
+       ssi = secure_open(rc_pathl);
+       g_free(rc_pathl);
+       if (!ssi)
+               {
+               log_printf(_("error saving default layout file: %s\n"), utf8_path);
+               return FALSE;
+               }
+
+       outstr = g_string_new("");
+       g_string_append_printf(outstr, "<!--\n");
+       g_string_append_printf(outstr, "######################################################################\n");
+       g_string_append_printf(outstr, "# %8s default layout file      version %-10s #\n", GQ_APPNAME, VERSION);
+       g_string_append_printf(outstr, "######################################################################\n");
+       WRITE_SEPARATOR();
+
+       WRITE_STRING("# Note: This file is autogenerated. Options can be changed here,\n");
+       WRITE_STRING("#       but user comments and formatting will be lost.\n");
+       WRITE_SEPARATOR();
+       WRITE_STRING("-->\n");
+       WRITE_SEPARATOR();
+
+       WRITE_STRING("<gq>\n");
+       indent++;
+
+       layout_write_config(lw, outstr, indent);
+
+       indent--;
+       WRITE_NL(); WRITE_STRING("</gq>\n");
+       WRITE_SEPARATOR();
+
+       secure_fputs(ssi, outstr->str);
+       g_string_free(outstr, TRUE);
+
+       if (secure_close(ssi))
+               {
+               log_printf(_("error saving config file: %s\nerror: %s\n"), utf8_path,
+                          secsave_strerror(secsave_errno));
+               return FALSE;
+               }
+
+       return TRUE;
+}
+
 /*
  *-----------------------------------------------------------------------------
  * loading attributes for elements (private)
index 919139b..4d873ba 100644 (file)
@@ -84,6 +84,7 @@ void options_parse_func_set_data(GQParserData *parser_data, gpointer data);
 
 
 gboolean save_config_to_file(const gchar *utf8_path, ConfOptions *options, LayoutWindow *lw);
+gboolean save_default_layout_options_to_file(const gchar *utf8_path, ConfOptions *options, LayoutWindow *lw);
 
 gboolean load_config_from_buf(const gchar *buf, gsize size, gboolean startup);
 gboolean load_config_from_file(const gchar *utf8_path, gboolean startup);
index 7149c3c..90030ac 100644 (file)
@@ -460,7 +460,8 @@ static void gr_new_window(const gchar *text, GIOChannel *channel, gpointer data)
 
        if (!layout_valid(&lw)) return;
 
-       lw_id = layout_menu_new_window(NULL, lw);
+       lw_id = layout_new_from_default();
+
        layout_set_path(lw_id, pwd);
 }