Create AppImages
authorColin Clark <colin.clark@cclark.uk>
Sun, 13 Jun 2021 10:44:42 +0000 (11:44 +0100)
committerColin Clark <colin.clark@cclark.uk>
Sun, 13 Jun 2021 10:44:42 +0000 (11:44 +0100)
Change fixed paths to relative paths so that AppImages can be created.

Include documentation of how to create an AppImage, and a sample shell
script.

12 files changed:
README.md
appimages/README.md [new file with mode: 0644]
configure.ac
scripts/generate-appimage.sh [new file with mode: 0755]
src/desktop_file.c
src/editors.c
src/layout_util.c
src/main.c
src/main.h
src/misc.c
src/preferences.c
src/window.c

index 4ef910c..35d2ec4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -103,7 +103,15 @@ Animated GIFs are supported.
 # <a name="downloading"></a>
 ## Downloading
 
-Geeqie is available as a package with some distributions, however Geeqie is stable and you may compile the latest version from sources.
+Geeqie is available:  
+
+* as a package with some distributions.
+
+* as a [flatpak](https://flathub.org/apps/details/org.geeqie.Geeqie) from the [Flathub site](https://flathub.org/home).
+
+* as an [AppImage](https://cclark.uk/Geeqie).
+
+However Geeqie is stable and you may compile the latest version from sources.
 
 There are two scripts which will download and compile the sources for you.
 
@@ -122,8 +130,6 @@ Either: `git clone git://www.geeqie.org/geeqie.git`
 
 Or: `git clone http://www.geeqie.org/git/geeqie.git`
 
-Also [Geeqie is available as a flatpak](https://flathub.org/apps/details/org.geeqie.Geeqie) from the [Flathub site](https://flathub.org/home).
-
 ## Manual Installation
 
 List compile options: `./autogen.sh --help`
diff --git a/appimages/README.md b/appimages/README.md
new file mode 100644 (file)
index 0000000..778ecb7
--- /dev/null
@@ -0,0 +1,47 @@
+# How to create AppImages for Geeqie
+
+## Download the required tools:
+
+Download the `linuxdeploy` tool. At the time of writing, this is:  
+
+`wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage`
+
+
+Move this file to `$HOME/bin` or somewhere else in your `$PATH` and make executable.
+
+
+## Generate the executable
+
+`cd <your working area>`
+
+Download Geeqie sources:  
+`git clone git://www.geeqie.org/geeqie.git`  
+`cd geeqie`  
+
+If a run has already been made, remove any existing targets:  
+`rm -r  <target dir>/AppDir`  
+`sudo rm -rf doc/html`  
+
+Create a fresh target directory:  
+`mkdir <target dir>/AppDir`
+
+Generate the Geeqie executable:  
+`sudo make maintainer-clean`  
+`./autogen.sh --prefix="/usr/"`  
+`make -j`  
+`make install DESTDIR=<full path to target dir>/AppDir`  
+
+## Generate the AppImage
+
+`cd <target dir>`  
+`linuxdeploy-x86_64.AppImage \`  
+`--appdir ./AppDir --output appimage \`  
+`--desktop-file ./AppDir/usr/share/applications/geeqie.desktop \`  
+`--icon-file ./AppDir/usr/share/pixmaps/geeqie.png \`  
+`--executable ./AppDir/usr/bin/geeqie`  
+
+## Rename AppImage
+If required, rename the AppImage executable - e.g.:  
+`mv ./Geeqie-v1.6-x86_64.AppImage $(./Geeqie-v1.6-x86_64.AppImage -v | sed 's/git//' | sed 's/-.* /-/' | sed 's/ /-v/' | sed 's/-GTK3//').AppImage`
+
+The script `./scripts/generate-appimage.sh` automates this process.
index 799128b..21e91dd 100644 (file)
@@ -376,7 +376,7 @@ AC_ARG_ENABLE([raw],
     [libraw=$enableval], [libraw=auto])
 
 if test "x${libraw}" != "xno"; then
-  PKG_CHECK_MODULES(RAW, [libraw >= 0.20],
+  PKG_CHECK_MODULES(RAW, [libraw >= 0.19.5],
     [
       HAVE_RAW=yes
       AC_DEFINE(HAVE_RAW, 1, [define to enable libraw support])
diff --git a/scripts/generate-appimage.sh b/scripts/generate-appimage.sh
new file mode 100755 (executable)
index 0000000..bd24820
--- /dev/null
@@ -0,0 +1,65 @@
+#! /bin/bash
+#**********************************************************************
+# Copyright (C) 2021 - The Geeqie Team
+#
+# Author: Colin Clark
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#**********************************************************************
+#
+# This script will generate a Geeqie AppImage.
+#
+# It must be run from the base Geeqie folder.
+# The single parameter is the directory where the AppDir
+# will be created.
+#
+#**********************************************************************
+
+
+if [[ ! -f geeqie.spec.in ]] || [[ ! -d .git ]]
+then
+       echo "This is not a Geeqie folder"
+       exit 1
+fi
+
+target_dir=$(realpath $1)
+
+if [[ $? -ne 0 ]]
+then
+       echo "No target dir specified"
+       exit 1
+fi
+
+rm -rf "$target_dir"/AppDir
+mkdir "$target_dir"/Appdir
+
+sudo rm -rf doc/html
+
+sudo make maintainer-clean
+./autogen.sh --prefix="/usr/"
+make -j
+make install DESTDIR="$target_dir"/AppDir
+
+export VERSION=$(git tag | tail -1)
+
+cd $target_dir
+
+linuxdeploy-x86_64.AppImage \
+--appdir ./AppDir --output appimage \
+--desktop-file ./AppDir/usr/share/applications/geeqie.desktop \
+--icon-file ./AppDir/usr/share/pixmaps/geeqie.png \
+--executable ./AppDir/usr/bin/geeqie
+
+mv ./Geeqie-$VERSION-x86_64.AppImage $(./Geeqie-$VERSION-x86_64.AppImage -v | sed 's/git//' | sed 's/-.* /-/' | sed 's/ /-v/' | sed 's/-GTK3//').AppImage
index 4142666..c74cc88 100644 (file)
@@ -381,7 +381,7 @@ static void editor_list_window_edit_cb(GtkWidget *widget, gpointer data)
 
 static void editor_list_window_new_cb(GtkWidget *widget, gpointer data)
 {
-       editor_window_new(DESKTOP_FILE_TEMPLATE, _("new.desktop"));
+       editor_window_new(desktop_file_template, _("new.desktop"));
 }
 
 static void editor_list_window_help_cb(GtkWidget *widget, gpointer data)
index b2ce46d..902e736 100644 (file)
@@ -458,7 +458,7 @@ GList *editor_get_desktop_files(void)
        else
                xdg_data_dirs = g_strdup("/usr/share");
 
-       all_dirs = g_strconcat(get_rc_dir(), ":", GQ_APP_DIR, ":", xdg_data_home_get(), ":", xdg_data_dirs, NULL);
+       all_dirs = g_strconcat(get_rc_dir(), ":", gq_app_dir, ":", xdg_data_home_get(), ":", xdg_data_dirs, NULL);
 
        g_free(xdg_data_dirs);
 
index 42b49c4..d4dc6eb 100644 (file)
@@ -602,7 +602,7 @@ static void layout_menu_write_rotate(GtkToggleAction *action, gpointer data, gbo
                        }
 
                rotation = g_strdup_printf("%d", fd_n->user_orientation);
-               command = g_strconcat(GQ_BIN_DIR, "/geeqie-rotate -r ", rotation,
+               command = g_strconcat(gq_bin_dir, "/geeqie-rotate -r ", rotation,
                                                                keep_date ? " -t \"" : " \"", fd_n->path, "\"", NULL);
                cmdstatus = runcmd(command);
                run_result = WEXITSTATUS(cmdstatus);
index 14c0a7f..a70b7fa 100644 (file)
 gboolean thumb_format_changed = FALSE;
 static RemoteConnection *remote_connection = NULL;
 
+gchar *gq_prefix;
+gchar *gq_localedir;
+gchar *gq_helpdir;
+gchar *gq_htmldir;
+gchar *gq_app_dir;
+gchar *gq_bin_dir;
+gchar *desktop_file_template;
+
 /*
  *-----------------------------------------------------------------------------
  * keyboard functions
@@ -609,7 +617,7 @@ static gboolean parse_command_line_for_clutter_option(gint argc, gchar *argv[])
 static void setup_env_path(void)
 {
        const gchar *old_path = g_getenv("PATH");
-       gchar *path = g_strconcat(GQ_BIN_DIR, ":", old_path, NULL);
+       gchar *path = g_strconcat(gq_bin_dir, ":", old_path, NULL);
         g_setenv("PATH", path, TRUE);
        g_free(path);
 }
@@ -921,6 +929,46 @@ static void setup_sigbus_handler(void)
 #endif
 }
 
+/**
+ * @brief Set up the application paths
+ * 
+ * This function is required for use of AppImages. AppImages are
+ * relocatable, and therefore cannot use fixed paths to various components.
+ * These paths were originally #defines created during compilation.
+ * They are now variables, all defined relative to one level above the
+ * directory that the executable is run from.
+ */
+static void create_application_paths()
+{
+       gchar buf[1024];
+       gchar *dirname;
+       gchar *basename;
+       gchar *tmp;
+
+       memset(buf, 0, sizeof(buf));
+       if (readlink("/proc/self/exe", buf, sizeof(buf) - 1) < 0)
+               {
+               /* There was an error. Perhaps the path does not exist
+                * or the buffer is not big enough. */
+               log_printf("Can't get path from /proc/self/exe");
+               exit(1);
+               }
+
+       dirname = g_path_get_dirname(buf); // default is /usr/bin/
+       gq_prefix = g_path_get_dirname(dirname);
+
+       gq_localedir = g_build_filename(gq_prefix, "share", "locale", NULL);
+       tmp = g_build_filename(gq_prefix, "share", "doc", NULL);
+       gq_helpdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, "geeqie-", VERSION, NULL);
+       gq_htmldir = g_build_filename(gq_helpdir, "html", NULL);
+       gq_app_dir = g_build_filename(gq_prefix, "share", "geeqie", NULL);
+       gq_bin_dir = g_build_filename(gq_prefix, "lib", "geeqie", NULL);
+       desktop_file_template = g_build_filename(gq_app_dir, "template.desktop", NULL);
+
+       g_free(tmp);
+       g_free(dirname);
+}
+
 gint main(gint argc, gchar *argv[])
 {
        CollectionData *first_collection = NULL;
@@ -942,11 +990,13 @@ gint main(gint argc, gchar *argv[])
        /* init execution time counter (debug only) */
        init_exec_time();
 
+       create_application_paths();
+
        /* setup locale, i18n */
        setlocale(LC_ALL, "");
 
 #ifdef ENABLE_NLS
-       bindtextdomain(PACKAGE, GQ_LOCALEDIR);
+       bindtextdomain(PACKAGE, gq_localedir);
        bind_textdomain_codeset(PACKAGE, "UTF-8");
        textdomain(PACKAGE);
 #endif
index 957331a..61cc21d 100644 (file)
 #include "debug.h"
 #include "options.h"
 
-#define DESKTOP_FILE_TEMPLATE GQ_APP_DIR "/template.desktop"
-
 #define TIMEZONE_DATABASE GQ_WEBSITE"downloads/timezone21.bin"
 
 #define HELP_SEARCH_ENGINE "https://duckduckgo.com/?q=site:geeqie.org/help "
 
 extern gboolean thumb_format_changed;
 
+extern gchar *gq_prefix;
+extern gchar *gq_localedir;
+extern gchar *gq_helpdir;
+extern gchar *gq_htmldir;
+extern gchar *gq_app_dir;
+extern gchar *gq_bin_dir;
+extern gchar *desktop_file_template;
+
 void keyboard_scroll_calc(gint *x, gint *y, GdkEventKey *event);
 gint key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data);
 
index 89763ba..d8b1440 100644 (file)
@@ -178,7 +178,7 @@ gchar *decode_geo_parameters(const gchar *input_text)
        gchar *message;
        gchar *dir;
 
-       message = decode_geo_script(GQ_BIN_DIR, input_text);
+       message = decode_geo_script(gq_bin_dir, input_text);
        if (strstr(message, "Error"))
                {
                g_free(message);
index c2d7c0e..d0d34a2 100644 (file)
@@ -3907,7 +3907,7 @@ void show_about_window(LayoutWindow *lw)
        g_free(basename);
 
        authors[0] = NULL;
-       path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
+       path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
        fp = fopen(path, "r");
        if (fp)
                {
index 43d63b5..7495759 100644 (file)
@@ -246,7 +246,7 @@ void help_window_show(const gchar *key)
 
        if (key && strstr(key, ".html") != 0)
                {
-               path = g_build_filename(GQ_HTMLDIR, key, NULL);
+               path = g_build_filename(gq_htmldir, key, NULL);
                if (!isfile(path))
                        {
                        if (g_strcmp0(key, "index.html") == 0)
@@ -272,18 +272,18 @@ void help_window_show(const gchar *key)
 
        if (!strcmp(key, "release_notes"))
                {
-               path = g_build_filename(GQ_HELPDIR, "README.html", NULL);
+               path = g_build_filename(gq_helpdir, "README.html", NULL);
                if (isfile(path))
                        {
                        g_free(path);
-                       path = g_build_filename("file://", GQ_HELPDIR, "README.html", NULL);
+                       path = g_build_filename("file://", gq_helpdir, "README.html", NULL);
                        help_browser_run(path);
                        g_free(path);
                        }
                else
                        {
                        g_free(path);
-                       path = g_build_filename(GQ_HELPDIR, "README.md", NULL);
+                       path = g_build_filename(gq_helpdir, "README.md", NULL);
                        help_window = help_window_new(_("Help"), "help", path, key);
                        g_free(path);
 
@@ -293,18 +293,18 @@ void help_window_show(const gchar *key)
                }
        else
                {
-               path = g_build_filename(GQ_HELPDIR, "ChangeLog.html", NULL);
+               path = g_build_filename(gq_helpdir, "ChangeLog.html", NULL);
                if (isfile(path))
                        {
                        g_free(path);
-                       path = g_build_filename("file://", GQ_HELPDIR, "ChangeLog.html", NULL);
+                       path = g_build_filename("file://", gq_helpdir, "ChangeLog.html", NULL);
                        help_browser_run(path);
                        g_free(path);
                        }
                else
                        {
                        g_free(path);
-                       path = g_build_filename(GQ_HELPDIR, "ChangeLog", NULL);
+                       path = g_build_filename(gq_helpdir, "ChangeLog", NULL);
                        help_window = help_window_new(_("Help"), "help", path, key);
                        g_free(path);