Fix #652: Automated cache maintenance
authorColin Clark <colin.clark@cclark.uk>
Fri, 20 Aug 2021 14:33:20 +0000 (15:33 +0100)
committerColin Clark <colin.clark@cclark.uk>
Fri, 20 Aug 2021 14:33:20 +0000 (15:33 +0100)
https://github.com/BestImageViewer/geeqie/issues/652

If geeqie is called with --cache-maintenance <path>, the GUI is not
loaded and the program behaves as a command line program.

It runs recursively to clean thumbnail data, and create thumbnails and
.sim files.

CODING.md
README.md
doc/docbook/GuideOtherSoftware.xml
doc/docbook/GuideReferenceCommandLine.xml
doc/docbook/GuideReferenceManagement.xml
geeqie.1
src/cache_maint.c
src/cache_maint.h
src/main.c
src/remote.c

index 2e57b8c..7a517e9 100644 (file)
--- a/CODING.md
+++ b/CODING.md
@@ -1,4 +1,4 @@
-[Log Window](#log-window)  
+[Error Logging](#error-logging)  
 [GPL header](#gpl-header)  
 [Git change log](#git-change-log)  
 [Sources](#sources)  
@@ -7,8 +7,8 @@
 -----------
 
 
-# <a name='log-window'>
-# Log Window
+# <a name='error-logging'>
+# Error Logging
 
 `DEBUG_0()`  
 Use `DEBUG_0()` only for temporary debugging i.e. not in code in the repository.
@@ -18,6 +18,12 @@ The user will then not see irrelevant debug output when the default
 `log_printf()`  
 If the first word of the message is "error" or "warning" (case insensitive) the message will be color-coded appropriately.
 
+ - Note that these messages are output in the idle loop.
+
+`print_term(gboolean err, const gchar *text_utf8)`
+
+- If `err` is TRUE output is to STDERR, otherwise to STDOUT
+
 
 `DEBUG_NAME(widget)`  
 For use with the [GTKInspector](https://wiki.gnome.org/action/show/Projects/GTK/Inspector?action=show&redirect=Projects%2FGTK%2B%2FInspector) to provide a visual indication of where objects are declared.
index 9f78709..779893f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -100,6 +100,8 @@ Animated GIFs are supported.
 
 * Maps from [OpenStreetMap](http://www.openstreetmap.org) may be displayed in a side panel. If an image has GPS coordinates embedded, its position will be displayed on the map - if Image Direction is encoded, that will be displayed also. If an image does not have embedded GPS coordinates, it may be dragged-and-dropped onto the map to encode its position.
 
+* Speed of operation can be increased by caching thumbnails and similarity data of images. When Geeqie is run as a stand-alone command line program (`geeqie --cache-maintenance <path>`) these data will be recursively created from the defined start point. This program can be called from `cron` or `anacron` so that cache updating is automatically done at specified intervals.
+
 # <a name="downloading"></a>
 ## Downloading
 
@@ -139,7 +141,7 @@ List compile options: `./autogen.sh --help`
 Common options:
 `./autogen.sh --disable-gtk3`,
 
-Compilation: `./autogen.sh [options]; make -j<no. of cpu cores> `
+Compilation: `./autogen.sh [options]; make -j`
 
 Install: `[sudo] make install`
 
index 52765dd..90647ee 100644 (file)
@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>\r
 <chapter id="GuideOtherSoftware">\r
-  <title id="titleGuideOtherSoftware">Other Software</title>\r
+  <title id="titleGuideOtherSoftware">Useful Software</title>\r
   <para>This is a list of other software that users might find useful in conjunction with Geeqie.</para>\r
+  <section id="OtherSoftware">\r
   <section id="Entangle">\r
     <title>Entangle</title>\r
     <para>\r
       <ulink url="https://photini.readthedocs.io/en/latest/">https://photini.readthedocs.io/en/latest/</ulink>\r
     </para>\r
   </section>\r
+  <section id="GeeqieCacheMaintenance">\r
+    <title>Geeqie Cache Maintenance</title>\r
+    <para>\r
+      Command line program to automatically create or update thumbnails and similarity data: <link linkend="CacheMaintenance"><code>geeqie-cache-maintenance</code></link>\r
+    </para>\r
+  </section>\r
+  <section id="KeywordMerge">\r
+    <title>Keyword Merge</title>\r
+    <para>\r
+       This program will merge the keyword tree of one Geeqie configuration file into another. The keyword trees are simply concatenated. When Geeqie loads the resulting configuration file, any duplicates are discarded: <ulink url="https://raw.githubusercontent.com/BestImageViewer/geeqie/master/scripts/keyword_merge.sh">keyword_merge.sh</ulink>\r
+    </para>\r
+  </section>\r
+  <section id="InstallDebian">\r
+    <title>Install Geeqie from sources on Debian</title>\r
+    <para>\r
+      This script will clone the Geeqie repository, fulfill all dependecies, and install Geeqie on a Debian based system: <ulink url="https://raw.githubusercontent.com/BestImageViewer/geeqie/master/web/geeqie-install-debian.sh">geeqie-install-debian.sh</ulink>\r
+    </para>\r
+  </section>\r
+  <section id="GenericInstall">\r
+    <title>Generic install script</title>\r
+    <para>\r
+      This script will install Geeqie to a defined location, and will run under any system. However, it is left to you to make sure dependencies are fulfilled: <ulink url="https://raw.githubusercontent.com/pixlsus/Scripts/master/build-geeqie">build-geeqie</ulink>\r
+    </para>\r
+  </section>\r
+  <section id="DecodeSim">\r
+    <title>Decoder for .sim files</title>\r
+    <para>\r
+      This program is unlikely to be of interest to most users. It shows a summary of the contents of a .sim file. (Requires perl to be installed): <ulink url="https://raw.githubusercontent.com/BestImageViewer/geeqie/master/scripts/decode_sim">decode_sim</ulink>\r
+    </para>\r
+  </section>\r
+  </section>\r
 </chapter>\r
index 4a72a0a..2f9ebbb 100644 (file)
           <entry>--disable-clutter</entry>\r
           <entry>Disable use of Clutter library (i.e. GPU accel.). If the Clutter library is compiled into Geeqie but Clutter fails to initialize, it is necessary to start Geeqie with this option.</entry>\r
         </row>\r
+        <row>\r
+          <entry />\r
+          <entry>--cache-maintenance &lt;path&gt;</entry>\r
+          <entry>\r
+            Run cache maintenance\r
+            <footnote id='cachemaintenance'>\r
+              <para><link linkend="CacheMaintenance">Cache Maintenance</link>.</para>\r
+            </footnote>\r
+            in non-GUI mode.\r
+          </entry>\r
+        </row>\r
       </tbody>\r
     </tgroup>\r
   </table>\r
index 073c3f9..0ca7d2f 100644 (file)
       </varlistentry>\r
     </variablelist>\r
   </section>\r
+  <section id="CacheMaintenance">\r
+    <title>Command line program</title>\r
+    <para>\r
+      Geeqie can be run as a command line program: <code>geeqie --cache-maintenance &lt;path&gt;</code>. It will recursively remove orphaned thumbnails, and create thumbnails and similarity data for all images found.\r
+    <para/>\r
+      It may also be called from <code>cron</code> or <code>anacron</code> thus enabling automatic updating of the cached data for all your images.\r
+    </para>\r
+  </section>\r
 </section>\r
index 828239e..430b266 100644 (file)
--- a/geeqie.1
+++ b/geeqie.1
@@ -89,6 +89,10 @@ Print command line options.
 .B
 .IP \-\-disable-clutter
 Disable use of Clutter library (i.e. GPU accel.).
+.br
+.B
+.IP \-\-cache-maintenance\ <path>
+Run cache maintenance in non-GUI mode.
 
 .SH REMOTE OPTIONS
 .B
index d76ee8c..04b8bd5 100644 (file)
@@ -26,6 +26,7 @@
 #include "cache-loader.h"
 #include "filedata.h"
 #include "layout.h"
+#include "pixbuf_util.h"
 #include "thumb.h"
 #include "thumb_standard.h"
 #include "ui_fileops.h"
@@ -54,6 +55,65 @@ struct _CMData
 
 #define PURGE_DIALOG_WIDTH 400
 
+/*
+ *-----------------------------------------------------------------------------
+ * Command line cache maintenance program functions *-----------------------------------------------------------------------------
+ */
+static gchar *cache_maintenance_path = NULL;
+static GtkStatusIcon *status_icon;
+
+static void cache_maintenance_sim_stop_cb(gpointer data)
+{
+       exit(EXIT_SUCCESS);
+}
+
+static void cache_maintenance_render_stop_cb(gpointer data)
+{
+       gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating sim data..."));
+       cache_manager_sim_remote(cache_maintenance_path, TRUE, (GDestroyNotify *)cache_maintenance_sim_stop_cb);
+}
+
+static void cache_maintenance_clean_stop_cb(gpointer data)
+{
+       gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Creating thumbs..."));
+       cache_manager_render_remote(cache_maintenance_path, TRUE, options->thumbnails.cache_into_dirs, (GDestroyNotify *)cache_maintenance_render_stop_cb);
+}
+
+static void cache_maintenance_user_cancel_cb()
+{
+       exit(EXIT_FAILURE);
+}
+
+static void cache_maintenance_status_icon_activate_cb(GtkStatusIcon *status, gpointer data)
+{
+       GtkWidget *menu;
+       GtkWidget *item;
+
+       menu = gtk_menu_new();
+
+       item = gtk_menu_item_new_with_label("Exit Geeqie Cache Maintenance");
+
+       g_signal_connect(G_OBJECT(item), "activate", cache_maintenance_user_cancel_cb, item);
+       gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+       gtk_widget_show(item);
+
+       /* take ownership of menu */
+       g_object_ref_sink(G_OBJECT(menu));
+
+       gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
+}
+
+void cache_maintenance(const gchar *path)
+{
+       cache_maintenance_path = g_strdup(path);
+
+       status_icon = gtk_status_icon_new_from_pixbuf(pixbuf_inline(PIXBUF_INLINE_ICON));
+       gtk_status_icon_set_tooltip_text(status_icon, _("Geeqie: Cleaning thumbs..."));
+       gtk_status_icon_set_visible(status_icon, TRUE);
+       g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(cache_maintenance_status_icon_activate_cb), NULL);
+
+       cache_maintain_home_remote(FALSE, FALSE, (GDestroyNotify *)cache_maintenance_clean_stop_cb);
+}
 
 /*
  *-------------------------------------------------------------------
@@ -355,7 +415,15 @@ void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent)
        cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
 }
 
-void cache_maintain_home_remote(gboolean metadata, gboolean clear)
+/**
+ * @brief Clears or culls cached data
+ * @param metadata TRUE - work on metadata cache, FALSE - work on thumbnail cache
+ * @param clear TRUE - clear cache, FALSE - delete orphaned cached items
+ * @param func Function called when idle loop function terminates
+ * 
+ * 
+ */
+void cache_maintain_home_remote(gboolean metadata, gboolean clear, GDestroyNotify *func)
 {
        CMData *cm;
        GList *dlist;
@@ -387,7 +455,7 @@ void cache_maintain_home_remote(gboolean metadata, gboolean clear)
        cm->metadata = metadata;
        cm->remote = TRUE;
 
-       cm->idle_id = g_idle_add(cache_maintain_home_cb, cm);
+       cm->idle_id = g_idle_add_full(G_PRIORITY_LOW, cache_maintain_home_cb, cm, (GDestroyNotify)func);
 }
 
 static void cache_file_move(const gchar *src, const gchar *dest)
@@ -556,6 +624,7 @@ struct _CacheOpsData
        GenericDialog *gd;
        ThumbLoaderStd *tl;
        CacheLoader *cl;
+       GDestroyNotify *destroy_func; /* Used by the command line prog. functions */
 
        GList *list;
        GList *list_dir;
@@ -713,9 +782,17 @@ static gboolean cache_manager_render_file(CacheOpsData *cd)
                return TRUE;
                }
 
-       gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
+       if (!cd->remote)
+               {
+               gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
+               }
        cache_manager_render_finish(cd);
 
+       if (cd->destroy_func)
+               {
+               g_idle_add((GSourceFunc)cd->destroy_func, NULL);
+               }
+
        return FALSE;
 }
 
@@ -861,7 +938,16 @@ static void cache_manager_render_dialog(GtkWidget *widget, const gchar *path)
        gtk_widget_show(cd->gd->dialog);
 }
 
-void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local)
+/**
+ * @brief Create thumbnails
+ * @param path Path to image folder
+ * @param recurse 
+ * @param local Create thumbnails in same folder as images
+ * @param func Function called when idle loop function terminates
+ * 
+ * 
+ */
+void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local, GDestroyNotify *func)
 {
        CacheOpsData *cd;
 
@@ -869,6 +955,7 @@ void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean l
        cd->recurse = recurse;
        cd->local = local;
        cd->remote = TRUE;
+       cd->destroy_func = func;
 
        cache_manager_render_start_render_remote(cd, path);
 }
@@ -1285,6 +1372,50 @@ static void cache_manager_sim_file_done_cb(CacheLoader *cl, gint error, gpointer
        while (cache_manager_sim_file(cd));
 }
 
+static void cache_manager_sim_start_sim_remote(CacheOpsData *cd, const gchar *user_path)
+{
+       gchar *path;
+
+       path = remove_trailing_slash(user_path);
+       parse_out_relatives(path);
+
+       if (!isdir(path))
+               {
+               log_printf("The specified folder can not be found: %s\n", path);
+               }
+       else
+               {
+               FileData *dir_fd;
+
+               dir_fd = file_data_new_dir(path);
+               cache_manager_sim_folder(cd, dir_fd);
+               file_data_unref(dir_fd);
+               while (cache_manager_sim_file(cd));
+               }
+
+       g_free(path);
+}
+
+/**
+ * @brief Generate .sim files
+ * @param path Path to image folder
+ * @param recurse 
+ * @param func Function called when idle loop function terminates
+ * 
+ * 
+ */
+void cache_manager_sim_remote(const gchar *path, gboolean recurse, GDestroyNotify *func)
+{
+       CacheOpsData *cd;
+
+       cd = g_new0(CacheOpsData, 1);
+       cd->recurse = recurse;
+       cd->remote = TRUE;
+       cd->destroy_func = func;
+
+       cache_manager_sim_start_sim_remote(cd, path);
+}
+
 static gboolean cache_manager_sim_file(CacheOpsData *cd)
 {
        CacheDataType load_mask;
@@ -1298,11 +1429,17 @@ static gboolean cache_manager_sim_file(CacheOpsData *cd)
                load_mask = CACHE_LOADER_DIMENSIONS | CACHE_LOADER_DATE | CACHE_LOADER_MD5SUM | CACHE_LOADER_SIMILARITY;
                cd->cl = (CacheLoader *)cache_loader_new(fd, load_mask, (cache_manager_sim_file_done_cb), cd);
 
-               gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
+               if (!cd->remote)
+                       {
+                       gtk_entry_set_text(GTK_ENTRY(cd->progress), fd->path);
+                       }
 
                file_data_unref(fd);
                cd->count_done = cd->count_done + 1;
-               gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), (gdouble)cd->count_done / cd->count_total);
+               if (!cd->remote)
+                       {
+                       gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(cd->progress_bar), (gdouble)cd->count_done / cd->count_total);
+                       }
 
                return FALSE;
                }
@@ -1319,9 +1456,18 @@ static gboolean cache_manager_sim_file(CacheOpsData *cd)
                return TRUE;
                }
 
-       gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
+               if (!cd->remote)
+                       {
+                       gtk_entry_set_text(GTK_ENTRY(cd->progress), _("done"));
+                       }
+
        cache_manager_sim_finish((CacheOpsData *)cd);
 
+       if (cd->destroy_func)
+               {
+               g_idle_add((GSourceFunc)cd->destroy_func, NULL);
+               }
+
        return FALSE;
 }
 
index d839496..816d39b 100644 (file)
@@ -27,8 +27,10 @@ void cache_maintain_home(gboolean metadata, gboolean clear, GtkWidget *parent);
 void cache_notify_cb(FileData *fd, NotifyType type, gpointer data);
 void cache_manager_show(void);
 
-void cache_maintain_home_remote(gboolean metadata, gboolean clear);
+void cache_maintain_home_remote(gboolean metadata, gboolean clear, GDestroyNotify *func);
 void cache_manager_standard_process_remote(gboolean clear);
-void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local);
+void cache_manager_render_remote(const gchar *path, gboolean recurse, gboolean local, GDestroyNotify *func);
+void cache_manager_sim_remote(const gchar *path, gboolean recurse, GDestroyNotify *func);
+void cache_maintenance(const gchar *path);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index 57e17f6..6b19d98 100644 (file)
@@ -605,7 +605,8 @@ static void parse_command_line(gint argc, gchar *argv[])
                                print_term(FALSE, _("  -o:<file>, --log-file:<file>     save log data to file\n"));
                                print_term(FALSE, _("  -v, --version                    print version info\n"));
                                print_term(FALSE, _("  -h, --help                       show this message\n"));
-                               print_term(FALSE, _("      --disable-clutter            disable use of Clutter library (i.e. GPU accel.)\n\n"));
+                               print_term(FALSE, _("      --disable-clutter            disable use of Clutter library (i.e. GPU accel.)\n"));
+                               print_term(FALSE, _("      --cache-maintenance <path>   run cache maintenance in non-GUI mode\n\n"));
 
 #if 0
                                /* these options are not officially supported!
@@ -799,6 +800,95 @@ static gboolean parse_command_line_for_clutter_option(gint argc, gchar *argv[])
 }
 #endif
 
+static gboolean parse_command_line_for_cache_maintenance_option(gint argc, gchar *argv[])
+{
+       const gchar *cache_maintenance_option = "--cache-maintenance";
+       gint len = strlen(cache_maintenance_option);
+       gboolean ret = FALSE;
+
+       if (argc >= 2)
+               {
+               const gchar *cmd_line = argv[1];
+               if (strncmp(cmd_line, cache_maintenance_option, len) == 0)
+                       {
+                       ret = TRUE;
+                       }
+               }
+
+       return ret;
+}
+
+static void process_command_line_for_cache_maintenance_option(gint argc, gchar *argv[])
+{
+       gchar *rc_path;
+       gchar *folder_path = NULL;
+       gsize size;
+       gsize i = 0;
+       gchar *buf_config_file;
+       gint diff_count;
+
+       if (argc >= 3)
+               {
+               folder_path = expand_tilde(argv[2]);
+
+               if (isdir(folder_path))
+                       {
+                       rc_path = g_build_filename(get_rc_dir(), RC_FILE_NAME, NULL);
+
+                       if (isfile(rc_path))
+                               {
+                               if (g_file_get_contents(rc_path, &buf_config_file, &size, NULL))
+                                       {
+                                       while (i < size)
+                                               {
+                                               diff_count = strncmp("</global>", &buf_config_file[i], 9);
+                                               if (diff_count == 0)
+                                                       {
+                                                       break;
+                                                       }
+                                               i++;
+                                               }
+                                       /* Load only the <global> section */
+                                       load_config_from_buf(buf_config_file, i + 9, FALSE);
+
+                                       if (options->thumbnails.enable_caching)
+                                               {
+                                               cache_maintenance(folder_path);
+                                               }
+                                       else
+                                               {
+                                               print_term(TRUE, "Caching not enabled\n");
+                                               exit(EXIT_FAILURE);
+                                               }
+                                       g_free(buf_config_file);
+                                       }
+                               else
+                                       {
+                                       print_term(TRUE, g_strconcat(_("Cannot load "), rc_path, "\n", NULL));
+                                       exit(EXIT_FAILURE);
+                                       }
+                               }
+                       else
+                               {
+                               print_term(TRUE, g_strconcat(_("Configuration file path "), rc_path, _(" is not a file\n"), NULL));
+                               exit(EXIT_FAILURE);
+                               }
+                       g_free(rc_path);
+                       }
+               else
+                       {
+                       print_term(TRUE, g_strconcat(argv[2], _(" is not a folder\n"), NULL));
+                       exit(EXIT_FAILURE);
+                       }
+               g_free(folder_path);
+               }
+       else
+               {
+               print_term(TRUE, _("No path parameter given\n"));
+               exit(EXIT_FAILURE);
+               }
+}
+
 /*
  *-----------------------------------------------------------------------------
  * startup, init, and exit
@@ -1257,9 +1347,6 @@ gint main(gint argc, gchar *argv[])
                options->disable_gpu = TRUE;
                }
 
-       DEBUG_1("%s main: parse_command_line", get_exec_time());
-       parse_command_line(argc, argv);
-
        DEBUG_1("%s main: mkdir_if_not_exists", get_exec_time());
        /* these functions don't depend on config file */
        mkdir_if_not_exists(get_rc_dir());
@@ -1270,185 +1357,195 @@ gint main(gint argc, gchar *argv[])
 
        setup_env_path();
 
-       keys_load();
-       accel_map_load();
+       if (parse_command_line_for_cache_maintenance_option(argc, argv))
+               {
+               process_command_line_for_cache_maintenance_option(argc, argv);
+               }
+       else
+               {
+               DEBUG_1("%s main: parse_command_line", get_exec_time());
+               parse_command_line(argc, argv);
 
-       /* restore session from the config file */
+               keys_load();
+               accel_map_load();
 
+               /* restore session from the config file */
 
-       DEBUG_1("%s main: load_options", get_exec_time());
-       if (!load_options(options))
-               {
-               /* load_options calls these functions after it parses global options, we have to call it here if it fails */
-               filter_add_defaults();
-               filter_rebuild();
-               }
 
-#ifdef HAVE_CLUTTER
-/** @FIXME For the background of this see:
- * https://github.com/BestImageViewer/geeqie/issues/397
- * The feature CLUTTER_FEATURE_SWAP_EVENTS indictates if the
- * system is liable to exhibit this problem.
- * The user is provided with an override in Preferences/Behavior
- */
-       if (!options->override_disable_gpu && !options->disable_gpu)
-               {
-               DEBUG_1("CLUTTER_FEATURE_SWAP_EVENTS %d",clutter_feature_available(CLUTTER_FEATURE_SWAP_EVENTS));
-               if (clutter_feature_available(CLUTTER_FEATURE_SWAP_EVENTS) != 0)
+               DEBUG_1("%s main: load_options", get_exec_time());
+               if (!load_options(options))
                        {
-                       options->disable_gpu = TRUE;
+                       /* load_options calls these functions after it parses global options, we have to call it here if it fails */
+                       filter_add_defaults();
+                       filter_rebuild();
                        }
-               }
-#endif
-
-       /* handle missing config file and commandline additions*/
-       if (!layout_window_list)
-               {
-               /* broken or no config file or no <layout> section */
-               layout_new_from_default();
-               }
-
-       layout_editors_reload_start();
 
-       /* If no --list option, open a separate collection window for each
-        * .gqv file on the command line
+       #ifdef HAVE_CLUTTER
+       /** @FIXME For the background of this see:
+        * https://github.com/BestImageViewer/geeqie/issues/397
+        * The feature CLUTTER_FEATURE_SWAP_EVENTS indictates if the
+        * system is liable to exhibit this problem.
+        * The user is provided with an override in Preferences/Behavior
         */
-       if (command_line->collection_list && !command_line->startup_command_line_collection)
-               {
-               GList *work;
+               if (!options->override_disable_gpu && !options->disable_gpu)
+                       {
+                       DEBUG_1("CLUTTER_FEATURE_SWAP_EVENTS %d",clutter_feature_available(CLUTTER_FEATURE_SWAP_EVENTS));
+                       if (clutter_feature_available(CLUTTER_FEATURE_SWAP_EVENTS) != 0)
+                               {
+                               options->disable_gpu = TRUE;
+                               }
+                       }
+       #endif
 
-               work = command_line->collection_list;
-               while (work)
+               /* handle missing config file and commandline additions*/
+               if (!layout_window_list)
                        {
-                       CollectWindow *cw;
-                       const gchar *path;
+                       /* broken or no config file or no <layout> section */
+                       layout_new_from_default();
+                       }
 
-                       path = work->data;
-                       work = work->next;
+               layout_editors_reload_start();
 
-                       cw = collection_window_new(path);
-                       if (!first_collection && cw) first_collection = cw->cd;
-                       }
-               }
+               /* If no --list option, open a separate collection window for each
+                * .gqv file on the command line
+                */
+               if (command_line->collection_list && !command_line->startup_command_line_collection)
+                       {
+                       GList *work;
 
-       if (command_line->log_file)
-               {
-               gchar *pathl;
-               gchar *path = g_strdup(command_line->log_file);
+                       work = command_line->collection_list;
+                       while (work)
+                               {
+                               CollectWindow *cw;
+                               const gchar *path;
 
-               pathl = path_from_utf8(path);
-               command_line->ssi = secure_open(pathl);
-               }
+                               path = work->data;
+                               work = work->next;
 
-       /* If there is a files list on the command line and no --list option,
-        * check if they are all in the same folder
-        */
-       if (command_line->cmd_list && !(command_line->startup_command_line_collection))
-               {
-               GList *work;
-               gchar *path = NULL;
+                               cw = collection_window_new(path);
+                               if (!first_collection && cw) first_collection = cw->cd;
+                               }
+                       }
 
-               work = command_line->cmd_list;
+               if (command_line->log_file)
+                       {
+                       gchar *pathl;
+                       gchar *path = g_strdup(command_line->log_file);
 
-               while (work && single_dir)
+                       pathl = path_from_utf8(path);
+                       command_line->ssi = secure_open(pathl);
+                       }
+
+               /* If there is a files list on the command line and no --list option,
+                * check if they are all in the same folder
+                */
+               if (command_line->cmd_list && !(command_line->startup_command_line_collection))
                        {
-                       gchar *dirname;
+                       GList *work;
+                       gchar *path = NULL;
 
-                       dirname = g_path_get_dirname(work->data);
-                       if (!path)
-                               {
-                               path = g_strdup(dirname);
-                               }
-                       else
+                       work = command_line->cmd_list;
+
+                       while (work && single_dir)
                                {
-                               if (g_strcmp0(path, dirname) != 0)
+                               gchar *dirname;
+
+                               dirname = g_path_get_dirname(work->data);
+                               if (!path)
                                        {
-                                       single_dir = FALSE;
+                                       path = g_strdup(dirname);
                                        }
+                               else
+                                       {
+                                       if (g_strcmp0(path, dirname) != 0)
+                                               {
+                                               single_dir = FALSE;
+                                               }
+                                       }
+                               g_free(dirname);
+                               work = work->next;
                                }
-                       g_free(dirname);
-                       work = work->next;
+                       g_free(path);
                        }
-               g_free(path);
-               }
-
-       /* Files from multiple folders, or --list option given
-        * then open an unnamed collection and insert all files
-        */
-       if ((command_line->cmd_list && !single_dir) || (command_line->startup_command_line_collection && command_line->cmd_list))
-               {
-               GList *work;
-               CollectWindow *cw;
 
-               cw = collection_window_new(NULL);
-               cd = cw->cd;
+               /* Files from multiple folders, or --list option given
+                * then open an unnamed collection and insert all files
+                */
+               if ((command_line->cmd_list && !single_dir) || (command_line->startup_command_line_collection && command_line->cmd_list))
+                       {
+                       GList *work;
+                       CollectWindow *cw;
 
-               collection_path_changed(cd);
+                       cw = collection_window_new(NULL);
+                       cd = cw->cd;
 
-               work = command_line->cmd_list;
-               while (work)
-                       {
-                       FileData *fd;
+                       collection_path_changed(cd);
 
-                       fd = file_data_new_simple(work->data);
-                       collection_add(cd, fd, FALSE);
-                       file_data_unref(fd);
-                       work = work->next;
-                       }
+                       work = command_line->cmd_list;
+                       while (work)
+                               {
+                               FileData *fd;
 
-               work = command_line->collection_list;
-               while (work)
-                       {
-                       collection_load(cd, (gchar *)work->data, COLLECTION_LOAD_APPEND);
-                       work = work->next;
-                       }
+                               fd = file_data_new_simple(work->data);
+                               collection_add(cd, fd, FALSE);
+                               file_data_unref(fd);
+                               work = work->next;
+                               }
 
-               if (cd->list) layout_image_set_collection(NULL, cd, cd->list->data);
+                       work = command_line->collection_list;
+                       while (work)
+                               {
+                               collection_load(cd, (gchar *)work->data, COLLECTION_LOAD_APPEND);
+                               work = work->next;
+                               }
 
-               /* mem leak, we never unref this collection when !startup_command_line_collection
-                * (the image view of the main window does not hold a ref to the collection)
-                * this is sort of unavoidable, for if it did hold a ref, next/back
-                * may not work as expected when closing collection windows.
-                *
-                * collection_unref(cd);
-                */
+                       if (cd->list) layout_image_set_collection(NULL, cd, cd->list->data);
 
-               }
-       else if (first_collection)
-               {
-               layout_image_set_collection(NULL, first_collection,
-                                           collection_get_first(first_collection));
-               }
+                       /* mem leak, we never unref this collection when !startup_command_line_collection
+                        * (the image view of the main window does not hold a ref to the collection)
+                        * this is sort of unavoidable, for if it did hold a ref, next/back
+                        * may not work as expected when closing collection windows.
+                        *
+                        * collection_unref(cd);
+                        */
 
-       /* If the files on the command line are from one folder, select those files
-        * unless it is a command line collection - then leave focus on collection window
-        */
-       lw = NULL;
-       layout_valid(&lw);
+                       }
+               else if (first_collection)
+                       {
+                       layout_image_set_collection(NULL, first_collection,
+                                                   collection_get_first(first_collection));
+                       }
 
-       if (single_dir && command_line->cmd_list && !command_line->startup_command_line_collection)
-               {
-               GList *work;
-               GList *selected;
-               FileData *fd;
+               /* If the files on the command line are from one folder, select those files
+                * unless it is a command line collection - then leave focus on collection window
+                */
+               lw = NULL;
+               layout_valid(&lw);
 
-               selected = NULL;
-               work = command_line->cmd_list;
-               while (work)
+               if (single_dir && command_line->cmd_list && !command_line->startup_command_line_collection)
                        {
-                       fd = file_data_new_simple((gchar *)work->data);
-                       selected = g_list_append(selected, fd);
-                       file_data_unref(fd);
-                       work = work->next;
+                       GList *work;
+                       GList *selected;
+                       FileData *fd;
+
+                       selected = NULL;
+                       work = command_line->cmd_list;
+                       while (work)
+                               {
+                               fd = file_data_new_simple((gchar *)work->data);
+                               selected = g_list_append(selected, fd);
+                               file_data_unref(fd);
+                               work = work->next;
+                               }
+                       layout_select_list(lw, selected);
                        }
-               layout_select_list(lw, selected);
-               }
 
-       buf = g_build_filename(get_rc_dir(), ".command", NULL);
-       remote_connection = remote_server_init(buf, cd);
-       g_free(buf);
+               buf = g_build_filename(get_rc_dir(), ".command", NULL);
+               remote_connection = remote_server_init(buf, cd);
+               g_free(buf);
 
-       marks_load();
+               marks_load();
+       }
 
        DEBUG_1("%s main: gtk_main", get_exec_time());
        gtk_main();
index 90030ac..a6b66fa 100644 (file)
@@ -541,9 +541,13 @@ static void gr_slideshow_start_rec(const gchar *text, GIOChannel *channel, gpoin
 static void gr_cache_thumb(const gchar *text, GIOChannel *channel, gpointer data)
 {
        if (!g_strcmp0(text, "clear"))
-               cache_maintain_home_remote(FALSE, TRUE);
+               {
+               cache_maintain_home_remote(FALSE, TRUE, NULL);
+               }
        else if (!g_strcmp0(text, "clean"))
-               cache_maintain_home_remote(FALSE, FALSE);
+               {
+               cache_maintain_home_remote(FALSE, FALSE, NULL);
+               }
 }
 
 static void gr_cache_shared(const gchar *text, GIOChannel *channel, gpointer data)
@@ -556,29 +560,33 @@ static void gr_cache_shared(const gchar *text, GIOChannel *channel, gpointer dat
 
 static void gr_cache_metadata(const gchar *text, GIOChannel *channel, gpointer data)
 {
-       cache_maintain_home_remote(TRUE, FALSE);
+       cache_maintain_home_remote(TRUE, FALSE, NULL);
 }
 
 static void gr_cache_render(const gchar *text, GIOChannel *channel, gpointer data)
 {
-       cache_manager_render_remote(text, FALSE, FALSE);
+       cache_manager_render_remote(text, FALSE, FALSE, NULL);
 }
 
 static void gr_cache_render_recurse(const gchar *text, GIOChannel *channel, gpointer data)
 {
-       cache_manager_render_remote(text, TRUE, FALSE);
+       cache_manager_render_remote(text, TRUE, FALSE, NULL);
 }
 
 static void gr_cache_render_standard(const gchar *text, GIOChannel *channel, gpointer data)
 {
        if(options->thumbnails.spec_standard)
-               cache_manager_render_remote(text, FALSE, TRUE);
+               {
+               cache_manager_render_remote(text, FALSE, TRUE, NULL);
+               }
 }
 
 static void gr_cache_render_standard_recurse(const gchar *text, GIOChannel *channel, gpointer data)
 {
        if(options->thumbnails.spec_standard)
-               cache_manager_render_remote(text, TRUE, TRUE);
+               {
+               cache_manager_render_remote(text, TRUE, TRUE, NULL);
+               }
 }
 
 static void gr_slideshow_toggle(const gchar *text, GIOChannel *channel, gpointer data)