From: Klaus Ethgen Date: Sat, 17 Jul 2021 10:31:25 +0000 (+0100) Subject: Mergin several old merge requests X-Git-Tag: v1.7~86^2 X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=commitdiff_plain;h=7a0e70421c6096eebfc2e821d0bccef3d70e12f0;hp=b2044632dfb8ff4d1b99b0603ab9d4378dc86ed1 Mergin several old merge requests That merge requests got implemented in the past. This just completes the merges to have a correct display in git. * commit '8abb834383bd': fixed uvbuntu url * commit 'b2044632dfb8': Update Slovak translation * commit 'eaf4dcdd76e4': Generate sRGB thumbnails for images with embedded color profile data * commit 'cfb686d65005': Fix doc building with newer yelp * commit '75794b0d6592': dupe: Eliminate O(n^2) code in dupe_files_add_queue_cb() dupe: Optimize memory handling in dupe_files_add_queue_cb() dupe: Avoid O(n) operations in dupe_files_add_queue_cb() * commit '319f58d9c1d7': Use binary units for sizes, not decimal values. * commit '0436ed321b88': Add image/webp mime type * commit '8eb3ee5d331b': Update Dutch translation (nl_nl) * commit '1424f6b6831b': Fix spelling mistake emdedded -> embedded * commit '7ea866b2aa83': Cast `struct sockaddr_un*` properly Use POSIX options for tail and tr * commit '865a8ba3888f': Updated Catalan translation * commit 'f4fad426aed9': updated german translation updated german translation * commit '0d981a84c8cb': fixed wrong spelled words * commit '121db0ea48ef': fixed spelling mistakes * commit '3c363439f022': New pop-up menu action "Copy image to clipboard" * commit '18ad1ee9552a': Fix building on GTK2 again, adding #ifdefs for gtk_label_set_[x,y]align * commit '50ccf27c1a5e': Use gtk_label_set_[x,y]align instead of gtk_misc_set_alignment * commit 'e108b2e5c089': Add keymap_template.h to geeqie_SOURCES too * commit '546dbdfa2dd7': Fix building with --enable-debug-flags * commit 'c113dd9a8a29': Fix mistakes in Czech translation * commit 'f6e88fcd6955': Update Slovak translation * commit '635569789cf5': Slightly improve plugin template --- diff --git a/CHECKLIST.md b/CHECKLIST.md new file mode 100644 index 00000000..a02f11ef --- /dev/null +++ b/CHECKLIST.md @@ -0,0 +1,31 @@ +## A checklist to be used after Geeqie has been updated + +Before compiling the sources, carry out the following actions when necessary: + +* Update ```org.geeqie.Geeqie.appdata.xml.in``` with the latest released version and date +* If source files have been added or removed from ```.src/``` directory, resync ```./po/POTFILES.in``` +``` +cd ./po +./regen_potfiles.sh | patch -p0 +``` +* Keep translations in sync with the code +``` +cd ./po +make update-po +``` +* Update the the timezone database +``` +./scripts/zonedetect/create_timezone_database +``` + +After compiling the sources, carry out the following actions when necessary: + +* Generate a new AppImage (note that this should be run on a **20.04 system**) +``` +./scripts/generate-appimage.sh +``` +* Copy Help html files to `````` +* Copy ```geeqie.desktop``` to `````` +* Copy ```org.geeqie.Geeqie.appdata.xml``` to `````` +* Upload to GeeqieWeb + diff --git a/CODING b/CODING deleted file mode 100644 index 9a8cbc16..00000000 --- a/CODING +++ /dev/null @@ -1,228 +0,0 @@ -Log Window: - -DEBUG_0() -Use DEBUG_0() only for temporary debugging i.e. not in code in the repository. -The user will then not see irrelevant debug output when the default -debug level = 0 is used. - -log_printf() -If the first word of the message is "error" or "warning" (case insensitive) -the message will be color-coded appropriately. - - -GTKInspector: - -DEBUG_NAME(widget) -For use with the GTKInspector to provide a visual indication of where objects are declared. - -Sample command line call: -GTK_DEBUG=interactive src/geeqie - --------------------------------------------------------------------------------- - -GPL header, in every file, like this: - -/** \file - * \short Short description of this file. - * \author Author1 - * \author Author2 - * - * Optionally detailed description of this file - * on more lines. - */ - -/* - * This file is a part of Geeqie project (http://www.geeqie.org/). - * Copyright (C) 2008 - 2016 The Geeqie Team - * - * 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. - */ - --------------------------------------------------------------------------------- - -git change-log: - -If referencing a Geeqie GitHub issue, include the issue number in the summary line. -Start with a short summary in the first line (without a dot at the end) followed -by a empty line. - -If referencing a Geeqie GitHub issue, include a hyperlink to the GitHub issue page -in the message body. -Use whole sentences begins with Capital letter. For each -modification use new line. Or you can write the theme, colon and then every -change on new line, begin with "- ". - -See also: http://www.tpope.net/node/106 - -Example: - - I did some bugfixes - - There was the bug that something was wrong. I fixed it. - - Library: - - the interface was modified - - new functions were added - -Also please use your full name and a working e-mail address as author for any contribution. - --------------------------------------------------------------------------------- - -sources: - -Indentation: tabs -Names of variables & functions: small_letters - of defines: CAPITAL_LETTERS - -Try to use explicit variable and function names. - -Try not to use macros. -Use EITHER "struct foo" OR "foo"; never both - - -Conditions, cycles: - -if () - { - ; - ... - ; - } -else - { - ; - ... - ; - } - -if ( && - ) - ; - -switch () - { - case 0: - ; - ; - break; - case 1: - ; break; - } - -for (i = 0; i <= 10; i++) - { - ; - ... - ; - } - - -Functions: - -gint bar(, , ) -{ - ; - ... - ; - - return 0; // i.e. SUCCESS; if error, you must return minus -} - -void bar2(void) -{ - ; - ... - ; -} - -Pragma: (Indentation 2 spaces) - -#ifdef ENABLE_NLS -# undef _ -# define _(String) (String) -#endif /* ENABLE_NLS */ - -Headers: - -#ifndef _FILENAME_H - --------------------------------------------------------------------------------- - -Use spaces around every operator (except ".", "->", "++" and "--"); - unary operator '*' and '&' are missing the space from right; - (and also unary '-'). -As you can see above, parentheses are closed to inside, i.e. " (blah blah) " - In "function()" there are no space before '('. -You MAY use more tabs/spaces than you OUGHT TO (according to this CodingStyle), if - it makes your code nicer in being vertically indented. -Variables declarations should be followed by a blank line and should always be -at the start of the block. - --------------------------------------------------------------------------------- - -Use glib types when possible (ie. gint and gchar instead of int and char). -Use glib functions when possible (ie. g_ascii_isspace() instead of isspace()). -Check if used functions are not deprecated. - --------------------------------------------------------------------------------- - -Documentation: - -Use American, rather than British English, spelling. This will facilitate consistent -text searches. User text may be translated via the en_GB.po file. - -To document the code use the following rules to allow extraction with doxygen. -Do not save with comments. Not all comments have to be doxygen comments. - -- Use C comments in plain C files and use C++ comments in C++ files for one line - comments. -- Use '/**' (note the two asterisks) to start comments to be extracted by - doxygen and start every following line with " *". -- Use '@' to indicate doxygen keywords/commands (see below). -- Use the '@deprecated' command to tell if the function is subject to be deleted - or to a complete rewrite. - -Example: - -To document functions or big structures: - /** - * @brief This is a short description of the function. - * - * This function does ... - * - * @param x1 This is the first parameter named x1 - * @param y1 This is the second parameter named y1 - * @return What the function returns - * You can extend that return description (or anything else) by indenting the - * following lines until the next empty line or the next keyword/command. - * @see Cross reference - */ - -To document members of a structure that have to be documented (use it at least -for big structures) use the '/**<' format: - int counter; /**< This counter counts images */ - -Document TODO or FIXME comments as: - /** - * @todo -or - /** - * @FIXME - -For further documentation about doxygen see -http://www.stack.nl/~dimitri/doxygen/manual.html. For the possible commands you -can use see http://www.stack.nl/~dimitri/doxygen/commands.html. - -But in case just think about that the documentation is for other developers not -for the end user. So keep the focus. - -The file ./scripts/doxygen-help.sh may be used to integrate access to the -Doxygen files into a code editor. diff --git a/CODING.md b/CODING.md new file mode 100644 index 00000000..2e57b8c8 --- /dev/null +++ b/CODING.md @@ -0,0 +1,254 @@ +[Log Window](#log-window) +[GPL header](#gpl-header) +[Git change log](#git-change-log) +[Sources](#sources) +[Documentation](#documentation) + +----------- + + +# +# Log Window + +`DEBUG_0()` +Use `DEBUG_0()` only for temporary debugging i.e. not in code in the repository. +The user will then not see irrelevant debug output when the default +`debug level = 0` is used. + +`log_printf()` +If the first word of the message is "error" or "warning" (case insensitive) the message will be color-coded appropriately. + + +`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. + +Sample command line call: +`GTK_DEBUG=interactive src/geeqie` + +-------------------------------------------------------------------------------- + +# +# GPL header + +Include a header in every file, like this: + + /** @file + * @brief Short description of this file. + * @author Author1 + * @author Author2 + * + * Optionally detailed description of this file + * on more lines. + */ + + /* + * This file is a part of Geeqie project (http://www.geeqie.org/). + * Copyright (C) 2008 - 2021 The Geeqie Team + * + * 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. + */ + +------------- + +# +# git change-log + +If referencing a Geeqie GitHub issue, include the issue number in the summary line. Start with a short summary in the first line (without a dot at the end) followed by a empty line. + +If referencing a Geeqie GitHub issue, include a hyperlink to the GitHub issue webpage in the message body. Use whole sentences beginning with Capital letter. For each modification use a new line. Or you can write the theme, colon and then every change on new line, begin with "- ". + +See also [A Note About Git Commit Messages](http://www.tpope.net/node/106) + +Example: + + `I did some bugfixes` + + `There was the bug that something was wrong. I fixed it.` + + ` Library:` + `- the interface was modified` + `- new functions were added` + +Also please use your full name and a working e-mail address as author for any contribution. + +-------------------------------------------------------------------------------- + +# +# Sources + +Indentation: tabs at 4 spaces + + +Names: + +- of variables & functions: small\_letters +- of defines: CAPITAL\_LETTERS + +Try to use explicit variable and function names. +Try not to use macros. +Use EITHER "struct foo" OR "foo"; never both + + +Conditions, cycles: + + if () + { + ; + ... + ; + } + else + { + ; + ... + ; + } + + if ( && + ) + ; + + switch () + { + case 0: + ; + ; + break; + case 1: + ; break; + } + + for (i = 0; i <= 10; i++) + { + ; + ... + ; + } + +Functions: + + gint bar(, , ) + { + ; + ... + ; + + return 0; // i.e. SUCCESS; if error, you must return minus + } + + void bar2(void) + { + ; + ... + ; + } + +Pragma: (Indentation 2 spaces) + + #ifdef ENABLE_NLS + # undef _ + # define _(String) (String) + #endif /* ENABLE_NLS */ + +Headers: + + #ifndef _FILENAME_H + + +Use spaces around every operator (except ".", "->", "++" and "--"). +Unary operator '*' and '&' are missing the space from right, (and also unary '-'). + +As you can see above, parentheses are closed to inside, i.e. " (blah blah) " +In "`function()`" there is no space before the '('. +You MAY use more tabs/spaces than you OUGHT TO (according to this CodingStyle), if it makes your code nicer in being vertically indented. +Variables declarations should be followed by a blank line and should always be at the start of the block. + + +Use glib types when possible (ie. gint and gchar instead of int and char). +Use glib functions when possible (ie. `g_ascii_isspace()` instead of `isspace()`). +Check if used functions are not deprecated. + +-------------------------------------------------------------------------------- + +# +# Documentation + +Use American, rather than British English, spelling. This will facilitate consistent +text searches. User text may be translated via the en_GB.po file. + +To document the code use the following rules to allow extraction with doxygen. +Do not save with comments. Not all comments have to be doxygen comments. + +- Use C comments in plain C files and use C++ comments in C++ files for one line + comments. +- Use '/**' (note the two asterisks) to start comments to be extracted by + doxygen and start every following line with " *". +- Use '@' to indicate doxygen keywords/commands (see below). +- Use the '@deprecated' command to tell if the function is subject to be deleted + or to a complete rewrite. + +Example: + +To document functions or big structures: + + /** + * @brief This is a short description of the function. + * + * This function does ... + * + * @param x1 This is the first parameter named x1 + * @param y1 This is the second parameter named y1 + * @return What the function returns + * You can extend that return description (or anything else) by indenting the + * following lines until the next empty line or the next keyword/command. + * @see Cross reference + */ + +To document members of a structure that have to be documented (use it at least +for big structures) use the `/**<` format: +`int counter; /**< This counter counts images */` + +Document TODO or FIXME comments as: + + /** + * @todo + +or + + /** + * @FIXME + +For further documentation about doxygen see the [Doxygen Manual](https://www.doxygen.nl/index.html). +For the possible commands you may use, see [Doxygen Special Commands](https://www.doxygen.nl/manual/commands.html). + +The file `./scripts/doxygen-help.sh` may be used to integrate access to the Doxygen files into a code editor. + +The following environment variables may be set to personalize the Doxygen output: +`DOCDIR=` +`SRCDIR=` +`PROJECT=` +`VERSION=` +`PLANTUML_JAR_PATH=` +`INLINE_SOURCES=` +`STRIP_CODE_COMMENTS=` + +Ref: [INLINE\_SOURCES](https://www.doxygen.nl/manual/config.html#cfg_inline_sources) +Ref: [STRIP\_CODE\_COMMENTS](https://www.doxygen.nl/manual/config.html#cfg_strip_code_comments) + +To include diagrams (if any) in the Doxygen output, the following are required to be installed. The installation process will vary between distributions: +[The PlantUML jar](https://plantuml.com/download) +`sudo apt install default-jre` +`sudo apt install texlive-font-utils` + +------------- + +But in case just think about that the documentation is for other developers not +for the end user. So keep the focus. diff --git a/HACKING b/HACKING deleted file mode 100644 index d7e27b75..00000000 --- a/HACKING +++ /dev/null @@ -1,21 +0,0 @@ -A brief overview for those that wish to work with the source. - -The Makefiles and configure script are generated by the autogen.sh script, -usually only distributed with snapshot releases. Running autogen.sh requires -automake and autoconf. GNU gettext may also be needed by autogen.sh. - -Git commits _require_ an explicit log message. Think it will be used in the -release Changelog. - -Coders should respect general coding style (see CODING). - -Coders, please resync po/POTFILES.in if you add or remove source files from src/ -directory (using regen_potfiles.sh script in po/) and re-run make update-po when -appropriate to keep translations in sync with the code. - -Maintainers, don't forget to run make update-po before releases. - -The scripts folder contains a script for generating the timezone database. -The database will need updating occasionally. - -Translators, please have a look at po/README. 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/doc/Makefile.am b/doc/Makefile.am index 78b96233..a09a809b 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -5,7 +5,7 @@ helpdir = @htmldir@ EXTRA_DIST = docbook2html.sh docbook icons html/GuideIndex.html: docbook/GuideIndex.xml - rm -rf html; mkdir html; cp $(srcdir)/icons/* html/ + rm -rf html; mkdir html; cp $(srcdir)/icons/* html/; ./create-doxygen-lua-api.sh if [ -x "$(GNOME_DOC_TOOL)" ]; then \ "$(GNOME_DOC_TOOL)" html -i -o html/ $(srcdir)/docbook/GuideIndex.xml ; \ else \ @@ -19,10 +19,12 @@ install-data-hook: html $(MKDIR_P) "$(DESTDIR)$(helpdir)" || exit 1; \ cd $(srcdir)/html; for f in * ; do $(INSTALL_DATA) "$$f" "$(DESTDIR)$(helpdir)/$$f" ; done; \ ln -s -f GuideIndex.html "$(DESTDIR)$(helpdir)/index.html" ; \ + $(MKDIR_P) "$(DESTDIR)$(helpdir)/lua-api" || exit 1; \ + cd ./lua-api/html; for f in * ; do $(INSTALL_DATA) "$$f" "$(DESTDIR)$(helpdir)/lua-api/$$f" ; done; \ fi uninstall-hook: - rm "$(DESTDIR)$(helpdir)/"* + rm -r "$(DESTDIR)$(helpdir)/"* clean-local: rm -rf html diff --git a/doc/create-doxygen-lua-api.sh b/doc/create-doxygen-lua-api.sh new file mode 100755 index 00000000..38c92edf --- /dev/null +++ b/doc/create-doxygen-lua-api.sh @@ -0,0 +1,99 @@ +#!/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 create the Lua API html document, which is part of +# the Geeqie Help file. +# +# It is run during the generation of the help files. +# +# The generated Lua html files are placed in doc/html/lua-api +# +# The doxygen.conf file is modified to extract only those comments +# that are useful as part of an API description. +# +#********************************************************************** + +export PROJECT="Geeqie" +export VERSION=$(git tag --list v[1-9]* | tail -1) +export SRCDIR="$PWD/.." +export DOCDIR="$PWD/html/lua-api" + +TMPFILE=$(mktemp) || exit 1 + +# Modify the Geeqie doxygen.conf file to produce +# only the data needed for the lua API document +awk ' +BEGIN { + FILE_PATTERNS_found = "FALSE" +} +{ + if (FILE_PATTERNS_found == "TRUE") + { + if ($0 ~ /\\/) + { + next + } + else + { + FILE_PATTERNS_found = "FALSE" + } + } + if ($1 == SHOW_INCLUDE_FILES) + { + {print "SHOW_INCLUDE_FILES = NO"} + } + else if ($1 == "FILE_PATTERNS") + { + print "FILE_PATTERNS = lua.c" + FILE_PATTERNS_found = "TRUE" + next + } + else if ($1 == "EXCLUDE_SYMBOLS") + { + print "EXCLUDE_SYMBOLS = L \\" + print "lua_callvalue \\" + print "lua_check_exif \\" + print "lua_check_image \\" + print "lua_init \\" + print "_XOPEN_SOURCE \\" + print "LUA_register_global \\" + print "LUA_register_meta" + } + else if ($1 == "SOURCE_BROWSER") + { + print "SOURCE_BROWSER = NO" + } + else if ($1 == "HAVE_DOT") + { + {print "HAVE_DOT = NO"} + } + else + { + {print} + } +} +' ../doxygen.conf > $TMPFILE + +doxygen $TMPFILE + +rm $TMPFILE + diff --git a/doc/docbook/GuideIndex.xml b/doc/docbook/GuideIndex.xml index 0f76e27e..986b8ef9 100644 --- a/doc/docbook/GuideIndex.xml +++ b/doc/docbook/GuideIndex.xml @@ -72,6 +72,7 @@ + diff --git a/doc/docbook/GuideOptionsAdvanced.xml b/doc/docbook/GuideOptionsAdvanced.xml new file mode 100644 index 00000000..e02a5623 --- /dev/null +++ b/doc/docbook/GuideOptionsAdvanced.xml @@ -0,0 +1,88 @@ + +
+ External preview extraction + + The intention of this feature is to give the user the possibility to display image previews of files + that the standard libraries cannot decode. + + An example is the .dng files produced by LG V30 cameras. Neither + exiv2 + nor + libraw + can + extract a preview, but the command line program + dcraw + can. + + This feature allows a work-around until the standard libraries provide a solution. + + Two command files are required: one to identify which files to process, and one to extract or decode the preview image. + + The format for the identification tool is: + +
+      
+        Parameter 1: (input) full path name to the current image.
+        
+        Returns: 0 for file match, any other value for no match.
+      
+    
+ + The format for the extraction tool is: + +
+      
+        Parameter 1: (input) full path name to the current image.
+        
+        Parameter 2: (output) a temporary file name generated by Geeqie. The tool should load this file with the decoded image.
+        
+        Returns: not used.
+      
+    
+ + This is an example of an identification tool using a shell script: + +
+      #! /bin/bash
+
+        filename=$(basename -- "$1")
+        extension="${filename##*.}"
+
+        shopt -s nocasematch
+        if [[ $extension == "DNG" ]]
+        then
+            cameramodel=$(exiv2 -K Exif.Image.UniqueCameraModel -Pt "$1" )
+            if [[ $cameramodel  == "LG-H930" ]]
+            then
+                exit 0
+            else
+                exit 1
+            fi
+        else
+            exit 1
+        fi
+    
+
+ + This is an example of an extraction/decode tool using a shell script: +
+      #! /bin/bash
+        dcraw -e -c   "$1" > "$2"
+    
+ + Alternatively: +
+      #! /bin/bash
+        gm convert "$1" "$2"
+    
+
+ + If the decode tool requires an output file with a particular extension, use this method: +
+      #! /bin/bash
+        tmpfile=$(mktemp --tmpdir=$tempdir geeqie_tmp_XXXXXX.jpg)
+        gm convert "$1" $tmpfile
+        mv $tmpfile "$2"
+    
+
+
diff --git a/doc/docbook/GuideOptionsMain.xml b/doc/docbook/GuideOptionsMain.xml index 9b927ddc..3f7feb6f 100644 --- a/doc/docbook/GuideOptionsMain.xml +++ b/doc/docbook/GuideOptionsMain.xml @@ -33,6 +33,7 @@ + diff --git a/doc/docbook/GuideOtherSoftware.xml b/doc/docbook/GuideOtherSoftware.xml new file mode 100644 index 00000000..52765ddb --- /dev/null +++ b/doc/docbook/GuideOtherSoftware.xml @@ -0,0 +1,19 @@ + + + Other Software + This is a list of other software that users might find useful in conjunction with Geeqie. +
+ Entangle + + Tethered photography: + https://entangle-photo.org/ + +
+
+ Photini + + Digital photograph metadata editor: + https://photini.readthedocs.io/en/latest/ + +
+
diff --git a/doc/docbook/GuideReference.xml b/doc/docbook/GuideReference.xml index a8c62f3e..88f936dd 100644 --- a/doc/docbook/GuideReference.xml +++ b/doc/docbook/GuideReference.xml @@ -6,6 +6,7 @@ + diff --git a/doc/docbook/GuideReferenceKeyboardShortcuts.xml b/doc/docbook/GuideReferenceKeyboardShortcuts.xml index 3a1aecf6..34b7ad87 100644 --- a/doc/docbook/GuideReferenceKeyboardShortcuts.xml +++ b/doc/docbook/GuideReferenceKeyboardShortcuts.xml @@ -767,7 +767,7 @@ Ctrl + - Keypad + + = @@ -777,7 +777,7 @@ Ctrl + - Keypad - + - diff --git a/doc/docbook/GuideReferenceLuaAPI.xml b/doc/docbook/GuideReferenceLuaAPI.xml new file mode 100644 index 00000000..5d36e667 --- /dev/null +++ b/doc/docbook/GuideReferenceLuaAPI.xml @@ -0,0 +1,7 @@ + +
+ Lua API + + The Lua API document + +
diff --git a/doc/docbook/GuideReferenceStandards.xml b/doc/docbook/GuideReferenceStandards.xml index bb43b572..e6676b93 100644 --- a/doc/docbook/GuideReferenceStandards.xml +++ b/doc/docbook/GuideReferenceStandards.xml @@ -11,7 +11,7 @@
XMP: - + IPTC4XMP: @@ -19,7 +19,7 @@ Pango mark up: - + Thumbnails: diff --git a/doxygen.conf b/doxygen.conf index d952f4bc..074a2d7e 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -1001,14 +1001,14 @@ SOURCE_BROWSER = YES # classes and enums directly into the documentation. # The default value is: NO. -INLINE_SOURCES = NO +INLINE_SOURCES = $(INLINE_SOURCES) # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. -STRIP_CODE_COMMENTS = YES +STRIP_CODE_COMMENTS = $(STRIP_CODE_COMMENTS) # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. @@ -2435,7 +2435,7 @@ DIAFILE_DIRS = # generate a warning when it encounters a \startuml command in this case and # will not generate output for the diagram. -PLANTUML_JAR_PATH = +PLANTUML_JAR_PATH = $(PLANTUML_JAR_PATH) # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a # configuration file for plantuml. diff --git a/org.geeqie.Geeqie.appdata.xml.in b/org.geeqie.Geeqie.appdata.xml.in index da331910..cb5a0b0d 100644 --- a/org.geeqie.Geeqie.appdata.xml.in +++ b/org.geeqie.Geeqie.appdata.xml.in @@ -23,7 +23,7 @@ - + image diff --git a/po/sk.po b/po/sk.po index 56cac614..76a4dad9 100644 --- a/po/sk.po +++ b/po/sk.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: geeqie-1.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-05-01 10:24+0100\n" -"PO-Revision-Date: 2021-05-16 09:37+0200\n" +"PO-Revision-Date: 2021-06-26 22:12+0200\n" "Last-Translator: Jose Riha \n" "Language-Team: Peter Tuhársky \n" "Language: sk_SK\n" @@ -1215,7 +1215,7 @@ msgstr "Tlač..." # src/collect-table.c:1818 src/dupe.c:2170 #: ../src/collect-table.c:2236 ../src/dupe.c:4894 ../src/img-view.c:1521 msgid "Dropped list includes folders." -msgstr "Odstraňovaný zoznam obsahuje priečinky." +msgstr "Umiestnený zoznam obsahuje priečinky." # src/collect-table.c:1820 src/dupe.c:2172 #: ../src/collect-table.c:2238 ../src/dupe.c:4896 ../src/img-view.c:1523 @@ -5971,9 +5971,8 @@ msgstr "Použiť uložené pozície okien aj pre nové okná" # src/preferences.c:782 #: ../src/preferences.c:2307 -#, fuzzy msgid "Remember window workspace" -msgstr "Pamätať si pozície okien" +msgstr "Pamätať si plochu" # src/preferences.c:784 #: ../src/preferences.c:2311 @@ -6410,13 +6409,12 @@ msgstr "" # src/collect-dlg.c:206 #: ../src/preferences.c:3355 -#, fuzzy msgid "Circular selection lists" -msgstr "Zbierka už existuje" +msgstr "Výbery v nekonečnej slučke" #: ../src/preferences.c:3357 msgid "Traverse selection lists in a circular manner" -msgstr "" +msgstr "Prechádzať zoznamy s výberom v nekonečnej slučke" #: ../src/preferences.c:3359 msgid "Save marks on exit" diff --git a/scripts/generate-appimage.sh b/scripts/generate-appimage.sh new file mode 100755 index 00000000..0b7639aa --- /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/Makefile.am b/src/Makefile.am index bff64e13..339af632 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -191,6 +191,8 @@ geeqie_SOURCES = \ image_load_tiff.h\ image_load_dds.c\ image_load_dds.h\ + image_load_external.c\ + image_load_external.h\ image_load_collection.c\ image_load_collection.h\ image_load_pdf.c\ 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/dupe.c b/src/dupe.c index 4002d50c..f9c624e9 100644 --- a/src/dupe.c +++ b/src/dupe.c @@ -128,6 +128,7 @@ static GtkWidget *dupe_menu_popup_second(DupeWindow *dw, DupeItem *di); static void dupe_dnd_init(DupeWindow *dw); static void dupe_notify_cb(FileData *fd, NotifyType type, gpointer data); +static void delete_finished_cb(gboolean success, const gchar *dest_path, gpointer data); static GtkWidget *submenu_add_export(GtkWidget *menu, GtkWidget **menu_item, GCallback func, gpointer data); static void dupe_pop_menu_export_cb(GtkWidget *widget, gpointer data); @@ -1849,6 +1850,7 @@ static void dupe_array_check(DupeWindow *dw ) DupeMatchType mask = dw->match_mask; param_match_mask = dw->match_mask; guint out_match_index; + gboolean match_found = FALSE;; if (!dw->list) return; @@ -1894,7 +1896,27 @@ static void dupe_array_check(DupeWindow *dw ) continue; } } - if (g_array_binary_search(array_set2, di1, dupe_match_binary_search_cb, &out_match_index)) + +#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION >= 62)) + match_found = g_array_binary_search(array_set2, di1, dupe_match_binary_search_cb, &out_match_index); +#else + gint i; + + match_found = FALSE; + for(i=0; i < array_set2->len; i++) + { + di2 = g_array_index(array_set2, gpointer, i); + check_result = dupe_match_check(di1, di2, dw); + if (check_result == DUPE_MATCH) + { + match_found = TRUE; + out_match_index = i; + break; + } + } +#endif + + if (match_found) { di2 = g_array_index(array_set2, gpointer, out_match_index); @@ -3361,7 +3383,7 @@ static void dupe_menu_delete_cb(GtkWidget *widget, gpointer data) DupeWindow *dw = data; options->file_ops.safe_delete_enable = FALSE; - file_util_delete(NULL, dupe_listview_get_selection(dw, dw->listview), dw->window); + file_util_delete_notify_done(NULL, dupe_listview_get_selection(dw, dw->listview), dw->window, delete_finished_cb, dw); } static void dupe_menu_move_to_trash_cb(GtkWidget *widget, gpointer data) @@ -3369,7 +3391,7 @@ static void dupe_menu_move_to_trash_cb(GtkWidget *widget, gpointer data) DupeWindow *dw = data; options->file_ops.safe_delete_enable = TRUE; - file_util_delete(NULL, dupe_listview_get_selection(dw, dw->listview), dw->window); + file_util_delete_notify_done(NULL, dupe_listview_get_selection(dw, dw->listview), dw->window, delete_finished_cb, dw); } static void dupe_menu_copy_path_cb(GtkWidget *widget, gpointer data) @@ -5113,7 +5135,7 @@ static void dupe_notify_cb(FileData *fd, NotifyType type, gpointer data) case FILEDATA_CHANGE_COPY: break; case FILEDATA_CHANGE_DELETE: - while (dupe_item_remove_by_path(dw, fd->path)); + /* Update the UI only once, after the operation finishes */ break; case FILEDATA_CHANGE_UNSPECIFIED: case FILEDATA_CHANGE_WRITE_METADATA: @@ -5122,6 +5144,29 @@ static void dupe_notify_cb(FileData *fd, NotifyType type, gpointer data) } +/** + * @brief Refresh window after a file delete operation + * @param success (ud->phase != UTILITY_PHASE_CANCEL) #file_util_dialog_run + * @param dest_path Not used + * @param data #DupeWindow + * + * If the window is refreshed after each file of a large set is deleted, + * the UI slows to an unacceptable level. The #FileUtilDoneFunc is used + * to call this function once, when the entire delete operation is completed. + */ +static void delete_finished_cb(gboolean success, const gchar *dest_path, gpointer data) +{ + DupeWindow *dw = data; + GList *work; + + if (!success) + { + return; + } + + dupe_window_remove_selection(dw, dw->listview); +} + /* *------------------------------------------------------------------- * Export duplicates 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/exiv2.cc b/src/exiv2.cc index f1f72903..f8761270 100644 --- a/src/exiv2.cc +++ b/src/exiv2.cc @@ -451,7 +451,7 @@ void exif_init(void) bind_textdomain_codeset (EXV_PACKAGE, "UTF-8"); #endif -#if EXIV2_TEST_VERSION(0,27,4) +#ifdef EXV_ENABLE_BMFF Exiv2::enableBMFF(TRUE); #endif } diff --git a/src/image-load.c b/src/image-load.c index 0ddf32cc..07588cbb 100644 --- a/src/image-load.c +++ b/src/image-load.c @@ -27,6 +27,7 @@ #include "image_load_tiff.h" #include "image_load_dds.h" #include "image_load_djvu.h" +#include "image_load_external.h" #include "image_load_pdf.h" #include "image_load_psd.h" #include "image_load_heif.h" @@ -36,6 +37,7 @@ #include "image_load_j2k.h" #include "image_load_libraw.h" #include "image_load_svgz.h" +#include "misc.h" #include "exif.h" #include "filedata.h" @@ -48,7 +50,68 @@ #define IMAGE_LOADER_READ_BUFFER_SIZE_DEFAULT 4096 #define IMAGE_LOADER_IDLE_READ_LOOP_COUNT_DEFAULT 1 - +/** + * @page diagrams Diagrams + * @section image_load_overview Image Load Overview + * @startuml + * object image_change + * object image_change_complete + * object image_load_begin + * object image_loader_start + * object image_loader_start_thread + * object image_loader_start_idle + * object image_loader_setup_source + * object image_loader_thread_run + * object image_loader_begin + * object image_loader_setuploader + * circle "il->memory_mapped" + * object exif_get_preview_ + * object exif_get_preview + * object libraw_get_preview + * + * image_change : image.c + * image_change_complete : image.c + * image_load_begin : image.c + * image_loader_start : image_load.c + * image_loader_start_thread : image_load.c + * image_loader_start_idle : image_load.c + * image_loader_thread_run : image_load.c + * image_loader_begin : image_load.c + * image_loader_setuploader : image_load.c + * image_loader_setuploader : - + * image_loader_setuploader : Select backend using magic + * image_loader_setup_source : image_load.c + * exif_get_preview : exiv2.cc + * exif_get_preview : EXIV2_TEST_VERSION(0,17,90) + * exif_get_preview_ : exif.c + * exif_get_preview_ : - + * exif_get_preview_ : If exiv2 not installed + * libraw_get_preview : image_load_libraw.c + * + * image_change --> image_change_complete + * image_change_complete --> image_load_begin + * image_load_begin --> image_loader_start + * image_loader_start --> image_loader_start_thread + * image_loader_start --> image_loader_start_idle : Obsolete - no threads version + * image_loader_start_thread --> image_loader_thread_run + * image_loader_start_thread --> image_loader_setup_source + * image_loader_setup_source --> exif_get_preview_ + * image_loader_setup_source --> exif_get_preview + * image_loader_setup_source --> libraw_get_preview : Try libraw if exiv2 fails + * exif_get_preview_ ..> "il->memory_mapped" + * exif_get_preview ..> "il->memory_mapped" + * libraw_get_preview ..> "il->memory_mapped" + * image_loader_thread_run --> image_loader_begin + * image_loader_begin --> image_loader_setuploader + * "il->memory_mapped" ..> image_loader_setuploader + * note left of "il->memory_mapped" : Points to first byte of embedded jpeg (#FFD8)\n if preview found, otherwise to first byte of file + * @enduml + */ + /** + * @file + * @ref image_load_overview "Image Load Overview" + */ + /**************************************************************************************/ /* image loader class */ @@ -629,7 +692,31 @@ static void image_loader_setup_loader(ImageLoader *il) gchar *format; #endif + gint external_preview = 1; + g_mutex_lock(il->data_mutex); + + if (options->external_preview.enable) + { + gchar *cmd_line; + gchar *tilde_filename; + + tilde_filename = expand_tilde(options->external_preview.select); + + cmd_line = g_strdup_printf("\"%s\" \"%s\"" , tilde_filename, il->fd->path); + + external_preview = runcmd(cmd_line); + g_free(cmd_line); + g_free(tilde_filename); + } + + if (external_preview == 0) + { + DEBUG_1("Using custom external loader"); + image_loader_backend_set_external(&il->backend); + } + else + #ifdef HAVE_FFMPEGTHUMBNAILER if (il->fd->format_class == FORMAT_CLASS_VIDEO) { @@ -651,7 +738,8 @@ static void image_loader_setup_loader(ImageLoader *il) if (il->bytes_total >= 12 && ((memcmp(il->mapped_file + 4, "ftypheic", 8) == 0) || (memcmp(il->mapped_file + 4, "ftypmsf1", 8) == 0) || - (memcmp(il->mapped_file + 4, "ftypmif1", 8) == 0))) + (memcmp(il->mapped_file + 4, "ftypmif1", 8) == 0) || + (memcmp(il->mapped_file + 4, "ftypavif", 8) == 0))) { DEBUG_1("Using custom heif loader"); image_loader_backend_set_heif(&il->backend); @@ -972,7 +1060,16 @@ static gboolean image_loader_setup_source(ImageLoader *il) if (il->mapped_file) { - il->preview = IMAGE_LOADER_PREVIEW_EXIF; + /* Both exiv2 and libraw sometimes return a pointer to a file + * section that is not a jpeg */ + if (!(il->mapped_file[0] == 0xFF && il->mapped_file[1] == 0xD8)) + { + il->mapped_file = NULL; + } + else + { + il->preview = IMAGE_LOADER_PREVIEW_EXIF; + } } } @@ -983,7 +1080,14 @@ static gboolean image_loader_setup_source(ImageLoader *il) if (il->mapped_file) { - il->preview = IMAGE_LOADER_PREVIEW_LIBRAW; + if (!(il->mapped_file[0] == 0xFF && il->mapped_file[1] == 0xD8)) + { + il->mapped_file = NULL; + } + else + { + il->preview = IMAGE_LOADER_PREVIEW_LIBRAW; + } } } diff --git a/src/image_load_external.c b/src/image_load_external.c new file mode 100644 index 00000000..7eb1770a --- /dev/null +++ b/src/image_load_external.c @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#include "main.h" + +#include "image-load.h" +#include "image_load_external.h" + +#include "misc.h" +#include "ui_fileops.h" + +typedef struct _ImageLoaderExternal ImageLoaderExternal; +struct _ImageLoaderExternal { + ImageLoaderBackendCbAreaUpdated area_updated_cb; + ImageLoaderBackendCbSize size_cb; + ImageLoaderBackendCbAreaPrepared area_prepared_cb; + gpointer data; + GdkPixbuf *pixbuf; + guint requested_width; + guint requested_height; + gboolean abort; +}; + +static gboolean image_loader_external_load(gpointer loader, const guchar *buf, gsize count, GError **error) +{ + ImageLoaderExternal *ld = (ImageLoaderExternal *) loader; + ImageLoader *il = ld->data; + gchar *cmd_line; + gchar *randname; + gchar *tilde_filename; + + tilde_filename = expand_tilde(options->external_preview.extract); + + randname = g_strdup("/tmp/geeqie_external_preview_XXXXXX"); + g_mkstemp(randname); + + cmd_line = g_strdup_printf("\"%s\" \"%s\" \"%s\"" , tilde_filename, il->fd->path, randname); + + runcmd(cmd_line); + + ld->pixbuf = gdk_pixbuf_new_from_file(randname, NULL); + + ld->area_updated_cb(loader, 0, 0, gdk_pixbuf_get_width(ld->pixbuf), gdk_pixbuf_get_height(ld->pixbuf), ld->data); + + g_free(cmd_line); + unlink_file(randname); + g_free(randname); + g_free(tilde_filename); + + return TRUE; +} + +static gpointer image_loader_external_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data) +{ + ImageLoaderExternal *loader = g_new0(ImageLoaderExternal, 1); + loader->area_updated_cb = area_updated_cb; + loader->size_cb = size_cb; + loader->area_prepared_cb = area_prepared_cb; + loader->data = data; + return (gpointer) loader; +} + +static void image_loader_external_set_size(gpointer loader, int width, int height) +{ + ImageLoaderExternal *ld = (ImageLoaderExternal *) loader; + ld->requested_width = width; + ld->requested_height = height; +} + +static GdkPixbuf* image_loader_external_get_pixbuf(gpointer loader) +{ + ImageLoaderExternal *ld = (ImageLoaderExternal *) loader; + return ld->pixbuf; +} + +static gchar* image_loader_external_get_format_name(gpointer loader) +{ + return g_strdup("external"); +} + +static gchar** image_loader_external_get_format_mime_types(gpointer loader) +{ + static gchar *mime[] = {"application/octet-stream", NULL}; + return g_strdupv(mime); +} + +static gboolean image_loader_external_close(gpointer loader, GError **error) +{ + return TRUE; +} + +static void image_loader_external_abort(gpointer loader) +{ + ImageLoaderExternal *ld = (ImageLoaderExternal *) loader; + ld->abort = TRUE; +} + +static void image_loader_external_free(gpointer loader) +{ + ImageLoaderExternal *ld = (ImageLoaderExternal *) loader; + if (ld->pixbuf) g_object_unref(ld->pixbuf); + g_free(ld); +} + +void image_loader_backend_set_external(ImageLoaderBackend *funcs) +{ + funcs->loader_new = image_loader_external_new; + funcs->set_size = image_loader_external_set_size; + funcs->load = image_loader_external_load; + funcs->write = NULL; + funcs->get_pixbuf = image_loader_external_get_pixbuf; + funcs->close = image_loader_external_close; + funcs->abort = image_loader_external_abort; + funcs->free = image_loader_external_free; + funcs->get_format_name = image_loader_external_get_format_name; + funcs->get_format_mime_types = image_loader_external_get_format_mime_types; +} + + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/image_load_external.h b/src/image_load_external.h new file mode 100644 index 00000000..a6929d86 --- /dev/null +++ b/src/image_load_external.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef IMAGE_LOAD_EXTERNAL_H +#define IMAGE_LOAD_EXTERNAL_H + +void image_loader_backend_set_external(ImageLoaderBackend *funcs); + +#endif +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/layout.c b/src/layout.c index 26b12e62..37fe728a 100644 --- a/src/layout.c +++ b/src/layout.c @@ -660,6 +660,10 @@ void layout_status_update_progress(LayoutWindow *lw, gdouble val, const gchar *t void layout_status_update_info(LayoutWindow *lw, const gchar *text) { gchar *buf = NULL; + gint hrs; + gint min; + gdouble sec; + GString *delay; if (!layout_valid(&lw)) return; @@ -674,22 +678,40 @@ void layout_status_update_info(LayoutWindow *lw, const gchar *text) { guint s; gint64 s_bytes = 0; - const gchar *ss; + gchar *ss; if (layout_image_slideshow_active(lw)) { + if (!layout_image_slideshow_paused(lw)) { - ss = _(" Slideshow"); + delay = g_string_new(_(" Slideshow [")); } else { - ss = _(" Paused"); + delay = g_string_new(_(" Paused [")); + } + hrs = options->slideshow.delay / (36000); + min = (options->slideshow.delay -(36000 * hrs))/600; + sec = (gdouble)(options->slideshow.delay -(36000 * hrs)-(min * 600)) / 10; + + if (hrs > 0) + { + g_string_append_printf(delay, "%dh ", hrs); + } + if (min > 0) + { + g_string_append_printf(delay, "%dm ", min); } + g_string_append_printf(delay, "%.1fs]", sec); + + ss = g_strdup(delay->str); + + g_string_free(delay, TRUE); } else { - ss = ""; + ss = g_strdup(""); } s = layout_selection_count(lw, &s_bytes); @@ -703,16 +725,19 @@ void layout_status_update_info(LayoutWindow *lw, const gchar *text) buf = g_strdup_printf(_("%s, %d files (%s, %d)%s"), b, n, sb, s, ss); g_free(b); g_free(sb); + g_free(ss); } else if (n > 0) { gchar *b = text_from_size_abrev(n_bytes); buf = g_strdup_printf(_("%s, %d files%s"), b, n, ss); g_free(b); + g_free(ss); } else { buf = g_strdup_printf(_("%d files%s"), n, ss); + g_free(ss); } text = buf; @@ -879,7 +904,7 @@ static void layout_status_setup(LayoutWindow *lw, GtkWidget *box, gboolean small lw->info_status = layout_status_label(NULL, lw->info_box, TRUE, 0, (!small_format)); DEBUG_NAME(lw->info_status); - gtk_widget_set_tooltip_text(GTK_WIDGET(lw->info_status), _("Folder contents (files selected)")); + gtk_widget_set_tooltip_text(GTK_WIDGET(lw->info_status), _("Folder contents (files selected)\nSlideshow [time interval]")); if (small_format) { @@ -2780,6 +2805,12 @@ void layout_write_attributes(LayoutOptions *layout, GString *outstr, gint indent WRITE_NL(); WRITE_INT(*layout, log_window.w); WRITE_NL(); WRITE_INT(*layout, log_window.h); + WRITE_NL(); WRITE_INT(*layout, preferences_window.x); + WRITE_NL(); WRITE_INT(*layout, preferences_window.y); + WRITE_NL(); WRITE_INT(*layout, preferences_window.w); + WRITE_NL(); WRITE_INT(*layout, preferences_window.h); + WRITE_NL(); WRITE_INT(*layout, preferences_window.page_number); + WRITE_NL(); WRITE_INT(*layout, search_window.x); WRITE_NL(); WRITE_INT(*layout, search_window.y); WRITE_NL(); WRITE_INT(*layout, search_window.w); @@ -2883,6 +2914,12 @@ void layout_load_attributes(LayoutOptions *layout, const gchar **attribute_names if (READ_INT(*layout, log_window.w)) continue; if (READ_INT(*layout, log_window.h)) continue; + if (READ_INT(*layout, preferences_window.x)) continue; + if (READ_INT(*layout, preferences_window.y)) continue; + if (READ_INT(*layout, preferences_window.w)) continue; + if (READ_INT(*layout, preferences_window.h)) continue; + if (READ_INT(*layout, preferences_window.page_number)) continue; + if (READ_INT(*layout, search_window.x)) continue; if (READ_INT(*layout, search_window.y)) continue; if (READ_INT(*layout, search_window.w)) continue; diff --git a/src/layout_util.c b/src/layout_util.c index b24f6e29..a9c7da75 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); @@ -661,7 +661,7 @@ static void layout_menu_config_cb(GtkAction *action, gpointer data) LayoutWindow *lw = data; layout_exit_fullscreen(lw); - show_config_window(); + show_config_window(lw); } static void layout_menu_editors_cb(GtkAction *action, gpointer data) @@ -2557,8 +2557,8 @@ static GtkActionEntry menu_entries[] = { { "HistogramModeCycle",NULL, N_("Cycle through histogram mo_des"), "J", N_("Cycle through histogram modes"), CB(layout_menu_histogram_toggle_mode_cb) }, { "HideTools", PIXBUF_INLINE_ICON_HIDETOOLS, N_("_Hide file list"), "H", N_("Hide file list"), CB(layout_menu_hide_cb) }, { "SlideShowPause", GTK_STOCK_MEDIA_PAUSE, N_("_Pause slideshow"), "P", N_("Pause slideshow"), CB(layout_menu_slideshow_pause_cb) }, - { "SlideShowFaster", GTK_STOCK_FILE, N_("Faster"), "KP_Add", N_("Slideshow Faster"), CB(layout_menu_slideshow_faster_cb) }, - { "SlideShowSlower", GTK_STOCK_FILE, N_("Slower"), "KP_Subtract", N_("Slideshow Slower"), CB(layout_menu_slideshow_slower_cb) }, + { "SlideShowFaster", GTK_STOCK_FILE, N_("Faster"), "equal", N_("Slideshow Faster"), CB(layout_menu_slideshow_faster_cb) }, + { "SlideShowSlower", GTK_STOCK_FILE, N_("Slower"), "minus", N_("Slideshow Slower"), CB(layout_menu_slideshow_slower_cb) }, { "Refresh", GTK_STOCK_REFRESH, N_("_Refresh"), "R", N_("Refresh"), CB(layout_menu_refresh_cb) }, { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", N_("Contents"), CB(layout_menu_help_cb) }, { "HelpSearch", NULL, N_("On-line help search"), NULL, N_("On-line help search"), CB(layout_menu_help_search_cb) }, diff --git a/src/lua.c b/src/lua.c index 384037fd..cb0eb650 100644 --- a/src/lua.c +++ b/src/lua.c @@ -38,6 +38,18 @@ #include "ui_fileops.h" #include "exif.h" +/** + * @file + * User API consists of the following namespaces: + * + * @link image_methods Image:@endlink basic image information + * + * Collection: not implemented + * + * @link exif_methods :get_datum() @endlink get single exif parameter + * + */ + static lua_State *L; /** The LUA object needed for all operations (NOTE: That is * a upper-case variable to match the documentation!) */ @@ -69,6 +81,13 @@ static FileData *lua_check_image(lua_State *L, int index) return *fd; } +/** + * @brief Get exif structure of selected image + * @param L + * @returns An @ref ExifData data structure containing the entire exif data + * + * To be used in conjunction with @link lua_exif_get_datum :get_datum() @endlink + */ static int lua_image_get_exif(lua_State *L) { FileData *fd; @@ -87,6 +106,13 @@ static int lua_image_get_exif(lua_State *L) return 1; } +/** + * @brief Get full path of selected image + * @param L + * @returns char The full path of the file, including filename and extension + * + * + */ static int lua_image_get_path(lua_State *L) { FileData *fd; @@ -96,6 +122,13 @@ static int lua_image_get_path(lua_State *L) return 1; } +/** + * @brief Get full filename of selected image + * @param L + * @returns char The full filename including extension + * + * + */ static int lua_image_get_name(lua_State *L) { FileData *fd; @@ -105,6 +138,13 @@ static int lua_image_get_name(lua_State *L) return 1; } +/** + * @brief Get file extension of selected image + * @param L + * @returns char The file extension including preceding dot + * + * + */ static int lua_image_get_extension(lua_State *L) { FileData *fd; @@ -114,6 +154,14 @@ static int lua_image_get_extension(lua_State *L) return 1; } +/** + * @brief Get file date of selected image + * @param L + * @returns time_t The file date in Unix timestamp format. + * + * time_t - signed integer which represents the number of seconds since + * the start of the Unix epoch: midnight UTC of January 1, 1970 + */ static int lua_image_get_date(lua_State *L) { FileData *fd; @@ -123,6 +171,13 @@ static int lua_image_get_date(lua_State *L) return 1; } +/** + * @brief Get file size of selected image + * @param L + * @returns integer The file size in bytes + * + * + */ static int lua_image_get_size(lua_State *L) { FileData *fd; @@ -132,6 +187,15 @@ static int lua_image_get_size(lua_State *L) return 1; } +/** + * @brief Get marks of selected image + * @param L + * @returns unsigned integer Bit map of marks set + * + * Bit 0 == Mark 1 etc. + * + * + */ static int lua_image_get_marks(lua_State *L) { FileData *fd; @@ -150,7 +214,21 @@ static ExifData *lua_check_exif(lua_State *L, int index) return *exif; } -/* Interface for EXIF data */ +/** + * @brief Interface for EXIF data + * @param L + * @returns return A single exif tag extracted from a structure output by the @link lua_image_get_exif Image:get_exif() @endlink command + * + * e.g. \n + * exif_structure = Image:get_exif(); \n + * DateTimeDigitized = exif_structure:get_datum("Exif.Photo.DateTimeDigitized"); + * + * Where return is: \n + * Exif.Photo.DateTimeOriginal = signed integer time_t \n + * Exif.Photo.DateTimeDigitized = signed integer time_t \n + * otherwise char + * + */ static int lua_exif_get_datum(lua_State *L) { const gchar *key; @@ -206,6 +284,37 @@ static int lua_exif_get_datum(lua_State *L) return 1; } +/** + * @brief Image: metatable and methods \n + * Call by e.g. \n + * path_name = @link lua_image_get_path Image:getpath() @endlink \n + * where the keyword Image represents the currently selected image + */ +static const luaL_Reg image_methods[] = { + {"get_path", lua_image_get_path}, + {"get_name", lua_image_get_name}, + {"get_extension", lua_image_get_extension}, + {"get_date", lua_image_get_date}, + {"get_size", lua_image_get_size}, + {"get_exif", lua_image_get_exif}, + {"get_marks", lua_image_get_marks}, + {NULL, NULL} +}; + +/** + * @brief exif: table and methods \n + * Call by e.g. \n + * @link lua_exif_get_datum :get_datum() @endlink \n + * where is the output of @link lua_image_get_exif Image:get_exif() @endlink + * + * exif_structure = Image:get_exif(); \n + * DateTimeDigitized = exif_structure:get_datum("Exif.Photo.DateTimeDigitized"); + */ +static const luaL_Reg exif_methods[] = { + {"get_datum", lua_exif_get_datum}, + {NULL, NULL} +}; + /** * @brief Initialize the lua interpreter. */ @@ -219,17 +328,6 @@ void lua_init(void) {NULL, NULL} }; - /* The Image metatable and methodes */ - static const luaL_Reg image_methods[] = { - {"get_path", lua_image_get_path}, - {"get_name", lua_image_get_name}, - {"get_extension", lua_image_get_extension}, - {"get_date", lua_image_get_date}, - {"get_size", lua_image_get_size}, - {"get_exif", lua_image_get_exif}, - {"get_marks", lua_image_get_marks}, - {NULL, NULL} - }; LUA_register_global(L, "Image", image_methods); luaL_newmetatable(L, "Image"); LUA_register_meta(L, meta_methods); @@ -242,11 +340,6 @@ void lua_init(void) lua_pop(L, 1); lua_pop(L, 1); - /* The Exif table and methodes */ - static const luaL_Reg exif_methods[] = { - {"get_datum", lua_exif_get_datum}, - {NULL, NULL} - }; LUA_register_global(L, "Exif", exif_methods); luaL_newmetatable(L, "Exif"); LUA_register_meta(L, meta_methods); diff --git a/src/main.c b/src/main.c index 14c0a7f5..fd3343ee 100644 --- a/src/main.c +++ b/src/main.c @@ -42,6 +42,7 @@ #include "layout.h" #include "layout_image.h" #include "layout_util.h" +#include "misc.h" #include "options.h" #include "remote.h" #include "secure_save.h" @@ -69,6 +70,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 +618,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 +930,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 +991,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 @@ -985,6 +1036,7 @@ gint main(gint argc, gchar *argv[]) if (gtk_clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS) { log_printf("Can't initialize clutter-gtk.\nStart Geeqie with the option \"geeqie --disable-clutter\""); + runcmd("zenity --error --title=\"Geeqie\" --text \"Can't initialize clutter-gtk.\n\nStart Geeqie with the option:\n geeqie --disable-clutter\" --width=300"); exit(1); } } 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/options.c b/src/options.c index 0cf60928..09cc2728 100644 --- a/src/options.c +++ b/src/options.c @@ -330,6 +330,8 @@ LayoutOptions *init_layout_options(LayoutOptions *options) options->bars_state.hidden = FALSE; options->log_window.w = 520; options->log_window.h = 400; + options->preferences_window.w = 700; + options->preferences_window.h = 600; options->split_pane_sync = FALSE; options->workspace = -1; return options; diff --git a/src/options.h b/src/options.h index 702889b7..c1f9256e 100644 --- a/src/options.h +++ b/src/options.h @@ -310,6 +310,13 @@ struct _ConfOptions } tmp; } stereo; + /* External preview extraction */ + struct { + gboolean enable; + gchar *select; /**< path to executable */ + gchar *extract; /**< path to executable */ + } external_preview; + /** * @struct cp_mv_rn * copy move rename diff --git a/src/preferences.c b/src/preferences.c index cf72e35c..d0d34a2c 100644 --- a/src/preferences.c +++ b/src/preferences.c @@ -137,6 +137,8 @@ static GtkWidget *safe_delete_path_entry; static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS]; static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS]; static GtkWidget *color_profile_screen_file_entry; +static GtkWidget *external_preview_select_entry; +static GtkWidget *external_preview_extract_entry; static GtkWidget *sidecar_ext_entry; static GtkWidget *help_search_engine_entry; @@ -434,6 +436,10 @@ static void config_window_apply(void) options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen; config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL); + options->external_preview.enable = c_options->external_preview.enable; + config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL); + config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL); + options->read_metadata_in_idle = c_options->read_metadata_in_idle; options->star_rating.star = c_options->star_rating.star; @@ -510,7 +516,8 @@ static void config_window_help_cb(GtkWidget *widget, gpointer data) "GuideOptionsStereo.html", "GuideOptionsBehavior.html", "GuideOptionsToolbar.html", - "GuideOptionsToolbar.html" + "GuideOptionsToolbar.html", + "GuideOptionsAdvanced.html" }; i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)); @@ -526,8 +533,28 @@ static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpoi static void config_window_ok_cb(GtkWidget *widget, gpointer data) { LayoutWindow *lw; + GtkNotebook *notebook = data; + GdkWindow *window; + gint x; + gint y; + gint w; + gint h; + gint page_number; + lw = layout_window_list->data; + window = gtk_widget_get_window(widget); + gdk_window_get_root_origin(window, &x, &y); + w = gdk_window_get_width(window); + h = gdk_window_get_height(window); + page_number = gtk_notebook_get_current_page(notebook); + + lw->options.preferences_window.x = x; + lw->options.preferences_window.y = y; + lw->options.preferences_window.w = w; + lw->options.preferences_window.h = h; + lw->options.preferences_window.page_number = page_number; + config_window_apply(); layout_util_sync(lw); save_options(options); @@ -3567,6 +3594,92 @@ static void config_tab_toolbar_status(GtkWidget *notebook) gtk_widget_show(vbox); } +/* advanced tab */ +static gint extension_sort_cb(gconstpointer a, gconstpointer b) +{ + return g_strcmp0((gchar *)a, (gchar *)b); +} + +static void config_tab_advanced(GtkWidget *notebook) +{ + GtkWidget *vbox; + GtkWidget *group; + GSList *formats_list; + GList *extensions_list = NULL; + gchar **extensions; + GtkWidget *tabcomp; + GdkPixbufFormat *fm; + gint i; + GString *types_string = g_string_new(NULL); + + vbox = scrolled_notebook_page(notebook, _("Advanced")); + group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL); + + pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable); + + pref_spacer(group, PREF_PAD_GROUP); + + formats_list = gdk_pixbuf_get_formats(); + + while (formats_list) + { + fm = formats_list->data; + extensions = gdk_pixbuf_format_get_extensions(fm); + + i = 0; + while (extensions[i]) + { + extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb); + i++; + } + + g_strfreev(extensions); + formats_list = formats_list->next; + } + + while (extensions_list) + { + if (types_string->len == 0) + { + types_string = g_string_append(types_string, extensions_list->data); + } + else + { + types_string = g_string_append(types_string, ", "); + types_string = g_string_append(types_string, extensions_list->data); + } + + extensions_list = extensions_list->next; + } + + types_string = g_string_prepend(types_string, _("Usable file types:\n")); + pref_label_new(group, types_string->str); + GtkWidget *types_string_label = gtk_label_new(types_string->str); + gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE); + + pref_spacer(group, PREF_PAD_GROUP); + + group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL); + external_preview_select_entry = gtk_entry_new(); + tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL); + tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE); + gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0); + gtk_widget_show(tabcomp); + + group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL); + external_preview_extract_entry = gtk_entry_new(); + tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL); + tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE); + gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0); + gtk_widget_show(tabcomp); + + gtk_widget_show(vbox); + + g_slist_free(formats_list); + string_list_free(extensions_list); + g_string_free(types_string, TRUE); +} + /* stereo tab */ static void config_tab_stereo(GtkWidget *notebook) { @@ -3645,7 +3758,7 @@ static void config_tab_stereo(GtkWidget *notebook) } /* Main preferences window */ -static void config_window_create(void) +static void config_window_create(LayoutWindow *lw) { GtkWidget *win_vbox; GtkWidget *hbox; @@ -3660,7 +3773,15 @@ static void config_window_create(void) gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG); g_signal_connect(G_OBJECT(configwindow), "delete_event", G_CALLBACK(config_window_delete), NULL); - gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT); + if (options->save_dialog_window_positions) + { + gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h); + gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y); + } + else + { + gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT); + } gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE); gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER); @@ -3686,6 +3807,9 @@ static void config_window_create(void) config_tab_behavior(notebook); config_tab_toolbar_main(notebook); config_tab_toolbar_status(notebook); + config_tab_advanced(notebook); + + gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number); hbox = gtk_hbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END); @@ -3700,7 +3824,7 @@ static void config_window_create(void) gtk_widget_show(button); button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE, - G_CALLBACK(config_window_ok_cb), NULL); + G_CALLBACK(config_window_ok_cb), notebook); gtk_container_add(GTK_CONTAINER(hbox), button); gtk_widget_set_can_default(button, TRUE); gtk_widget_grab_default(button); @@ -3730,7 +3854,7 @@ static void config_window_create(void) *----------------------------------------------------------------------------- */ -void show_config_window(void) +void show_config_window(LayoutWindow *lw) { if (configwindow) { @@ -3738,7 +3862,7 @@ void show_config_window(void) return; } - config_window_create(); + config_window_create(lw); } /* @@ -3783,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/preferences.h b/src/preferences.h index e910dc58..840d5dd2 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -23,7 +23,7 @@ #define PREFERENCES_H -void show_config_window(void); +void show_config_window(LayoutWindow *lw); void show_about_window(LayoutWindow *lw); /** diff --git a/src/rcfile.c b/src/rcfile.c index cac00af1..7f3d3842 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -353,6 +353,10 @@ static void write_global_attributes(GString *outstr, gint indent) WRITE_NL(); WRITE_BOOL(*options, marks_save); WRITE_NL(); WRITE_CHAR(*options, help_search_engine); + WRITE_NL(); WRITE_BOOL(*options, external_preview.enable); + WRITE_NL(); WRITE_CHAR(*options, external_preview.select); + WRITE_NL(); WRITE_CHAR(*options, external_preview.extract); + WRITE_NL(); WRITE_BOOL(*options, with_rename); WRITE_NL(); WRITE_BOOL(*options, collections_on_top); WRITE_NL(); WRITE_BOOL(*options, hide_window_in_fullscreen); @@ -786,6 +790,10 @@ static gboolean load_global_params(const gchar **attribute_names, const gchar ** if (READ_BOOL(*options, marks_save)) continue; if (READ_CHAR(*options, help_search_engine)) continue; + if (READ_BOOL(*options, external_preview.enable)) continue; + if (READ_CHAR(*options, external_preview.select)) continue; + if (READ_CHAR(*options, external_preview.extract)) continue; + if (READ_BOOL(*options, collections_on_top)) continue; if (READ_BOOL(*options, hide_window_in_fullscreen)) continue; diff --git a/src/typedefs.h b/src/typedefs.h index ad4c1a3d..d9c5e04a 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -710,6 +710,14 @@ struct _LayoutOptions gint y; } log_window; + struct { + gint w; + gint h; + gint x; + gint y; + gint page_number; + } preferences_window; + struct { gint w; gint h; diff --git a/src/utilops.c b/src/utilops.c index e65430ca..222c95bd 100644 --- a/src/utilops.c +++ b/src/utilops.c @@ -2180,8 +2180,7 @@ static void file_util_mark_ungrouped_files(GList *work) } } - -static void file_util_delete_full(FileData *source_fd, GList *flist, GtkWidget *parent, UtilityPhase phase) +static void file_util_delete_full(FileData *source_fd, GList *flist, GtkWidget *parent, UtilityPhase phase, FileUtilDoneFunc done_func, gpointer done_data) { UtilityData *ud; GList *ungrouped = NULL; @@ -2216,6 +2215,8 @@ static void file_util_delete_full(FileData *source_fd, GList *flist, GtkWidget * ud->flist = flist; ud->content_list = NULL; ud->parent = parent; + ud->done_data = done_data; + ud->done_func = done_func; ud->details_func = file_util_details_dialog; if(options->file_ops.safe_delete_enable) @@ -3032,7 +3033,12 @@ static gboolean file_util_write_metadata_first(UtilityType type, UtilityPhase ph void file_util_delete(FileData *source_fd, GList *source_list, GtkWidget *parent) { - file_util_delete_full(source_fd, source_list, parent, options->file_ops.confirm_delete ? UTILITY_PHASE_START : UTILITY_PHASE_ENTERING); + file_util_delete_full(source_fd, source_list, parent, options->file_ops.confirm_delete ? UTILITY_PHASE_START : UTILITY_PHASE_ENTERING, NULL, NULL); +} + +void file_util_delete_notify_done(FileData *source_fd, GList *source_list, GtkWidget *parent, FileUtilDoneFunc done_func, gpointer done_data) +{ + file_util_delete_full(source_fd, source_list, parent, options->file_ops.confirm_delete ? UTILITY_PHASE_START : UTILITY_PHASE_ENTERING, done_func, done_data); } void file_util_write_metadata(FileData *source_fd, GList *source_list, GtkWidget *parent, gboolean force_dialog, FileUtilDoneFunc done_func, gpointer done_data) diff --git a/src/utilops.h b/src/utilops.h index 43a6b2a6..1a5eca4a 100644 --- a/src/utilops.h +++ b/src/utilops.h @@ -43,6 +43,7 @@ GenericDialog *file_util_warning_dialog(const gchar *heading, const gchar *messa /* all functions takes over the filelist and frees it when done */ void file_util_delete(FileData *source_fd, GList *source_list, GtkWidget *parent); +void file_util_delete_notify_done(FileData *source_fd, GList *source_list, GtkWidget *parent, FileUtilDoneFunc done_func, gpointer done_data); void file_util_move(FileData *source_fd, GList *source_list, const gchar *dest_path, GtkWidget *parent); void file_util_copy(FileData *source_fd, GList *source_list, const gchar *dest_path, GtkWidget *parent); void file_util_rename(FileData *source_fd, GList *source_list, GtkWidget *parent); 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); diff --git a/web/index.html b/web/index.html index 73f60b2d..57e4a41d 100644 --- a/web/index.html +++ b/web/index.html @@ -27,7 +27,7 @@ -