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
 
 # <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.
 
 
 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`
 
 
 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`
 ## 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
     [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])
     [
       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)
 {
 
 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)
 }
 
 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");
 
        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);
 
 
        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);
                        }
 
                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);
                                                                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;
 
 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
 /*
  *-----------------------------------------------------------------------------
  * 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");
 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);
 }
         g_setenv("PATH", path, TRUE);
        g_free(path);
 }
@@ -921,6 +929,46 @@ static void setup_sigbus_handler(void)
 #endif
 }
 
 #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;
 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();
 
        /* init execution time counter (debug only) */
        init_exec_time();
 
+       create_application_paths();
+
        /* setup locale, i18n */
        setlocale(LC_ALL, "");
 
 #ifdef ENABLE_NLS
        /* 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
        bind_textdomain_codeset(PACKAGE, "UTF-8");
        textdomain(PACKAGE);
 #endif
index 957331a..61cc21d 100644 (file)
 #include "debug.h"
 #include "options.h"
 
 #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 "
 #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 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);
 
 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;
 
        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);
        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;
        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)
                {
        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)
                {
 
        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)
                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"))
                {
 
        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);
                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);
                        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);
 
                        help_window = help_window_new(_("Help"), "help", path, key);
                        g_free(path);
 
@@ -293,18 +293,18 @@ void help_window_show(const gchar *key)
                }
        else
                {
                }
        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);
                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);
                        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);
 
                        help_window = help_window_new(_("Help"), "help", path, key);
                        g_free(path);