From c8d2429eb95aa63619e821fbbf80c6b9cde7cfbf Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Sun, 13 Jun 2021 11:44:42 +0100 Subject: [PATCH] Create AppImages 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. --- README.md | 12 +++++-- appimages/README.md | 47 ++++++++++++++++++++++++++ configure.ac | 2 +- scripts/generate-appimage.sh | 65 ++++++++++++++++++++++++++++++++++++ src/desktop_file.c | 2 +- src/editors.c | 2 +- src/layout_util.c | 2 +- src/main.c | 54 ++++++++++++++++++++++++++++-- src/main.h | 10 ++++-- src/misc.c | 2 +- src/preferences.c | 2 +- src/window.c | 14 ++++---- 12 files changed, 194 insertions(+), 20 deletions(-) create mode 100644 appimages/README.md create mode 100755 scripts/generate-appimage.sh diff --git a/README.md b/README.md index 4ef910ce..35d2ec46 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,15 @@ Animated GIFs are supported. # ## 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 index 00000000..778ecb78 --- /dev/null +++ b/appimages/README.md @@ -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 ` + +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 /AppDir` +`sudo rm -rf doc/html` + +Create a fresh target directory: +`mkdir /AppDir` + +Generate the Geeqie executable: +`sudo make maintainer-clean` +`./autogen.sh --prefix="/usr/"` +`make -j` +`make install DESTDIR=/AppDir` + +## Generate the AppImage + +`cd ` +`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. diff --git a/configure.ac b/configure.ac index 799128bc..21e91dd0 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 00000000..bd248205 --- /dev/null +++ b/scripts/generate-appimage.sh @@ -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 diff --git a/src/desktop_file.c b/src/desktop_file.c index 41426663..c74cc88b 100644 --- a/src/desktop_file.c +++ b/src/desktop_file.c @@ -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) diff --git a/src/editors.c b/src/editors.c index b2ce46d6..902e7360 100644 --- a/src/editors.c +++ b/src/editors.c @@ -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); diff --git a/src/layout_util.c b/src/layout_util.c index 42b49c4c..d4dc6eb1 100644 --- a/src/layout_util.c +++ b/src/layout_util.c @@ -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); diff --git a/src/main.c b/src/main.c index 14c0a7f5..a70b7fa0 100644 --- a/src/main.c +++ b/src/main.c @@ -69,6 +69,14 @@ 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 diff --git a/src/main.h b/src/main.h index 957331aa..61cc21d3 100644 --- a/src/main.h +++ b/src/main.h @@ -124,8 +124,6 @@ #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 " @@ -146,6 +144,14 @@ 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); diff --git a/src/misc.c b/src/misc.c index 89763ba1..d8b1440d 100644 --- a/src/misc.c +++ b/src/misc.c @@ -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); diff --git a/src/preferences.c b/src/preferences.c index c2d7c0eb..d0d34a2c 100644 --- a/src/preferences.c +++ b/src/preferences.c @@ -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) { diff --git a/src/window.c b/src/window.c index 43d63b51..74957598 100644 --- a/src/window.c +++ b/src/window.c @@ -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); -- 2.20.1