changeset 2714:e0251a8eba95

Merge remote-tracking branches 'github/merge-requests/581', 'github/merge-requests/576', 'github/merge-requests/574' and 'github/merge-requests/573' * github/merge-requests/581: Fix crash after strange behaviour of the "Really Continue" dialog * github/merge-requests/576: Trap build errors * github/merge-requests/574: Fix spelling mistake occured/occurred * github/merge-requests/573: Partially fix #561: Hi-DPI-aware rendering of images.
author Klaus Ethgen <Klaus@Ethgen.de>
date Mon, 22 Jan 2018 21:07:11 +0100
parents 3040da7c5c35 (diff) cac6dcf7e2e7 (current diff)
children cf6d3d6a6dc2
files src/print.c src/remote.c src/renderer-tiles.c
diffstat 26 files changed, 556 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/doc/docbook/GuideImageSearchSearch.xml	Mon Jan 22 21:07:11 2018 +0100
+++ b/doc/docbook/GuideImageSearchSearch.xml	Mon Jan 22 21:07:11 2018 +0100
@@ -89,7 +89,7 @@
           <guilabel>File date</guilabel>
         </term>
         <listitem>
-          The search will match if the file modification time on disk is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
+          The search will match if the file date is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
           <emphasis>between</emphasis>
           test is inclusive, for example a file with date of 10/04/2003 will match if the date parameters are between 10/04/2003 and 12/31/2003.
           <para />
@@ -103,9 +103,10 @@
           </code>
           button displays a pop up calendar to enter the date.
           <para />
-          The
-          <emphasis role="strong">Exif date</emphasis>
-          checkbox permits searches to be made on the exif date of images. If an image does not have an exif date, it will default to 01 January 1970.
+          One of four date types may be selected. They are described in the
+          <link linkend="GuideReferenceFileDates">Reference section</link>
+          .
+          <note>If an image does not have an exif date, it will default to 01 January 1970.</note>
         </listitem>
       </varlistentry>
       <varlistentry>
@@ -161,6 +162,21 @@
           </note>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term>
+          <guilabel>Class</guilabel>
+        </term>
+        <listitem>
+          The search will match if the file's class is, or is not, one of the following types.
+          <itemizedlist>
+            <listitem>Unknown</listitem>
+            <listitem>Image</listitem>
+            <listitem>Raw Image</listitem>
+            <listitem>Video</listitem>
+            <listitem>Metadata</listitem>
+          </itemizedlist>
+        </listitem>
+      </varlistentry>
     </variablelist>
     <para />
     <para />
--- a/doc/docbook/GuideMainWindowStatusBar.xml	Mon Jan 22 21:07:11 2018 +0100
+++ b/doc/docbook/GuideMainWindowStatusBar.xml	Mon Jan 22 21:07:11 2018 +0100
@@ -39,18 +39,14 @@
       </varlistentry>
       <varlistentry>
         <term>
-          <guilabel>File Creation Date</guilabel>
+          <guilabel>File Date</guilabel>
         </term>
         <listitem>
-          <para>Images are sorted by file creation date.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>
-          <guilabel>Exif Date</guilabel>
-        </term>
-        <listitem>
-          <para>Images are sorted by file Exif date.</para>
+          <para>
+            Images are sorted by one of four types of file date. They are described in the
+            <link linkend="GuideReferenceFileDates">Reference section</link>
+            .
+          </para>
         </listitem>
       </varlistentry>
       <varlistentry>
@@ -58,7 +54,30 @@
           <guilabel>Size</guilabel>
         </term>
         <listitem>
-          <para>Image are sorted by file size on disk.</para>
+          <para>Images are sorted by file size on disk.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>
+          <guilabel>Rating</guilabel>
+        </term>
+        <listitem>
+          <para>Image are sorted by Xmp.xmp.Rating.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>
+          <guilabel>Class</guilabel>
+        </term>
+        <listitem>
+          <para>Image are sorted by class. The class types, and sort order, is:</para>
+          <itemizedlist>
+            <listitem>Unknown</listitem>
+            <listitem>Image</listitem>
+            <listitem>Raw Image</listitem>
+            <listitem>Video</listitem>
+            <listitem>Metadata</listitem>
+          </itemizedlist>
         </listitem>
       </varlistentry>
       <varlistentry>
@@ -70,7 +89,7 @@
         </listitem>
       </varlistentry>
     </variablelist>
-    <para />
+    <note>When images have equal rank, for example in rating or class sorts, within each section images will be sorted by filename.</note>
   </section>
   <section id="Filelist">
     <title>File list</title>
--- a/doc/docbook/GuideOtherWindowsPanView.xml	Mon Jan 22 21:07:11 2018 +0100
+++ b/doc/docbook/GuideOtherWindowsPanView.xml	Mon Jan 22 21:07:11 2018 +0100
@@ -22,6 +22,11 @@
     You can pan the view as you pan an image in normal view mode, using left mouse button and drag.
   </para>
   <para>A primary mouse button click on any image will display informations about the image. Secondary mouse button will show a context menu.</para>
+  <para>
+    The
+    <link linkend="GuideReferenceKeyboardShortcuts" endterm="titleGuideReferenceKeyboardShortcuts" />
+    available are listed in the Reference section.
+  </para>
   <note>
     <para>Pan view recursively visits each folder under the specified folder. This can consume considerable computer resources.</para>
   </note>
@@ -209,4 +214,4 @@
       </varlistentry>
     </variablelist>
   </section>
-</section>
+</section>
--- a/plugins/rotate/geeqie-rotate	Mon Jan 22 21:07:11 2018 +0100
+++ b/plugins/rotate/geeqie-rotate	Mon Jan 22 21:07:11 2018 +0100
@@ -11,38 +11,57 @@
     [ "x$ext" = "x" ] && return 1 #no extension
 
     gq_metadata="$GQ_METADATA_DIR/$1.gq.xmp"
-    if [ -f "$gq_metadata" ]; then
-	gq_orientation=`exiv2 -PXkv "$gq_metadata"|grep Xmp.tiff.Orientation|sed -e "s|Xmp.tiff.Orientation *||"`
+    if [ -f "$gq_metadata" ] ; then
+		gq_orientation=`exiv2 -PXkv "$gq_metadata"|grep Xmp.tiff.Orientation|sed -e "s|Xmp.tiff.Orientation *||"`
+		[ $? != 0 ] && exit 1
     else
-	gq_orientation=
+		gq_orientation=
     fi
 
     case "$ext" in
 	jpg|jpeg) 
-		[ -n "$gq_orientation" ] && exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+		if [ -n "$gq_orientaqtion" ] ; then
+			exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+			[ $? != 0 ] && exit 1
+		fi
 		if exiftran -aip "$1" ; then
 		    # exiftran ignores xmp, set it manually
 		    exiv2 -M "set Xmp.tiff.Orientation 1" "$1"
+			[ $? != 0 ] && exit 1
 		    #http://dev.exiv2.org/issues/show/639
-		    [ -n "$gq_orientation" ] && exiv2 -M "set Xmp.tiff.Orientation 1" \
-		                                      -M "set Exif.Image.Orientation 1" "$gq_metadata"
+			if [ -n "$gq_orientation" ] ; then
+				exiv2 -M "set Xmp.tiff.Orientation 1" \
+								-M "set Exif.Image.Orientation 1" "$gq_metadata"
+				[ $? != 0 ] && exit 1
+			fi
 		    return 0
+		else
+			exit 1
 		fi
 		;;
 	
 	tif|tiff|png)
-		[ -n "$gq_orientation" ] && exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+		if [ -n "$gq_orientation" ] ; then
+			exiv2 -M "set Exif.Image.Orientation $gq_orientation" "$1"
+			[ $? != 0 ] && exit 1
+		fi
 		if mogrify -auto-orient "$1" ; then
 		    # mogrify ignores xmp, set it manually
 		    exiv2 -M "set Xmp.tiff.Orientation 1" "$1"
+			[ $? != 0 ] && exit 1
 		    #http://dev.exiv2.org/issues/show/639
-		    [ -n "$gq_orientation" ] && exiv2 -M "set Xmp.tiff.Orientation 1" \
-		                                      -M "set Exif.Image.Orientation 1" "$gq_metadata"
+			if [ -n "$gq_orientation" ] ; then
+				exiv2 -M "set Xmp.tiff.Orientation 1" \
+								-M "set Exif.Image.Orientation 1" "$gq_metadata"
+				[ $? != 0 ] && exit 1
+			fi
 		    return 0
+		else
+			exit 1
 		fi
 		;;
 	*)	#not supported
-		return 0
+		return 4
 		;;
     esac
 }
@@ -50,17 +69,19 @@
 rotate_image_file()
 {
 	ext=`echo "${3##*.}" |tr "[:upper:]" "[:lower:]"`
-	[ "x$ext" = "x" ] && return 4 #no extension
+	[ "x$ext" = "x" ] && return 1 #no extension
 
 	case "$ext" in
 	jpg|jpeg)
 		exiftran -i "$1" "$3"
-		return 0
+		[ $? != 0 ]  && return 6
+		return 0;
 		;;
 
 	tif|tiff|png)
 		mogrify $2 "$3"
-		return 0
+		[ $? != 0 ]  && return 7
+		return 0;
 		;;
 
 	*)	#not supported
@@ -131,9 +152,15 @@
         # get the sidecars:
         geeqie -r --get-sidecars:"$file" |while read sidecar ; do
             # the main file is included in the sidecar file list, no special handling is required
+			[ ! -w "$sidecar" ] && exit 5
             rotate "$sidecar"
+			ret=$?
         done
+		# Bourne shell runs DO loops in a sub-shell
+		ret=$?
+		[ $ret != 0 ] && exit $ret
     else
+		[ ! -w "$file" ] && exit 5
 		if [ -n "$rotate_image_file" ] ; then
 			if [ -n "$preserve_mtime" ] ; then
 				mtime=`mktemp /tmp/geeqie-rotate.XXXXXXXXXX` || exit 3
@@ -147,12 +174,13 @@
 				touch --reference="$mtime" "$file"
 				rm "$mtime"
 			fi
-			if [ $ret -eq 4 ] ; then
-				exit 4
-			fi
+			[ $ret != 0 ]  && exit $ret
 		else
 			rotate "$file"
+			ret=$?
+			[ $ret != 0 ] && exit $ret
 		fi
     fi
 done
 
+exit 0
--- a/src/advanced_exif.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/advanced_exif.c	Mon Jan 22 21:07:11 2018 +0100
@@ -26,6 +26,7 @@
 #include "metadata.h"
 #include "filedata.h"
 #include "history_list.h"
+#include "layout_util.h"
 #include "misc.h"
 #include "ui_misc.h"
 #include "window.h"
@@ -360,6 +361,11 @@
 				break;
 			}
 		} // if (event->state & GDK_CONTROL...
+	if (!stop_signal && is_help_key(event))
+		{
+		help_window_show("GuideOtherWindowsExif.html");
+		stop_signal = TRUE;
+		}
 
 	return stop_signal;
 } // static gboolean advanced_exif_...
--- a/src/collect.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/collect.c	Mon Jan 22 21:07:11 2018 +0100
@@ -30,6 +30,7 @@
 #include "img-view.h"
 #include "layout.h"
 #include "layout_image.h"
+#include "layout_util.h"
 #include "misc.h"
 #include "pixbuf_util.h"
 #include "print.h"
@@ -168,9 +169,25 @@
 			if (cia->fd->cdate > cib->fd->cdate) return 1;
 			return 0;
 			break;
+		case SORT_EXIFTIME:
+			if (cia->fd->exifdate < cib->fd->exifdate) return -1;
+			if (cia->fd->exifdate > cib->fd->exifdate) return 1;
+			break;
+		case SORT_EXIFTIMEDIGITIZED:
+			if (cia->fd->exifdate_digitized < cib->fd->exifdate_digitized) return -1;
+			if (cia->fd->exifdate_digitized > cib->fd->exifdate_digitized) return 1;
+			break;
+		case SORT_RATING:
+			if (cia->fd->rating < cib->fd->rating) return -1;
+			if (cia->fd->rating > cib->fd->rating) return 1;
+			break;
 		case SORT_PATH:
 			return utf8_compare(cia->fd->path, cib->fd->path, options->file_sort.case_sensitive);
 			break;
+		case SORT_CLASS:
+			if (cia->fd->format_class < cib->fd->format_class) return -1;
+			if (cia->fd->format_class > cib->fd->format_class) return 1;
+			break;
 #ifdef HAVE_STRVERSCMP
 		case SORT_NUMBER:
 			return strverscmp(cia->fd->name, cib->fd->name);
@@ -992,14 +1009,17 @@
 					collection_remove_by_info(cw->cd, collection_table_get_focus_info(cw->table));
 					}
 				break;
-			case GDK_KEY_F1:
-				help_window_show("GuideReferenceKeyboardShortcuts.html#CollectionsKeyboardShortcuts");
-				break;
 			default:
 				stop_signal = FALSE;
 				break;
 			}
 		}
+	if (!stop_signal && is_help_key(event))
+		{
+		help_window_show("GuideCollections.html");
+		stop_signal = TRUE;
+		}
+
 	return stop_signal;
 }
 
--- a/src/color-man.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/color-man.c	Mon Jan 22 21:07:11 2018 +0100
@@ -443,7 +443,7 @@
 				cmsUInt32Number r;
 				char buffer[20];
 				buffer[0] = '\0';
-				r = cmsGetProfileInfoASCII(profile, cmsInfoDescription, "en", "US", buffer, 20);
+				cmsGetProfileInfoASCII(profile, cmsInfoDescription, "en", "US", buffer, 20);
 				buffer[19] = '\0'; /* Just to be sure */
 				return g_strdup(buffer);
 #else
--- a/src/dupe.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/dupe.c	Mon Jan 22 21:07:11 2018 +0100
@@ -32,6 +32,7 @@
 #include "img-view.h"
 #include "layout.h"
 #include "layout_image.h"
+#include "layout_util.h"
 #include "md5-util.h"
 #include "menu.h"
 #include "misc.h"
@@ -2361,7 +2362,7 @@
 	submenu_add_edit(menu, &item, G_CALLBACK(dupe_menu_edit_cb), dw, editmenu_fd_list);
 	if (!on_row) gtk_widget_set_sensitive(item, FALSE);
 
-	submenu = submenu_add_collections(menu, &item,
+	submenu_add_collections(menu, &item,
 								G_CALLBACK(dupe_pop_menu_collections_cb), dw);
 	gtk_widget_set_sensitive(item, on_row);
 
@@ -3165,14 +3166,16 @@
 						       dupe_popup_menu_pos_cb, listview, 0, GDK_CURRENT_TIME);
 					}
 				break;
-			case GDK_KEY_F1:
-				help_window_show("GuideReferenceKeyboardShortcuts.html#DuplicatesKeyboardShortcuts");
-				break;
 			default:
 				stop_signal = FALSE;
 				break;
 			}
 		}
+	if (!stop_signal && is_help_key(event))
+		{
+		help_window_show("GuideImageSearchFindingDuplicates.html");
+		stop_signal = TRUE;
+		}
 
 	return stop_signal;
 }
--- a/src/exif-common.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/exif-common.c	Mon Jan 22 21:07:11 2018 +0100
@@ -250,6 +250,57 @@
 	return text;
 }
 
+static gchar *exif_build_formatted_DateTimeDigitized(ExifData *exif)
+{
+	gchar *text = exif_get_data_as_text(exif, "Exif.Photo.DateTimeDigitized");
+	gchar *subsec = NULL;
+	gchar buf[128];
+	gchar *tmp;
+	gint buflen;
+	struct tm tm;
+	GError *error = NULL;
+
+	if (text)
+		{
+		subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTimeDigitized");
+		}
+	else
+		{
+		text = exif_get_data_as_text(exif, "Exif.Image.DateTime");
+		if (text) subsec = exif_get_data_as_text(exif, "Exif.Photo.SubSecTime");
+		}
+
+	/* Convert the stuff into a tm struct */
+	memset(&tm, 0, sizeof(tm)); /* Uh, strptime could let garbage in tm! */
+	if (text && strptime(text, "%Y:%m:%d %H:%M:%S", &tm))
+		{
+		buflen = strftime(buf, sizeof(buf), "%x %X", &tm);
+		if (buflen > 0)
+			{
+			tmp = g_locale_to_utf8(buf, buflen, NULL, NULL, &error);
+			if (error)
+				{
+				log_printf("Error converting locale strftime to UTF-8: %s\n", error->message);
+				g_error_free(error);
+				}
+			else
+				{
+				g_free(text);
+				text = g_strdup(tmp);
+				}
+			}
+		}
+
+	if (subsec)
+		{
+		tmp = text;
+		text = g_strconcat(tmp, ".", subsec, NULL);
+		g_free(tmp);
+		g_free(subsec);
+		}
+	return text;
+}
+
 static gchar *exif_build_formatted_ShutterSpeed(ExifData *exif)
 {
 	ExifRational *r;
@@ -563,6 +614,7 @@
 ExifFormattedText ExifFormattedList[] = {
 	EXIF_FORMATTED_TAG(Camera,		N_("Camera")),
 	EXIF_FORMATTED_TAG(DateTime,		N_("Date")),
+	EXIF_FORMATTED_TAG(DateTimeDigitized,	N_("DateDigitized")),
 	EXIF_FORMATTED_TAG(ShutterSpeed,	N_("Shutter speed")),
 	EXIF_FORMATTED_TAG(Aperture,		N_("Aperture")),
 	EXIF_FORMATTED_TAG(ExposureBias,	N_("Exposure bias")),
--- a/src/filedata.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/filedata.c	Mon Jan 22 21:07:11 2018 +0100
@@ -503,6 +503,41 @@
 		}
 }
 
+void read_exif_time_digitized_data(FileData *file)
+{
+	if (file->exifdate > 0)
+		{
+		DEBUG_1("%s set_exif_time_digitized_data: Already exists for %s", get_exec_time(), file->path);
+		return;
+		}
+
+	file->exif = exif_read_fd(file);
+
+	if (file->exif)
+		{
+		gchar *tmp = exif_get_data_as_text(file->exif, "Exif.Photo.DateTimeDigitized");
+		DEBUG_2("%s set_exif_time_digitized_data: reading %p %s", get_exec_time(), file, file->path);
+
+		if (tmp)
+			{
+			struct tm time_str;
+			uint year, month, day, hour, min, sec;
+
+			sscanf(tmp, "%4d:%2d:%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
+			time_str.tm_year  = year - 1900;
+			time_str.tm_mon   = month - 1;
+			time_str.tm_mday  = day;
+			time_str.tm_hour  = hour;
+			time_str.tm_min   = min;
+			time_str.tm_sec   = sec;
+			time_str.tm_isdst = 0;
+
+			file->exifdate_digitized = mktime(&time_str);
+			g_free(tmp);
+			}
+		}
+}
+
 void set_exif_time_data(GList *files)
 {
 	DEBUG_1("%s set_exif_time_data: ...", get_exec_time());
@@ -516,6 +551,19 @@
 		}
 }
 
+void set_exif_time_digitized_data(GList *files)
+{
+	DEBUG_1("%s set_exif_time_digitized_data: ...", get_exec_time());
+
+	while (files)
+		{
+		FileData *file = files->data;
+
+		read_exif_time_digitized_data(file);
+		files = files->next;
+		}
+}
+
 void set_rating_data(GList *files)
 {
 	gchar *rating_str;
@@ -1046,11 +1094,21 @@
 			if (fa->exifdate > fb->exifdate) return 1;
 			/* fall back to name */
 			break;
+		case SORT_EXIFTIMEDIGITIZED:
+			if (fa->exifdate_digitized < fb->exifdate_digitized) return -1;
+			if (fa->exifdate_digitized > fb->exifdate_digitized) return 1;
+			/* fall back to name */
+			break;
 		case SORT_RATING:
 			if (fa->rating < fb->rating) return -1;
 			if (fa->rating > fb->rating) return 1;
 			/* fall back to name */
 			break;
+		case SORT_CLASS:
+			if (fa->format_class < fb->format_class) return -1;
+			if (fa->format_class > fb->format_class) return 1;
+			/* fall back to name */
+			break;
 #ifdef HAVE_STRVERSCMP
 		case SORT_NUMBER:
 			ret = strverscmp(fa->name, fb->name);
@@ -1106,6 +1164,10 @@
 		{
 		set_exif_time_data(list);
 		}
+	if (method == SORT_EXIFTIMEDIGITIZED)
+		{
+		set_exif_time_digitized_data(list);
+		}
 	if (method == SORT_RATING)
 		{
 		set_rating_data(list);
--- a/src/filedata.h	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/filedata.h	Mon Jan 22 21:07:11 2018 +0100
@@ -162,5 +162,6 @@
 gboolean file_data_unregister_real_time_monitor(FileData *fd);
 
 void read_exif_time_data(FileData *file);
+void read_exif_time_digitized_data(FileData *file);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/img-view.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/img-view.c	Mon Jan 22 21:07:11 2018 +0100
@@ -32,6 +32,7 @@
 #include "image-overlay.h"
 #include "layout.h"
 #include "layout_image.h"
+#include "layout_util.h"
 #include "menu.h"
 #include "misc.h"
 #include "pixbuf_util.h"
@@ -563,6 +564,11 @@
 				break;
 			}
 		}
+	if (!stop_signal && is_help_key(event))
+		{
+		help_window_show("GuideOtherWindowsImageWindow.html");
+		stop_signal = TRUE;
+		}
 
 	return stop_signal;
 }
@@ -1329,7 +1335,7 @@
 
 	menu_item_add_divider(menu);
 
-	submenu = submenu_add_collections(menu, &item,
+	submenu_add_collections(menu, &item,
 				G_CALLBACK(image_pop_menu_collections_cb), vw);
 	gtk_widget_set_sensitive(item, TRUE);
 	menu_item_add_divider(menu);
--- a/src/layout_image.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/layout_image.c	Mon Jan 22 21:07:11 2018 +0100
@@ -342,7 +342,7 @@
 {
 	if (!layout_valid(&lw)) return FALSE;
 
-	if(!lw->options.animate || lw->image->image_fd == NULL)
+	if(!lw->options.animate || lw->image->image_fd == NULL || lw->image->image_fd->extension == NULL || g_ascii_strcasecmp(lw->image->image_fd->extension,".GIF")!=0)
 		{
 		if(lw->animation)
 			{
--- a/src/layout_util.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/layout_util.c	Mon Jan 22 21:07:11 2018 +0100
@@ -510,8 +510,7 @@
 
 		rotation = g_strdup_printf("%d", fd_n->user_orientation);
 		command = g_strconcat(GQ_BIN_DIR, "/geeqie-rotate -r ", rotation,
-													keep_date ? " -t " : " ", fd_n->path, NULL);
-
+								keep_date ? " -t \"" : " \"", fd_n->path, "\"", NULL);
 		run_result = WEXITSTATUS(runcmd(command));
 		if (!run_result)
 			{
@@ -522,13 +521,20 @@
 			message = g_string_new("");
 			message = g_string_append(message, _("Operation failed:\n"));
 
-			if (run_result == 3)
-				message = g_string_append(message, _("Cannot create tmp file"));
-			else
-				{
-				message = g_string_append(message, _("File: "));
-				message = g_string_append(message, fd_n->name);
-				}
+			if (run_result == 1)
+				message = g_string_append(message, _("No file extension\n"));
+			else if (run_result == 3)
+				message = g_string_append(message, _("Cannot create tmp file\n"));
+			else if (run_result == 4)
+				message = g_string_append(message, _("Operation not supported for filetype\n"));
+			else if (run_result == 5)
+				message = g_string_append(message, _("File is not writable\n"));
+			else if (run_result == 6)
+				message = g_string_append(message, _("Exiftran error\n"));
+			else if (run_result == 7)
+				message = g_string_append(message, _("Mogrify error\n"));
+
+			message = g_string_append(message, fd_n->name);
 
 			gd = generic_dialog_new(_("Image orientation"),
 			"Image orientation", NULL, TRUE, NULL, NULL);
@@ -3005,6 +3011,34 @@
 //	layout_menu_edit_update(lw);
 }
 
+/**
+ * @brief Checks if event key is mapped to Help
+ * @param event 
+ * @returns 
+ * 
+ * Used to check if the user has re-mapped the Help key
+ * in Preferences/Keyboard
+ * 
+ * Note: help_key.accel_mods and event->state
+ * differ in the higher bits
+ */
+gboolean is_help_key(GdkEventKey *event)
+{
+	GtkAccelKey help_key;
+	gboolean ret = FALSE;
+	guint mask = GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK;
+
+	if (gtk_accel_map_lookup_entry("<Actions>/MenuActions/HelpContents", &help_key))
+		{
+		if (help_key.accel_key == event->keyval &&
+					(help_key.accel_mods & mask) == (event->state & mask))
+			{
+			ret = TRUE;
+			}
+		}
+
+	return ret;
+}
 
 /*
  *-----------------------------------------------------------------------------
--- a/src/layout_util.h	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/layout_util.h	Mon Jan 22 21:07:11 2018 +0100
@@ -71,5 +71,7 @@
 
 void layout_exif_window_new(LayoutWindow *lw);
 
+gboolean is_help_key(GdkEventKey *event);
+
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/lua.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/lua.c	Mon Jan 22 21:07:11 2018 +0100
@@ -167,7 +167,22 @@
 			lua_pushnil(L);
 			return 1;
 			}
-		} // if (strcmp(key, "Exif.Photo.Da...
+		}
+	else if (strcmp(key, "Exif.Photo.DateTimeDigitized") == 0)
+		{
+		memset(&tm, 0, sizeof(tm));
+		if (value && strptime(value, "%Y:%m:%d %H:%M:%S", &tm))
+			{
+			datetime = mktime(&tm);
+			lua_pushnumber(L, datetime);
+			return 1;
+			}
+		else
+			{
+			lua_pushnil(L);
+			return 1;
+			}
+		}
 	lua_pushstring(L, value);
 	return 1;
 }
--- a/src/menu.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/menu.c	Mon Jan 22 21:07:11 2018 +0100
@@ -149,7 +149,10 @@
 			return _("Sort by file creation date");
 			break;
 		case SORT_EXIFTIME:
-			return _("Sort by Exif-date");
+			return _("Sort by Exif date original");
+			break;
+		case SORT_EXIFTIMEDIGITIZED:
+			return _("Sort by Exif date digitized");
 			break;
 		case SORT_NONE:
 			return _("Unsorted");
@@ -163,6 +166,9 @@
 		case SORT_RATING:
 			return _("Sort by rating");
 			break;
+		case SORT_CLASS:
+			return _("Sort by class");
+			break;
 		case SORT_NAME:
 		default:
 			return _("Sort by name");
@@ -209,8 +215,10 @@
 	submenu_add_sort_item(submenu, func, SORT_TIME, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_CTIME, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_EXIFTIME, show_current, type);
+	submenu_add_sort_item(submenu, func, SORT_EXIFTIMEDIGITIZED, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_SIZE, show_current, type);
 	submenu_add_sort_item(submenu, func, SORT_RATING, show_current, type);
+	submenu_add_sort_item(submenu, func, SORT_CLASS, show_current, type);
 	if (include_path) submenu_add_sort_item(submenu, func, SORT_PATH, show_current, type);
 	if (include_none) submenu_add_sort_item(submenu, func, SORT_NONE, show_current, type);
 
@@ -409,7 +417,7 @@
 		{
 		const gchar *collection_name = work->data;
 
-		item = menu_item_add(menu, collection_name, func,
+		menu_item_add(menu, collection_name, func,
 													GINT_TO_POINTER(index));
 		work = work->next;
 		index++;
--- a/src/pan-view/pan-view.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/pan-view/pan-view.c	Mon Jan 22 21:07:11 2018 +0100
@@ -29,6 +29,7 @@
 #include "history_list.h"
 #include "image.h"
 #include "img-view.h"
+#include "layout_util.h"
 #include "menu.h"
 #include "metadata.h"
 #include "misc.h"
@@ -1299,15 +1300,16 @@
 				case '/':
 					pan_search_toggle_visible(pw, TRUE);
 					break;
-				case GDK_KEY_F1:
-					help_window_show("GuideReferenceKeyboardShortcuts.html#PanViewKeyboardShortcuts");
-					break;
-				default:
 					stop_signal = FALSE;
 					break;
 				}
 			}
 		}
+	if (!stop_signal && is_help_key(event))
+		{
+		help_window_show("GuideOtherWindowsPanView.html");
+		stop_signal = TRUE;
+		}
 
 	return stop_signal;
 }
--- a/src/print.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/print.c	Mon Jan 22 21:07:11 2018 +0100
@@ -1975,7 +1975,7 @@
 				parent, TRUE, NULL, NULL);
 	generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, NULL, TRUE);
 
-	buf = g_strdup_printf(_("An error occured printing to %s."), print_output_name(pw->output));
+	buf = g_strdup_printf(_("An error occurred printing to %s."), print_output_name(pw->output));
 	generic_dialog_add_message(gd, GTK_STOCK_DIALOG_ERROR, _("Printing error"), buf, TRUE);
 	g_free(buf);
 
--- a/src/remote.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/remote.c	Mon Jan 22 21:07:11 2018 +0100
@@ -279,11 +279,11 @@
 	return rc;
 }
 
-static sig_atomic_t sigpipe_occured = FALSE;
+static sig_atomic_t sigpipe_occurred = FALSE;
 
 static void sighandler_sigpipe(gint sig)
 {
-	sigpipe_occured = TRUE;
+	sigpipe_occurred = TRUE;
 }
 
 static gboolean remote_client_send(RemoteConnection *rc, const gchar *text)
@@ -296,7 +296,7 @@
 	if (!rc || rc->server) return FALSE;
 	if (!text) return TRUE;
 
-	sigpipe_occured = FALSE;
+	sigpipe_occurred = FALSE;
 
 	new_action.sa_handler = sighandler_sigpipe;
 	sigemptyset(&new_action.sa_mask);
--- a/src/renderer-tiles.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/renderer-tiles.c	Mon Jan 22 21:07:11 2018 +0100
@@ -147,6 +147,7 @@
 	gint x_scroll;  /* allow local adjustment and mirroring */
 	gint y_scroll;
 
+	gint hidpi_scale;
 };
 
 
@@ -499,6 +500,25 @@
 	return PR_TILE_SIZE * PR_TILE_SIZE * 4 / 8;
 }
 
+static void rt_hidpi_aware_draw(
+	RendererTiles *rt,
+	cairo_t *cr,
+	GdkPixbuf *pixbuf,
+	double x,
+	double y)
+{
+#if GTK_CHECK_VERSION(3, 10, 0)
+	cairo_surface_t *surface;
+	surface = gdk_cairo_surface_create_from_pixbuf(pixbuf, rt->hidpi_scale, NULL);
+	cairo_set_source_surface(cr, surface, x, y);
+	cairo_fill(cr);
+	cairo_surface_destroy(surface);
+#else
+	gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
+	cairo_fill(cr);
+#endif
+}
+
 static void rt_tile_prepare(RendererTiles *rt, ImageTile *it)
 {
 	PixbufRenderer *pr = rt->pr;
@@ -511,7 +531,7 @@
 		                                            CAIRO_CONTENT_COLOR,
 		                                            rt->tile_width, rt->tile_height);
 
-		size = pixmap_calc_size(surface);
+		size = pixmap_calc_size(surface) * rt->hidpi_scale * rt->hidpi_scale;
 		rt_tile_free_space(rt, size, it);
 
 		it->surface = surface;
@@ -523,9 +543,9 @@
 		{
 		GdkPixbuf *pixbuf;
 		guint size;
-		pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height);
+		pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->hidpi_scale * rt->tile_width, rt->hidpi_scale * rt->tile_height);
 
-		size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height;
+		size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height * rt->hidpi_scale;
 		rt_tile_free_space(rt, size, it);
 
 		it->pixbuf = pixbuf;
@@ -623,7 +643,7 @@
 				cairo_fill_preserve(cr);
 
 				gdk_cairo_set_source_pixbuf(cr, od->pixbuf, px - rx, py - ry);
-				cairo_fill (cr);
+				cairo_fill(cr);
 				cairo_destroy (cr);
 
 				cr = gdk_cairo_create(od->window);
@@ -881,7 +901,7 @@
 
 static GdkPixbuf *rt_get_spare_tile(RendererTiles *rt)
 {
-	if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height);
+	if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width * rt->hidpi_scale, rt->tile_height * rt->hidpi_scale);
 	return rt->spare_tile;
 }
 
@@ -896,7 +916,7 @@
 	guchar *sp, *dp;
 	guchar *ip, *spi, *dpi;
 	gint i, j;
-	gint tw = rt->tile_width;
+	gint tw = rt->tile_width * rt->hidpi_scale;
 
 	srs = gdk_pixbuf_get_rowstride(src);
 	s_pix = gdk_pixbuf_get_pixels(src);
@@ -932,7 +952,7 @@
 	guchar *sp, *dp;
 	guchar *ip, *spi, *dpi;
 	gint i, j;
-	gint th = rt->tile_height;
+	gint th = rt->tile_height * rt->hidpi_scale;
 
 	srs = gdk_pixbuf_get_rowstride(src);
 	s_pix = gdk_pixbuf_get_pixels(src);
@@ -969,7 +989,7 @@
 	guchar *spi, *dpi;
 	gint i, j;
 
-	gint tw = rt->tile_width;
+	gint tw = rt->tile_width * rt->hidpi_scale;
 
 	srs = gdk_pixbuf_get_rowstride(src);
 	s_pix = gdk_pixbuf_get_pixels(src);
@@ -1005,8 +1025,8 @@
 	guchar *sp, *dp;
 	guchar *dpi;
 	gint i, j;
-	gint tw = rt->tile_width;
-	gint th = rt->tile_height;
+	gint tw = rt->tile_width * rt->hidpi_scale;
+	gint th = rt->tile_height * rt->hidpi_scale;
 
 	srs = gdk_pixbuf_get_rowstride(src);
 	s_pix = gdk_pixbuf_get_pixels(src);
@@ -1041,7 +1061,7 @@
 	guchar *sp, *dp;
 	guchar *spi, *dpi;
 	gint i;
-	gint th = rt->tile_height;
+	gint th = rt->tile_height * rt->hidpi_scale;
 
 	srs = gdk_pixbuf_get_rowstride(src);
 	s_pix = gdk_pixbuf_get_pixels(src);
@@ -1150,12 +1170,12 @@
 				if (st->blank)
 					{
 					cairo_set_source_rgb(cr, 0, 0, 0);
+					cairo_fill (cr);
 					}
 				else /* (pr->zoom == 1.0 || pr->scale == 1.0) */
 					{
-					gdk_cairo_set_source_pixbuf(cr, st->pixbuf, -it->x + st->x, -it->y + st->y);
+					rt_hidpi_aware_draw(rt, cr, st->pixbuf, -it->x + st->x, -it->y + st->y);
 					}
-				cairo_fill (cr);
 				cairo_destroy (cr);
 				}
 			}
@@ -1356,8 +1376,8 @@
 
 		if (pr->image_width == 0 || pr->image_height == 0) return;
 
-		scale_x = (gdouble)pr->width / pr->image_width;
-		scale_y = (gdouble)pr->height / pr->image_height;
+		scale_x = rt->hidpi_scale * (gdouble)pr->width / pr->image_width;
+		scale_y = rt->hidpi_scale * (gdouble)pr->height / pr->image_height;
 
 		pr_tile_coords_map_orientation(orientation, it->x, it->y,
 					    pr->width, pr->height,
@@ -1369,6 +1389,13 @@
 					    &pb_x, &pb_y,
 					    &pb_w, &pb_h);
 
+		src_x *= rt->hidpi_scale;
+		src_y *= rt->hidpi_scale;
+		pb_x *= rt->hidpi_scale;
+		pb_y *= rt->hidpi_scale;
+		pb_w *= rt->hidpi_scale;
+		pb_h *= rt->hidpi_scale;
+
 		switch (orientation)
 			{
 			gdouble tmp;
@@ -1424,8 +1451,7 @@
 
 		cr = cairo_create(it->surface);
 		cairo_rectangle (cr, x, y, w, h);
-		gdk_cairo_set_source_pixbuf(cr, it->pixbuf, 0, 0);
-		cairo_fill (cr);
+		rt_hidpi_aware_draw(rt, cr, it->pixbuf, 0, 0);
 		cairo_destroy (cr);
 		}
 }
@@ -2164,6 +2190,12 @@
 	rt->stereo_off_x = 0;
 	rt->stereo_off_y = 0;
 
+#if GTK_CHECK_VERSION(3, 10, 0)
+	rt->hidpi_scale = gtk_widget_get_scale_factor(GTK_WIDGET(rt->pr));
+#else
+	rt->hidpi_scale = 1;
+#endif
+
 	g_signal_connect(G_OBJECT(pr), "hierarchy-changed",
 			 G_CALLBACK(rt_hierarchy_changed_cb), rt);
 
@@ -2174,6 +2206,7 @@
 	g_signal_connect(G_OBJECT(pr), "expose_event",
 	                 G_CALLBACK(rt_expose_cb), rt);
 #endif
+
 	return (RendererFuncs *) rt;
 }
 
--- a/src/search.c	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/search.c	Mon Jan 22 21:07:11 2018 +0100
@@ -32,6 +32,7 @@
 #include "image-load.h"
 #include "img-view.h"
 #include "layout.h"
+#include "layout_util.h"
 #include "math.h"
 #include "menu.h"
 #include "metadata.h"
@@ -118,6 +119,7 @@
 	GtkWidget *menu_date;
 	GtkWidget *date_sel;
 	GtkWidget *date_sel_end;
+	GtkWidget *date_type;
 
 	GtkWidget *check_dimensions;
 	GtkWidget *menu_dimensions;
@@ -143,6 +145,10 @@
 	GtkWidget *spin_rating;
 	GtkWidget *spin_rating_end;
 
+	GtkWidget *check_class;
+	GtkWidget *menu_class;
+	GtkWidget *class_type;
+
 	FileData *search_dir_fd;
 	gboolean   search_path_recurse;
 	gchar *search_name;
@@ -167,7 +173,6 @@
 	gint   search_rating;
 	gint   search_rating_end;
 	gboolean   search_comment_match_case;
-	gboolean   search_date_exif;
 
 	MatchType search_type;
 
@@ -179,6 +184,7 @@
 	MatchType match_comment;
 	MatchType match_rating;
 	MatchType match_gps;
+	MatchType match_class;
 
 	gboolean match_name_enable;
 	gboolean match_size_enable;
@@ -188,6 +194,7 @@
 	gboolean match_keywords_enable;
 	gboolean match_comment_enable;
 	gboolean match_rating_enable;
+	gboolean match_class_enable;
 
 	GList *search_folder_list;
 	GList *search_done_list;
@@ -289,6 +296,11 @@
 	{ N_("greater than"),	SEARCH_MATCH_OVER }
 };
 
+static const MatchList text_search_menu_class[] = {
+	{ N_("is"),	SEARCH_MATCH_EQUAL },
+	{ N_("is not"),	SEARCH_MATCH_NONE }
+};
+
 static GList *search_window_list = NULL;
 
 
@@ -1075,7 +1087,7 @@
 	submenu_add_edit(menu, &item, G_CALLBACK(sr_menu_edit_cb), sd, editmenu_fd_list);
 	if (!on_row) gtk_widget_set_sensitive(item, FALSE);
 
-	submenu = submenu_add_collections(menu, &item,
+	submenu_add_collections(menu, &item,
 				G_CALLBACK(search_pop_menu_collections_cb), sd);
 	gtk_widget_set_sensitive(item, on_row);
 
@@ -1367,9 +1379,6 @@
 					       search_result_menu_pos_cb, sd, 0, GDK_CURRENT_TIME);
 				}
 				break;
-			case GDK_KEY_F1:
-				help_window_show("GuideReferenceKeyboardShortcuts.html#SearchKeyboardShortcuts");
-				break;
 			default:
 				stop_signal = FALSE;
 				break;
@@ -1401,6 +1410,11 @@
 				break;
 			}
 		}
+	if (!stop_signal && is_help_key(event))
+		{
+		help_window_show("GuideImageSearchSearch.html");
+		stop_signal = TRUE;
+		}
 
 	return stop_signal;
 }
@@ -1845,11 +1859,23 @@
 		tested = TRUE;
 		match = FALSE;
 
-		if (sd->search_date_exif)
+		if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->date_type)), _("Changed")) == 0)
+			{
+			file_date = fd->cdate;
+			}
+		else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->date_type)), _("Original")) == 0)
 			{
 			read_exif_time_data(fd);
 			file_date = fd->exifdate;
 			}
+		else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->date_type)), _("Digitized")) == 0)
+			{
+			read_exif_time_digitized_data(fd);
+			file_date = fd->exifdate_digitized;
+			}
 		else
 			{
 			file_date = fd->date;
@@ -2029,6 +2055,49 @@
 			}
 		}
 
+	if (match && sd->match_class_enable)
+		{
+		tested = TRUE;
+		match = FALSE;
+		gint class;
+		FileFormatClass search_class;
+
+		if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->class_type)), _("Image")) == 0)
+			{
+			search_class = FORMAT_CLASS_IMAGE;
+			}
+		else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->class_type)), _("Raw Image")) == 0)
+			{
+			search_class = FORMAT_CLASS_RAWIMAGE;
+			}
+		else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->class_type)), _("Video")) == 0)
+			{
+			search_class = FORMAT_CLASS_VIDEO;
+			}
+		else if (g_strcmp0(gtk_combo_box_text_get_active_text(
+						GTK_COMBO_BOX_TEXT(sd->class_type)), _("Metadata")) == 0)
+			{
+			search_class = FORMAT_CLASS_META;
+			}
+		else
+			{
+			search_class = FORMAT_CLASS_UNKNOWN;
+			}
+
+		class = fd->format_class;
+		if (sd->match_class == SEARCH_MATCH_EQUAL)
+			{
+			match = (class == search_class);
+			}
+		else if (sd->match_class == SEARCH_MATCH_NONE)
+			{
+			match = (class != search_class);
+			}
+		}
+
 	if (match && sd->match_gps_enable)
 		{
 		/* Calculate the distance the image is from the specified origin.
@@ -2615,6 +2684,13 @@
 				(sd->match_rating == SEARCH_MATCH_BETWEEN));
 }
 
+static void menu_choice_class_cb(GtkWidget *combo, gpointer data)
+{
+	SearchData *sd = data;
+
+	if (!menu_choice_get_match_type(combo, &sd->match_class)) return;
+}
+
 static void menu_choice_date_cb(GtkWidget *combo, gpointer data)
 {
 	SearchData *sd = data;
@@ -2844,6 +2920,7 @@
 	sd->match_keywords = SEARCH_MATCH_ALL;
 	sd->match_comment = SEARCH_MATCH_CONTAINS;
 	sd->match_rating = SEARCH_MATCH_EQUAL;
+	sd->match_class = SEARCH_MATCH_EQUAL;
 
 	sd->match_name_enable = TRUE;
 
@@ -2933,6 +3010,7 @@
 			   _("File date is"), &sd->match_date_enable,
 			   text_search_menu_date, sizeof(text_search_menu_date) / sizeof(MatchList),
 			   G_CALLBACK(menu_choice_date_cb), sd);
+
 	sd->date_sel = date_selection_new();
 	date_selection_time_set(sd->date_sel, time(NULL));
 	gtk_box_pack_start(GTK_BOX(hbox), sd->date_sel, FALSE, FALSE, 0);
@@ -2945,8 +3023,16 @@
 	date_selection_time_set(sd->date_sel_end, time(NULL));
 	gtk_box_pack_start(GTK_BOX(hbox2), sd->date_sel_end, FALSE, FALSE, 0);
 	gtk_widget_show(sd->date_sel_end);
-	pref_checkbox_new_int(hbox, _("Exif date"),
-				sd->search_date_exif, &sd->search_date_exif);
+
+	sd->date_type = gtk_combo_box_text_new();
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Modified"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Status Changed"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Original"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->date_type), _("Digitized"));
+	gtk_box_pack_start(GTK_BOX(hbox), sd->date_type, FALSE, FALSE, 0);
+	gtk_combo_box_set_active(GTK_COMBO_BOX(sd->date_type), 0);
+	gtk_widget_set_tooltip_text(sd->date_type, "Modified (mtime)\nStatus Changed (ctime)\nOriginal (Exif.Photo.DateTimeOriginal)\nDigitized (Exif.Photo.DateTimeDigitized)");
+	gtk_widget_show(sd->date_type);
 
 	/* Search for image dimensions */
 	hbox = menu_choice(sd->box_search, &sd->check_dimensions, &sd->menu_dimensions,
@@ -3059,6 +3145,22 @@
 
 	gtk_widget_show(sd->entry_gps_coord);
 
+	/* Search for image class */
+	hbox = menu_choice(sd->box_search, &sd->check_class, &sd->menu_class,
+			   _("Image class"), &sd->match_class_enable,
+			   text_search_menu_class, sizeof(text_search_menu_class) / sizeof(MatchList),
+			   G_CALLBACK(menu_choice_class_cb), sd);
+
+	sd->class_type = gtk_combo_box_text_new();
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Image"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Raw Image"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Video"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Metadata"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sd->class_type), _("Unknown"));
+	gtk_box_pack_start(GTK_BOX(hbox), sd->class_type, FALSE, FALSE, 0);
+	gtk_combo_box_set_active(GTK_COMBO_BOX(sd->class_type), 0);
+	gtk_widget_show(sd->class_type);
+
 	/* Done the types of searches */
 
 	scrolled = gtk_scrolled_window_new(NULL, NULL);
--- a/src/typedefs.h	Mon Jan 22 21:07:11 2018 +0100
+++ b/src/typedefs.h	Mon Jan 22 21:07:11 2018 +0100
@@ -74,7 +74,9 @@
 	SORT_PATH,
 	SORT_NUMBER,
 	SORT_EXIFTIME,
-	SORT_RATING
+	SORT_EXIFTIMEDIGITIZED,
+	SORT_RATING,
+	SORT_CLASS
 } SortType;
 
 typedef enum {
@@ -587,6 +589,7 @@
 
 	ExifData *exif;
 	time_t exifdate;
+	time_t exifdate_digitized;
 	GHashTable *modified_xmp; // hash table which contains unwritten xmp metadata in format: key->list of string values
 	GList *cached_metadata;
 	gint rating;
--- a/web/help/GuideImageSearchSearch.html	Mon Jan 22 21:07:11 2018 +0100
+++ b/web/help/GuideImageSearchSearch.html	Mon Jan 22 21:07:11 2018 +0100
@@ -543,7 +543,7 @@
           <span class="guilabel">File date</span>
         </dt>
 <dd>
-          The search will match if the file modification time on disk is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
+          The search will match if the file date is equal to, before, after, or between the entered date, depending on the method selected from the drop down menu. The
           <span class="emphasis">between</span>
           test is inclusive, for example a file with date of 10/04/2003 will match if the date parameters are between 10/04/2003 and 12/31/2003.
           <p class="para block"></p>
@@ -557,9 +557,10 @@
           </span>
           button displays a pop up calendar to enter the date.
           <p class="para block"></p>
-          The
-          <span class="emphasis emphasis-bold">Exif date</span>
-          checkbox permits searches to be made on the exif date of images. If an image does not have an exif date, it will default to 01 January 1970.
+          One of four date types may be selected. They are described in the
+          <a class="link" href=".html#GuideReferenceFileDates" title="">Reference section</a>
+          .
+          <div class="admonition block note block-indent"><div class="note-inner">If an image does not have an exif date, it will default to 01 January 1970.</div></div>
         </dd>
 <dt class="term">
           <span class="guilabel">Image dimensions</span>
@@ -606,6 +607,19 @@
             for details on how to create this file.
           </div></div>
         </dd>
+<dt class="term">
+          <span class="guilabel">Class</span>
+        </dt>
+<dd>
+          The search will match if the file's class is, or is not, one of the following types.
+          <div class="block list itemizedlist"><ul class="itemizedlist">
+<li class="li-first">Unknown</li>
+<li>Image</li>
+<li>Raw Image</li>
+<li>Video</li>
+<li>Metadata</li>
+</ul></div>
+        </dd>
 </dl></div>
 <p class="para block"></p>
 <p class="para block"></p>
--- a/web/help/GuideMainWindowStatusBar.html	Mon Jan 22 21:07:11 2018 +0100
+++ b/web/help/GuideMainWindowStatusBar.html	Mon Jan 22 21:07:11 2018 +0100
@@ -501,22 +501,39 @@
           <p class="para block block-first">Images are sorted by file modification date.</p>
         </dd>
 <dt class="term">
-          <span class="guilabel">File Creation Date</span>
+          <span class="guilabel">File Date</span>
         </dt>
 <dd>
-          <p class="para block block-first">Images are sorted by file creation date.</p>
-        </dd>
-<dt class="term">
-          <span class="guilabel">Exif Date</span>
-        </dt>
-<dd>
-          <p class="para block block-first">Images are sorted by file Exif date.</p>
+          <p class="para block block-first">
+            Images are sorted by one of four types of file date. They are described in the
+            <a class="link" href=".html#GuideReferenceFileDates" title="">Reference section</a>
+            .
+          </p>
         </dd>
 <dt class="term">
           <span class="guilabel">Size</span>
         </dt>
 <dd>
-          <p class="para block block-first">Image are sorted by file size on disk.</p>
+          <p class="para block block-first">Images are sorted by file size on disk.</p>
+        </dd>
+<dt class="term">
+          <span class="guilabel">Rating</span>
+        </dt>
+<dd>
+          <p class="para block block-first">Image are sorted by Xmp.xmp.Rating.</p>
+        </dd>
+<dt class="term">
+          <span class="guilabel">Class</span>
+        </dt>
+<dd>
+          <p class="para block block-first">Image are sorted by class. The class types, and sort order, is:</p>
+          <div class="block list itemizedlist"><ul class="itemizedlist">
+<li class="li-first">Unknown</li>
+<li>Image</li>
+<li>Raw Image</li>
+<li>Video</li>
+<li>Metadata</li>
+</ul></div>
         </dd>
 <dt class="term">
           <span class="guilabel">Ascending</span>
@@ -525,7 +542,7 @@
           <p class="para block block-first">Toggles between increasing and decreasing sort order. A check will appear next to this entry to indicate ascending sort order.</p>
         </dd>
 </dl></div>
-<p class="para block"></p>
+<div class="admonition block note block-indent"><div class="note-inner">When images have equal rank, for example in rating or class sorts, within each section images will be sorted by filename.</div></div>
 </div>
 <div class="division section">
 <a name="Filelist"></a><div class="header"><h2 class="section title"><span class="title"><span class="label">2.6.3. </span>File list</span></h2></div>
--- a/web/help/GuideOtherWindowsPanView.html	Mon Jan 22 21:07:11 2018 +0100
+++ b/web/help/GuideOtherWindowsPanView.html	Mon Jan 22 21:07:11 2018 +0100
@@ -464,6 +464,11 @@
     You can pan the view as you pan an image in normal view mode, using left mouse button and drag.
   </p>
 <p class="para block">A primary mouse button click on any image will display informations about the image. Secondary mouse button will show a context menu.</p>
+<p class="para block">
+    The
+    <a class="link" href="GuideReferenceKeyboardShortcuts.html" title="Keyboard and Mouse Shortcuts">Keyboard and Mouse Shortcuts</a>
+    available are listed in the Reference section.
+  </p>
 <div class="admonition block note block-indent"><div class="note-inner">
     <p class="para block block-first">Pan view recursively visits each folder under the specified folder. This can consume considerable computer resources.</p>
   </div></div>