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.
# <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.
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`
--- /dev/null
+# 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.
[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])
--- /dev/null
+#! /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
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)
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);
}
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);
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
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);
}
#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;
/* 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
#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);
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);
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)
{
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 (!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);
}
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);