changeset 2521:3a586dd0188a

Refactor: move view_file implementations to their own subdirectory.
author Omari Stephens <xsdg@google.com>
date Wed, 05 Jul 2017 21:41:18 +0000
parents 8057b4b9fe34
children 5dfc01705fb1
files src/Makefile.am src/view_file.c src/view_file/Makefile.am src/view_file/view_file_icon.c src/view_file/view_file_icon.h src/view_file/view_file_list.c src/view_file/view_file_list.h src/view_file_icon.c src/view_file_icon.h src/view_file_list.c src/view_file_list.h
diffstat 11 files changed, 4513 insertions(+), 4510 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Thu Jun 29 11:05:59 2017 +0100
+++ b/src/Makefile.am	Wed Jul 05 21:41:18 2017 +0000
@@ -81,12 +81,14 @@
 	$(extra_ICONS)
 
 include $(srcdir)/pan-view/Makefile.am
+include $(srcdir)/view_file/Makefile.am
 
 bin_PROGRAMS = geeqie
 
 geeqie_SOURCES = \
 	$(module_SLIK)	\
 	$(module_pan_view)	\
+	$(module_view_file)	\
 	ClayRGB1998.icc \
 	ClayRGB1998_icc.h \
 	advanced_exif.c	\
@@ -251,10 +253,6 @@
 	view_dir_tree.h	\
 	view_file.c	\
 	view_file.h	\
-	view_file_list.c	\
-	view_file_list.h	\
-	view_file_icon.c	\
-	view_file_icon.h	\
 	window.c	\
 	window.h	\
 	lua.c		\
--- a/src/view_file.c	Thu Jun 29 11:05:59 2017 +0100
+++ b/src/view_file.c	Wed Jul 05 21:41:18 2017 +0000
@@ -31,8 +31,8 @@
 #include "ui_menu.h"
 #include "ui_fileops.h"
 #include "utilops.h"
-#include "view_file_list.h"
-#include "view_file_icon.h"
+#include "view_file/view_file_list.h"
+#include "view_file/view_file_icon.h"
 
 /*
  *-----------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/view_file/Makefile.am	Wed Jul 05 21:41:18 2017 +0000
@@ -0,0 +1,5 @@
+module_view_file = \
+	%D%/view_file_icon.c	\
+	%D%/view_file_icon.h	\
+	%D%/view_file_list.c	\
+	%D%/view_file_list.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/view_file/view_file_icon.c	Wed Jul 05 21:41:18 2017 +0000
@@ -0,0 +1,2300 @@
+/*
+ * Copyright (C) 2006 John Ellis
+ * Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ * Author: John Ellis
+ *
+ * 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 "view_file_icon.h"
+
+#include "bar.h"
+#include "cellrenderericon.h"
+#include "collect.h"
+#include "collect-io.h"
+#include "collect-table.h"
+#include "dnd.h"
+#include "editors.h"
+#include "img-view.h"
+#include "filedata.h"
+#include "layout.h"
+#include "layout_image.h"
+#include "menu.h"
+#include "metadata.h"
+#include "thumb.h"
+#include "utilops.h"
+#include "ui_fileops.h"
+#include "ui_menu.h"
+#include "ui_tree_edit.h"
+#include "uri_utils.h"
+#include "view_file.h"
+
+#include <gdk/gdkkeysyms.h> /* for keyboard values */
+
+
+/* between these, the icon width is increased by thumb_max_width / 2 */
+#define THUMB_MIN_ICON_WIDTH 128
+#define THUMB_MAX_ICON_WIDTH 150
+
+#define VFICON_MAX_COLUMNS 32
+#define THUMB_BORDER_PADDING 2
+
+#define VFICON_TIP_DELAY 500
+
+enum {
+	FILE_COLUMN_POINTER = 0,
+	FILE_COLUMN_COUNT
+};
+
+static gint vficon_index_by_id(ViewFile *vf, IconData *in_id);
+
+static IconData *vficon_icon_data(ViewFile *vf, FileData *fd)
+{
+	IconData *id = NULL;
+	GList *work;
+
+	if (!fd) return NULL;
+	work = vf->list;
+	while (work && !id)
+		{
+		IconData *chk = work->data;
+		work = work->next;
+		if (chk->fd == fd) id = chk;
+		}
+	return id;
+}
+
+static void iconlist_free(GList *list)
+{
+	GList *work = list;
+	while (work)
+		{
+		IconData *id = work->data;
+		file_data_unref(id->fd);
+		g_free(id);
+		work = work->next;
+		}
+
+	g_list_free(list);
+
+}
+
+gint iconlist_sort_file_cb(gpointer a, gpointer b)
+{
+	IconData *ida = a;
+	IconData *idb = b;
+	return filelist_sort_compare_filedata(ida->fd, idb->fd);
+}
+
+GList *iconlist_sort(GList *list, SortType method, gboolean ascend)
+{
+	return filelist_sort_full(list, method, ascend, (GCompareFunc) iconlist_sort_file_cb);
+}
+
+GList *iconlist_insert_sort(GList *list, IconData *id, SortType method, gboolean ascend)
+{
+	return filelist_insert_sort_full(list, id, method, ascend, (GCompareFunc) iconlist_sort_file_cb);
+}
+
+
+static void vficon_toggle_filenames(ViewFile *vf);
+static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter);
+static void vficon_move_focus(ViewFile *vf, gint row, gint col, gboolean relative);
+static void vficon_set_focus(ViewFile *vf, IconData *id);
+static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gboolean force);
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * pop-up menu
+ *-----------------------------------------------------------------------------
+ */
+
+GList *vficon_selection_get_one(ViewFile *vf, FileData *fd)
+{
+	return g_list_prepend(filelist_copy(fd->sidecar_files), file_data_ref(fd));
+}
+
+GList *vficon_pop_menu_file_list(ViewFile *vf)
+{
+	if (!VFICON(vf)->click_id) return NULL;
+
+	if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+		{
+		return vf_selection_get_list(vf);
+		}
+
+	return vficon_selection_get_one(vf, VFICON(vf)->click_id->fd);
+}
+
+void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	if (!VFICON(vf)->click_id) return;
+
+	if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+		{
+		GList *list;
+
+		list = vf_selection_get_list(vf);
+		view_window_new_from_list(list);
+		filelist_free(list);
+		}
+	else
+		{
+		view_window_new(VFICON(vf)->click_id->fd);
+		}
+}
+
+void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	file_util_rename(NULL, vf_pop_menu_file_list(vf), vf->listview);
+}
+
+void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vficon_toggle_filenames(vf);
+}
+
+void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vf_refresh(vf);
+}
+
+void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+	vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
+	VFICON(vf)->click_id = NULL;
+	vf->popup = NULL;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * signals
+ *-------------------------------------------------------------------
+ */
+
+static void vficon_send_layout_select(ViewFile *vf, IconData *id)
+{
+	FileData *read_ahead_fd = NULL;
+	FileData *sel_fd;
+	FileData *cur_fd;
+
+	if (!vf->layout || !id || !id->fd) return;
+
+	sel_fd = id->fd;
+
+	cur_fd = layout_image_get_fd(vf->layout);
+	if (sel_fd == cur_fd) return; /* no change */
+
+	if (options->image.enable_read_ahead)
+		{
+		gint row;
+
+		row = g_list_index(vf->list, id);
+		if (row > vficon_index_by_fd(vf, cur_fd) &&
+		    (guint) (row + 1) < vf_count(vf, NULL))
+			{
+			read_ahead_fd = vf_index_get_data(vf, row + 1);
+			}
+		else if (row > 0)
+			{
+			read_ahead_fd = vf_index_get_data(vf, row - 1);
+			}
+		}
+
+	layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
+}
+
+static void vficon_toggle_filenames(ViewFile *vf)
+{
+	GtkAllocation allocation;
+	VFICON(vf)->show_text = !VFICON(vf)->show_text;
+	options->show_icon_names = VFICON(vf)->show_text;
+
+	gtk_widget_get_allocation(vf->listview, &allocation);
+	vficon_populate_at_new_size(vf, allocation.width, allocation.height, TRUE);
+}
+
+static gint vficon_get_icon_width(ViewFile *vf)
+{
+	gint width;
+
+	if (!VFICON(vf)->show_text) return options->thumbnails.max_width;
+
+	width = options->thumbnails.max_width + options->thumbnails.max_width / 2;
+	if (width < THUMB_MIN_ICON_WIDTH) width = THUMB_MIN_ICON_WIDTH;
+	if (width > THUMB_MAX_ICON_WIDTH) width = options->thumbnails.max_width;
+
+	return width;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * misc utils
+ *-------------------------------------------------------------------
+ */
+
+static gboolean vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint *col)
+{
+	gint n;
+
+	n = g_list_index(vf->list, id);
+
+	if (n < 0) return FALSE;
+
+	*row = n / VFICON(vf)->columns;
+	*col = n - (*row * VFICON(vf)->columns);
+
+	return TRUE;
+}
+
+static gboolean vficon_find_iter(ViewFile *vf, IconData *id, GtkTreeIter *iter, gint *column)
+{
+	GtkTreeModel *store;
+	gint row, col;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	if (!vficon_find_position(vf, id, &row, &col)) return FALSE;
+	if (!gtk_tree_model_iter_nth_child(store, iter, NULL, row)) return FALSE;
+	if (column) *column = col;
+
+	return TRUE;
+}
+
+static IconData *vficon_find_data(ViewFile *vf, gint row, gint col, GtkTreeIter *iter)
+{
+	GtkTreeModel *store;
+	GtkTreeIter p;
+
+	if (row < 0 || col < 0) return NULL;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	if (gtk_tree_model_iter_nth_child(store, &p, NULL, row))
+		{
+		GList *list;
+
+		gtk_tree_model_get(store, &p, FILE_COLUMN_POINTER, &list, -1);
+		if (!list) return NULL;
+
+		if (iter) *iter = p;
+
+		return g_list_nth_data(list, col);
+		}
+
+	return NULL;
+}
+
+static IconData *vficon_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
+{
+	GtkTreePath *tpath;
+	GtkTreeViewColumn *column;
+
+	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
+					  &tpath, &column, NULL, NULL))
+		{
+		GtkTreeModel *store;
+		GtkTreeIter row;
+		GList *list;
+		gint n;
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		gtk_tree_model_get_iter(store, &row, tpath);
+		gtk_tree_path_free(tpath);
+
+		gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
+
+		n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_number"));
+		if (list)
+			{
+			if (iter) *iter = row;
+			return g_list_nth_data(list, n);
+			}
+		}
+
+	return NULL;
+}
+
+static void vficon_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreeModel *store;
+	GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
+	GtkTreeIter row;
+	gint column;
+	GList *list;
+	guint toggled_mark;
+	IconData *id;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	if (!path || !gtk_tree_model_get_iter(store, &row, path))
+		return;
+
+	gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
+
+	column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_number"));
+	g_object_get(G_OBJECT(cell), "toggled_mark", &toggled_mark, NULL);
+
+	id = g_list_nth_data(list, column);
+	if (id)
+		{
+		FileData *fd = id->fd;
+		file_data_set_mark(fd, toggled_mark, !file_data_get_mark(fd, toggled_mark));
+		}
+}
+
+
+/*
+ *-------------------------------------------------------------------
+ * tooltip type window
+ *-------------------------------------------------------------------
+ */
+
+static void tip_show(ViewFile *vf)
+{
+	GtkWidget *label;
+	gint x, y;
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkDisplay *display;
+	GdkDeviceManager *device_manager;
+	GdkDevice *device;
+#endif
+
+	if (VFICON(vf)->tip_window) return;
+
+#if GTK_CHECK_VERSION(3,0,0)
+	device_manager = gdk_display_get_device_manager(gdk_window_get_display(
+						gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview))));
+	device = gdk_device_manager_get_client_pointer(device_manager);
+	gdk_window_get_device_position(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)),
+						device, &x, &y, NULL);
+#else
+	gdk_window_get_pointer(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)), &x, &y, NULL);
+#endif
+
+	VFICON(vf)->tip_id = vficon_find_data_by_coord(vf, x, y, NULL);
+	if (!VFICON(vf)->tip_id) return;
+
+	VFICON(vf)->tip_window = gtk_window_new(GTK_WINDOW_POPUP);
+	gtk_window_set_resizable(GTK_WINDOW(VFICON(vf)->tip_window), FALSE);
+	gtk_container_set_border_width(GTK_CONTAINER(VFICON(vf)->tip_window), 2);
+
+	label = gtk_label_new(VFICON(vf)->tip_id->fd->name);
+
+	g_object_set_data(G_OBJECT(VFICON(vf)->tip_window), "tip_label", label);
+	gtk_container_add(GTK_CONTAINER(VFICON(vf)->tip_window), label);
+	gtk_widget_show(label);
+
+#if GTK_CHECK_VERSION(3,0,0)
+	display = gdk_display_get_default();
+	device_manager = gdk_display_get_device_manager(display);
+	device = gdk_device_manager_get_client_pointer(device_manager);
+	gdk_device_get_position(device, NULL, &x, &y);
+#else
+	gdk_window_get_pointer(NULL, &x, &y, NULL);
+#endif
+
+	if (!gtk_widget_get_realized(VFICON(vf)->tip_window)) gtk_widget_realize(VFICON(vf)->tip_window);
+	gtk_window_move(GTK_WINDOW(VFICON(vf)->tip_window), x + 16, y + 16);
+	gtk_widget_show(VFICON(vf)->tip_window);
+}
+
+static void tip_hide(ViewFile *vf)
+{
+	if (VFICON(vf)->tip_window) gtk_widget_destroy(VFICON(vf)->tip_window);
+	VFICON(vf)->tip_window = NULL;
+}
+
+static gboolean tip_schedule_cb(gpointer data)
+{
+	ViewFile *vf = data;
+	GtkWidget *window;
+
+	if (!VFICON(vf)->tip_delay_id) return FALSE;
+
+	window = gtk_widget_get_toplevel(vf->listview);
+
+	if (gtk_widget_get_sensitive(window) &&
+	    gtk_window_has_toplevel_focus(GTK_WINDOW(window)))
+		{
+		tip_show(vf);
+		}
+
+	VFICON(vf)->tip_delay_id = 0;
+	return FALSE;
+}
+
+static void tip_schedule(ViewFile *vf)
+{
+	tip_hide(vf);
+
+	if (VFICON(vf)->tip_delay_id)
+		{
+		g_source_remove(VFICON(vf)->tip_delay_id);
+		VFICON(vf)->tip_delay_id = 0;
+		}
+
+	if (!VFICON(vf)->show_text)
+		{
+		VFICON(vf)->tip_delay_id = g_timeout_add(VFICON_TIP_DELAY, tip_schedule_cb, vf);
+		}
+}
+
+static void tip_unschedule(ViewFile *vf)
+{
+	tip_hide(vf);
+
+	if (VFICON(vf)->tip_delay_id)
+		{
+		g_source_remove(VFICON(vf)->tip_delay_id);
+		VFICON(vf)->tip_delay_id = 0;
+		}
+}
+
+static void tip_update(ViewFile *vf, IconData *id)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkDisplay *display = gdk_display_get_default();
+	GdkDeviceManager *device_manager = gdk_display_get_device_manager(display);
+	GdkDevice *device = gdk_device_manager_get_client_pointer(device_manager);
+#endif
+
+	if (VFICON(vf)->tip_window)
+		{
+		gint x, y;
+
+#if GTK_CHECK_VERSION(3,0,0)
+		gdk_device_get_position(device, NULL, &x, &y);
+#else
+		gdk_window_get_pointer(NULL, &x, &y, NULL);
+#endif
+		gtk_window_move(GTK_WINDOW(VFICON(vf)->tip_window), x + 16, y + 16);
+
+		if (id != VFICON(vf)->tip_id)
+			{
+			GtkWidget *label;
+
+			VFICON(vf)->tip_id = id;
+
+			if (!VFICON(vf)->tip_id)
+				{
+				tip_hide(vf);
+				tip_schedule(vf);
+				return;
+				}
+
+			label = g_object_get_data(G_OBJECT(VFICON(vf)->tip_window), "tip_label");
+			gtk_label_set_text(GTK_LABEL(label), VFICON(vf)->tip_id->fd->name);
+			}
+		}
+	else
+		{
+		tip_schedule(vf);
+		}
+}
+
+/*
+ *-------------------------------------------------------------------
+ * dnd
+ *-------------------------------------------------------------------
+ */
+
+static void vficon_dnd_get(GtkWidget *widget, GdkDragContext *context,
+			   GtkSelectionData *selection_data, guint info,
+			   guint time, gpointer data)
+{
+	ViewFile *vf = data;
+	GList *list = NULL;
+
+	if (!VFICON(vf)->click_id) return;
+
+	if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+		{
+		list = vf_selection_get_list(vf);
+		}
+	else
+		{
+		list = g_list_append(NULL, file_data_ref(VFICON(vf)->click_id->fd));
+		}
+
+	if (!list) return;
+	uri_selection_data_set_uris_from_filelist(selection_data, list);
+	filelist_free(list);
+}
+
+static void vficon_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
+				      int x, int y, GtkSelectionData *selection,
+				      guint info, guint time, gpointer data)
+{
+	ViewFile *vf = data;
+
+	if (info == TARGET_TEXT_PLAIN) {
+		IconData *id = vficon_find_data_by_coord(vf, x, y, NULL);
+
+		if (id && id->fd) {
+			/* Add keywords to file */
+			FileData *fd = id->fd;
+			gchar *str = (gchar *) gtk_selection_data_get_text(selection);
+			GList *kw_list = string_to_keywords_list(str);
+
+			metadata_append_list(fd, KEYWORD_KEY, kw_list);
+			string_list_free(kw_list);
+			g_free(str);
+		}
+	}
+}
+
+static void vficon_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
+{
+	ViewFile *vf = data;
+
+	tip_unschedule(vf);
+
+	if (VFICON(vf)->click_id && VFICON(vf)->click_id->fd->thumb_pixbuf)
+		{
+		gint items;
+
+		if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+			items = g_list_length(VFICON(vf)->selection);
+		else
+			items = 1;
+
+		dnd_set_drag_icon(widget, context, VFICON(vf)->click_id->fd->thumb_pixbuf, items);
+		}
+}
+
+static void vficon_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
+
+	if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
+		{
+		vf_refresh(vf);
+		}
+
+	tip_unschedule(vf);
+}
+
+void vficon_dnd_init(ViewFile *vf)
+{
+	gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
+			    dnd_file_drag_types, dnd_file_drag_types_count,
+			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+	gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
+			    dnd_file_drag_types, dnd_file_drag_types_count,
+			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+
+	g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
+			 G_CALLBACK(vficon_dnd_get), vf);
+	g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
+			 G_CALLBACK(vficon_dnd_begin), vf);
+	g_signal_connect(G_OBJECT(vf->listview), "drag_end",
+			 G_CALLBACK(vficon_dnd_end), vf);
+	g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
+			 G_CALLBACK(vficon_drag_data_received), vf);
+}
+
+/*
+ *-------------------------------------------------------------------
+ * cell updates
+ *-------------------------------------------------------------------
+ */
+
+static void vficon_selection_set(ViewFile *vf, IconData *id, SelectionType value, GtkTreeIter *iter)
+{
+	GtkTreeModel *store;
+	GList *list;
+
+	if (!id) return;
+
+
+	if (id->selected == value) return;
+	id->selected = value;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	if (iter)
+		{
+		gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1);
+		if (list) gtk_list_store_set(GTK_LIST_STORE(store), iter, FILE_COLUMN_POINTER, list, -1);
+		}
+	else
+		{
+		GtkTreeIter row;
+
+		if (vficon_find_iter(vf, id, &row, NULL))
+			{
+			gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
+			if (list) gtk_list_store_set(GTK_LIST_STORE(store), &row, FILE_COLUMN_POINTER, list, -1);
+			}
+		}
+}
+
+static void vficon_selection_add(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
+{
+	if (!id) return;
+
+	vficon_selection_set(vf, id, id->selected | mask, iter);
+}
+
+static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
+{
+	if (!id) return;
+
+	vficon_selection_set(vf, id, id->selected & ~mask, iter);
+}
+
+void vficon_marks_set(ViewFile *vf, gint enable)
+{
+	GtkAllocation allocation;
+	gtk_widget_get_allocation(vf->listview, &allocation);
+	vficon_populate_at_new_size(vf, allocation.width, allocation.height, TRUE);
+}
+
+/*
+ *-------------------------------------------------------------------
+ * selections
+ *-------------------------------------------------------------------
+ */
+
+static void vficon_verify_selections(ViewFile *vf)
+{
+	GList *work;
+
+	work = VFICON(vf)->selection;
+	while (work)
+		{
+		IconData *id = work->data;
+		work = work->next;
+
+		if (vficon_index_by_id(vf, id) >= 0) continue;
+
+		VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
+		}
+}
+
+void vficon_select_all(ViewFile *vf)
+{
+	GList *work;
+
+	g_list_free(VFICON(vf)->selection);
+	VFICON(vf)->selection = NULL;
+
+	work = vf->list;
+	while (work)
+		{
+		IconData *id = work->data;
+		work = work->next;
+
+		VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
+		vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
+		}
+
+	vf_send_update(vf);
+}
+
+void vficon_select_none(ViewFile *vf)
+{
+	GList *work;
+
+	work = VFICON(vf)->selection;
+	while (work)
+		{
+		IconData *id = work->data;
+		work = work->next;
+
+		vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
+		}
+
+	g_list_free(VFICON(vf)->selection);
+	VFICON(vf)->selection = NULL;
+
+	vf_send_update(vf);
+}
+
+void vficon_select_invert(ViewFile *vf)
+{
+	GList *work;
+
+	work = vf->list;
+	while (work)
+		{
+		IconData *id = work->data;
+		work = work->next;
+
+		if (id->selected & SELECTION_SELECTED)
+			{
+			VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
+			vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
+			}
+		else
+			{
+			VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
+			vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
+			}
+		}
+
+	vf_send_update(vf);
+}
+
+static void vficon_select(ViewFile *vf, IconData *id)
+{
+	VFICON(vf)->prev_selection = id;
+
+	if (!id || id->selected & SELECTION_SELECTED) return;
+
+	VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
+	vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
+
+	vf_send_update(vf);
+}
+
+static void vficon_unselect(ViewFile *vf, IconData *id)
+{
+	VFICON(vf)->prev_selection = id;
+
+	if (!id || !(id->selected & SELECTION_SELECTED) ) return;
+
+	VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
+	vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
+
+	vf_send_update(vf);
+}
+
+static void vficon_select_util(ViewFile *vf, IconData *id, gboolean select)
+{
+	if (select)
+		{
+		vficon_select(vf, id);
+		}
+	else
+		{
+		vficon_unselect(vf, id);
+		}
+}
+
+static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *end, gboolean select)
+{
+	gint row1, col1;
+	gint row2, col2;
+	gint t;
+	gint i, j;
+
+	if (!vficon_find_position(vf, start, &row1, &col1) ||
+	    !vficon_find_position(vf, end, &row2, &col2) ) return;
+
+	VFICON(vf)->prev_selection = end;
+
+	if (!options->collections.rectangular_selection)
+		{
+		GList *work;
+		IconData *id;
+
+		if (g_list_index(vf->list, start) > g_list_index(vf->list, end))
+			{
+			id = start;
+			start = end;
+			end = id;
+			}
+
+		work = g_list_find(vf->list, start);
+		while (work)
+			{
+			id = work->data;
+			vficon_select_util(vf, id, select);
+
+			if (work->data != end)
+				work = work->next;
+			else
+				work = NULL;
+			}
+		return;
+		}
+
+	if (row2 < row1)
+		{
+		t = row1;
+		row1 = row2;
+		row2 = t;
+		}
+	if (col2 < col1)
+		{
+		t = col1;
+		col1 = col2;
+		col2 = t;
+		}
+
+	DEBUG_1("table: %d x %d to %d x %d", row1, col1, row2, col2);
+
+	for (i = row1; i <= row2; i++)
+		{
+		for (j = col1; j <= col2; j++)
+			{
+			IconData *id = vficon_find_data(vf, i, j, NULL);
+			if (id) vficon_select_util(vf, id, select);
+			}
+		}
+}
+
+gboolean vficon_index_is_selected(ViewFile *vf, gint row)
+{
+	IconData *id = g_list_nth_data(vf->list, row);
+
+	if (!id) return FALSE;
+
+	return (id->selected & SELECTION_SELECTED);
+}
+
+guint vficon_selection_count(ViewFile *vf, gint64 *bytes)
+{
+	if (bytes)
+		{
+		gint64 b = 0;
+		GList *work;
+
+		work = VFICON(vf)->selection;
+		while (work)
+			{
+			IconData *id = work->data;
+			FileData *fd = id->fd;
+			g_assert(fd->magick == FD_MAGICK);
+			b += fd->size;
+
+			work = work->next;
+			}
+
+		*bytes = b;
+		}
+
+	return g_list_length(VFICON(vf)->selection);
+}
+
+GList *vficon_selection_get_list(ViewFile *vf)
+{
+	GList *list = NULL;
+	GList *work, *work2;
+
+	work = VFICON(vf)->selection;
+	while (work)
+		{
+		IconData *id = work->data;
+		FileData *fd = id->fd;
+		g_assert(fd->magick == FD_MAGICK);
+
+		list = g_list_prepend(list, file_data_ref(fd));
+
+		work2 = fd->sidecar_files;
+		while (work2)
+			{
+			fd = work2->data;
+			list = g_list_prepend(list, file_data_ref(fd));
+			work2 = work2->next;
+			}
+
+		work = work->next;
+		}
+
+	list = g_list_reverse(list);
+
+	return list;
+}
+
+GList *vficon_selection_get_list_by_index(ViewFile *vf)
+{
+	GList *list = NULL;
+	GList *work;
+
+	work = VFICON(vf)->selection;
+	while (work)
+		{
+		list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, work->data)));
+		work = work->next;
+		}
+
+	return g_list_reverse(list);
+}
+
+static void vficon_select_by_id(ViewFile *vf, IconData *id)
+{
+	if (!id) return;
+
+	if (!(id->selected & SELECTION_SELECTED))
+		{
+		vf_select_none(vf);
+		vficon_select(vf, id);
+		}
+
+	vficon_set_focus(vf, id);
+}
+
+void vficon_select_by_fd(ViewFile *vf, FileData *fd)
+{
+	IconData *id = NULL;
+	GList *work;
+
+	if (!fd) return;
+	work = vf->list;
+	while (work && !id)
+		{
+		IconData *chk = work->data;
+		work = work->next;
+		if (chk->fd == fd) id = chk;
+		}
+	vficon_select_by_id(vf, id);
+}
+
+void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
+{
+	GList *work;
+	gint n = mark - 1;
+
+	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
+
+	work = vf->list;
+	while (work)
+		{
+		IconData *id = work->data;
+		FileData *fd = id->fd;
+		gboolean mark_val, selected;
+
+		g_assert(fd->magick == FD_MAGICK);
+
+		mark_val = file_data_get_mark(fd, n);
+		selected = (id->selected & SELECTION_SELECTED);
+
+		switch (mode)
+			{
+			case MTS_MODE_SET: selected = mark_val;
+				break;
+			case MTS_MODE_OR: selected = mark_val || selected;
+				break;
+			case MTS_MODE_AND: selected = mark_val && selected;
+				break;
+			case MTS_MODE_MINUS: selected = !mark_val && selected;
+				break;
+			}
+
+		vficon_select_util(vf, id, selected);
+
+		work = work->next;
+		}
+}
+
+void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
+{
+	GList *slist;
+	GList *work;
+	gint n = mark -1;
+
+	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
+
+	slist = vf_selection_get_list(vf);
+	work = slist;
+	while (work)
+		{
+		FileData *fd = work->data;
+
+		switch (mode)
+			{
+			case STM_MODE_SET: file_data_set_mark(fd, n, 1);
+				break;
+			case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
+				break;
+			case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
+				break;
+			}
+		work = work->next;
+		}
+	filelist_free(slist);
+}
+
+static void vficon_select_closest(ViewFile *vf, FileData *sel_fd)
+{
+	GList *work;
+	IconData *id = NULL;
+
+	if (sel_fd->parent) sel_fd = sel_fd->parent;
+	work = vf->list;
+
+	while (work)
+		{
+		gint match;
+		FileData *fd;
+
+		id = work->data;
+		fd = id->fd;
+		work = work->next;
+
+		match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
+
+		if (match >= 0) break;
+		}
+
+	if (id)
+		{
+		vficon_select(vf, id);
+		vficon_send_layout_select(vf, id);
+		}
+}
+
+
+/*
+ *-------------------------------------------------------------------
+ * focus
+ *-------------------------------------------------------------------
+ */
+
+static void vficon_move_focus(ViewFile *vf, gint row, gint col, gboolean relative)
+{
+	gint new_row;
+	gint new_col;
+
+	if (relative)
+		{
+		new_row = VFICON(vf)->focus_row;
+		new_col = VFICON(vf)->focus_column;
+
+		new_row += row;
+		if (new_row < 0) new_row = 0;
+		if (new_row >= VFICON(vf)->rows) new_row = VFICON(vf)->rows - 1;
+
+		while (col != 0)
+			{
+			if (col < 0)
+				{
+				new_col--;
+				col++;
+				}
+			else
+				{
+				new_col++;
+				col--;
+				}
+
+			if (new_col < 0)
+				{
+				if (new_row > 0)
+					{
+					new_row--;
+					new_col = VFICON(vf)->columns - 1;
+					}
+				else
+					{
+					new_col = 0;
+					}
+				}
+			if (new_col >= VFICON(vf)->columns)
+				{
+				if (new_row < VFICON(vf)->rows - 1)
+					{
+					new_row++;
+					new_col = 0;
+					}
+				else
+					{
+					new_col = VFICON(vf)->columns - 1;
+					}
+				}
+			}
+		}
+	else
+		{
+		new_row = row;
+		new_col = col;
+
+		if (new_row >= VFICON(vf)->rows)
+			{
+			if (VFICON(vf)->rows > 0)
+				new_row = VFICON(vf)->rows - 1;
+			else
+				new_row = 0;
+			new_col = VFICON(vf)->columns - 1;
+			}
+		if (new_col >= VFICON(vf)->columns) new_col = VFICON(vf)->columns - 1;
+		}
+
+	if (new_row == VFICON(vf)->rows - 1)
+		{
+		gint l;
+
+		/* if we moved beyond the last image, go to the last image */
+
+		l = g_list_length(vf->list);
+		if (VFICON(vf)->rows > 1) l -= (VFICON(vf)->rows - 1) * VFICON(vf)->columns;
+		if (new_col >= l) new_col = l - 1;
+		}
+
+	vficon_set_focus(vf, vficon_find_data(vf, new_row, new_col, NULL));
+}
+
+static void vficon_set_focus(ViewFile *vf, IconData *id)
+{
+	GtkTreeIter iter;
+	gint row, col;
+
+	if (g_list_find(vf->list, VFICON(vf)->focus_id))
+		{
+		if (id == VFICON(vf)->focus_id)
+			{
+			/* ensure focus row col are correct */
+			vficon_find_position(vf, VFICON(vf)->focus_id, &VFICON(vf)->focus_row, &VFICON(vf)->focus_column);
+#if GTK_CHECK_VERSION(3,0,0)
+/* FIXME: Refer to issue #467 on Github. The thumbnail position is not
+ * preserved when the icon view is refreshed. Caused by an unknown call from
+ * the idle loop. This patch hides the problem.
+ */
+			if (vficon_find_iter(vf, VFICON(vf)->focus_id, &iter, NULL))
+				{
+				tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
+				}
+#endif
+			return;
+			}
+		vficon_selection_remove(vf, VFICON(vf)->focus_id, SELECTION_FOCUS, NULL);
+		}
+
+	if (!vficon_find_position(vf, id, &row, &col))
+		{
+		VFICON(vf)->focus_id = NULL;
+		VFICON(vf)->focus_row = -1;
+		VFICON(vf)->focus_column = -1;
+		return;
+		}
+
+	VFICON(vf)->focus_id = id;
+	VFICON(vf)->focus_row = row;
+	VFICON(vf)->focus_column = col;
+	vficon_selection_add(vf, VFICON(vf)->focus_id, SELECTION_FOCUS, NULL);
+
+	if (vficon_find_iter(vf, VFICON(vf)->focus_id, &iter, NULL))
+		{
+		GtkTreePath *tpath;
+		GtkTreeViewColumn *column;
+		GtkTreeModel *store;
+
+		tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		tpath = gtk_tree_model_get_path(store, &iter);
+		/* focus is set to an extra column with 0 width to hide focus, we draw it ourself */
+		column = gtk_tree_view_get_column(GTK_TREE_VIEW(vf->listview), VFICON_MAX_COLUMNS);
+		gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, column, FALSE);
+		gtk_tree_path_free(tpath);
+		}
+}
+
+/* used to figure the page up/down distances */
+static gint page_height(ViewFile *vf)
+{
+	GtkAdjustment *adj;
+	gint page_size;
+	gint row_height;
+	gint ret;
+
+	adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(vf->listview));
+	page_size = (gint)gtk_adjustment_get_page_increment(adj);
+
+	row_height = options->thumbnails.max_height + THUMB_BORDER_PADDING * 2;
+	if (VFICON(vf)->show_text) row_height += options->thumbnails.max_height / 3;
+
+	ret = page_size / row_height;
+	if (ret < 1) ret = 1;
+
+	return ret;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * keyboard
+ *-------------------------------------------------------------------
+ */
+
+static void vfi_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreeModel *store;
+	GtkTreeIter iter;
+	gint column;
+	GtkTreePath *tpath;
+	gint cw, ch;
+
+	if (!vficon_find_iter(vf, VFICON(vf)->click_id, &iter, &column)) return;
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	tpath = gtk_tree_model_get_path(store, &iter);
+	tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, column, FALSE, x, y, &cw, &ch);
+	gtk_tree_path_free(tpath);
+	*y += ch;
+	popup_menu_position_clamp(menu, x, y, 0);
+}
+
+gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+	ViewFile *vf = data;
+	gint focus_row = 0;
+	gint focus_col = 0;
+	IconData *id;
+	gboolean stop_signal;
+
+	stop_signal = TRUE;
+	switch (event->keyval)
+		{
+		case GDK_KEY_Left: case GDK_KEY_KP_Left:
+			focus_col = -1;
+			break;
+		case GDK_KEY_Right: case GDK_KEY_KP_Right:
+			focus_col = 1;
+			break;
+		case GDK_KEY_Up: case GDK_KEY_KP_Up:
+			focus_row = -1;
+			break;
+		case GDK_KEY_Down: case GDK_KEY_KP_Down:
+			focus_row = 1;
+			break;
+		case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up:
+			focus_row = -page_height(vf);
+			break;
+		case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down:
+			focus_row = page_height(vf);
+			break;
+		case GDK_KEY_Home: case GDK_KEY_KP_Home:
+			focus_row = -VFICON(vf)->focus_row;
+			focus_col = -VFICON(vf)->focus_column;
+			break;
+		case GDK_KEY_End: case GDK_KEY_KP_End:
+			focus_row = VFICON(vf)->rows - 1 - VFICON(vf)->focus_row;
+			focus_col = VFICON(vf)->columns - 1 - VFICON(vf)->focus_column;
+			break;
+		case GDK_KEY_space:
+			id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+			if (id)
+				{
+				VFICON(vf)->click_id = id;
+				if (event->state & GDK_CONTROL_MASK)
+					{
+					gint selected;
+
+					selected = id->selected & SELECTION_SELECTED;
+					if (selected)
+						{
+						vficon_unselect(vf, id);
+						}
+					else
+						{
+						vficon_select(vf, id);
+						vficon_send_layout_select(vf, id);
+						}
+					}
+				else
+					{
+					vf_select_none(vf);
+					vficon_select(vf, id);
+					vficon_send_layout_select(vf, id);
+					}
+				}
+			break;
+		case GDK_KEY_Menu:
+			id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+			VFICON(vf)->click_id = id;
+
+			vficon_selection_add(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
+			tip_unschedule(vf);
+
+			vf->popup = vf_pop_menu(vf);
+			gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vfi_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
+			break;
+		default:
+			stop_signal = FALSE;
+			break;
+		}
+
+	if (focus_row != 0 || focus_col != 0)
+		{
+		IconData *new_id;
+		IconData *old_id;
+
+		old_id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+		vficon_move_focus(vf, focus_row, focus_col, TRUE);
+		new_id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+
+		if (new_id != old_id)
+			{
+			if (event->state & GDK_SHIFT_MASK)
+				{
+				if (!options->collections.rectangular_selection)
+					{
+					vficon_select_region_util(vf, old_id, new_id, FALSE);
+					}
+				else
+					{
+					vficon_select_region_util(vf, VFICON(vf)->click_id, old_id, FALSE);
+					}
+				vficon_select_region_util(vf, VFICON(vf)->click_id, new_id, TRUE);
+				vficon_send_layout_select(vf, new_id);
+				}
+			else if (event->state & GDK_CONTROL_MASK)
+				{
+				VFICON(vf)->click_id = new_id;
+				}
+			else
+				{
+				VFICON(vf)->click_id = new_id;
+				vf_select_none(vf);
+				vficon_select(vf, new_id);
+				vficon_send_layout_select(vf, new_id);
+				}
+			}
+		}
+
+	if (stop_signal)
+		{
+		tip_unschedule(vf);
+		}
+
+	return stop_signal;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * mouse
+ *-------------------------------------------------------------------
+ */
+
+static gboolean vficon_motion_cb(GtkWidget *widget, GdkEventMotion *event, gpointer data)
+{
+	ViewFile *vf = data;
+	IconData *id;
+
+	id = vficon_find_data_by_coord(vf, (gint)event->x, (gint)event->y, NULL);
+	tip_update(vf, id);
+
+	return FALSE;
+}
+
+gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreeIter iter;
+	IconData *id;
+
+	tip_unschedule(vf);
+
+	id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
+
+	VFICON(vf)->click_id = id;
+	vficon_selection_add(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, &iter);
+
+	switch (bevent->button)
+		{
+		case MOUSE_BUTTON_LEFT:
+			if (!gtk_widget_has_focus(vf->listview))
+				{
+				gtk_widget_grab_focus(vf->listview);
+				}
+
+			if (bevent->type == GDK_2BUTTON_PRESS &&
+			    vf->layout)
+				{
+				vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, &iter);
+				layout_image_full_screen_start(vf->layout);
+				}
+			break;
+		case MOUSE_BUTTON_RIGHT:
+			vf->popup = vf_pop_menu(vf);
+			gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
+			break;
+		default:
+			break;
+		}
+
+	return FALSE;
+}
+
+gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreeIter iter;
+	IconData *id = NULL;
+	gboolean was_selected;
+
+	tip_schedule(vf);
+
+	if ((gint)bevent->x != 0 || (gint)bevent->y != 0)
+		{
+		id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
+		}
+
+	if (VFICON(vf)->click_id)
+		{
+		vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
+		}
+
+	if (!id || VFICON(vf)->click_id != id) return TRUE;
+
+	was_selected = !!(id->selected & SELECTION_SELECTED);
+
+	switch (bevent->button)
+		{
+		case MOUSE_BUTTON_LEFT:
+			{
+			vficon_set_focus(vf, id);
+
+			if (bevent->state & GDK_CONTROL_MASK)
+				{
+				gboolean select;
+
+				select = !(id->selected & SELECTION_SELECTED);
+				if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection)
+					{
+					vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, select);
+					}
+				else
+					{
+					vficon_select_util(vf, id, select);
+					}
+				}
+			else
+				{
+				vf_select_none(vf);
+
+				if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection)
+					{
+					vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, TRUE);
+					}
+				else
+					{
+					vficon_select_util(vf, id, TRUE);
+					was_selected = FALSE;
+					}
+				}
+			}
+			break;
+		case MOUSE_BUTTON_MIDDLE:
+			{
+			vficon_select_util(vf, id, !(id->selected & SELECTION_SELECTED));
+			}
+			break;
+		default:
+			break;
+		}
+
+	if (!was_selected && (id->selected & SELECTION_SELECTED))
+		{
+		vficon_send_layout_select(vf, id);
+		}
+
+	return TRUE;
+}
+
+static gboolean vficon_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
+{
+	ViewFile *vf = data;
+
+	tip_unschedule(vf);
+	return FALSE;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * population
+ *-------------------------------------------------------------------
+ */
+
+static gboolean vficon_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GtkTreeIter *iter, gpointer data)
+{
+	GList *list;
+
+	gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1);
+
+	/* it seems that gtk_list_store_clear may call some callbacks
+	   that use the column. Set the pointer to NULL to be safe. */
+	gtk_list_store_set(GTK_LIST_STORE(store), iter, FILE_COLUMN_POINTER, NULL, -1);
+	g_list_free(list);
+
+	return FALSE;
+}
+
+static void vficon_clear_store(ViewFile *vf)
+{
+	GtkTreeModel *store;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_model_foreach(store, vficon_destroy_node_cb, NULL);
+
+	gtk_list_store_clear(GTK_LIST_STORE(store));
+}
+
+static GList *vficon_add_row(ViewFile *vf, GtkTreeIter *iter)
+{
+	GtkListStore *store;
+	GList *list = NULL;
+	gint i;
+
+	for (i = 0; i < VFICON(vf)->columns; i++) list = g_list_prepend(list, NULL);
+
+	store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+	gtk_list_store_append(store, iter);
+	gtk_list_store_set(store, iter, FILE_COLUMN_POINTER, list, -1);
+
+	return list;
+}
+
+static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_position)
+{
+	GtkTreeModel *store;
+	GtkTreePath *tpath;
+	GList *work;
+	IconData *visible_id = NULL;
+	gint r, c;
+	gboolean valid;
+	GtkTreeIter iter;
+
+	vficon_verify_selections(vf);
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+
+	if (keep_position && gtk_widget_get_realized(vf->listview) &&
+	    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
+		{
+		GtkTreeIter iter;
+		GList *list;
+
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_path_free(tpath);
+
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
+		if (list) visible_id = list->data;
+		}
+
+
+	if (resize)
+		{
+		gint i;
+		gint thumb_width;
+
+		vficon_clear_store(vf);
+
+		thumb_width = vficon_get_icon_width(vf);
+
+		for (i = 0; i < VFICON_MAX_COLUMNS; i++)
+			{
+			GtkTreeViewColumn *column;
+			GtkCellRenderer *cell;
+			GList *list;
+
+			column = gtk_tree_view_get_column(GTK_TREE_VIEW(vf->listview), i);
+			gtk_tree_view_column_set_visible(column, (i < VFICON(vf)->columns));
+			gtk_tree_view_column_set_fixed_width(column, thumb_width + (THUMB_BORDER_PADDING * 6));
+
+			list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
+			cell = (list) ? list->data : NULL;
+			g_list_free(list);
+
+			if (cell && GQV_IS_CELL_RENDERER_ICON(cell))
+				{
+				g_object_set(G_OBJECT(cell), "fixed_width", thumb_width,
+							     "fixed_height", options->thumbnails.max_height,
+							     "show_text", VFICON(vf)->show_text,
+							     "show_marks", vf->marks_enabled,
+							     "num_marks", FILEDATA_MARKS_SIZE,
+							     NULL);
+				}
+			}
+		if (gtk_widget_get_realized(vf->listview)) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+		}
+
+	r = -1;
+	c = 0;
+
+	valid = gtk_tree_model_iter_children(store, &iter, NULL);
+
+	work = vf->list;
+	while (work)
+		{
+		GList *list;
+		r++;
+		c = 0;
+		if (valid)
+			{
+			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
+			gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1);
+			}
+		else
+			{
+			list = vficon_add_row(vf, &iter);
+			}
+
+		while (list)
+			{
+			IconData *id;
+
+			if (work)
+				{
+				id = work->data;
+				work = work->next;
+				c++;
+				}
+			else
+				{
+				id = NULL;
+				}
+
+			list->data = id;
+			list = list->next;
+			}
+		if (valid) valid = gtk_tree_model_iter_next(store, &iter);
+		}
+
+	r++;
+	while (valid)
+		{
+		GList *list;
+
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
+		valid = gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
+		g_list_free(list);
+		}
+
+	VFICON(vf)->rows = r;
+
+	if (visible_id &&
+	    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
+		{
+		GtkTreeIter iter;
+		GList *list;
+
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_path_free(tpath);
+
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
+		if (g_list_find(list, visible_id) == NULL &&
+		    vficon_find_iter(vf, visible_id, &iter, NULL))
+			{
+			tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
+			}
+		}
+
+
+	vf_send_update(vf);
+	vf_thumb_update(vf);
+}
+
+static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gboolean force)
+{
+	gint new_cols;
+	gint thumb_width;
+
+	thumb_width = vficon_get_icon_width(vf);
+
+	new_cols = w / (thumb_width + (THUMB_BORDER_PADDING * 6));
+	if (new_cols < 1) new_cols = 1;
+
+	if (!force && new_cols == VFICON(vf)->columns) return;
+
+	VFICON(vf)->columns = new_cols;
+
+	vficon_populate(vf, TRUE, TRUE);
+
+	DEBUG_1("col tab pop cols=%d rows=%d", VFICON(vf)->columns, VFICON(vf)->rows);
+}
+
+static void vficon_sized_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vficon_populate_at_new_size(vf, allocation->width, allocation->height, FALSE);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * misc
+ *-----------------------------------------------------------------------------
+ */
+
+void vficon_sort_set(ViewFile *vf, SortType type, gboolean ascend)
+{
+	if (vf->sort_method == type && vf->sort_ascend == ascend) return;
+
+	vf->sort_method = type;
+	vf->sort_ascend = ascend;
+
+	if (!vf->list) return;
+
+	vf_refresh(vf);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * thumb updates
+ *-----------------------------------------------------------------------------
+ */
+
+void vficon_thumb_progress_count(GList *list, gint *count, gint *done)
+{
+	GList *work = list;
+	while (work)
+		{
+		IconData *id = work->data;
+		FileData *fd = id->fd;
+		work = work->next;
+
+		if (fd->thumb_pixbuf) (*done)++;
+		(*count)++;
+		}
+}
+
+void vficon_set_thumb_fd(ViewFile *vf, FileData *fd)
+{
+	GtkTreeModel *store;
+	GtkTreeIter iter;
+	GList *list;
+
+	if (!vficon_find_iter(vf, vficon_icon_data(vf, fd), &iter, NULL)) return;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+
+	gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
+	gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1);
+}
+
+
+FileData *vficon_thumb_next_fd(ViewFile *vf)
+{
+	GtkTreePath *tpath;
+	FileData *fd = NULL;
+
+	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
+		{
+		GtkTreeModel *store;
+		GtkTreeIter iter;
+		gboolean valid = TRUE;
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_path_free(tpath);
+
+		while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
+			{
+			GList *list;
+
+			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
+
+			while (!fd && list)
+				{
+				IconData *id = list->data;
+				if (id && !id->fd->thumb_pixbuf) fd = id->fd;
+				list = list->next;
+				}
+
+			valid = gtk_tree_model_iter_next(store, &iter);
+			}
+		}
+
+	/* then find first undone */
+
+	if (!fd)
+		{
+		GList *work = vf->list;
+		while (work && !fd)
+			{
+			IconData *id = work->data;
+			FileData *fd_p = id->fd;
+			work = work->next;
+
+			if (!fd_p->thumb_pixbuf) fd = fd_p;
+			}
+		}
+
+	return fd;
+}
+
+void vficon_thumb_reset_all(ViewFile *vf)
+{
+	GList *work = vf->list;
+
+	while (work)
+		{
+		IconData *id = work->data;
+		FileData *fd = id->fd;
+		if (fd->thumb_pixbuf)
+			{
+			g_object_unref(fd->thumb_pixbuf);
+			fd->thumb_pixbuf = NULL;
+			}
+		work = work->next;
+		}
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * row stuff
+ *-----------------------------------------------------------------------------
+ */
+
+FileData *vficon_index_get_data(ViewFile *vf, gint row)
+{
+	IconData *id;
+
+	id = g_list_nth_data(vf->list, row);
+	return id ? id->fd : NULL;
+}
+
+
+gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd)
+{
+	gint p = 0;
+	GList *work;
+
+	if (!in_fd) return -1;
+
+	work = vf->list;
+	while (work)
+		{
+		IconData *id = work->data;
+		FileData *fd = id->fd;
+		if (fd == in_fd) return p;
+		work = work->next;
+		p++;
+		}
+
+	return -1;
+}
+
+static gint vficon_index_by_id(ViewFile *vf, IconData *in_id)
+{
+	gint p = 0;
+	GList *work;
+
+	if (!in_id) return -1;
+
+	work = vf->list;
+	while (work)
+		{
+		IconData *id = work->data;
+		if (id == in_id) return p;
+		work = work->next;
+		p++;
+		}
+
+	return -1;
+}
+
+guint vficon_count(ViewFile *vf, gint64 *bytes)
+{
+	if (bytes)
+		{
+		gint64 b = 0;
+		GList *work;
+
+		work = vf->list;
+		while (work)
+			{
+			IconData *id = work->data;
+			FileData *fd = id->fd;
+			work = work->next;
+
+			b += fd->size;
+			}
+
+		*bytes = b;
+		}
+
+	return g_list_length(vf->list);
+}
+
+GList *vficon_get_list(ViewFile *vf)
+{
+	GList *list = NULL;
+	GList *work;
+
+	work = vf->list;
+	while (work)
+		{
+		IconData *id = work->data;
+		FileData *fd = id->fd;
+		work = work->next;
+
+		list = g_list_prepend(list, file_data_ref(fd));
+		}
+
+	return g_list_reverse(list);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
+{
+	gboolean ret = TRUE;
+	GList *work, *work_fd;
+	IconData *focus_id;
+	GList *new_filelist = NULL;
+	FileData *first_selected = NULL;
+	GList *new_iconlist = NULL;
+
+	focus_id = VFICON(vf)->focus_id;
+
+	if (vf->dir_fd)
+		{
+		ret = filelist_read(vf->dir_fd, &new_filelist, NULL);
+		new_filelist = file_data_filter_marks_list(new_filelist, vf_marks_get_filter(vf));
+		}
+
+	vf->list = iconlist_sort(vf->list, vf->sort_method, vf->sort_ascend); /* the list might not be sorted if there were renames */
+	new_filelist = filelist_sort(new_filelist, vf->sort_method, vf->sort_ascend);
+
+	if (VFICON(vf)->selection)
+		{
+		first_selected = ((IconData *)(VFICON(vf)->selection->data))->fd;
+		file_data_ref(first_selected);
+		g_list_free(VFICON(vf)->selection);
+		VFICON(vf)->selection = NULL;
+
+
+		}
+
+	/* check for same files from old_list */
+	work = vf->list;
+	work_fd = new_filelist;
+	while (work || work_fd)
+		{
+		IconData *id = NULL;
+		FileData *fd = NULL;
+		FileData *new_fd = NULL;
+		gint match;
+
+		if (work && work_fd)
+			{
+			id = work->data;
+			fd = id->fd;
+
+			new_fd = work_fd->data;
+
+			if (fd == new_fd)
+				{
+				/* not changed, go to next */
+				work = work->next;
+				work_fd = work_fd->next;
+				if (id->selected & SELECTION_SELECTED)
+					{
+					VFICON(vf)->selection = g_list_prepend(VFICON(vf)->selection, id);
+					}
+				continue;
+				}
+
+			match = filelist_sort_compare_filedata_full(fd, new_fd, vf->sort_method, vf->sort_ascend);
+			if (match == 0) g_warning("multiple fd for the same path");
+			}
+		else if (work)
+			{
+			id = work->data;
+			fd = id->fd;
+			match = -1;
+			}
+		else /* work_fd */
+			{
+			new_fd = work_fd->data;
+			match = 1;
+			}
+
+		if (match < 0)
+			{
+			/* file no longer exists, delete from vf->list */
+			GList *to_delete = work;
+			work = work->next;
+			if (id == VFICON(vf)->prev_selection) VFICON(vf)->prev_selection = NULL;
+			if (id == VFICON(vf)->click_id) VFICON(vf)->click_id = NULL;
+			file_data_unref(fd);
+			g_free(id);
+			vf->list = g_list_delete_link(vf->list, to_delete);
+			}
+		else
+			{
+			/* new file, add to vf->list */
+			id = g_new0(IconData, 1);
+
+			id->selected = SELECTION_NONE;
+			id->fd = file_data_ref(new_fd);
+			if (work)
+				vf->list = g_list_insert_before(vf->list, work, id);
+			else
+				new_iconlist = g_list_prepend(new_iconlist, id); /* it is faster to append all new entries together later */
+
+			work_fd = work_fd->next;
+			}
+
+		}
+
+	if (new_iconlist)
+		{
+		vf->list = g_list_concat(vf->list, g_list_reverse(new_iconlist));
+		}
+
+	VFICON(vf)->selection = g_list_reverse(VFICON(vf)->selection);
+
+	filelist_free(new_filelist);
+
+	vficon_populate(vf, TRUE, keep_position);
+
+	if (first_selected && !VFICON(vf)->selection)
+		{
+		/* all selected files disappeared */
+		vficon_select_closest(vf, first_selected);
+		}
+	file_data_unref(first_selected);
+
+	/* attempt to keep focus on same icon when refreshing */
+	if (focus_id && g_list_find(vf->list, focus_id))
+		{
+		vficon_set_focus(vf, focus_id);
+		}
+
+	return ret;
+}
+
+gboolean vficon_refresh(ViewFile *vf)
+{
+	return vficon_refresh_real(vf, TRUE);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * draw, etc.
+ *-----------------------------------------------------------------------------
+ */
+
+typedef struct _ColumnData ColumnData;
+struct _ColumnData
+{
+	ViewFile *vf;
+	gint number;
+};
+
+static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+				GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+	GList *list;
+	IconData *id;
+	ColumnData *cd = data;
+	ViewFile *vf = cd->vf;
+
+	if (!GQV_IS_CELL_RENDERER_ICON(cell)) return;
+
+	gtk_tree_model_get(tree_model, iter, FILE_COLUMN_POINTER, &list, -1);
+
+	id = g_list_nth_data(list, cd->number);
+
+	if (id)
+		{
+		GdkColor color_fg;
+		GdkColor color_bg;
+		GtkStyle *style;
+		gchar *name_sidecars;
+		gchar *link;
+		GtkStateType state = GTK_STATE_NORMAL;
+
+		g_assert(id->fd->magick == FD_MAGICK);
+
+		link = islink(id->fd->path) ? GQ_LINK_STR : "";
+		if (id->fd->sidecar_files)
+			{
+			gchar *sidecars = file_data_sc_list_to_string(id->fd);
+			name_sidecars = g_strdup_printf("%s%s %s", link, id->fd->name, sidecars);
+			g_free(sidecars);
+			}
+		else
+			{
+			gchar *disabled_grouping = id->fd->disable_grouping ? _(" [NO GROUPING]") : "";
+			name_sidecars = g_strdup_printf("%s%s%s", link, id->fd->name, disabled_grouping);
+			}
+
+		style = gtk_widget_get_style(vf->listview);
+		if (id->selected & SELECTION_SELECTED)
+			{
+			state = GTK_STATE_SELECTED;
+			}
+
+		memcpy(&color_fg, &style->text[state], sizeof(color_fg));
+		memcpy(&color_bg, &style->base[state], sizeof(color_bg));
+
+		if (id->selected & SELECTION_PRELIGHT)
+			{
+			shift_color(&color_bg, -1, 0);
+			}
+
+		g_object_set(cell,	"pixbuf", id->fd->thumb_pixbuf,
+					"text", name_sidecars,
+					"marks", file_data_get_marks(id->fd),
+					"show_marks", vf->marks_enabled,
+					"cell-background-gdk", &color_bg,
+					"cell-background-set", TRUE,
+					"foreground-gdk", &color_fg,
+					"foreground-set", TRUE,
+					"has-focus", (VFICON(vf)->focus_id == id), NULL);
+		g_free(name_sidecars);
+		}
+	else
+		{
+		g_object_set(cell,	"pixbuf", NULL,
+					"text", NULL,
+					"show_marks", FALSE,
+					"cell-background-set", FALSE,
+					"foreground-set", FALSE,
+					"has-focus", FALSE, NULL);
+		}
+}
+
+static void vficon_append_column(ViewFile *vf, gint n)
+{
+	ColumnData *cd;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_min_width(column, 0);
+
+	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
+	gtk_tree_view_column_set_alignment(column, 0.5);
+
+	renderer = gqv_cell_renderer_icon_new();
+	gtk_tree_view_column_pack_start(column, renderer, FALSE);
+	g_object_set(G_OBJECT(renderer), "xpad", THUMB_BORDER_PADDING * 2,
+					 "ypad", THUMB_BORDER_PADDING,
+					 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
+
+	g_object_set_data(G_OBJECT(column), "column_number", GINT_TO_POINTER(n));
+	g_object_set_data(G_OBJECT(renderer), "column_number", GINT_TO_POINTER(n));
+
+	cd = g_new0(ColumnData, 1);
+	cd->vf = vf;
+	cd->number = n;
+	gtk_tree_view_column_set_cell_data_func(column, renderer, vficon_cell_data_cb, cd, g_free);
+
+	gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
+
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vficon_mark_toggled_cb), vf);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * base
+ *-----------------------------------------------------------------------------
+ */
+
+gboolean vficon_set_fd(ViewFile *vf, FileData *dir_fd)
+{
+	gboolean ret;
+
+	if (!dir_fd) return FALSE;
+	if (vf->dir_fd == dir_fd) return TRUE;
+
+	file_data_unref(vf->dir_fd);
+	vf->dir_fd = file_data_ref(dir_fd);
+
+	g_list_free(VFICON(vf)->selection);
+	VFICON(vf)->selection = NULL;
+
+	iconlist_free(vf->list);
+	vf->list = NULL;
+
+	/* NOTE: populate will clear the store for us */
+	ret = vficon_refresh_real(vf, FALSE);
+
+	VFICON(vf)->focus_id = NULL;
+	vficon_move_focus(vf, 0, 0, FALSE);
+
+	return ret;
+}
+
+void vficon_destroy_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vf_refresh_idle_cancel(vf);
+
+	file_data_unregister_notify_func(vf_notify_cb, vf);
+
+	tip_unschedule(vf);
+
+	vf_thumb_cleanup(vf);
+
+	iconlist_free(vf->list);
+	g_list_free(VFICON(vf)->selection);
+}
+
+ViewFile *vficon_new(ViewFile *vf, FileData *dir_fd)
+{
+	GtkListStore *store;
+	GtkTreeSelection *selection;
+	gint i;
+
+	vf->info = g_new0(ViewFileInfoIcon, 1);
+
+	VFICON(vf)->show_text = options->show_icon_names;
+
+	store = gtk_list_store_new(1, G_TYPE_POINTER);
+	vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+	g_object_unref(store);
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_NONE);
+
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
+	gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
+
+	for (i = 0; i < VFICON_MAX_COLUMNS; i++)
+		{
+		vficon_append_column(vf, i);
+		}
+
+	/* zero width column to hide tree view focus, we draw it ourselves */
+	vficon_append_column(vf, i);
+	/* end column to fill white space */
+	vficon_append_column(vf, i);
+
+	g_signal_connect(G_OBJECT(vf->listview), "size_allocate",
+			 G_CALLBACK(vficon_sized_cb), vf);
+
+	gtk_widget_set_events(vf->listview, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK |
+			      GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK);
+
+	g_signal_connect(G_OBJECT(vf->listview),"motion_notify_event",
+			 G_CALLBACK(vficon_motion_cb), vf);
+	g_signal_connect(G_OBJECT(vf->listview), "leave_notify_event",
+			 G_CALLBACK(vficon_leave_cb), vf);
+
+	/* force VFICON(vf)->columns to be at least 1 (sane) - this will be corrected in the size_cb */
+	vficon_populate_at_new_size(vf, 1, 1, FALSE);
+
+	file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+
+	return vf;
+}
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/view_file/view_file_icon.h	Wed Jul 05 21:41:18 2017 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ * Author: John Ellis
+ *
+ * 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 VIEW_FILE_VIEW_FILE_ICON_H
+#define VIEW_FILE_VIEW_FILE_ICON_H
+
+gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data);
+gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
+gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
+
+void vficon_dnd_init(ViewFile *vf);
+
+void vficon_destroy_cb(GtkWidget *widget, gpointer data);
+ViewFile *vficon_new(ViewFile *vf, FileData *dir_fd);
+
+gboolean vficon_set_fd(ViewFile *vf, FileData *dir_fd);
+gboolean vficon_refresh(ViewFile *vf);
+
+void vficon_sort_set(ViewFile *vf, SortType type, gboolean ascend);
+
+void vficon_marks_set(ViewFile *vf, gboolean enable);
+
+GList *vficon_selection_get_one(ViewFile *vf, FileData *fd);
+GList *vficon_pop_menu_file_list(ViewFile *vf);
+void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data);
+void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data);
+void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data);
+void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data);
+void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data);
+
+FileData *vficon_index_get_data(ViewFile *vf, gint row);
+gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd);
+guint vficon_count(ViewFile *vf, gint64 *bytes);
+GList *vficon_get_list(ViewFile *vf);
+
+gboolean vficon_index_is_selected(ViewFile *vf, gint row);
+guint vficon_selection_count(ViewFile *vf, gint64 *bytes);
+GList *vficon_selection_get_list(ViewFile *vf);
+GList *vficon_selection_get_list_by_index(ViewFile *vf);
+
+void vficon_select_all(ViewFile *vf);
+void vficon_select_none(ViewFile *vf);
+void vficon_select_invert(ViewFile *vf);
+void vficon_select_by_fd(ViewFile *vf, FileData *fd);
+
+void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode);
+void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode);
+
+
+void vficon_thumb_progress_count(GList *list, gint *count, gint *done);
+void vficon_set_thumb_fd(ViewFile *vf, FileData *fd);
+FileData *vficon_thumb_next_fd(ViewFile *vf);
+void vficon_thumb_reset_all(ViewFile *vf);
+
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/view_file/view_file_list.c	Wed Jul 05 21:41:18 2017 +0000
@@ -0,0 +1,2052 @@
+/*
+ * Copyright (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ * Author: John Ellis
+ *
+ * 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 "view_file_list.h"
+
+#include "bar.h"
+#include "cache_maint.h"
+#include "dnd.h"
+#include "editors.h"
+#include "img-view.h"
+#include "layout.h"
+#include "layout_image.h"
+#include "menu.h"
+#include "metadata.h"
+#include "thumb.h"
+#include "utilops.h"
+#include "ui_fileops.h"
+#include "ui_menu.h"
+#include "ui_tree_edit.h"
+#include "uri_utils.h"
+#include "view_file.h"
+
+#include <gdk/gdkkeysyms.h> /* for keyboard values */
+
+/* Index to tree store */
+enum {
+	FILE_COLUMN_POINTER = 0,
+	FILE_COLUMN_VERSION,
+	FILE_COLUMN_THUMB,
+	FILE_COLUMN_FORMATTED,
+	FILE_COLUMN_NAME,
+	FILE_COLUMN_SIDECARS,
+	FILE_COLUMN_SIZE,
+	FILE_COLUMN_DATE,
+	FILE_COLUMN_EXPANDED,
+	FILE_COLUMN_COLOR,
+	FILE_COLUMN_MARKS,
+	FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
+	FILE_COLUMN_COUNT
+};
+
+
+/* Index to tree view */
+enum {
+	FILE_VIEW_COLUMN_MARKS = 0,
+	FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
+	FILE_VIEW_COLUMN_THUMB,
+	FILE_VIEW_COLUMN_FORMATTED,
+	FILE_VIEW_COLUMN_SIZE,
+	FILE_VIEW_COLUMN_DATE,
+	FILE_VIEW_COLUMN_COUNT
+};
+
+
+
+static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd);
+static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
+static void vflist_populate_view(ViewFile *vf, gboolean force);
+static gboolean vflist_is_multiline(ViewFile *vf);
+static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded);
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * misc
+ *-----------------------------------------------------------------------------
+ */
+typedef struct {
+	FileData *fd;
+	GtkTreeIter *iter;
+	gboolean found;
+	gint row;
+} ViewFileFindRowData;
+
+static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+	ViewFileFindRowData *find = data;
+	FileData *fd;
+	gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
+	if (fd == find->fd)
+		{
+		*find->iter = *iter;
+		find->found = TRUE;
+		return TRUE;
+		}
+	find->row++;
+	return FALSE;
+}
+
+static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
+{
+	GtkTreeModel *store;
+	ViewFileFindRowData data = {fd, iter, FALSE, 0};
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
+
+	if (data.found)
+		{
+		return data.row;
+		}
+
+	return -1;
+}
+
+static FileData *vflist_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
+{
+	GtkTreePath *tpath;
+	GtkTreeViewColumn *column;
+
+	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
+					  &tpath, &column, NULL, NULL))
+		{
+		GtkTreeModel *store;
+		GtkTreeIter row;
+		FileData *fd;
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		gtk_tree_model_get_iter(store, &row, tpath);
+		gtk_tree_path_free(tpath);
+		gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &fd, -1);
+
+		return fd;
+		}
+
+	return NULL;
+}
+
+static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+	FileData *fd;
+	gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
+
+	/* it seems that gtk_tree_store_clear may call some callbacks
+	   that use the column. Set the pointer to NULL to be safe. */
+	gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILE_COLUMN_POINTER, NULL, -1);
+	file_data_unref(fd);
+	return FALSE;
+}
+
+static void vflist_store_clear(ViewFile *vf, gboolean unlock_files)
+{
+	GtkTreeModel *store;
+	GList *files = NULL;
+
+	if (unlock_files && vf->marks_enabled)
+		{
+		// unlock locked files in this directory
+		filelist_read(vf->dir_fd, &files, NULL);
+		while (files)
+			{
+			FileData *fd = files->data;
+			files = files->next;
+			file_data_unlock(fd);
+			file_data_unref(fd);  // undo the ref that got added in filelist_read
+			}
+		}
+
+	g_list_free(files);
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
+	gtk_tree_store_clear(GTK_TREE_STORE(store));
+}
+
+void vflist_color_set(ViewFile *vf, FileData *fd, gboolean color_set)
+{
+	GtkTreeModel *store;
+	GtkTreeIter iter;
+
+	if (vflist_find_row(vf, fd, &iter) < 0) return;
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
+}
+
+static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
+{
+	GtkTreeModel *store;
+	GtkTreePath *tpath;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+
+	tpath = gtk_tree_model_get_path(store, iter);
+	gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
+	gtk_tree_path_free(tpath);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * dnd
+ *-----------------------------------------------------------------------------
+ */
+
+static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
+			   GtkSelectionData *selection_data, guint info,
+			   guint time, gpointer data)
+{
+	ViewFile *vf = data;
+	GList *list = NULL;
+
+	if (!VFLIST(vf)->click_fd) return;
+
+	if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
+		{
+		list = vf_selection_get_list(vf);
+		}
+	else
+		{
+		list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
+		}
+
+	if (!list) return;
+	uri_selection_data_set_uris_from_filelist(selection_data, list);
+	filelist_free(list);
+}
+
+static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vflist_color_set(vf, VFLIST(vf)->click_fd, TRUE);
+
+	if (VFLIST(vf)->thumbs_enabled &&
+	    VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
+		{
+		guint items;
+
+		if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
+			items = vf_selection_count(vf, NULL);
+		else
+			items = 1;
+
+		dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
+		}
+}
+
+static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
+
+	if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
+		{
+		vf_refresh(vf);
+		}
+}
+
+static void vflist_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
+				      int x, int y, GtkSelectionData *selection,
+				      guint info, guint time, gpointer data)
+{
+	ViewFile *vf = data;
+
+	if (info == TARGET_TEXT_PLAIN) {
+		FileData *fd = vflist_find_data_by_coord(vf, x, y, NULL);
+
+		if (fd) {
+			/* Add keywords to file */
+			gchar *str = (gchar *) gtk_selection_data_get_text(selection);
+			GList *kw_list = string_to_keywords_list(str);
+
+			metadata_append_list(fd, KEYWORD_KEY, kw_list);
+			string_list_free(kw_list);
+			g_free(str);
+		}
+	}
+}
+
+void vflist_dnd_init(ViewFile *vf)
+{
+	gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
+			    dnd_file_drag_types, dnd_file_drag_types_count,
+			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+	gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
+			    dnd_file_drag_types, dnd_file_drag_types_count,
+			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+
+	g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
+			 G_CALLBACK(vflist_dnd_get), vf);
+	g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
+			 G_CALLBACK(vflist_dnd_begin), vf);
+	g_signal_connect(G_OBJECT(vf->listview), "drag_end",
+			 G_CALLBACK(vflist_dnd_end), vf);
+	g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
+			 G_CALLBACK(vflist_drag_data_received), vf);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * pop-up menu
+ *-----------------------------------------------------------------------------
+ */
+
+GList *vflist_selection_get_one(ViewFile *vf, FileData *fd)
+{
+	GList *list = g_list_append(NULL, file_data_ref(fd));
+
+	if (fd->sidecar_files)
+		{
+		/* check if the row is expanded */
+		GtkTreeModel *store;
+		GtkTreeIter iter;
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		if (vflist_find_row(vf, fd, &iter) >= 0)
+			{
+			GtkTreePath *tpath;
+
+			tpath = gtk_tree_model_get_path(store, &iter);
+			if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
+				{
+				/* unexpanded - add whole group */
+				GList *work = fd->sidecar_files;
+				while (work)
+					{
+					FileData *sfd = work->data;
+					list = g_list_prepend(list, file_data_ref(sfd));
+					work = work->next;
+					}
+				}
+			gtk_tree_path_free(tpath);
+			}
+		list = g_list_reverse(list);
+		}
+
+	return list;
+}
+
+GList *vflist_pop_menu_file_list(ViewFile *vf)
+{
+	if (!VFLIST(vf)->click_fd) return NULL;
+
+	if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
+		{
+		return vf_selection_get_list(vf);
+		}
+	return vflist_selection_get_one(vf, VFLIST(vf)->click_fd);
+}
+
+
+void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
+		{
+		GList *list;
+
+		list = vf_selection_get_list(vf);
+		view_window_new_from_list(list);
+		filelist_free(list);
+		}
+	else
+		{
+		view_window_new(VFLIST(vf)->click_fd);
+		}
+}
+
+void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+	GList *list;
+
+	list = vf_pop_menu_file_list(vf);
+	if (options->file_ops.enable_in_place_rename &&
+	    list && !list->next && VFLIST(vf)->click_fd)
+		{
+		GtkTreeModel *store;
+		GtkTreeIter iter;
+
+		filelist_free(list);
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
+			{
+			GtkTreePath *tpath;
+
+			tpath = gtk_tree_model_get_path(store, &iter);
+			tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
+					  FILE_VIEW_COLUMN_FORMATTED, VFLIST(vf)->click_fd->name,
+					  vflist_row_rename_cb, vf);
+			gtk_tree_path_free(tpath);
+			}
+		return;
+		}
+
+	file_util_rename(NULL, list, vf->listview);
+}
+
+void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
+	if (vf->layout)
+		{
+		layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
+		}
+	else
+		{
+		vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
+		}
+}
+
+void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
+	vf_refresh(vf);
+	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+}
+
+void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
+	VFLIST(vf)->click_fd = NULL;
+	vf->popup = NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * callbacks
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
+{
+	ViewFile *vf = data;
+	gchar *new_path;
+
+	if (!new || !new[0]) return FALSE;
+
+	new_path = g_build_filename(vf->dir_fd->path, new, NULL);
+
+	if (strchr(new, G_DIR_SEPARATOR) != NULL)
+		{
+		gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
+		file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
+		g_free(text);
+		}
+	else
+		{
+		gchar *old_path = g_build_filename(vf->dir_fd->path, old, NULL);
+		FileData *fd = file_data_new_group(old_path); /* get the fd from cache */
+		file_util_rename_simple(fd, new_path, vf->listview);
+		file_data_unref(fd);
+		g_free(old_path);
+		}
+
+	g_free(new_path);
+
+	return FALSE;
+}
+
+static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreeModel *store;
+	GtkTreeIter iter;
+	GtkTreePath *tpath;
+	gint cw, ch;
+
+	if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	tpath = gtk_tree_model_get_path(store, &iter);
+	tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
+	gtk_tree_path_free(tpath);
+	*y += ch;
+	popup_menu_position_clamp(menu, x, y, 0);
+}
+
+gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreePath *tpath;
+
+	if (event->keyval != GDK_KEY_Menu) return FALSE;
+
+	gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
+	if (tpath)
+		{
+		GtkTreeModel *store;
+		GtkTreeIter iter;
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
+		gtk_tree_path_free(tpath);
+		}
+	else
+		{
+		VFLIST(vf)->click_fd = NULL;
+		}
+
+	vf->popup = vf_pop_menu(vf);
+	gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
+
+	return TRUE;
+}
+
+gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreePath *tpath;
+	GtkTreeIter iter;
+	FileData *fd = NULL;
+	GtkTreeViewColumn *column;
+
+	vf->clicked_mark = 0;
+
+	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
+					  &tpath, &column, NULL, NULL))
+		{
+		GtkTreeModel *store;
+		gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
+
+		if (bevent->button == MOUSE_BUTTON_LEFT &&
+		    col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
+			return FALSE;
+
+		if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
+			vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
+
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+		gtk_tree_path_free(tpath);
+		}
+
+	VFLIST(vf)->click_fd = fd;
+
+	if (bevent->button == MOUSE_BUTTON_RIGHT)
+		{
+		vf->popup = vf_pop_menu(vf);
+		gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
+				bevent->button, bevent->time);
+		return TRUE;
+		}
+
+	if (!fd) return FALSE;
+
+	if (bevent->button == MOUSE_BUTTON_MIDDLE)
+		{
+		if (!vflist_row_is_selected(vf, fd))
+			{
+			vflist_color_set(vf, fd, TRUE);
+			}
+		return TRUE;
+		}
+
+
+	if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
+	    !(bevent->state & GDK_SHIFT_MASK ) &&
+	    !(bevent->state & GDK_CONTROL_MASK ) &&
+	    vflist_row_is_selected(vf, fd))
+		{
+		GtkTreeSelection *selection;
+
+		gtk_widget_grab_focus(widget);
+
+
+		/* returning FALSE and further processing of the event is needed for
+		   correct operation of the expander, to show the sidecar files.
+		   It however resets the selection of multiple files. With this condition
+		   it should work for both cases */
+		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
+		return (gtk_tree_selection_count_selected_rows(selection) > 1);
+		}
+
+	if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
+		{
+		if (vf->layout) layout_image_full_screen_start(vf->layout);
+		}
+
+	return FALSE;
+}
+
+gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreePath *tpath;
+	GtkTreeIter iter;
+	FileData *fd = NULL;
+
+	if (bevent->button == MOUSE_BUTTON_MIDDLE)
+		{
+		vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
+		}
+
+	if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
+		{
+		return TRUE;
+		}
+
+	if ((bevent->x != 0 || bevent->y != 0) &&
+	    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
+					  &tpath, NULL, NULL, NULL))
+		{
+		GtkTreeModel *store;
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+		gtk_tree_path_free(tpath);
+		}
+
+	if (bevent->button == MOUSE_BUTTON_MIDDLE)
+		{
+		if (fd && VFLIST(vf)->click_fd == fd)
+			{
+			GtkTreeSelection *selection;
+
+			selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
+			if (vflist_row_is_selected(vf, fd))
+				{
+				gtk_tree_selection_unselect_iter(selection, &iter);
+				}
+			else
+				{
+				gtk_tree_selection_select_iter(selection, &iter);
+				}
+			}
+		return TRUE;
+		}
+
+	if (fd && VFLIST(vf)->click_fd == fd &&
+	    !(bevent->state & GDK_SHIFT_MASK ) &&
+	    !(bevent->state & GDK_CONTROL_MASK ) &&
+	    vflist_row_is_selected(vf, fd))
+		{
+		GtkTreeSelection *selection;
+
+		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
+		gtk_tree_selection_unselect_all(selection);
+		gtk_tree_selection_select_iter(selection, &iter);
+		vflist_move_cursor(vf, &iter);
+		}
+
+	return FALSE;
+}
+
+static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
+{
+	FileData *read_ahead_fd = NULL;
+	gint row;
+	FileData *cur_fd;
+
+	if (!sel_fd) return;
+
+	cur_fd = layout_image_get_fd(vf->layout);
+	if (sel_fd == cur_fd) return; /* no change */
+
+	row = g_list_index(vf->list, sel_fd);
+	// FIXME sidecar data
+
+	if (sel_fd && options->image.enable_read_ahead && row >= 0)
+		{
+		if (row > g_list_index(vf->list, cur_fd) &&
+		    (guint) (row + 1) < vf_count(vf, NULL))
+			{
+			read_ahead_fd = vf_index_get_data(vf, row + 1);
+			}
+		else if (row > 0)
+			{
+			read_ahead_fd = vf_index_get_data(vf, row - 1);
+			}
+		}
+
+	layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
+}
+
+static gboolean vflist_select_idle_cb(gpointer data)
+{
+	ViewFile *vf = data;
+
+	if (!vf->layout)
+		{
+		VFLIST(vf)->select_idle_id = 0;
+		return FALSE;
+		}
+
+	vf_send_update(vf);
+
+	if (VFLIST(vf)->select_fd)
+		{
+		vflist_select_image(vf, VFLIST(vf)->select_fd);
+		VFLIST(vf)->select_fd = NULL;
+		}
+
+	VFLIST(vf)->select_idle_id = 0;
+	return FALSE;
+}
+
+static void vflist_select_idle_cancel(ViewFile *vf)
+{
+	if (VFLIST(vf)->select_idle_id)
+		{
+		g_source_remove(VFLIST(vf)->select_idle_id);
+		VFLIST(vf)->select_idle_id = 0;
+		}
+}
+
+static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
+				 gboolean path_currently_selected, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreeIter iter;
+
+	if (!path_currently_selected &&
+	    gtk_tree_model_get_iter(store, &iter, tpath))
+		{
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
+		}
+	else
+		{
+		VFLIST(vf)->select_fd = NULL;
+		}
+
+	if (vf->layout &&
+	    !VFLIST(vf)->select_idle_id)
+		{
+		VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
+		}
+
+	return TRUE;
+}
+
+static void vflist_expand_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
+{
+	ViewFile *vf = data;
+	vflist_set_expanded(vf, iter, TRUE);
+}
+
+static void vflist_collapse_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
+{
+	ViewFile *vf = data;
+	vflist_set_expanded(vf, iter, FALSE);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * misc
+ *-----------------------------------------------------------------------------
+ */
+
+
+static gchar* vflist_get_formatted(ViewFile *vf, const gchar *name, const gchar *sidecars, const gchar *size, const gchar *time, gboolean expanded)
+ {
+	gboolean multiline = vflist_is_multiline(vf);
+	gchar *text;
+
+	if (multiline)
+		{
+		text = g_strdup_printf("%s %s\n%s\n%s", name, expanded ? "" : sidecars, size, time);
+		}
+	else
+		{
+		text = g_strdup_printf("%s %s", name, expanded ? "" : sidecars);
+		}
+	return text;
+}
+
+static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded)
+{
+	GtkTreeStore *store;
+	gchar *name;
+	gchar *sidecars;
+	gchar *size;
+	gchar *time;
+	gchar *formatted;
+
+	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+
+	gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
+					FILE_COLUMN_NAME, &name,
+					FILE_COLUMN_SIDECARS, &sidecars,
+					FILE_COLUMN_SIZE, &size,
+					FILE_COLUMN_DATE, &time,
+					-1);
+	formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
+
+	gtk_tree_store_set(store, iter, FILE_COLUMN_FORMATTED, formatted,
+					FILE_COLUMN_EXPANDED, expanded,
+					-1);
+	g_free(time);
+	g_free(size);
+	g_free(sidecars);
+	g_free(name);
+	g_free(formatted);
+}
+
+static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
+{
+	gchar *size;
+	gchar *sidecars = NULL;
+	gchar *name;
+	const gchar *time = text_from_time(fd->date);
+	gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
+	const gchar *disabled_grouping;
+	gchar *formatted;
+	gboolean expanded = FALSE;
+
+	if (fd->sidecar_files) /* expanded has no effect on files without sidecars */
+		{
+		gtk_tree_model_get(GTK_TREE_MODEL(store), iter, FILE_COLUMN_EXPANDED, &expanded, -1);
+		}
+
+	sidecars = file_data_sc_list_to_string(fd);
+
+	disabled_grouping = fd->disable_grouping ? _(" [NO GROUPING]") : "";
+	name = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping);
+	size = text_from_size(fd->size);
+
+	formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
+
+	gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
+					FILE_COLUMN_VERSION, fd->version,
+					FILE_COLUMN_THUMB, fd->thumb_pixbuf,
+					FILE_COLUMN_FORMATTED, formatted,
+					FILE_COLUMN_SIDECARS, sidecars,
+					FILE_COLUMN_NAME, name,
+					FILE_COLUMN_SIZE, size,
+					FILE_COLUMN_DATE, time,
+#define STORE_SET_IS_SLOW 1
+#if STORE_SET_IS_SLOW
+/* this is 3x faster on a directory with 20000 files */
+					FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
+					FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
+					FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
+					FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
+					FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
+					FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
+#if FILEDATA_MARKS_SIZE != 6
+#error this needs to be updated
+#endif
+#endif
+					FILE_COLUMN_COLOR, FALSE, -1);
+
+#if !STORE_SET_IS_SLOW
+	{
+	gint i;
+	for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
+		gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
+	}
+#endif
+	g_free(size);
+	g_free(sidecars);
+	g_free(name);
+	g_free(formatted);
+}
+
+static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected, gboolean force)
+{
+	GList *work;
+	GtkTreeIter iter;
+	gboolean valid;
+	gint num_ordered = 0;
+	gint num_prepended = 0;
+
+	valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
+
+	work = list;
+	while (work)
+		{
+		gint match;
+		FileData *fd = work->data;
+		gboolean done = FALSE;
+
+		while (!done)
+			{
+			FileData *old_fd = NULL;
+			gint old_version = 0;
+
+			if (valid)
+				{
+				gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
+						   FILE_COLUMN_POINTER, &old_fd,
+						   FILE_COLUMN_VERSION, &old_version,
+						   -1);
+
+				if (fd == old_fd)
+					{
+					match = 0;
+					}
+				else
+					{
+					if (parent_iter)
+						match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
+					else
+						match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
+
+					if (match == 0) g_warning("multiple fd for the same path");
+					}
+
+				}
+			else
+				{
+				match = -1;
+				}
+
+			if (match < 0)
+				{
+				GtkTreeIter new;
+
+				if (valid)
+					{
+					num_ordered++;
+					gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
+					}
+				else
+					{
+					/*
+					    here should be used gtk_tree_store_append, but this function seems to be O(n)
+					    and it seems to be much faster to add new entries to the beginning and reorder later
+					*/
+					num_prepended++;
+					gtk_tree_store_prepend(store, &new, parent_iter);
+					}
+
+				vflist_setup_iter(vf, store, &new, file_data_ref(fd));
+				vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected, force);
+
+				if (g_list_find(selected, fd))
+					{
+					/* renamed files - the same fd appears at different position - select it again*/
+					GtkTreeSelection *selection;
+					selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+					gtk_tree_selection_select_iter(selection, &new);
+					}
+
+				done = TRUE;
+				}
+			else if (match > 0)
+				{
+				file_data_unref(old_fd);
+				valid = gtk_tree_store_remove(store, &iter);
+				}
+			else
+				{
+				num_ordered++;
+				if (fd->version != old_version || force)
+					{
+					vflist_setup_iter(vf, store, &iter, fd);
+					vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected, force);
+					}
+
+				if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
+
+				done = TRUE;
+				}
+			}
+		work = work->next;
+		}
+
+	while (valid)
+		{
+		FileData *old_fd;
+		gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
+		file_data_unref(old_fd);
+
+		valid = gtk_tree_store_remove(store, &iter);
+		}
+
+	/* move the prepended entries to the correct position */
+	if (num_prepended)
+		{
+		gint i;
+		gint num_total = num_prepended + num_ordered;
+		gint *new_order = g_malloc(num_total * sizeof(gint));
+
+		for (i = 0; i < num_total; i++)
+			{
+			if (i < num_ordered)
+				new_order[i] = num_prepended + i;
+			else
+				new_order[i] = num_total - 1 - i;
+			}
+		gtk_tree_store_reorder(store, parent_iter, new_order);
+
+		g_free(new_order);
+		}
+}
+
+void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend)
+{
+	gint i;
+	GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
+	gint *new_order;
+	GtkTreeStore *store;
+	GList *work;
+
+	if (vf->sort_method == type && vf->sort_ascend == ascend) return;
+	if (!vf->list) return;
+
+	work = vf->list;
+	i = 0;
+	while (work)
+		{
+		FileData *fd = work->data;
+		g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
+		i++;
+		work = work->next;
+		}
+
+	vf->sort_method = type;
+	vf->sort_ascend = ascend;
+
+	vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
+
+	new_order = g_malloc(i * sizeof(gint));
+
+	work = vf->list;
+	i = 0;
+	while (work)
+		{
+		FileData *fd = work->data;
+		new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
+		i++;
+		work = work->next;
+		}
+
+	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+	gtk_tree_store_reorder(store, NULL, new_order);
+
+	g_free(new_order);
+	g_hash_table_destroy(fd_idx_hash);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * thumb updates
+ *-----------------------------------------------------------------------------
+ */
+
+
+void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
+{
+	GList *work = list;
+	while (work)
+		{
+		FileData *fd = work->data;
+		work = work->next;
+
+		if (fd->thumb_pixbuf) (*done)++;
+
+		if (fd->sidecar_files)
+			{
+			vflist_thumb_progress_count(fd->sidecar_files, count, done);
+			}
+		(*count)++;
+		}
+}
+
+void vflist_set_thumb_fd(ViewFile *vf, FileData *fd)
+{
+	GtkTreeStore *store;
+	GtkTreeIter iter;
+
+	if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
+
+	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+	gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
+}
+
+FileData *vflist_thumb_next_fd(ViewFile *vf)
+{
+	GtkTreePath *tpath;
+	FileData *fd = NULL;
+
+	/* first check the visible files */
+
+	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
+		{
+		GtkTreeModel *store;
+		GtkTreeIter iter;
+		gboolean valid = TRUE;
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_path_free(tpath);
+
+		while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
+			{
+			FileData *nfd;
+
+			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &nfd, -1);
+
+			if (!nfd->thumb_pixbuf) fd = nfd;
+
+			valid = gtk_tree_model_iter_next(store, &iter);
+			}
+		}
+
+	/* then find first undone */
+
+	if (!fd)
+		{
+		GList *work = vf->list;
+		while (work && !fd)
+			{
+			FileData *fd_p = work->data;
+			if (!fd_p->thumb_pixbuf)
+				fd = fd_p;
+			else
+				{
+				GList *work2 = fd_p->sidecar_files;
+
+				while (work2 && !fd)
+					{
+					fd_p = work2->data;
+					if (!fd_p->thumb_pixbuf) fd = fd_p;
+					work2 = work2->next;
+					}
+				}
+			work = work->next;
+			}
+		}
+
+	return fd;
+}
+
+
+void vflist_thumb_reset_all(ViewFile *vf)
+{
+	GList *work = vf->list;
+	while (work)
+		{
+		FileData *fd = work->data;
+		if (fd->thumb_pixbuf)
+			{
+			g_object_unref(fd->thumb_pixbuf);
+			fd->thumb_pixbuf = NULL;
+			}
+		work = work->next;
+		}
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * row stuff
+ *-----------------------------------------------------------------------------
+ */
+
+FileData *vflist_index_get_data(ViewFile *vf, gint row)
+{
+	return g_list_nth_data(vf->list, row);
+}
+
+gint vflist_index_by_fd(ViewFile *vf, FileData *fd)
+{
+	gint p = 0;
+	GList *work, *work2;
+
+	work = vf->list;
+	while (work)
+		{
+		FileData *list_fd = work->data;
+		if (list_fd == fd) return p;
+
+		work2 = list_fd->sidecar_files;
+		while (work2)
+			{
+			/* FIXME: return the same index also for sidecars
+			   it is sufficient for next/prev navigation but it should be rewritten
+			   without using indexes at all
+			*/
+			FileData *sidecar_fd = work2->data;
+			if (sidecar_fd == fd) return p;
+			work2 = work2->next;
+			}
+
+		work = work->next;
+		p++;
+		}
+
+	return -1;
+}
+
+guint vflist_count(ViewFile *vf, gint64 *bytes)
+{
+	if (bytes)
+		{
+		gint64 b = 0;
+		GList *work;
+
+		work = vf->list;
+		while (work)
+			{
+			FileData *fd = work->data;
+			work = work->next;
+			b += fd->size;
+			}
+
+		*bytes = b;
+		}
+
+	return g_list_length(vf->list);
+}
+
+GList *vflist_get_list(ViewFile *vf)
+{
+	GList *list = NULL;
+	GList *work;
+
+	work = vf->list;
+	while (work)
+		{
+		FileData *fd = work->data;
+		work = work->next;
+
+		list = g_list_prepend(list, file_data_ref(fd));
+		}
+
+	return g_list_reverse(list);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * selections
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd)
+{
+	GtkTreeModel *store;
+	GtkTreeSelection *selection;
+	GList *slist;
+	GList *work;
+	gboolean found = FALSE;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	slist = gtk_tree_selection_get_selected_rows(selection, &store);
+	work = slist;
+	while (!found && work)
+		{
+		GtkTreePath *tpath = work->data;
+		FileData *fd_n;
+		GtkTreeIter iter;
+
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
+		if (fd_n == fd) found = TRUE;
+		work = work->next;
+		}
+	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
+	g_list_free(slist);
+
+	return found;
+}
+
+gboolean vflist_index_is_selected(ViewFile *vf, gint row)
+{
+	FileData *fd;
+
+	fd = vf_index_get_data(vf, row);
+	return vflist_row_is_selected(vf, fd);
+}
+
+guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
+{
+	GtkTreeModel *store;
+	GtkTreeSelection *selection;
+	GList *slist;
+	guint count;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	slist = gtk_tree_selection_get_selected_rows(selection, &store);
+
+	if (bytes)
+		{
+		gint64 b = 0;
+		GList *work;
+
+		work = slist;
+		while (work)
+			{
+			GtkTreePath *tpath = work->data;
+			GtkTreeIter iter;
+			FileData *fd;
+
+			gtk_tree_model_get_iter(store, &iter, tpath);
+			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+			b += fd->size;
+
+			work = work->next;
+			}
+
+		*bytes = b;
+		}
+
+	count = g_list_length(slist);
+	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
+	g_list_free(slist);
+
+	return count;
+}
+
+GList *vflist_selection_get_list(ViewFile *vf)
+{
+	GtkTreeModel *store;
+	GtkTreeSelection *selection;
+	GList *slist;
+	GList *list = NULL;
+	GList *work;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	slist = gtk_tree_selection_get_selected_rows(selection, &store);
+	work = slist;
+	while (work)
+		{
+		GtkTreePath *tpath = work->data;
+		FileData *fd;
+		GtkTreeIter iter;
+
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+
+		list = g_list_prepend(list, file_data_ref(fd));
+
+		if (!fd->parent && !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
+			{
+			/* unexpanded - add whole group */
+			GList *work2 = fd->sidecar_files;
+			while (work2)
+				{
+				FileData *sfd = work2->data;
+				list = g_list_prepend(list, file_data_ref(sfd));
+				work2 = work2->next;
+				}
+			}
+
+		work = work->next;
+		}
+	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
+	g_list_free(slist);
+
+	return g_list_reverse(list);
+}
+
+GList *vflist_selection_get_list_by_index(ViewFile *vf)
+{
+	GtkTreeModel *store;
+	GtkTreeSelection *selection;
+	GList *slist;
+	GList *list = NULL;
+	GList *work;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	slist = gtk_tree_selection_get_selected_rows(selection, &store);
+	work = slist;
+	while (work)
+		{
+		GtkTreePath *tpath = work->data;
+		FileData *fd;
+		GtkTreeIter iter;
+
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+
+		list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
+
+		work = work->next;
+		}
+	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
+	g_list_free(slist);
+
+	return g_list_reverse(list);
+}
+
+void vflist_select_all(ViewFile *vf)
+{
+	GtkTreeSelection *selection;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_selection_select_all(selection);
+
+	VFLIST(vf)->select_fd = NULL;
+}
+
+void vflist_select_none(ViewFile *vf)
+{
+	GtkTreeSelection *selection;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_selection_unselect_all(selection);
+}
+
+static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
+{
+	GtkTreePath *tpath;
+	gboolean result;
+
+	tpath = gtk_tree_model_get_path(store, iter);
+	result = gtk_tree_path_prev(tpath);
+	if (result)
+		gtk_tree_model_get_iter(store, iter, tpath);
+
+	gtk_tree_path_free(tpath);
+
+	return result;
+}
+
+static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
+{
+	if (!gtk_tree_model_get_iter_first(store, iter))
+		return FALSE;
+
+	while (TRUE)
+		{
+		GtkTreeIter next = *iter;
+
+		if (gtk_tree_model_iter_next(store, &next))
+			*iter = next;
+		else
+			break;
+		}
+
+	return TRUE;
+}
+
+void vflist_select_invert(ViewFile *vf)
+{
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+	GtkTreeModel *store;
+	gboolean valid;
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+
+	/* Backward iteration prevents scrolling to the end of the list,
+	 * it scrolls to the first selected row instead. */
+	valid = tree_model_get_iter_last(store, &iter);
+
+	while (valid)
+		{
+		gboolean selected = gtk_tree_selection_iter_is_selected(selection, &iter);
+
+		if (selected)
+			gtk_tree_selection_unselect_iter(selection, &iter);
+		else
+			gtk_tree_selection_select_iter(selection, &iter);
+
+		valid = tree_model_iter_prev(store, &iter);
+		}
+}
+
+void vflist_select_by_fd(ViewFile *vf, FileData *fd)
+{
+	GtkTreeIter iter;
+
+	if (vflist_find_row(vf, fd, &iter) < 0) return;
+
+	tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
+
+	if (!vflist_row_is_selected(vf, fd))
+		{
+		GtkTreeSelection *selection;
+		GtkTreeModel *store;
+		GtkTreePath *tpath;
+
+		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+		gtk_tree_selection_unselect_all(selection);
+		gtk_tree_selection_select_iter(selection, &iter);
+		vflist_move_cursor(vf, &iter);
+
+		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+		tpath = gtk_tree_model_get_path(store, &iter);
+		gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
+		gtk_tree_path_free(tpath);
+		}
+}
+
+static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
+{
+	GList *work;
+	FileData *fd = NULL;
+
+	if (sel_fd->parent) sel_fd = sel_fd->parent;
+	work = vf->list;
+
+	while (work)
+		{
+		gint match;
+		fd = work->data;
+		work = work->next;
+
+		match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
+
+		if (match >= 0) break;
+		}
+
+	if (fd) vflist_select_by_fd(vf, fd);
+
+}
+
+void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
+{
+	GtkTreeModel *store;
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+	gboolean valid;
+	gint n = mark - 1;
+
+	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
+
+	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+
+	valid = gtk_tree_model_get_iter_first(store, &iter);
+	while (valid)
+		{
+		FileData *fd;
+		gboolean mark_val, selected;
+		gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
+
+		mark_val = file_data_get_mark(fd, n);
+		selected = gtk_tree_selection_iter_is_selected(selection, &iter);
+
+		switch (mode)
+			{
+			case MTS_MODE_SET: selected = mark_val;
+				break;
+			case MTS_MODE_OR: selected = mark_val || selected;
+				break;
+			case MTS_MODE_AND: selected = mark_val && selected;
+				break;
+			case MTS_MODE_MINUS: selected = !mark_val && selected;
+				break;
+			}
+
+		if (selected)
+			gtk_tree_selection_select_iter(selection, &iter);
+		else
+			gtk_tree_selection_unselect_iter(selection, &iter);
+
+		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
+		}
+}
+
+void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
+{
+	GtkTreeModel *store;
+	GtkTreeSelection *selection;
+	GList *slist;
+	GList *work;
+	gint n = mark - 1;
+
+	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	slist = gtk_tree_selection_get_selected_rows(selection, &store);
+	work = slist;
+	while (work)
+		{
+		GtkTreePath *tpath = work->data;
+		FileData *fd;
+		GtkTreeIter iter;
+
+		gtk_tree_model_get_iter(store, &iter, tpath);
+		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
+
+		/* the change has a very limited range and the standard notification would trigger
+		   complete re-read of the directory - try to do only minimal update instead */
+		file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
+
+		switch (mode)
+			{
+			case STM_MODE_SET: file_data_set_mark(fd, n, 1);
+				break;
+			case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
+				break;
+			case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
+				break;
+			}
+
+		if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
+			{
+			vf_refresh_idle(vf);
+			}
+		else
+			{
+			/* mark functions can have various side effects - update all columns to be sure */
+			vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
+			/* mark functions can change sidecars too */
+			vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
+			}
+
+
+		file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+
+		work = work->next;
+		}
+	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
+	g_list_free(slist);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * core (population)
+ *-----------------------------------------------------------------------------
+ */
+
+static void vflist_listview_set_columns(GtkWidget *listview, gboolean thumb, gboolean multiline)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *cell;
+	GList *list;
+
+	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
+	if (!column) return;
+
+	gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
+
+	list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
+	if (!list) return;
+	cell = list->data;
+	g_list_free(list);
+
+	g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
+	gtk_tree_view_column_set_visible(column, thumb);
+
+	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_FORMATTED);
+	if (!column) return;
+	gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
+
+	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
+	if (!column) return;
+	gtk_tree_view_column_set_visible(column, !multiline);
+
+	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
+	if (!column) return;
+	gtk_tree_view_column_set_visible(column, !multiline);
+}
+
+static gboolean vflist_is_multiline(ViewFile *vf)
+{
+	return (VFLIST(vf)->thumbs_enabled && options->thumbnails.max_height >= 48);
+}
+
+
+static void vflist_populate_view(ViewFile *vf, gboolean force)
+{
+	GtkTreeStore *store;
+	GList *selected;
+
+	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+
+	vf_thumb_stop(vf);
+
+	if (!vf->list)
+		{
+		vflist_store_clear(vf, FALSE);
+		vf_send_update(vf);
+		return;
+		}
+
+	vflist_listview_set_columns(vf->listview, VFLIST(vf)->thumbs_enabled, vflist_is_multiline(vf));
+
+	selected = vflist_selection_get_list(vf);
+
+	vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected, force);
+
+	if (selected && vflist_selection_count(vf, NULL) == 0)
+		{
+		/* all selected files disappeared */
+		vflist_select_closest(vf, selected->data);
+		}
+
+	filelist_free(selected);
+
+	vf_send_update(vf);
+	vf_thumb_update(vf);
+}
+
+gboolean vflist_refresh(ViewFile *vf)
+{
+	GList *old_list;
+	gboolean ret = TRUE;
+
+	old_list = vf->list;
+	vf->list = NULL;
+
+	DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
+	if (vf->dir_fd)
+		{
+		file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
+
+		ret = filelist_read(vf->dir_fd, &vf->list, NULL);
+
+		if (vf->marks_enabled)
+		        {
+		        // When marks are enabled, lock FileDatas so that we don't end up re-parsing XML
+		        // each time a mark is changed.
+		        file_data_lock_list(vf->list);
+		        }
+	        else
+			{
+			// FIXME: only do this when needed (aka when we just switched from
+			// FIXME: marks-enabled to marks-disabled)
+			file_data_unlock_list(vf->list);
+			}
+
+		vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
+		file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+
+		DEBUG_1("%s vflist_refresh: sort", get_exec_time());
+		vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
+		}
+
+	DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
+
+	vflist_populate_view(vf, FALSE);
+
+	DEBUG_1("%s vflist_refresh: free filelist", get_exec_time());
+
+	filelist_free(old_list);
+	DEBUG_1("%s vflist_refresh: done", get_exec_time());
+
+	return ret;
+}
+
+
+
+/* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
+
+#define CELL_HEIGHT_OVERRIDE 512
+
+static void cell_renderer_height_override(GtkCellRenderer *renderer)
+{
+	GParamSpec *spec;
+
+	spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
+	if (spec && G_IS_PARAM_SPEC_INT(spec))
+		{
+		GParamSpecInt *spec_int;
+
+		spec_int = G_PARAM_SPEC_INT(spec);
+		if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
+		}
+}
+
+static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
+{
+	static GdkColor color;
+	static GtkWidget *done = NULL;
+
+	if (done != widget)
+		{
+		GtkStyle *style;
+
+		style = gtk_widget_get_style(widget);
+		memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
+		shift_color(&color, -1, 0);
+		done = widget;
+		}
+
+	return &color;
+}
+
+static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
+				     GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+	ViewFile *vf = data;
+	gboolean set;
+
+	gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
+	g_object_set(G_OBJECT(cell),
+		     "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
+		     "cell-background-set", set, NULL);
+}
+
+static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gboolean image, gboolean right_justify, gboolean expand)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title(column, title);
+	gtk_tree_view_column_set_min_width(column, 4);
+
+	if (!image)
+		{
+		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
+		renderer = gtk_cell_renderer_text_new();
+		if (right_justify)
+			{
+			g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
+			}
+		gtk_tree_view_column_pack_start(column, renderer, TRUE);
+		gtk_tree_view_column_add_attribute(column, renderer, "text", n);
+		if (expand)
+			gtk_tree_view_column_set_expand(column, TRUE);
+		}
+	else
+		{
+		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
+		renderer = gtk_cell_renderer_pixbuf_new();
+		cell_renderer_height_override(renderer);
+		gtk_tree_view_column_pack_start(column, renderer, TRUE);
+		gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
+		}
+
+	gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
+	g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
+	g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
+
+	gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
+}
+
+static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
+{
+	ViewFile *vf = data;
+	GtkTreeStore *store;
+	GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
+	GtkTreeIter iter;
+	FileData *fd;
+	gboolean marked;
+	guint col_idx;
+
+	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
+	if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
+		return;
+
+	col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
+
+	g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
+
+	gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &marked, -1);
+	marked = !marked;
+
+	/* the change has a very limited range and the standard notification would trigger
+	   complete re-read of the directory - try to do only minimal update instead */
+	file_data_unregister_notify_func(vf_notify_cb, vf);
+	file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, marked);
+	if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
+		{
+		vf_refresh_idle(vf);
+		}
+	else
+		{
+		/* mark functions can have various side effects - update all columns to be sure */
+		vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
+		/* mark functions can change sidecars too */
+		vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
+		}
+	file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+
+	gtk_tree_path_free(path);
+}
+
+static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+
+	renderer = gtk_cell_renderer_toggle_new();
+	column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
+
+	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
+	g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
+	g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
+
+	gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
+	gtk_tree_view_column_set_fixed_width(column, 22);
+	gtk_tree_view_column_set_visible(column, vf->marks_enabled);
+
+
+	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * base
+ *-----------------------------------------------------------------------------
+ */
+
+gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd)
+{
+	gboolean ret;
+	if (!dir_fd) return FALSE;
+	if (vf->dir_fd == dir_fd) return TRUE;
+
+	file_data_unref(vf->dir_fd);
+	vf->dir_fd = file_data_ref(dir_fd);
+
+	/* force complete reload */
+	vflist_store_clear(vf, TRUE);
+
+	filelist_free(vf->list);
+	vf->list = NULL;
+
+	ret = vf_refresh(vf);
+	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+	return ret;
+}
+
+void vflist_destroy_cb(GtkWidget *widget, gpointer data)
+{
+	ViewFile *vf = data;
+
+	file_data_unregister_notify_func(vf_notify_cb, vf);
+
+	vflist_select_idle_cancel(vf);
+	vf_refresh_idle_cancel(vf);
+	vf_thumb_stop(vf);
+
+	filelist_free(vf->list);
+}
+
+ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
+{
+	GtkTreeStore *store;
+	GtkTreeSelection *selection;
+	GType flist_types[FILE_COLUMN_COUNT];
+	gint i;
+	gint column;
+
+	vf->info = g_new0(ViewFileInfoList, 1);
+
+	flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
+	flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
+	flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
+	flist_types[FILE_COLUMN_FORMATTED] = G_TYPE_STRING;
+	flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
+	flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
+	flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
+	flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
+	flist_types[FILE_COLUMN_EXPANDED] = G_TYPE_BOOLEAN;
+	flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
+	for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
+		flist_types[i] = G_TYPE_BOOLEAN;
+
+	store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
+
+	vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+	g_object_unref(store);
+
+	g_signal_connect(G_OBJECT(vf->listview), "row-expanded",
+			 G_CALLBACK(vflist_expand_cb), vf);
+
+	g_signal_connect(G_OBJECT(vf->listview), "row-collapsed",
+			 G_CALLBACK(vflist_collapse_cb), vf);
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
+	gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
+	gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
+
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
+	gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
+
+	column = 0;
+
+	for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
+		{
+		vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
+		g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
+		column++;
+		}
+
+	vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
+	g_assert(column == FILE_VIEW_COLUMN_THUMB);
+	column++;
+
+	vflist_listview_add_column(vf, FILE_COLUMN_FORMATTED, _("Name"), FALSE, FALSE, TRUE);
+	g_assert(column == FILE_VIEW_COLUMN_FORMATTED);
+	column++;
+
+	vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
+	g_assert(column == FILE_VIEW_COLUMN_SIZE);
+	column++;
+
+	vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
+	g_assert(column == FILE_VIEW_COLUMN_DATE);
+	column++;
+
+	file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
+	return vf;
+}
+
+void vflist_thumb_set(ViewFile *vf, gboolean enable)
+{
+	if (VFLIST(vf)->thumbs_enabled == enable) return;
+
+	VFLIST(vf)->thumbs_enabled = enable;
+
+	/* vflist_populate_view is better than vf_refresh:
+	   - no need to re-read the directory
+	   - force update because the formatted string has changed
+	*/
+	if (vf->layout)
+		{
+		vflist_populate_view(vf, TRUE);
+		gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
+		}
+}
+
+void vflist_marks_set(ViewFile *vf, gboolean enable)
+{
+	GList *columns, *work;
+
+	columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
+
+	work = columns;
+	while (work)
+		{
+		GtkTreeViewColumn *column = work->data;
+		gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
+		work = work->next;
+
+		if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
+			gtk_tree_view_column_set_visible(column, enable);
+		}
+
+	if (enable)
+		{
+		// Previously disabled, which means that vf->list is complete
+		file_data_lock_list(vf->list);
+		}
+	else
+		{
+		// Previously enabled, which means that vf->list is incomplete
+		}
+
+	g_list_free(columns);
+}
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/view_file/view_file_list.h	Wed Jul 05 21:41:18 2017 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ * Author: John Ellis
+ *
+ * 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 VIEW_FILE_VIEW_FILE_LIST_H
+#define VIEW_FILE_VIEW_FILE_LIST_H
+
+
+#include "filedata.h"
+
+gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data);
+gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
+gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
+
+void vflist_dnd_init(ViewFile *vf);
+
+void vflist_destroy_cb(GtkWidget *widget, gpointer data);
+ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd);
+
+gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd);
+gboolean vflist_refresh(ViewFile *vf);
+
+void vflist_thumb_set(ViewFile *vf, gboolean enable);
+void vflist_marks_set(ViewFile *vf, gboolean enable);
+void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend);
+
+GList *vflist_selection_get_one(ViewFile *vf, FileData *fd);
+GList *vflist_pop_menu_file_list(ViewFile *vf);
+void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data);
+void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data);
+void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data);
+void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data);
+void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data);
+
+FileData *vflist_index_get_data(ViewFile *vf, gint row);
+gint vflist_index_by_fd(ViewFile *vf, FileData *fd);
+guint vflist_count(ViewFile *vf, gint64 *bytes);
+GList *vflist_get_list(ViewFile *vf);
+
+gboolean vflist_index_is_selected(ViewFile *vf, gint row);
+guint vflist_selection_count(ViewFile *vf, gint64 *bytes);
+GList *vflist_selection_get_list(ViewFile *vf);
+GList *vflist_selection_get_list_by_index(ViewFile *vf);
+
+void vflist_select_all(ViewFile *vf);
+void vflist_select_none(ViewFile *vf);
+void vflist_select_invert(ViewFile *vf);
+void vflist_select_by_fd(ViewFile *vf, FileData *fd);
+
+void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode);
+void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode);
+
+void vflist_color_set(ViewFile *vf, FileData *fd, gboolean color_set);
+
+void vflist_thumb_progress_count(GList *list, gint *count, gint *done);
+void vflist_set_thumb_fd(ViewFile *vf, FileData *fd);
+FileData *vflist_thumb_next_fd(ViewFile *vf);
+void vflist_thumb_reset_all(ViewFile *vf);
+
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/view_file_icon.c	Thu Jun 29 11:05:59 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2300 +0,0 @@
-/*
- * Copyright (C) 2006 John Ellis
- * Copyright (C) 2008 - 2016 The Geeqie Team
- *
- * Author: John Ellis
- *
- * 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 "view_file_icon.h"
-
-#include "bar.h"
-#include "cellrenderericon.h"
-#include "collect.h"
-#include "collect-io.h"
-#include "collect-table.h"
-#include "dnd.h"
-#include "editors.h"
-#include "img-view.h"
-#include "filedata.h"
-#include "layout.h"
-#include "layout_image.h"
-#include "menu.h"
-#include "metadata.h"
-#include "thumb.h"
-#include "utilops.h"
-#include "ui_fileops.h"
-#include "ui_menu.h"
-#include "ui_tree_edit.h"
-#include "uri_utils.h"
-#include "view_file.h"
-
-#include <gdk/gdkkeysyms.h> /* for keyboard values */
-
-
-/* between these, the icon width is increased by thumb_max_width / 2 */
-#define THUMB_MIN_ICON_WIDTH 128
-#define THUMB_MAX_ICON_WIDTH 150
-
-#define VFICON_MAX_COLUMNS 32
-#define THUMB_BORDER_PADDING 2
-
-#define VFICON_TIP_DELAY 500
-
-enum {
-	FILE_COLUMN_POINTER = 0,
-	FILE_COLUMN_COUNT
-};
-
-static gint vficon_index_by_id(ViewFile *vf, IconData *in_id);
-
-static IconData *vficon_icon_data(ViewFile *vf, FileData *fd)
-{
-	IconData *id = NULL;
-	GList *work;
-
-	if (!fd) return NULL;
-	work = vf->list;
-	while (work && !id)
-		{
-		IconData *chk = work->data;
-		work = work->next;
-		if (chk->fd == fd) id = chk;
-		}
-	return id;
-}
-
-static void iconlist_free(GList *list)
-{
-	GList *work = list;
-	while (work)
-		{
-		IconData *id = work->data;
-		file_data_unref(id->fd);
-		g_free(id);
-		work = work->next;
-		}
-
-	g_list_free(list);
-
-}
-
-gint iconlist_sort_file_cb(gpointer a, gpointer b)
-{
-	IconData *ida = a;
-	IconData *idb = b;
-	return filelist_sort_compare_filedata(ida->fd, idb->fd);
-}
-
-GList *iconlist_sort(GList *list, SortType method, gboolean ascend)
-{
-	return filelist_sort_full(list, method, ascend, (GCompareFunc) iconlist_sort_file_cb);
-}
-
-GList *iconlist_insert_sort(GList *list, IconData *id, SortType method, gboolean ascend)
-{
-	return filelist_insert_sort_full(list, id, method, ascend, (GCompareFunc) iconlist_sort_file_cb);
-}
-
-
-static void vficon_toggle_filenames(ViewFile *vf);
-static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter);
-static void vficon_move_focus(ViewFile *vf, gint row, gint col, gboolean relative);
-static void vficon_set_focus(ViewFile *vf, IconData *id);
-static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gboolean force);
-
-
-/*
- *-----------------------------------------------------------------------------
- * pop-up menu
- *-----------------------------------------------------------------------------
- */
-
-GList *vficon_selection_get_one(ViewFile *vf, FileData *fd)
-{
-	return g_list_prepend(filelist_copy(fd->sidecar_files), file_data_ref(fd));
-}
-
-GList *vficon_pop_menu_file_list(ViewFile *vf)
-{
-	if (!VFICON(vf)->click_id) return NULL;
-
-	if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
-		{
-		return vf_selection_get_list(vf);
-		}
-
-	return vficon_selection_get_one(vf, VFICON(vf)->click_id->fd);
-}
-
-void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	if (!VFICON(vf)->click_id) return;
-
-	if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
-		{
-		GList *list;
-
-		list = vf_selection_get_list(vf);
-		view_window_new_from_list(list);
-		filelist_free(list);
-		}
-	else
-		{
-		view_window_new(VFICON(vf)->click_id->fd);
-		}
-}
-
-void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	file_util_rename(NULL, vf_pop_menu_file_list(vf), vf->listview);
-}
-
-void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vficon_toggle_filenames(vf);
-}
-
-void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vf_refresh(vf);
-}
-
-void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-	vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
-	VFICON(vf)->click_id = NULL;
-	vf->popup = NULL;
-}
-
-/*
- *-------------------------------------------------------------------
- * signals
- *-------------------------------------------------------------------
- */
-
-static void vficon_send_layout_select(ViewFile *vf, IconData *id)
-{
-	FileData *read_ahead_fd = NULL;
-	FileData *sel_fd;
-	FileData *cur_fd;
-
-	if (!vf->layout || !id || !id->fd) return;
-
-	sel_fd = id->fd;
-
-	cur_fd = layout_image_get_fd(vf->layout);
-	if (sel_fd == cur_fd) return; /* no change */
-
-	if (options->image.enable_read_ahead)
-		{
-		gint row;
-
-		row = g_list_index(vf->list, id);
-		if (row > vficon_index_by_fd(vf, cur_fd) &&
-		    (guint) (row + 1) < vf_count(vf, NULL))
-			{
-			read_ahead_fd = vf_index_get_data(vf, row + 1);
-			}
-		else if (row > 0)
-			{
-			read_ahead_fd = vf_index_get_data(vf, row - 1);
-			}
-		}
-
-	layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
-}
-
-static void vficon_toggle_filenames(ViewFile *vf)
-{
-	GtkAllocation allocation;
-	VFICON(vf)->show_text = !VFICON(vf)->show_text;
-	options->show_icon_names = VFICON(vf)->show_text;
-
-	gtk_widget_get_allocation(vf->listview, &allocation);
-	vficon_populate_at_new_size(vf, allocation.width, allocation.height, TRUE);
-}
-
-static gint vficon_get_icon_width(ViewFile *vf)
-{
-	gint width;
-
-	if (!VFICON(vf)->show_text) return options->thumbnails.max_width;
-
-	width = options->thumbnails.max_width + options->thumbnails.max_width / 2;
-	if (width < THUMB_MIN_ICON_WIDTH) width = THUMB_MIN_ICON_WIDTH;
-	if (width > THUMB_MAX_ICON_WIDTH) width = options->thumbnails.max_width;
-
-	return width;
-}
-
-/*
- *-------------------------------------------------------------------
- * misc utils
- *-------------------------------------------------------------------
- */
-
-static gboolean vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint *col)
-{
-	gint n;
-
-	n = g_list_index(vf->list, id);
-
-	if (n < 0) return FALSE;
-
-	*row = n / VFICON(vf)->columns;
-	*col = n - (*row * VFICON(vf)->columns);
-
-	return TRUE;
-}
-
-static gboolean vficon_find_iter(ViewFile *vf, IconData *id, GtkTreeIter *iter, gint *column)
-{
-	GtkTreeModel *store;
-	gint row, col;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	if (!vficon_find_position(vf, id, &row, &col)) return FALSE;
-	if (!gtk_tree_model_iter_nth_child(store, iter, NULL, row)) return FALSE;
-	if (column) *column = col;
-
-	return TRUE;
-}
-
-static IconData *vficon_find_data(ViewFile *vf, gint row, gint col, GtkTreeIter *iter)
-{
-	GtkTreeModel *store;
-	GtkTreeIter p;
-
-	if (row < 0 || col < 0) return NULL;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	if (gtk_tree_model_iter_nth_child(store, &p, NULL, row))
-		{
-		GList *list;
-
-		gtk_tree_model_get(store, &p, FILE_COLUMN_POINTER, &list, -1);
-		if (!list) return NULL;
-
-		if (iter) *iter = p;
-
-		return g_list_nth_data(list, col);
-		}
-
-	return NULL;
-}
-
-static IconData *vficon_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
-{
-	GtkTreePath *tpath;
-	GtkTreeViewColumn *column;
-
-	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
-					  &tpath, &column, NULL, NULL))
-		{
-		GtkTreeModel *store;
-		GtkTreeIter row;
-		GList *list;
-		gint n;
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		gtk_tree_model_get_iter(store, &row, tpath);
-		gtk_tree_path_free(tpath);
-
-		gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
-
-		n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_number"));
-		if (list)
-			{
-			if (iter) *iter = row;
-			return g_list_nth_data(list, n);
-			}
-		}
-
-	return NULL;
-}
-
-static void vficon_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreeModel *store;
-	GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
-	GtkTreeIter row;
-	gint column;
-	GList *list;
-	guint toggled_mark;
-	IconData *id;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	if (!path || !gtk_tree_model_get_iter(store, &row, path))
-		return;
-
-	gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
-
-	column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_number"));
-	g_object_get(G_OBJECT(cell), "toggled_mark", &toggled_mark, NULL);
-
-	id = g_list_nth_data(list, column);
-	if (id)
-		{
-		FileData *fd = id->fd;
-		file_data_set_mark(fd, toggled_mark, !file_data_get_mark(fd, toggled_mark));
-		}
-}
-
-
-/*
- *-------------------------------------------------------------------
- * tooltip type window
- *-------------------------------------------------------------------
- */
-
-static void tip_show(ViewFile *vf)
-{
-	GtkWidget *label;
-	gint x, y;
-#if GTK_CHECK_VERSION(3,0,0)
-	GdkDisplay *display;
-	GdkDeviceManager *device_manager;
-	GdkDevice *device;
-#endif
-
-	if (VFICON(vf)->tip_window) return;
-
-#if GTK_CHECK_VERSION(3,0,0)
-	device_manager = gdk_display_get_device_manager(gdk_window_get_display(
-						gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview))));
-	device = gdk_device_manager_get_client_pointer(device_manager);
-	gdk_window_get_device_position(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)),
-						device, &x, &y, NULL);
-#else
-	gdk_window_get_pointer(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)), &x, &y, NULL);
-#endif
-
-	VFICON(vf)->tip_id = vficon_find_data_by_coord(vf, x, y, NULL);
-	if (!VFICON(vf)->tip_id) return;
-
-	VFICON(vf)->tip_window = gtk_window_new(GTK_WINDOW_POPUP);
-	gtk_window_set_resizable(GTK_WINDOW(VFICON(vf)->tip_window), FALSE);
-	gtk_container_set_border_width(GTK_CONTAINER(VFICON(vf)->tip_window), 2);
-
-	label = gtk_label_new(VFICON(vf)->tip_id->fd->name);
-
-	g_object_set_data(G_OBJECT(VFICON(vf)->tip_window), "tip_label", label);
-	gtk_container_add(GTK_CONTAINER(VFICON(vf)->tip_window), label);
-	gtk_widget_show(label);
-
-#if GTK_CHECK_VERSION(3,0,0)
-	display = gdk_display_get_default();
-	device_manager = gdk_display_get_device_manager(display);
-	device = gdk_device_manager_get_client_pointer(device_manager);
-	gdk_device_get_position(device, NULL, &x, &y);
-#else
-	gdk_window_get_pointer(NULL, &x, &y, NULL);
-#endif
-
-	if (!gtk_widget_get_realized(VFICON(vf)->tip_window)) gtk_widget_realize(VFICON(vf)->tip_window);
-	gtk_window_move(GTK_WINDOW(VFICON(vf)->tip_window), x + 16, y + 16);
-	gtk_widget_show(VFICON(vf)->tip_window);
-}
-
-static void tip_hide(ViewFile *vf)
-{
-	if (VFICON(vf)->tip_window) gtk_widget_destroy(VFICON(vf)->tip_window);
-	VFICON(vf)->tip_window = NULL;
-}
-
-static gboolean tip_schedule_cb(gpointer data)
-{
-	ViewFile *vf = data;
-	GtkWidget *window;
-
-	if (!VFICON(vf)->tip_delay_id) return FALSE;
-
-	window = gtk_widget_get_toplevel(vf->listview);
-
-	if (gtk_widget_get_sensitive(window) &&
-	    gtk_window_has_toplevel_focus(GTK_WINDOW(window)))
-		{
-		tip_show(vf);
-		}
-
-	VFICON(vf)->tip_delay_id = 0;
-	return FALSE;
-}
-
-static void tip_schedule(ViewFile *vf)
-{
-	tip_hide(vf);
-
-	if (VFICON(vf)->tip_delay_id)
-		{
-		g_source_remove(VFICON(vf)->tip_delay_id);
-		VFICON(vf)->tip_delay_id = 0;
-		}
-
-	if (!VFICON(vf)->show_text)
-		{
-		VFICON(vf)->tip_delay_id = g_timeout_add(VFICON_TIP_DELAY, tip_schedule_cb, vf);
-		}
-}
-
-static void tip_unschedule(ViewFile *vf)
-{
-	tip_hide(vf);
-
-	if (VFICON(vf)->tip_delay_id)
-		{
-		g_source_remove(VFICON(vf)->tip_delay_id);
-		VFICON(vf)->tip_delay_id = 0;
-		}
-}
-
-static void tip_update(ViewFile *vf, IconData *id)
-{
-#if GTK_CHECK_VERSION(3,0,0)
-	GdkDisplay *display = gdk_display_get_default();
-	GdkDeviceManager *device_manager = gdk_display_get_device_manager(display);
-	GdkDevice *device = gdk_device_manager_get_client_pointer(device_manager);
-#endif
-
-	if (VFICON(vf)->tip_window)
-		{
-		gint x, y;
-
-#if GTK_CHECK_VERSION(3,0,0)
-		gdk_device_get_position(device, NULL, &x, &y);
-#else
-		gdk_window_get_pointer(NULL, &x, &y, NULL);
-#endif
-		gtk_window_move(GTK_WINDOW(VFICON(vf)->tip_window), x + 16, y + 16);
-
-		if (id != VFICON(vf)->tip_id)
-			{
-			GtkWidget *label;
-
-			VFICON(vf)->tip_id = id;
-
-			if (!VFICON(vf)->tip_id)
-				{
-				tip_hide(vf);
-				tip_schedule(vf);
-				return;
-				}
-
-			label = g_object_get_data(G_OBJECT(VFICON(vf)->tip_window), "tip_label");
-			gtk_label_set_text(GTK_LABEL(label), VFICON(vf)->tip_id->fd->name);
-			}
-		}
-	else
-		{
-		tip_schedule(vf);
-		}
-}
-
-/*
- *-------------------------------------------------------------------
- * dnd
- *-------------------------------------------------------------------
- */
-
-static void vficon_dnd_get(GtkWidget *widget, GdkDragContext *context,
-			   GtkSelectionData *selection_data, guint info,
-			   guint time, gpointer data)
-{
-	ViewFile *vf = data;
-	GList *list = NULL;
-
-	if (!VFICON(vf)->click_id) return;
-
-	if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
-		{
-		list = vf_selection_get_list(vf);
-		}
-	else
-		{
-		list = g_list_append(NULL, file_data_ref(VFICON(vf)->click_id->fd));
-		}
-
-	if (!list) return;
-	uri_selection_data_set_uris_from_filelist(selection_data, list);
-	filelist_free(list);
-}
-
-static void vficon_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
-				      int x, int y, GtkSelectionData *selection,
-				      guint info, guint time, gpointer data)
-{
-	ViewFile *vf = data;
-
-	if (info == TARGET_TEXT_PLAIN) {
-		IconData *id = vficon_find_data_by_coord(vf, x, y, NULL);
-
-		if (id && id->fd) {
-			/* Add keywords to file */
-			FileData *fd = id->fd;
-			gchar *str = (gchar *) gtk_selection_data_get_text(selection);
-			GList *kw_list = string_to_keywords_list(str);
-
-			metadata_append_list(fd, KEYWORD_KEY, kw_list);
-			string_list_free(kw_list);
-			g_free(str);
-		}
-	}
-}
-
-static void vficon_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
-{
-	ViewFile *vf = data;
-
-	tip_unschedule(vf);
-
-	if (VFICON(vf)->click_id && VFICON(vf)->click_id->fd->thumb_pixbuf)
-		{
-		gint items;
-
-		if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
-			items = g_list_length(VFICON(vf)->selection);
-		else
-			items = 1;
-
-		dnd_set_drag_icon(widget, context, VFICON(vf)->click_id->fd->thumb_pixbuf, items);
-		}
-}
-
-static void vficon_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
-
-	if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
-		{
-		vf_refresh(vf);
-		}
-
-	tip_unschedule(vf);
-}
-
-void vficon_dnd_init(ViewFile *vf)
-{
-	gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
-			    dnd_file_drag_types, dnd_file_drag_types_count,
-			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
-	gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
-			    dnd_file_drag_types, dnd_file_drag_types_count,
-			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
-
-	g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
-			 G_CALLBACK(vficon_dnd_get), vf);
-	g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
-			 G_CALLBACK(vficon_dnd_begin), vf);
-	g_signal_connect(G_OBJECT(vf->listview), "drag_end",
-			 G_CALLBACK(vficon_dnd_end), vf);
-	g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
-			 G_CALLBACK(vficon_drag_data_received), vf);
-}
-
-/*
- *-------------------------------------------------------------------
- * cell updates
- *-------------------------------------------------------------------
- */
-
-static void vficon_selection_set(ViewFile *vf, IconData *id, SelectionType value, GtkTreeIter *iter)
-{
-	GtkTreeModel *store;
-	GList *list;
-
-	if (!id) return;
-
-
-	if (id->selected == value) return;
-	id->selected = value;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	if (iter)
-		{
-		gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1);
-		if (list) gtk_list_store_set(GTK_LIST_STORE(store), iter, FILE_COLUMN_POINTER, list, -1);
-		}
-	else
-		{
-		GtkTreeIter row;
-
-		if (vficon_find_iter(vf, id, &row, NULL))
-			{
-			gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1);
-			if (list) gtk_list_store_set(GTK_LIST_STORE(store), &row, FILE_COLUMN_POINTER, list, -1);
-			}
-		}
-}
-
-static void vficon_selection_add(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
-{
-	if (!id) return;
-
-	vficon_selection_set(vf, id, id->selected | mask, iter);
-}
-
-static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
-{
-	if (!id) return;
-
-	vficon_selection_set(vf, id, id->selected & ~mask, iter);
-}
-
-void vficon_marks_set(ViewFile *vf, gint enable)
-{
-	GtkAllocation allocation;
-	gtk_widget_get_allocation(vf->listview, &allocation);
-	vficon_populate_at_new_size(vf, allocation.width, allocation.height, TRUE);
-}
-
-/*
- *-------------------------------------------------------------------
- * selections
- *-------------------------------------------------------------------
- */
-
-static void vficon_verify_selections(ViewFile *vf)
-{
-	GList *work;
-
-	work = VFICON(vf)->selection;
-	while (work)
-		{
-		IconData *id = work->data;
-		work = work->next;
-
-		if (vficon_index_by_id(vf, id) >= 0) continue;
-
-		VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
-		}
-}
-
-void vficon_select_all(ViewFile *vf)
-{
-	GList *work;
-
-	g_list_free(VFICON(vf)->selection);
-	VFICON(vf)->selection = NULL;
-
-	work = vf->list;
-	while (work)
-		{
-		IconData *id = work->data;
-		work = work->next;
-
-		VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
-		vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
-		}
-
-	vf_send_update(vf);
-}
-
-void vficon_select_none(ViewFile *vf)
-{
-	GList *work;
-
-	work = VFICON(vf)->selection;
-	while (work)
-		{
-		IconData *id = work->data;
-		work = work->next;
-
-		vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
-		}
-
-	g_list_free(VFICON(vf)->selection);
-	VFICON(vf)->selection = NULL;
-
-	vf_send_update(vf);
-}
-
-void vficon_select_invert(ViewFile *vf)
-{
-	GList *work;
-
-	work = vf->list;
-	while (work)
-		{
-		IconData *id = work->data;
-		work = work->next;
-
-		if (id->selected & SELECTION_SELECTED)
-			{
-			VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
-			vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
-			}
-		else
-			{
-			VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
-			vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
-			}
-		}
-
-	vf_send_update(vf);
-}
-
-static void vficon_select(ViewFile *vf, IconData *id)
-{
-	VFICON(vf)->prev_selection = id;
-
-	if (!id || id->selected & SELECTION_SELECTED) return;
-
-	VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
-	vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
-
-	vf_send_update(vf);
-}
-
-static void vficon_unselect(ViewFile *vf, IconData *id)
-{
-	VFICON(vf)->prev_selection = id;
-
-	if (!id || !(id->selected & SELECTION_SELECTED) ) return;
-
-	VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
-	vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
-
-	vf_send_update(vf);
-}
-
-static void vficon_select_util(ViewFile *vf, IconData *id, gboolean select)
-{
-	if (select)
-		{
-		vficon_select(vf, id);
-		}
-	else
-		{
-		vficon_unselect(vf, id);
-		}
-}
-
-static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *end, gboolean select)
-{
-	gint row1, col1;
-	gint row2, col2;
-	gint t;
-	gint i, j;
-
-	if (!vficon_find_position(vf, start, &row1, &col1) ||
-	    !vficon_find_position(vf, end, &row2, &col2) ) return;
-
-	VFICON(vf)->prev_selection = end;
-
-	if (!options->collections.rectangular_selection)
-		{
-		GList *work;
-		IconData *id;
-
-		if (g_list_index(vf->list, start) > g_list_index(vf->list, end))
-			{
-			id = start;
-			start = end;
-			end = id;
-			}
-
-		work = g_list_find(vf->list, start);
-		while (work)
-			{
-			id = work->data;
-			vficon_select_util(vf, id, select);
-
-			if (work->data != end)
-				work = work->next;
-			else
-				work = NULL;
-			}
-		return;
-		}
-
-	if (row2 < row1)
-		{
-		t = row1;
-		row1 = row2;
-		row2 = t;
-		}
-	if (col2 < col1)
-		{
-		t = col1;
-		col1 = col2;
-		col2 = t;
-		}
-
-	DEBUG_1("table: %d x %d to %d x %d", row1, col1, row2, col2);
-
-	for (i = row1; i <= row2; i++)
-		{
-		for (j = col1; j <= col2; j++)
-			{
-			IconData *id = vficon_find_data(vf, i, j, NULL);
-			if (id) vficon_select_util(vf, id, select);
-			}
-		}
-}
-
-gboolean vficon_index_is_selected(ViewFile *vf, gint row)
-{
-	IconData *id = g_list_nth_data(vf->list, row);
-
-	if (!id) return FALSE;
-
-	return (id->selected & SELECTION_SELECTED);
-}
-
-guint vficon_selection_count(ViewFile *vf, gint64 *bytes)
-{
-	if (bytes)
-		{
-		gint64 b = 0;
-		GList *work;
-
-		work = VFICON(vf)->selection;
-		while (work)
-			{
-			IconData *id = work->data;
-			FileData *fd = id->fd;
-			g_assert(fd->magick == FD_MAGICK);
-			b += fd->size;
-
-			work = work->next;
-			}
-
-		*bytes = b;
-		}
-
-	return g_list_length(VFICON(vf)->selection);
-}
-
-GList *vficon_selection_get_list(ViewFile *vf)
-{
-	GList *list = NULL;
-	GList *work, *work2;
-
-	work = VFICON(vf)->selection;
-	while (work)
-		{
-		IconData *id = work->data;
-		FileData *fd = id->fd;
-		g_assert(fd->magick == FD_MAGICK);
-
-		list = g_list_prepend(list, file_data_ref(fd));
-
-		work2 = fd->sidecar_files;
-		while (work2)
-			{
-			fd = work2->data;
-			list = g_list_prepend(list, file_data_ref(fd));
-			work2 = work2->next;
-			}
-
-		work = work->next;
-		}
-
-	list = g_list_reverse(list);
-
-	return list;
-}
-
-GList *vficon_selection_get_list_by_index(ViewFile *vf)
-{
-	GList *list = NULL;
-	GList *work;
-
-	work = VFICON(vf)->selection;
-	while (work)
-		{
-		list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, work->data)));
-		work = work->next;
-		}
-
-	return g_list_reverse(list);
-}
-
-static void vficon_select_by_id(ViewFile *vf, IconData *id)
-{
-	if (!id) return;
-
-	if (!(id->selected & SELECTION_SELECTED))
-		{
-		vf_select_none(vf);
-		vficon_select(vf, id);
-		}
-
-	vficon_set_focus(vf, id);
-}
-
-void vficon_select_by_fd(ViewFile *vf, FileData *fd)
-{
-	IconData *id = NULL;
-	GList *work;
-
-	if (!fd) return;
-	work = vf->list;
-	while (work && !id)
-		{
-		IconData *chk = work->data;
-		work = work->next;
-		if (chk->fd == fd) id = chk;
-		}
-	vficon_select_by_id(vf, id);
-}
-
-void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
-{
-	GList *work;
-	gint n = mark - 1;
-
-	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
-
-	work = vf->list;
-	while (work)
-		{
-		IconData *id = work->data;
-		FileData *fd = id->fd;
-		gboolean mark_val, selected;
-
-		g_assert(fd->magick == FD_MAGICK);
-
-		mark_val = file_data_get_mark(fd, n);
-		selected = (id->selected & SELECTION_SELECTED);
-
-		switch (mode)
-			{
-			case MTS_MODE_SET: selected = mark_val;
-				break;
-			case MTS_MODE_OR: selected = mark_val || selected;
-				break;
-			case MTS_MODE_AND: selected = mark_val && selected;
-				break;
-			case MTS_MODE_MINUS: selected = !mark_val && selected;
-				break;
-			}
-
-		vficon_select_util(vf, id, selected);
-
-		work = work->next;
-		}
-}
-
-void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
-{
-	GList *slist;
-	GList *work;
-	gint n = mark -1;
-
-	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
-
-	slist = vf_selection_get_list(vf);
-	work = slist;
-	while (work)
-		{
-		FileData *fd = work->data;
-
-		switch (mode)
-			{
-			case STM_MODE_SET: file_data_set_mark(fd, n, 1);
-				break;
-			case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
-				break;
-			case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
-				break;
-			}
-		work = work->next;
-		}
-	filelist_free(slist);
-}
-
-static void vficon_select_closest(ViewFile *vf, FileData *sel_fd)
-{
-	GList *work;
-	IconData *id = NULL;
-
-	if (sel_fd->parent) sel_fd = sel_fd->parent;
-	work = vf->list;
-
-	while (work)
-		{
-		gint match;
-		FileData *fd;
-
-		id = work->data;
-		fd = id->fd;
-		work = work->next;
-
-		match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
-
-		if (match >= 0) break;
-		}
-
-	if (id)
-		{
-		vficon_select(vf, id);
-		vficon_send_layout_select(vf, id);
-		}
-}
-
-
-/*
- *-------------------------------------------------------------------
- * focus
- *-------------------------------------------------------------------
- */
-
-static void vficon_move_focus(ViewFile *vf, gint row, gint col, gboolean relative)
-{
-	gint new_row;
-	gint new_col;
-
-	if (relative)
-		{
-		new_row = VFICON(vf)->focus_row;
-		new_col = VFICON(vf)->focus_column;
-
-		new_row += row;
-		if (new_row < 0) new_row = 0;
-		if (new_row >= VFICON(vf)->rows) new_row = VFICON(vf)->rows - 1;
-
-		while (col != 0)
-			{
-			if (col < 0)
-				{
-				new_col--;
-				col++;
-				}
-			else
-				{
-				new_col++;
-				col--;
-				}
-
-			if (new_col < 0)
-				{
-				if (new_row > 0)
-					{
-					new_row--;
-					new_col = VFICON(vf)->columns - 1;
-					}
-				else
-					{
-					new_col = 0;
-					}
-				}
-			if (new_col >= VFICON(vf)->columns)
-				{
-				if (new_row < VFICON(vf)->rows - 1)
-					{
-					new_row++;
-					new_col = 0;
-					}
-				else
-					{
-					new_col = VFICON(vf)->columns - 1;
-					}
-				}
-			}
-		}
-	else
-		{
-		new_row = row;
-		new_col = col;
-
-		if (new_row >= VFICON(vf)->rows)
-			{
-			if (VFICON(vf)->rows > 0)
-				new_row = VFICON(vf)->rows - 1;
-			else
-				new_row = 0;
-			new_col = VFICON(vf)->columns - 1;
-			}
-		if (new_col >= VFICON(vf)->columns) new_col = VFICON(vf)->columns - 1;
-		}
-
-	if (new_row == VFICON(vf)->rows - 1)
-		{
-		gint l;
-
-		/* if we moved beyond the last image, go to the last image */
-
-		l = g_list_length(vf->list);
-		if (VFICON(vf)->rows > 1) l -= (VFICON(vf)->rows - 1) * VFICON(vf)->columns;
-		if (new_col >= l) new_col = l - 1;
-		}
-
-	vficon_set_focus(vf, vficon_find_data(vf, new_row, new_col, NULL));
-}
-
-static void vficon_set_focus(ViewFile *vf, IconData *id)
-{
-	GtkTreeIter iter;
-	gint row, col;
-
-	if (g_list_find(vf->list, VFICON(vf)->focus_id))
-		{
-		if (id == VFICON(vf)->focus_id)
-			{
-			/* ensure focus row col are correct */
-			vficon_find_position(vf, VFICON(vf)->focus_id, &VFICON(vf)->focus_row, &VFICON(vf)->focus_column);
-#if GTK_CHECK_VERSION(3,0,0)
-/* FIXME: Refer to issue #467 on Github. The thumbnail position is not
- * preserved when the icon view is refreshed. Caused by an unknown call from
- * the idle loop. This patch hides the problem.
- */
-			if (vficon_find_iter(vf, VFICON(vf)->focus_id, &iter, NULL))
-				{
-				tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
-				}
-#endif
-			return;
-			}
-		vficon_selection_remove(vf, VFICON(vf)->focus_id, SELECTION_FOCUS, NULL);
-		}
-
-	if (!vficon_find_position(vf, id, &row, &col))
-		{
-		VFICON(vf)->focus_id = NULL;
-		VFICON(vf)->focus_row = -1;
-		VFICON(vf)->focus_column = -1;
-		return;
-		}
-
-	VFICON(vf)->focus_id = id;
-	VFICON(vf)->focus_row = row;
-	VFICON(vf)->focus_column = col;
-	vficon_selection_add(vf, VFICON(vf)->focus_id, SELECTION_FOCUS, NULL);
-
-	if (vficon_find_iter(vf, VFICON(vf)->focus_id, &iter, NULL))
-		{
-		GtkTreePath *tpath;
-		GtkTreeViewColumn *column;
-		GtkTreeModel *store;
-
-		tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		tpath = gtk_tree_model_get_path(store, &iter);
-		/* focus is set to an extra column with 0 width to hide focus, we draw it ourself */
-		column = gtk_tree_view_get_column(GTK_TREE_VIEW(vf->listview), VFICON_MAX_COLUMNS);
-		gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, column, FALSE);
-		gtk_tree_path_free(tpath);
-		}
-}
-
-/* used to figure the page up/down distances */
-static gint page_height(ViewFile *vf)
-{
-	GtkAdjustment *adj;
-	gint page_size;
-	gint row_height;
-	gint ret;
-
-	adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(vf->listview));
-	page_size = (gint)gtk_adjustment_get_page_increment(adj);
-
-	row_height = options->thumbnails.max_height + THUMB_BORDER_PADDING * 2;
-	if (VFICON(vf)->show_text) row_height += options->thumbnails.max_height / 3;
-
-	ret = page_size / row_height;
-	if (ret < 1) ret = 1;
-
-	return ret;
-}
-
-/*
- *-------------------------------------------------------------------
- * keyboard
- *-------------------------------------------------------------------
- */
-
-static void vfi_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreeModel *store;
-	GtkTreeIter iter;
-	gint column;
-	GtkTreePath *tpath;
-	gint cw, ch;
-
-	if (!vficon_find_iter(vf, VFICON(vf)->click_id, &iter, &column)) return;
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	tpath = gtk_tree_model_get_path(store, &iter);
-	tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, column, FALSE, x, y, &cw, &ch);
-	gtk_tree_path_free(tpath);
-	*y += ch;
-	popup_menu_position_clamp(menu, x, y, 0);
-}
-
-gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
-{
-	ViewFile *vf = data;
-	gint focus_row = 0;
-	gint focus_col = 0;
-	IconData *id;
-	gboolean stop_signal;
-
-	stop_signal = TRUE;
-	switch (event->keyval)
-		{
-		case GDK_KEY_Left: case GDK_KEY_KP_Left:
-			focus_col = -1;
-			break;
-		case GDK_KEY_Right: case GDK_KEY_KP_Right:
-			focus_col = 1;
-			break;
-		case GDK_KEY_Up: case GDK_KEY_KP_Up:
-			focus_row = -1;
-			break;
-		case GDK_KEY_Down: case GDK_KEY_KP_Down:
-			focus_row = 1;
-			break;
-		case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up:
-			focus_row = -page_height(vf);
-			break;
-		case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down:
-			focus_row = page_height(vf);
-			break;
-		case GDK_KEY_Home: case GDK_KEY_KP_Home:
-			focus_row = -VFICON(vf)->focus_row;
-			focus_col = -VFICON(vf)->focus_column;
-			break;
-		case GDK_KEY_End: case GDK_KEY_KP_End:
-			focus_row = VFICON(vf)->rows - 1 - VFICON(vf)->focus_row;
-			focus_col = VFICON(vf)->columns - 1 - VFICON(vf)->focus_column;
-			break;
-		case GDK_KEY_space:
-			id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
-			if (id)
-				{
-				VFICON(vf)->click_id = id;
-				if (event->state & GDK_CONTROL_MASK)
-					{
-					gint selected;
-
-					selected = id->selected & SELECTION_SELECTED;
-					if (selected)
-						{
-						vficon_unselect(vf, id);
-						}
-					else
-						{
-						vficon_select(vf, id);
-						vficon_send_layout_select(vf, id);
-						}
-					}
-				else
-					{
-					vf_select_none(vf);
-					vficon_select(vf, id);
-					vficon_send_layout_select(vf, id);
-					}
-				}
-			break;
-		case GDK_KEY_Menu:
-			id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
-			VFICON(vf)->click_id = id;
-
-			vficon_selection_add(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
-			tip_unschedule(vf);
-
-			vf->popup = vf_pop_menu(vf);
-			gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vfi_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
-			break;
-		default:
-			stop_signal = FALSE;
-			break;
-		}
-
-	if (focus_row != 0 || focus_col != 0)
-		{
-		IconData *new_id;
-		IconData *old_id;
-
-		old_id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
-		vficon_move_focus(vf, focus_row, focus_col, TRUE);
-		new_id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
-
-		if (new_id != old_id)
-			{
-			if (event->state & GDK_SHIFT_MASK)
-				{
-				if (!options->collections.rectangular_selection)
-					{
-					vficon_select_region_util(vf, old_id, new_id, FALSE);
-					}
-				else
-					{
-					vficon_select_region_util(vf, VFICON(vf)->click_id, old_id, FALSE);
-					}
-				vficon_select_region_util(vf, VFICON(vf)->click_id, new_id, TRUE);
-				vficon_send_layout_select(vf, new_id);
-				}
-			else if (event->state & GDK_CONTROL_MASK)
-				{
-				VFICON(vf)->click_id = new_id;
-				}
-			else
-				{
-				VFICON(vf)->click_id = new_id;
-				vf_select_none(vf);
-				vficon_select(vf, new_id);
-				vficon_send_layout_select(vf, new_id);
-				}
-			}
-		}
-
-	if (stop_signal)
-		{
-		tip_unschedule(vf);
-		}
-
-	return stop_signal;
-}
-
-/*
- *-------------------------------------------------------------------
- * mouse
- *-------------------------------------------------------------------
- */
-
-static gboolean vficon_motion_cb(GtkWidget *widget, GdkEventMotion *event, gpointer data)
-{
-	ViewFile *vf = data;
-	IconData *id;
-
-	id = vficon_find_data_by_coord(vf, (gint)event->x, (gint)event->y, NULL);
-	tip_update(vf, id);
-
-	return FALSE;
-}
-
-gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreeIter iter;
-	IconData *id;
-
-	tip_unschedule(vf);
-
-	id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
-
-	VFICON(vf)->click_id = id;
-	vficon_selection_add(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, &iter);
-
-	switch (bevent->button)
-		{
-		case MOUSE_BUTTON_LEFT:
-			if (!gtk_widget_has_focus(vf->listview))
-				{
-				gtk_widget_grab_focus(vf->listview);
-				}
-
-			if (bevent->type == GDK_2BUTTON_PRESS &&
-			    vf->layout)
-				{
-				vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, &iter);
-				layout_image_full_screen_start(vf->layout);
-				}
-			break;
-		case MOUSE_BUTTON_RIGHT:
-			vf->popup = vf_pop_menu(vf);
-			gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
-			break;
-		default:
-			break;
-		}
-
-	return FALSE;
-}
-
-gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreeIter iter;
-	IconData *id = NULL;
-	gboolean was_selected;
-
-	tip_schedule(vf);
-
-	if ((gint)bevent->x != 0 || (gint)bevent->y != 0)
-		{
-		id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
-		}
-
-	if (VFICON(vf)->click_id)
-		{
-		vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
-		}
-
-	if (!id || VFICON(vf)->click_id != id) return TRUE;
-
-	was_selected = !!(id->selected & SELECTION_SELECTED);
-
-	switch (bevent->button)
-		{
-		case MOUSE_BUTTON_LEFT:
-			{
-			vficon_set_focus(vf, id);
-
-			if (bevent->state & GDK_CONTROL_MASK)
-				{
-				gboolean select;
-
-				select = !(id->selected & SELECTION_SELECTED);
-				if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection)
-					{
-					vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, select);
-					}
-				else
-					{
-					vficon_select_util(vf, id, select);
-					}
-				}
-			else
-				{
-				vf_select_none(vf);
-
-				if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection)
-					{
-					vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, TRUE);
-					}
-				else
-					{
-					vficon_select_util(vf, id, TRUE);
-					was_selected = FALSE;
-					}
-				}
-			}
-			break;
-		case MOUSE_BUTTON_MIDDLE:
-			{
-			vficon_select_util(vf, id, !(id->selected & SELECTION_SELECTED));
-			}
-			break;
-		default:
-			break;
-		}
-
-	if (!was_selected && (id->selected & SELECTION_SELECTED))
-		{
-		vficon_send_layout_select(vf, id);
-		}
-
-	return TRUE;
-}
-
-static gboolean vficon_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
-{
-	ViewFile *vf = data;
-
-	tip_unschedule(vf);
-	return FALSE;
-}
-
-/*
- *-------------------------------------------------------------------
- * population
- *-------------------------------------------------------------------
- */
-
-static gboolean vficon_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GtkTreeIter *iter, gpointer data)
-{
-	GList *list;
-
-	gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1);
-
-	/* it seems that gtk_list_store_clear may call some callbacks
-	   that use the column. Set the pointer to NULL to be safe. */
-	gtk_list_store_set(GTK_LIST_STORE(store), iter, FILE_COLUMN_POINTER, NULL, -1);
-	g_list_free(list);
-
-	return FALSE;
-}
-
-static void vficon_clear_store(ViewFile *vf)
-{
-	GtkTreeModel *store;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_model_foreach(store, vficon_destroy_node_cb, NULL);
-
-	gtk_list_store_clear(GTK_LIST_STORE(store));
-}
-
-static GList *vficon_add_row(ViewFile *vf, GtkTreeIter *iter)
-{
-	GtkListStore *store;
-	GList *list = NULL;
-	gint i;
-
-	for (i = 0; i < VFICON(vf)->columns; i++) list = g_list_prepend(list, NULL);
-
-	store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-	gtk_list_store_append(store, iter);
-	gtk_list_store_set(store, iter, FILE_COLUMN_POINTER, list, -1);
-
-	return list;
-}
-
-static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_position)
-{
-	GtkTreeModel *store;
-	GtkTreePath *tpath;
-	GList *work;
-	IconData *visible_id = NULL;
-	gint r, c;
-	gboolean valid;
-	GtkTreeIter iter;
-
-	vficon_verify_selections(vf);
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-
-	if (keep_position && gtk_widget_get_realized(vf->listview) &&
-	    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
-		{
-		GtkTreeIter iter;
-		GList *list;
-
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_path_free(tpath);
-
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
-		if (list) visible_id = list->data;
-		}
-
-
-	if (resize)
-		{
-		gint i;
-		gint thumb_width;
-
-		vficon_clear_store(vf);
-
-		thumb_width = vficon_get_icon_width(vf);
-
-		for (i = 0; i < VFICON_MAX_COLUMNS; i++)
-			{
-			GtkTreeViewColumn *column;
-			GtkCellRenderer *cell;
-			GList *list;
-
-			column = gtk_tree_view_get_column(GTK_TREE_VIEW(vf->listview), i);
-			gtk_tree_view_column_set_visible(column, (i < VFICON(vf)->columns));
-			gtk_tree_view_column_set_fixed_width(column, thumb_width + (THUMB_BORDER_PADDING * 6));
-
-			list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
-			cell = (list) ? list->data : NULL;
-			g_list_free(list);
-
-			if (cell && GQV_IS_CELL_RENDERER_ICON(cell))
-				{
-				g_object_set(G_OBJECT(cell), "fixed_width", thumb_width,
-							     "fixed_height", options->thumbnails.max_height,
-							     "show_text", VFICON(vf)->show_text,
-							     "show_marks", vf->marks_enabled,
-							     "num_marks", FILEDATA_MARKS_SIZE,
-							     NULL);
-				}
-			}
-		if (gtk_widget_get_realized(vf->listview)) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
-		}
-
-	r = -1;
-	c = 0;
-
-	valid = gtk_tree_model_iter_children(store, &iter, NULL);
-
-	work = vf->list;
-	while (work)
-		{
-		GList *list;
-		r++;
-		c = 0;
-		if (valid)
-			{
-			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
-			gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1);
-			}
-		else
-			{
-			list = vficon_add_row(vf, &iter);
-			}
-
-		while (list)
-			{
-			IconData *id;
-
-			if (work)
-				{
-				id = work->data;
-				work = work->next;
-				c++;
-				}
-			else
-				{
-				id = NULL;
-				}
-
-			list->data = id;
-			list = list->next;
-			}
-		if (valid) valid = gtk_tree_model_iter_next(store, &iter);
-		}
-
-	r++;
-	while (valid)
-		{
-		GList *list;
-
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
-		valid = gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
-		g_list_free(list);
-		}
-
-	VFICON(vf)->rows = r;
-
-	if (visible_id &&
-	    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
-		{
-		GtkTreeIter iter;
-		GList *list;
-
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_path_free(tpath);
-
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
-		if (g_list_find(list, visible_id) == NULL &&
-		    vficon_find_iter(vf, visible_id, &iter, NULL))
-			{
-			tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
-			}
-		}
-
-
-	vf_send_update(vf);
-	vf_thumb_update(vf);
-}
-
-static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gboolean force)
-{
-	gint new_cols;
-	gint thumb_width;
-
-	thumb_width = vficon_get_icon_width(vf);
-
-	new_cols = w / (thumb_width + (THUMB_BORDER_PADDING * 6));
-	if (new_cols < 1) new_cols = 1;
-
-	if (!force && new_cols == VFICON(vf)->columns) return;
-
-	VFICON(vf)->columns = new_cols;
-
-	vficon_populate(vf, TRUE, TRUE);
-
-	DEBUG_1("col tab pop cols=%d rows=%d", VFICON(vf)->columns, VFICON(vf)->rows);
-}
-
-static void vficon_sized_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vficon_populate_at_new_size(vf, allocation->width, allocation->height, FALSE);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * misc
- *-----------------------------------------------------------------------------
- */
-
-void vficon_sort_set(ViewFile *vf, SortType type, gboolean ascend)
-{
-	if (vf->sort_method == type && vf->sort_ascend == ascend) return;
-
-	vf->sort_method = type;
-	vf->sort_ascend = ascend;
-
-	if (!vf->list) return;
-
-	vf_refresh(vf);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * thumb updates
- *-----------------------------------------------------------------------------
- */
-
-void vficon_thumb_progress_count(GList *list, gint *count, gint *done)
-{
-	GList *work = list;
-	while (work)
-		{
-		IconData *id = work->data;
-		FileData *fd = id->fd;
-		work = work->next;
-
-		if (fd->thumb_pixbuf) (*done)++;
-		(*count)++;
-		}
-}
-
-void vficon_set_thumb_fd(ViewFile *vf, FileData *fd)
-{
-	GtkTreeModel *store;
-	GtkTreeIter iter;
-	GList *list;
-
-	if (!vficon_find_iter(vf, vficon_icon_data(vf, fd), &iter, NULL)) return;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-
-	gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
-	gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1);
-}
-
-
-FileData *vficon_thumb_next_fd(ViewFile *vf)
-{
-	GtkTreePath *tpath;
-	FileData *fd = NULL;
-
-	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
-		{
-		GtkTreeModel *store;
-		GtkTreeIter iter;
-		gboolean valid = TRUE;
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_path_free(tpath);
-
-		while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
-			{
-			GList *list;
-
-			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
-
-			while (!fd && list)
-				{
-				IconData *id = list->data;
-				if (id && !id->fd->thumb_pixbuf) fd = id->fd;
-				list = list->next;
-				}
-
-			valid = gtk_tree_model_iter_next(store, &iter);
-			}
-		}
-
-	/* then find first undone */
-
-	if (!fd)
-		{
-		GList *work = vf->list;
-		while (work && !fd)
-			{
-			IconData *id = work->data;
-			FileData *fd_p = id->fd;
-			work = work->next;
-
-			if (!fd_p->thumb_pixbuf) fd = fd_p;
-			}
-		}
-
-	return fd;
-}
-
-void vficon_thumb_reset_all(ViewFile *vf)
-{
-	GList *work = vf->list;
-
-	while (work)
-		{
-		IconData *id = work->data;
-		FileData *fd = id->fd;
-		if (fd->thumb_pixbuf)
-			{
-			g_object_unref(fd->thumb_pixbuf);
-			fd->thumb_pixbuf = NULL;
-			}
-		work = work->next;
-		}
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * row stuff
- *-----------------------------------------------------------------------------
- */
-
-FileData *vficon_index_get_data(ViewFile *vf, gint row)
-{
-	IconData *id;
-
-	id = g_list_nth_data(vf->list, row);
-	return id ? id->fd : NULL;
-}
-
-
-gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd)
-{
-	gint p = 0;
-	GList *work;
-
-	if (!in_fd) return -1;
-
-	work = vf->list;
-	while (work)
-		{
-		IconData *id = work->data;
-		FileData *fd = id->fd;
-		if (fd == in_fd) return p;
-		work = work->next;
-		p++;
-		}
-
-	return -1;
-}
-
-static gint vficon_index_by_id(ViewFile *vf, IconData *in_id)
-{
-	gint p = 0;
-	GList *work;
-
-	if (!in_id) return -1;
-
-	work = vf->list;
-	while (work)
-		{
-		IconData *id = work->data;
-		if (id == in_id) return p;
-		work = work->next;
-		p++;
-		}
-
-	return -1;
-}
-
-guint vficon_count(ViewFile *vf, gint64 *bytes)
-{
-	if (bytes)
-		{
-		gint64 b = 0;
-		GList *work;
-
-		work = vf->list;
-		while (work)
-			{
-			IconData *id = work->data;
-			FileData *fd = id->fd;
-			work = work->next;
-
-			b += fd->size;
-			}
-
-		*bytes = b;
-		}
-
-	return g_list_length(vf->list);
-}
-
-GList *vficon_get_list(ViewFile *vf)
-{
-	GList *list = NULL;
-	GList *work;
-
-	work = vf->list;
-	while (work)
-		{
-		IconData *id = work->data;
-		FileData *fd = id->fd;
-		work = work->next;
-
-		list = g_list_prepend(list, file_data_ref(fd));
-		}
-
-	return g_list_reverse(list);
-}
-
-/*
- *-----------------------------------------------------------------------------
- *
- *-----------------------------------------------------------------------------
- */
-
-static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
-{
-	gboolean ret = TRUE;
-	GList *work, *work_fd;
-	IconData *focus_id;
-	GList *new_filelist = NULL;
-	FileData *first_selected = NULL;
-	GList *new_iconlist = NULL;
-
-	focus_id = VFICON(vf)->focus_id;
-
-	if (vf->dir_fd)
-		{
-		ret = filelist_read(vf->dir_fd, &new_filelist, NULL);
-		new_filelist = file_data_filter_marks_list(new_filelist, vf_marks_get_filter(vf));
-		}
-
-	vf->list = iconlist_sort(vf->list, vf->sort_method, vf->sort_ascend); /* the list might not be sorted if there were renames */
-	new_filelist = filelist_sort(new_filelist, vf->sort_method, vf->sort_ascend);
-
-	if (VFICON(vf)->selection)
-		{
-		first_selected = ((IconData *)(VFICON(vf)->selection->data))->fd;
-		file_data_ref(first_selected);
-		g_list_free(VFICON(vf)->selection);
-		VFICON(vf)->selection = NULL;
-
-
-		}
-
-	/* check for same files from old_list */
-	work = vf->list;
-	work_fd = new_filelist;
-	while (work || work_fd)
-		{
-		IconData *id = NULL;
-		FileData *fd = NULL;
-		FileData *new_fd = NULL;
-		gint match;
-
-		if (work && work_fd)
-			{
-			id = work->data;
-			fd = id->fd;
-
-			new_fd = work_fd->data;
-
-			if (fd == new_fd)
-				{
-				/* not changed, go to next */
-				work = work->next;
-				work_fd = work_fd->next;
-				if (id->selected & SELECTION_SELECTED)
-					{
-					VFICON(vf)->selection = g_list_prepend(VFICON(vf)->selection, id);
-					}
-				continue;
-				}
-
-			match = filelist_sort_compare_filedata_full(fd, new_fd, vf->sort_method, vf->sort_ascend);
-			if (match == 0) g_warning("multiple fd for the same path");
-			}
-		else if (work)
-			{
-			id = work->data;
-			fd = id->fd;
-			match = -1;
-			}
-		else /* work_fd */
-			{
-			new_fd = work_fd->data;
-			match = 1;
-			}
-
-		if (match < 0)
-			{
-			/* file no longer exists, delete from vf->list */
-			GList *to_delete = work;
-			work = work->next;
-			if (id == VFICON(vf)->prev_selection) VFICON(vf)->prev_selection = NULL;
-			if (id == VFICON(vf)->click_id) VFICON(vf)->click_id = NULL;
-			file_data_unref(fd);
-			g_free(id);
-			vf->list = g_list_delete_link(vf->list, to_delete);
-			}
-		else
-			{
-			/* new file, add to vf->list */
-			id = g_new0(IconData, 1);
-
-			id->selected = SELECTION_NONE;
-			id->fd = file_data_ref(new_fd);
-			if (work)
-				vf->list = g_list_insert_before(vf->list, work, id);
-			else
-				new_iconlist = g_list_prepend(new_iconlist, id); /* it is faster to append all new entries together later */
-
-			work_fd = work_fd->next;
-			}
-
-		}
-
-	if (new_iconlist)
-		{
-		vf->list = g_list_concat(vf->list, g_list_reverse(new_iconlist));
-		}
-
-	VFICON(vf)->selection = g_list_reverse(VFICON(vf)->selection);
-
-	filelist_free(new_filelist);
-
-	vficon_populate(vf, TRUE, keep_position);
-
-	if (first_selected && !VFICON(vf)->selection)
-		{
-		/* all selected files disappeared */
-		vficon_select_closest(vf, first_selected);
-		}
-	file_data_unref(first_selected);
-
-	/* attempt to keep focus on same icon when refreshing */
-	if (focus_id && g_list_find(vf->list, focus_id))
-		{
-		vficon_set_focus(vf, focus_id);
-		}
-
-	return ret;
-}
-
-gboolean vficon_refresh(ViewFile *vf)
-{
-	return vficon_refresh_real(vf, TRUE);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * draw, etc.
- *-----------------------------------------------------------------------------
- */
-
-typedef struct _ColumnData ColumnData;
-struct _ColumnData
-{
-	ViewFile *vf;
-	gint number;
-};
-
-static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
-				GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
-{
-	GList *list;
-	IconData *id;
-	ColumnData *cd = data;
-	ViewFile *vf = cd->vf;
-
-	if (!GQV_IS_CELL_RENDERER_ICON(cell)) return;
-
-	gtk_tree_model_get(tree_model, iter, FILE_COLUMN_POINTER, &list, -1);
-
-	id = g_list_nth_data(list, cd->number);
-
-	if (id)
-		{
-		GdkColor color_fg;
-		GdkColor color_bg;
-		GtkStyle *style;
-		gchar *name_sidecars;
-		gchar *link;
-		GtkStateType state = GTK_STATE_NORMAL;
-
-		g_assert(id->fd->magick == FD_MAGICK);
-
-		link = islink(id->fd->path) ? GQ_LINK_STR : "";
-		if (id->fd->sidecar_files)
-			{
-			gchar *sidecars = file_data_sc_list_to_string(id->fd);
-			name_sidecars = g_strdup_printf("%s%s %s", link, id->fd->name, sidecars);
-			g_free(sidecars);
-			}
-		else
-			{
-			gchar *disabled_grouping = id->fd->disable_grouping ? _(" [NO GROUPING]") : "";
-			name_sidecars = g_strdup_printf("%s%s%s", link, id->fd->name, disabled_grouping);
-			}
-
-		style = gtk_widget_get_style(vf->listview);
-		if (id->selected & SELECTION_SELECTED)
-			{
-			state = GTK_STATE_SELECTED;
-			}
-
-		memcpy(&color_fg, &style->text[state], sizeof(color_fg));
-		memcpy(&color_bg, &style->base[state], sizeof(color_bg));
-
-		if (id->selected & SELECTION_PRELIGHT)
-			{
-			shift_color(&color_bg, -1, 0);
-			}
-
-		g_object_set(cell,	"pixbuf", id->fd->thumb_pixbuf,
-					"text", name_sidecars,
-					"marks", file_data_get_marks(id->fd),
-					"show_marks", vf->marks_enabled,
-					"cell-background-gdk", &color_bg,
-					"cell-background-set", TRUE,
-					"foreground-gdk", &color_fg,
-					"foreground-set", TRUE,
-					"has-focus", (VFICON(vf)->focus_id == id), NULL);
-		g_free(name_sidecars);
-		}
-	else
-		{
-		g_object_set(cell,	"pixbuf", NULL,
-					"text", NULL,
-					"show_marks", FALSE,
-					"cell-background-set", FALSE,
-					"foreground-set", FALSE,
-					"has-focus", FALSE, NULL);
-		}
-}
-
-static void vficon_append_column(ViewFile *vf, gint n)
-{
-	ColumnData *cd;
-	GtkTreeViewColumn *column;
-	GtkCellRenderer *renderer;
-
-	column = gtk_tree_view_column_new();
-	gtk_tree_view_column_set_min_width(column, 0);
-
-	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
-	gtk_tree_view_column_set_alignment(column, 0.5);
-
-	renderer = gqv_cell_renderer_icon_new();
-	gtk_tree_view_column_pack_start(column, renderer, FALSE);
-	g_object_set(G_OBJECT(renderer), "xpad", THUMB_BORDER_PADDING * 2,
-					 "ypad", THUMB_BORDER_PADDING,
-					 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
-
-	g_object_set_data(G_OBJECT(column), "column_number", GINT_TO_POINTER(n));
-	g_object_set_data(G_OBJECT(renderer), "column_number", GINT_TO_POINTER(n));
-
-	cd = g_new0(ColumnData, 1);
-	cd->vf = vf;
-	cd->number = n;
-	gtk_tree_view_column_set_cell_data_func(column, renderer, vficon_cell_data_cb, cd, g_free);
-
-	gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
-
-	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vficon_mark_toggled_cb), vf);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * base
- *-----------------------------------------------------------------------------
- */
-
-gboolean vficon_set_fd(ViewFile *vf, FileData *dir_fd)
-{
-	gboolean ret;
-
-	if (!dir_fd) return FALSE;
-	if (vf->dir_fd == dir_fd) return TRUE;
-
-	file_data_unref(vf->dir_fd);
-	vf->dir_fd = file_data_ref(dir_fd);
-
-	g_list_free(VFICON(vf)->selection);
-	VFICON(vf)->selection = NULL;
-
-	iconlist_free(vf->list);
-	vf->list = NULL;
-
-	/* NOTE: populate will clear the store for us */
-	ret = vficon_refresh_real(vf, FALSE);
-
-	VFICON(vf)->focus_id = NULL;
-	vficon_move_focus(vf, 0, 0, FALSE);
-
-	return ret;
-}
-
-void vficon_destroy_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vf_refresh_idle_cancel(vf);
-
-	file_data_unregister_notify_func(vf_notify_cb, vf);
-
-	tip_unschedule(vf);
-
-	vf_thumb_cleanup(vf);
-
-	iconlist_free(vf->list);
-	g_list_free(VFICON(vf)->selection);
-}
-
-ViewFile *vficon_new(ViewFile *vf, FileData *dir_fd)
-{
-	GtkListStore *store;
-	GtkTreeSelection *selection;
-	gint i;
-
-	vf->info = g_new0(ViewFileInfoIcon, 1);
-
-	VFICON(vf)->show_text = options->show_icon_names;
-
-	store = gtk_list_store_new(1, G_TYPE_POINTER);
-	vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
-	g_object_unref(store);
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_NONE);
-
-	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
-	gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
-
-	for (i = 0; i < VFICON_MAX_COLUMNS; i++)
-		{
-		vficon_append_column(vf, i);
-		}
-
-	/* zero width column to hide tree view focus, we draw it ourselves */
-	vficon_append_column(vf, i);
-	/* end column to fill white space */
-	vficon_append_column(vf, i);
-
-	g_signal_connect(G_OBJECT(vf->listview), "size_allocate",
-			 G_CALLBACK(vficon_sized_cb), vf);
-
-	gtk_widget_set_events(vf->listview, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK |
-			      GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK);
-
-	g_signal_connect(G_OBJECT(vf->listview),"motion_notify_event",
-			 G_CALLBACK(vficon_motion_cb), vf);
-	g_signal_connect(G_OBJECT(vf->listview), "leave_notify_event",
-			 G_CALLBACK(vficon_leave_cb), vf);
-
-	/* force VFICON(vf)->columns to be at least 1 (sane) - this will be corrected in the size_cb */
-	vficon_populate_at_new_size(vf, 1, 1, FALSE);
-
-	file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
-
-	return vf;
-}
-
-/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/view_file_icon.h	Thu Jun 29 11:05:59 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2004 John Ellis
- * Copyright (C) 2008 - 2016 The Geeqie Team
- *
- * Author: John Ellis
- *
- * 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 VIEW_FILE_ICON_H
-#define VIEW_FILE_ICON_H
-
-gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data);
-gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
-gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
-
-void vficon_dnd_init(ViewFile *vf);
-
-void vficon_destroy_cb(GtkWidget *widget, gpointer data);
-ViewFile *vficon_new(ViewFile *vf, FileData *dir_fd);
-
-gboolean vficon_set_fd(ViewFile *vf, FileData *dir_fd);
-gboolean vficon_refresh(ViewFile *vf);
-
-void vficon_sort_set(ViewFile *vf, SortType type, gboolean ascend);
-
-void vficon_marks_set(ViewFile *vf, gboolean enable);
-
-GList *vficon_selection_get_one(ViewFile *vf, FileData *fd);
-GList *vficon_pop_menu_file_list(ViewFile *vf);
-void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data);
-void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data);
-void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data);
-void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data);
-void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data);
-
-FileData *vficon_index_get_data(ViewFile *vf, gint row);
-gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd);
-guint vficon_count(ViewFile *vf, gint64 *bytes);
-GList *vficon_get_list(ViewFile *vf);
-
-gboolean vficon_index_is_selected(ViewFile *vf, gint row);
-guint vficon_selection_count(ViewFile *vf, gint64 *bytes);
-GList *vficon_selection_get_list(ViewFile *vf);
-GList *vficon_selection_get_list_by_index(ViewFile *vf);
-
-void vficon_select_all(ViewFile *vf);
-void vficon_select_none(ViewFile *vf);
-void vficon_select_invert(ViewFile *vf);
-void vficon_select_by_fd(ViewFile *vf, FileData *fd);
-
-void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode);
-void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode);
-
-
-void vficon_thumb_progress_count(GList *list, gint *count, gint *done);
-void vficon_set_thumb_fd(ViewFile *vf, FileData *fd);
-FileData *vficon_thumb_next_fd(ViewFile *vf);
-void vficon_thumb_reset_all(ViewFile *vf);
-
-#endif
-/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/view_file_list.c	Thu Jun 29 11:05:59 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2052 +0,0 @@
-/*
- * Copyright (C) 2004 John Ellis
- * Copyright (C) 2008 - 2016 The Geeqie Team
- *
- * Author: John Ellis
- *
- * 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 "view_file_list.h"
-
-#include "bar.h"
-#include "cache_maint.h"
-#include "dnd.h"
-#include "editors.h"
-#include "img-view.h"
-#include "layout.h"
-#include "layout_image.h"
-#include "menu.h"
-#include "metadata.h"
-#include "thumb.h"
-#include "utilops.h"
-#include "ui_fileops.h"
-#include "ui_menu.h"
-#include "ui_tree_edit.h"
-#include "uri_utils.h"
-#include "view_file.h"
-
-#include <gdk/gdkkeysyms.h> /* for keyboard values */
-
-/* Index to tree store */
-enum {
-	FILE_COLUMN_POINTER = 0,
-	FILE_COLUMN_VERSION,
-	FILE_COLUMN_THUMB,
-	FILE_COLUMN_FORMATTED,
-	FILE_COLUMN_NAME,
-	FILE_COLUMN_SIDECARS,
-	FILE_COLUMN_SIZE,
-	FILE_COLUMN_DATE,
-	FILE_COLUMN_EXPANDED,
-	FILE_COLUMN_COLOR,
-	FILE_COLUMN_MARKS,
-	FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
-	FILE_COLUMN_COUNT
-};
-
-
-/* Index to tree view */
-enum {
-	FILE_VIEW_COLUMN_MARKS = 0,
-	FILE_VIEW_COLUMN_MARKS_LAST = FILE_VIEW_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
-	FILE_VIEW_COLUMN_THUMB,
-	FILE_VIEW_COLUMN_FORMATTED,
-	FILE_VIEW_COLUMN_SIZE,
-	FILE_VIEW_COLUMN_DATE,
-	FILE_VIEW_COLUMN_COUNT
-};
-
-
-
-static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd);
-static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
-static void vflist_populate_view(ViewFile *vf, gboolean force);
-static gboolean vflist_is_multiline(ViewFile *vf);
-static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded);
-
-
-/*
- *-----------------------------------------------------------------------------
- * misc
- *-----------------------------------------------------------------------------
- */
-typedef struct {
-	FileData *fd;
-	GtkTreeIter *iter;
-	gboolean found;
-	gint row;
-} ViewFileFindRowData;
-
-static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
-{
-	ViewFileFindRowData *find = data;
-	FileData *fd;
-	gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
-	if (fd == find->fd)
-		{
-		*find->iter = *iter;
-		find->found = TRUE;
-		return TRUE;
-		}
-	find->row++;
-	return FALSE;
-}
-
-static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
-{
-	GtkTreeModel *store;
-	ViewFileFindRowData data = {fd, iter, FALSE, 0};
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
-
-	if (data.found)
-		{
-		return data.row;
-		}
-
-	return -1;
-}
-
-static FileData *vflist_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
-{
-	GtkTreePath *tpath;
-	GtkTreeViewColumn *column;
-
-	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), x, y,
-					  &tpath, &column, NULL, NULL))
-		{
-		GtkTreeModel *store;
-		GtkTreeIter row;
-		FileData *fd;
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		gtk_tree_model_get_iter(store, &row, tpath);
-		gtk_tree_path_free(tpath);
-		gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &fd, -1);
-
-		return fd;
-		}
-
-	return NULL;
-}
-
-static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
-{
-	FileData *fd;
-	gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
-
-	/* it seems that gtk_tree_store_clear may call some callbacks
-	   that use the column. Set the pointer to NULL to be safe. */
-	gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILE_COLUMN_POINTER, NULL, -1);
-	file_data_unref(fd);
-	return FALSE;
-}
-
-static void vflist_store_clear(ViewFile *vf, gboolean unlock_files)
-{
-	GtkTreeModel *store;
-	GList *files = NULL;
-
-	if (unlock_files && vf->marks_enabled)
-		{
-		// unlock locked files in this directory
-		filelist_read(vf->dir_fd, &files, NULL);
-		while (files)
-			{
-			FileData *fd = files->data;
-			files = files->next;
-			file_data_unlock(fd);
-			file_data_unref(fd);  // undo the ref that got added in filelist_read
-			}
-		}
-
-	g_list_free(files);
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
-	gtk_tree_store_clear(GTK_TREE_STORE(store));
-}
-
-void vflist_color_set(ViewFile *vf, FileData *fd, gboolean color_set)
-{
-	GtkTreeModel *store;
-	GtkTreeIter iter;
-
-	if (vflist_find_row(vf, fd, &iter) < 0) return;
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
-}
-
-static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
-{
-	GtkTreeModel *store;
-	GtkTreePath *tpath;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-
-	tpath = gtk_tree_model_get_path(store, iter);
-	gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
-	gtk_tree_path_free(tpath);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * dnd
- *-----------------------------------------------------------------------------
- */
-
-static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
-			   GtkSelectionData *selection_data, guint info,
-			   guint time, gpointer data)
-{
-	ViewFile *vf = data;
-	GList *list = NULL;
-
-	if (!VFLIST(vf)->click_fd) return;
-
-	if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
-		{
-		list = vf_selection_get_list(vf);
-		}
-	else
-		{
-		list = g_list_append(NULL, file_data_ref(VFLIST(vf)->click_fd));
-		}
-
-	if (!list) return;
-	uri_selection_data_set_uris_from_filelist(selection_data, list);
-	filelist_free(list);
-}
-
-static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vflist_color_set(vf, VFLIST(vf)->click_fd, TRUE);
-
-	if (VFLIST(vf)->thumbs_enabled &&
-	    VFLIST(vf)->click_fd && VFLIST(vf)->click_fd->thumb_pixbuf)
-		{
-		guint items;
-
-		if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
-			items = vf_selection_count(vf, NULL);
-		else
-			items = 1;
-
-		dnd_set_drag_icon(widget, context, VFLIST(vf)->click_fd->thumb_pixbuf, items);
-		}
-}
-
-static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
-
-	if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
-		{
-		vf_refresh(vf);
-		}
-}
-
-static void vflist_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context,
-				      int x, int y, GtkSelectionData *selection,
-				      guint info, guint time, gpointer data)
-{
-	ViewFile *vf = data;
-
-	if (info == TARGET_TEXT_PLAIN) {
-		FileData *fd = vflist_find_data_by_coord(vf, x, y, NULL);
-
-		if (fd) {
-			/* Add keywords to file */
-			gchar *str = (gchar *) gtk_selection_data_get_text(selection);
-			GList *kw_list = string_to_keywords_list(str);
-
-			metadata_append_list(fd, KEYWORD_KEY, kw_list);
-			string_list_free(kw_list);
-			g_free(str);
-		}
-	}
-}
-
-void vflist_dnd_init(ViewFile *vf)
-{
-	gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
-			    dnd_file_drag_types, dnd_file_drag_types_count,
-			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
-	gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL,
-			    dnd_file_drag_types, dnd_file_drag_types_count,
-			    GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
-
-	g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
-			 G_CALLBACK(vflist_dnd_get), vf);
-	g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
-			 G_CALLBACK(vflist_dnd_begin), vf);
-	g_signal_connect(G_OBJECT(vf->listview), "drag_end",
-			 G_CALLBACK(vflist_dnd_end), vf);
-	g_signal_connect(G_OBJECT(vf->listview), "drag_data_received",
-			 G_CALLBACK(vflist_drag_data_received), vf);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * pop-up menu
- *-----------------------------------------------------------------------------
- */
-
-GList *vflist_selection_get_one(ViewFile *vf, FileData *fd)
-{
-	GList *list = g_list_append(NULL, file_data_ref(fd));
-
-	if (fd->sidecar_files)
-		{
-		/* check if the row is expanded */
-		GtkTreeModel *store;
-		GtkTreeIter iter;
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		if (vflist_find_row(vf, fd, &iter) >= 0)
-			{
-			GtkTreePath *tpath;
-
-			tpath = gtk_tree_model_get_path(store, &iter);
-			if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
-				{
-				/* unexpanded - add whole group */
-				GList *work = fd->sidecar_files;
-				while (work)
-					{
-					FileData *sfd = work->data;
-					list = g_list_prepend(list, file_data_ref(sfd));
-					work = work->next;
-					}
-				}
-			gtk_tree_path_free(tpath);
-			}
-		list = g_list_reverse(list);
-		}
-
-	return list;
-}
-
-GList *vflist_pop_menu_file_list(ViewFile *vf)
-{
-	if (!VFLIST(vf)->click_fd) return NULL;
-
-	if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
-		{
-		return vf_selection_get_list(vf);
-		}
-	return vflist_selection_get_one(vf, VFLIST(vf)->click_fd);
-}
-
-
-void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	if (vflist_row_is_selected(vf, VFLIST(vf)->click_fd))
-		{
-		GList *list;
-
-		list = vf_selection_get_list(vf);
-		view_window_new_from_list(list);
-		filelist_free(list);
-		}
-	else
-		{
-		view_window_new(VFLIST(vf)->click_fd);
-		}
-}
-
-void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-	GList *list;
-
-	list = vf_pop_menu_file_list(vf);
-	if (options->file_ops.enable_in_place_rename &&
-	    list && !list->next && VFLIST(vf)->click_fd)
-		{
-		GtkTreeModel *store;
-		GtkTreeIter iter;
-
-		filelist_free(list);
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) >= 0)
-			{
-			GtkTreePath *tpath;
-
-			tpath = gtk_tree_model_get_path(store, &iter);
-			tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
-					  FILE_VIEW_COLUMN_FORMATTED, VFLIST(vf)->click_fd->name,
-					  vflist_row_rename_cb, vf);
-			gtk_tree_path_free(tpath);
-			}
-		return;
-		}
-
-	file_util_rename(NULL, list, vf->listview);
-}
-
-void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
-	if (vf->layout)
-		{
-		layout_thumb_set(vf->layout, !VFLIST(vf)->thumbs_enabled);
-		}
-	else
-		{
-		vflist_thumb_set(vf, !VFLIST(vf)->thumbs_enabled);
-		}
-}
-
-void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
-	vf_refresh(vf);
-	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
-}
-
-void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-	vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
-	VFLIST(vf)->click_fd = NULL;
-	vf->popup = NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * callbacks
- *-----------------------------------------------------------------------------
- */
-
-static gboolean vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
-{
-	ViewFile *vf = data;
-	gchar *new_path;
-
-	if (!new || !new[0]) return FALSE;
-
-	new_path = g_build_filename(vf->dir_fd->path, new, NULL);
-
-	if (strchr(new, G_DIR_SEPARATOR) != NULL)
-		{
-		gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
-		file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
-		g_free(text);
-		}
-	else
-		{
-		gchar *old_path = g_build_filename(vf->dir_fd->path, old, NULL);
-		FileData *fd = file_data_new_group(old_path); /* get the fd from cache */
-		file_util_rename_simple(fd, new_path, vf->listview);
-		file_data_unref(fd);
-		g_free(old_path);
-		}
-
-	g_free(new_path);
-
-	return FALSE;
-}
-
-static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreeModel *store;
-	GtkTreeIter iter;
-	GtkTreePath *tpath;
-	gint cw, ch;
-
-	if (vflist_find_row(vf, VFLIST(vf)->click_fd, &iter) < 0) return;
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	tpath = gtk_tree_model_get_path(store, &iter);
-	tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
-	gtk_tree_path_free(tpath);
-	*y += ch;
-	popup_menu_position_clamp(menu, x, y, 0);
-}
-
-gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreePath *tpath;
-
-	if (event->keyval != GDK_KEY_Menu) return FALSE;
-
-	gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
-	if (tpath)
-		{
-		GtkTreeModel *store;
-		GtkTreeIter iter;
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->click_fd, -1);
-		gtk_tree_path_free(tpath);
-		}
-	else
-		{
-		VFLIST(vf)->click_fd = NULL;
-		}
-
-	vf->popup = vf_pop_menu(vf);
-	gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
-
-	return TRUE;
-}
-
-gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreePath *tpath;
-	GtkTreeIter iter;
-	FileData *fd = NULL;
-	GtkTreeViewColumn *column;
-
-	vf->clicked_mark = 0;
-
-	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
-					  &tpath, &column, NULL, NULL))
-		{
-		GtkTreeModel *store;
-		gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
-
-		if (bevent->button == MOUSE_BUTTON_LEFT &&
-		    col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
-			return FALSE;
-
-		if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
-			vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
-
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-		gtk_tree_path_free(tpath);
-		}
-
-	VFLIST(vf)->click_fd = fd;
-
-	if (bevent->button == MOUSE_BUTTON_RIGHT)
-		{
-		vf->popup = vf_pop_menu(vf);
-		gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
-				bevent->button, bevent->time);
-		return TRUE;
-		}
-
-	if (!fd) return FALSE;
-
-	if (bevent->button == MOUSE_BUTTON_MIDDLE)
-		{
-		if (!vflist_row_is_selected(vf, fd))
-			{
-			vflist_color_set(vf, fd, TRUE);
-			}
-		return TRUE;
-		}
-
-
-	if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
-	    !(bevent->state & GDK_SHIFT_MASK ) &&
-	    !(bevent->state & GDK_CONTROL_MASK ) &&
-	    vflist_row_is_selected(vf, fd))
-		{
-		GtkTreeSelection *selection;
-
-		gtk_widget_grab_focus(widget);
-
-
-		/* returning FALSE and further processing of the event is needed for
-		   correct operation of the expander, to show the sidecar files.
-		   It however resets the selection of multiple files. With this condition
-		   it should work for both cases */
-		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
-		return (gtk_tree_selection_count_selected_rows(selection) > 1);
-		}
-
-	if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
-		{
-		if (vf->layout) layout_image_full_screen_start(vf->layout);
-		}
-
-	return FALSE;
-}
-
-gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreePath *tpath;
-	GtkTreeIter iter;
-	FileData *fd = NULL;
-
-	if (bevent->button == MOUSE_BUTTON_MIDDLE)
-		{
-		vflist_color_set(vf, VFLIST(vf)->click_fd, FALSE);
-		}
-
-	if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
-		{
-		return TRUE;
-		}
-
-	if ((bevent->x != 0 || bevent->y != 0) &&
-	    gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
-					  &tpath, NULL, NULL, NULL))
-		{
-		GtkTreeModel *store;
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-		gtk_tree_path_free(tpath);
-		}
-
-	if (bevent->button == MOUSE_BUTTON_MIDDLE)
-		{
-		if (fd && VFLIST(vf)->click_fd == fd)
-			{
-			GtkTreeSelection *selection;
-
-			selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
-			if (vflist_row_is_selected(vf, fd))
-				{
-				gtk_tree_selection_unselect_iter(selection, &iter);
-				}
-			else
-				{
-				gtk_tree_selection_select_iter(selection, &iter);
-				}
-			}
-		return TRUE;
-		}
-
-	if (fd && VFLIST(vf)->click_fd == fd &&
-	    !(bevent->state & GDK_SHIFT_MASK ) &&
-	    !(bevent->state & GDK_CONTROL_MASK ) &&
-	    vflist_row_is_selected(vf, fd))
-		{
-		GtkTreeSelection *selection;
-
-		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
-		gtk_tree_selection_unselect_all(selection);
-		gtk_tree_selection_select_iter(selection, &iter);
-		vflist_move_cursor(vf, &iter);
-		}
-
-	return FALSE;
-}
-
-static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
-{
-	FileData *read_ahead_fd = NULL;
-	gint row;
-	FileData *cur_fd;
-
-	if (!sel_fd) return;
-
-	cur_fd = layout_image_get_fd(vf->layout);
-	if (sel_fd == cur_fd) return; /* no change */
-
-	row = g_list_index(vf->list, sel_fd);
-	// FIXME sidecar data
-
-	if (sel_fd && options->image.enable_read_ahead && row >= 0)
-		{
-		if (row > g_list_index(vf->list, cur_fd) &&
-		    (guint) (row + 1) < vf_count(vf, NULL))
-			{
-			read_ahead_fd = vf_index_get_data(vf, row + 1);
-			}
-		else if (row > 0)
-			{
-			read_ahead_fd = vf_index_get_data(vf, row - 1);
-			}
-		}
-
-	layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
-}
-
-static gboolean vflist_select_idle_cb(gpointer data)
-{
-	ViewFile *vf = data;
-
-	if (!vf->layout)
-		{
-		VFLIST(vf)->select_idle_id = 0;
-		return FALSE;
-		}
-
-	vf_send_update(vf);
-
-	if (VFLIST(vf)->select_fd)
-		{
-		vflist_select_image(vf, VFLIST(vf)->select_fd);
-		VFLIST(vf)->select_fd = NULL;
-		}
-
-	VFLIST(vf)->select_idle_id = 0;
-	return FALSE;
-}
-
-static void vflist_select_idle_cancel(ViewFile *vf)
-{
-	if (VFLIST(vf)->select_idle_id)
-		{
-		g_source_remove(VFLIST(vf)->select_idle_id);
-		VFLIST(vf)->select_idle_id = 0;
-		}
-}
-
-static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
-				 gboolean path_currently_selected, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreeIter iter;
-
-	if (!path_currently_selected &&
-	    gtk_tree_model_get_iter(store, &iter, tpath))
-		{
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST(vf)->select_fd, -1);
-		}
-	else
-		{
-		VFLIST(vf)->select_fd = NULL;
-		}
-
-	if (vf->layout &&
-	    !VFLIST(vf)->select_idle_id)
-		{
-		VFLIST(vf)->select_idle_id = g_idle_add(vflist_select_idle_cb, vf);
-		}
-
-	return TRUE;
-}
-
-static void vflist_expand_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
-{
-	ViewFile *vf = data;
-	vflist_set_expanded(vf, iter, TRUE);
-}
-
-static void vflist_collapse_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
-{
-	ViewFile *vf = data;
-	vflist_set_expanded(vf, iter, FALSE);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * misc
- *-----------------------------------------------------------------------------
- */
-
-
-static gchar* vflist_get_formatted(ViewFile *vf, const gchar *name, const gchar *sidecars, const gchar *size, const gchar *time, gboolean expanded)
- {
-	gboolean multiline = vflist_is_multiline(vf);
-	gchar *text;
-
-	if (multiline)
-		{
-		text = g_strdup_printf("%s %s\n%s\n%s", name, expanded ? "" : sidecars, size, time);
-		}
-	else
-		{
-		text = g_strdup_printf("%s %s", name, expanded ? "" : sidecars);
-		}
-	return text;
-}
-
-static void vflist_set_expanded(ViewFile *vf, GtkTreeIter *iter, gboolean expanded)
-{
-	GtkTreeStore *store;
-	gchar *name;
-	gchar *sidecars;
-	gchar *size;
-	gchar *time;
-	gchar *formatted;
-
-	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-
-	gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
-					FILE_COLUMN_NAME, &name,
-					FILE_COLUMN_SIDECARS, &sidecars,
-					FILE_COLUMN_SIZE, &size,
-					FILE_COLUMN_DATE, &time,
-					-1);
-	formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
-
-	gtk_tree_store_set(store, iter, FILE_COLUMN_FORMATTED, formatted,
-					FILE_COLUMN_EXPANDED, expanded,
-					-1);
-	g_free(time);
-	g_free(size);
-	g_free(sidecars);
-	g_free(name);
-	g_free(formatted);
-}
-
-static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
-{
-	gchar *size;
-	gchar *sidecars = NULL;
-	gchar *name;
-	const gchar *time = text_from_time(fd->date);
-	gchar *link = islink(fd->path) ? GQ_LINK_STR : "";
-	const gchar *disabled_grouping;
-	gchar *formatted;
-	gboolean expanded = FALSE;
-
-	if (fd->sidecar_files) /* expanded has no effect on files without sidecars */
-		{
-		gtk_tree_model_get(GTK_TREE_MODEL(store), iter, FILE_COLUMN_EXPANDED, &expanded, -1);
-		}
-
-	sidecars = file_data_sc_list_to_string(fd);
-
-	disabled_grouping = fd->disable_grouping ? _(" [NO GROUPING]") : "";
-	name = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping);
-	size = text_from_size(fd->size);
-
-	formatted = vflist_get_formatted(vf, name, sidecars, size, time, expanded);
-
-	gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
-					FILE_COLUMN_VERSION, fd->version,
-					FILE_COLUMN_THUMB, fd->thumb_pixbuf,
-					FILE_COLUMN_FORMATTED, formatted,
-					FILE_COLUMN_SIDECARS, sidecars,
-					FILE_COLUMN_NAME, name,
-					FILE_COLUMN_SIZE, size,
-					FILE_COLUMN_DATE, time,
-#define STORE_SET_IS_SLOW 1
-#if STORE_SET_IS_SLOW
-/* this is 3x faster on a directory with 20000 files */
-					FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
-					FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
-					FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
-					FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
-					FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
-					FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
-#if FILEDATA_MARKS_SIZE != 6
-#error this needs to be updated
-#endif
-#endif
-					FILE_COLUMN_COLOR, FALSE, -1);
-
-#if !STORE_SET_IS_SLOW
-	{
-	gint i;
-	for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
-		gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
-	}
-#endif
-	g_free(size);
-	g_free(sidecars);
-	g_free(name);
-	g_free(formatted);
-}
-
-static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected, gboolean force)
-{
-	GList *work;
-	GtkTreeIter iter;
-	gboolean valid;
-	gint num_ordered = 0;
-	gint num_prepended = 0;
-
-	valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
-
-	work = list;
-	while (work)
-		{
-		gint match;
-		FileData *fd = work->data;
-		gboolean done = FALSE;
-
-		while (!done)
-			{
-			FileData *old_fd = NULL;
-			gint old_version = 0;
-
-			if (valid)
-				{
-				gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
-						   FILE_COLUMN_POINTER, &old_fd,
-						   FILE_COLUMN_VERSION, &old_version,
-						   -1);
-
-				if (fd == old_fd)
-					{
-					match = 0;
-					}
-				else
-					{
-					if (parent_iter)
-						match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
-					else
-						match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
-
-					if (match == 0) g_warning("multiple fd for the same path");
-					}
-
-				}
-			else
-				{
-				match = -1;
-				}
-
-			if (match < 0)
-				{
-				GtkTreeIter new;
-
-				if (valid)
-					{
-					num_ordered++;
-					gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
-					}
-				else
-					{
-					/*
-					    here should be used gtk_tree_store_append, but this function seems to be O(n)
-					    and it seems to be much faster to add new entries to the beginning and reorder later
-					*/
-					num_prepended++;
-					gtk_tree_store_prepend(store, &new, parent_iter);
-					}
-
-				vflist_setup_iter(vf, store, &new, file_data_ref(fd));
-				vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected, force);
-
-				if (g_list_find(selected, fd))
-					{
-					/* renamed files - the same fd appears at different position - select it again*/
-					GtkTreeSelection *selection;
-					selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-					gtk_tree_selection_select_iter(selection, &new);
-					}
-
-				done = TRUE;
-				}
-			else if (match > 0)
-				{
-				file_data_unref(old_fd);
-				valid = gtk_tree_store_remove(store, &iter);
-				}
-			else
-				{
-				num_ordered++;
-				if (fd->version != old_version || force)
-					{
-					vflist_setup_iter(vf, store, &iter, fd);
-					vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected, force);
-					}
-
-				if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
-
-				done = TRUE;
-				}
-			}
-		work = work->next;
-		}
-
-	while (valid)
-		{
-		FileData *old_fd;
-		gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
-		file_data_unref(old_fd);
-
-		valid = gtk_tree_store_remove(store, &iter);
-		}
-
-	/* move the prepended entries to the correct position */
-	if (num_prepended)
-		{
-		gint i;
-		gint num_total = num_prepended + num_ordered;
-		gint *new_order = g_malloc(num_total * sizeof(gint));
-
-		for (i = 0; i < num_total; i++)
-			{
-			if (i < num_ordered)
-				new_order[i] = num_prepended + i;
-			else
-				new_order[i] = num_total - 1 - i;
-			}
-		gtk_tree_store_reorder(store, parent_iter, new_order);
-
-		g_free(new_order);
-		}
-}
-
-void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend)
-{
-	gint i;
-	GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
-	gint *new_order;
-	GtkTreeStore *store;
-	GList *work;
-
-	if (vf->sort_method == type && vf->sort_ascend == ascend) return;
-	if (!vf->list) return;
-
-	work = vf->list;
-	i = 0;
-	while (work)
-		{
-		FileData *fd = work->data;
-		g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
-		i++;
-		work = work->next;
-		}
-
-	vf->sort_method = type;
-	vf->sort_ascend = ascend;
-
-	vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
-
-	new_order = g_malloc(i * sizeof(gint));
-
-	work = vf->list;
-	i = 0;
-	while (work)
-		{
-		FileData *fd = work->data;
-		new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
-		i++;
-		work = work->next;
-		}
-
-	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-	gtk_tree_store_reorder(store, NULL, new_order);
-
-	g_free(new_order);
-	g_hash_table_destroy(fd_idx_hash);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * thumb updates
- *-----------------------------------------------------------------------------
- */
-
-
-void vflist_thumb_progress_count(GList *list, gint *count, gint *done)
-{
-	GList *work = list;
-	while (work)
-		{
-		FileData *fd = work->data;
-		work = work->next;
-
-		if (fd->thumb_pixbuf) (*done)++;
-
-		if (fd->sidecar_files)
-			{
-			vflist_thumb_progress_count(fd->sidecar_files, count, done);
-			}
-		(*count)++;
-		}
-}
-
-void vflist_set_thumb_fd(ViewFile *vf, FileData *fd)
-{
-	GtkTreeStore *store;
-	GtkTreeIter iter;
-
-	if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
-
-	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-	gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->thumb_pixbuf, -1);
-}
-
-FileData *vflist_thumb_next_fd(ViewFile *vf)
-{
-	GtkTreePath *tpath;
-	FileData *fd = NULL;
-
-	/* first check the visible files */
-
-	if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
-		{
-		GtkTreeModel *store;
-		GtkTreeIter iter;
-		gboolean valid = TRUE;
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_path_free(tpath);
-
-		while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
-			{
-			FileData *nfd;
-
-			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &nfd, -1);
-
-			if (!nfd->thumb_pixbuf) fd = nfd;
-
-			valid = gtk_tree_model_iter_next(store, &iter);
-			}
-		}
-
-	/* then find first undone */
-
-	if (!fd)
-		{
-		GList *work = vf->list;
-		while (work && !fd)
-			{
-			FileData *fd_p = work->data;
-			if (!fd_p->thumb_pixbuf)
-				fd = fd_p;
-			else
-				{
-				GList *work2 = fd_p->sidecar_files;
-
-				while (work2 && !fd)
-					{
-					fd_p = work2->data;
-					if (!fd_p->thumb_pixbuf) fd = fd_p;
-					work2 = work2->next;
-					}
-				}
-			work = work->next;
-			}
-		}
-
-	return fd;
-}
-
-
-void vflist_thumb_reset_all(ViewFile *vf)
-{
-	GList *work = vf->list;
-	while (work)
-		{
-		FileData *fd = work->data;
-		if (fd->thumb_pixbuf)
-			{
-			g_object_unref(fd->thumb_pixbuf);
-			fd->thumb_pixbuf = NULL;
-			}
-		work = work->next;
-		}
-}
-
-/*
- *-----------------------------------------------------------------------------
- * row stuff
- *-----------------------------------------------------------------------------
- */
-
-FileData *vflist_index_get_data(ViewFile *vf, gint row)
-{
-	return g_list_nth_data(vf->list, row);
-}
-
-gint vflist_index_by_fd(ViewFile *vf, FileData *fd)
-{
-	gint p = 0;
-	GList *work, *work2;
-
-	work = vf->list;
-	while (work)
-		{
-		FileData *list_fd = work->data;
-		if (list_fd == fd) return p;
-
-		work2 = list_fd->sidecar_files;
-		while (work2)
-			{
-			/* FIXME: return the same index also for sidecars
-			   it is sufficient for next/prev navigation but it should be rewritten
-			   without using indexes at all
-			*/
-			FileData *sidecar_fd = work2->data;
-			if (sidecar_fd == fd) return p;
-			work2 = work2->next;
-			}
-
-		work = work->next;
-		p++;
-		}
-
-	return -1;
-}
-
-guint vflist_count(ViewFile *vf, gint64 *bytes)
-{
-	if (bytes)
-		{
-		gint64 b = 0;
-		GList *work;
-
-		work = vf->list;
-		while (work)
-			{
-			FileData *fd = work->data;
-			work = work->next;
-			b += fd->size;
-			}
-
-		*bytes = b;
-		}
-
-	return g_list_length(vf->list);
-}
-
-GList *vflist_get_list(ViewFile *vf)
-{
-	GList *list = NULL;
-	GList *work;
-
-	work = vf->list;
-	while (work)
-		{
-		FileData *fd = work->data;
-		work = work->next;
-
-		list = g_list_prepend(list, file_data_ref(fd));
-		}
-
-	return g_list_reverse(list);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * selections
- *-----------------------------------------------------------------------------
- */
-
-static gboolean vflist_row_is_selected(ViewFile *vf, FileData *fd)
-{
-	GtkTreeModel *store;
-	GtkTreeSelection *selection;
-	GList *slist;
-	GList *work;
-	gboolean found = FALSE;
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	slist = gtk_tree_selection_get_selected_rows(selection, &store);
-	work = slist;
-	while (!found && work)
-		{
-		GtkTreePath *tpath = work->data;
-		FileData *fd_n;
-		GtkTreeIter iter;
-
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
-		if (fd_n == fd) found = TRUE;
-		work = work->next;
-		}
-	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
-	g_list_free(slist);
-
-	return found;
-}
-
-gboolean vflist_index_is_selected(ViewFile *vf, gint row)
-{
-	FileData *fd;
-
-	fd = vf_index_get_data(vf, row);
-	return vflist_row_is_selected(vf, fd);
-}
-
-guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
-{
-	GtkTreeModel *store;
-	GtkTreeSelection *selection;
-	GList *slist;
-	guint count;
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	slist = gtk_tree_selection_get_selected_rows(selection, &store);
-
-	if (bytes)
-		{
-		gint64 b = 0;
-		GList *work;
-
-		work = slist;
-		while (work)
-			{
-			GtkTreePath *tpath = work->data;
-			GtkTreeIter iter;
-			FileData *fd;
-
-			gtk_tree_model_get_iter(store, &iter, tpath);
-			gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-			b += fd->size;
-
-			work = work->next;
-			}
-
-		*bytes = b;
-		}
-
-	count = g_list_length(slist);
-	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
-	g_list_free(slist);
-
-	return count;
-}
-
-GList *vflist_selection_get_list(ViewFile *vf)
-{
-	GtkTreeModel *store;
-	GtkTreeSelection *selection;
-	GList *slist;
-	GList *list = NULL;
-	GList *work;
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	slist = gtk_tree_selection_get_selected_rows(selection, &store);
-	work = slist;
-	while (work)
-		{
-		GtkTreePath *tpath = work->data;
-		FileData *fd;
-		GtkTreeIter iter;
-
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-
-		list = g_list_prepend(list, file_data_ref(fd));
-
-		if (!fd->parent && !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vf->listview), tpath))
-			{
-			/* unexpanded - add whole group */
-			GList *work2 = fd->sidecar_files;
-			while (work2)
-				{
-				FileData *sfd = work2->data;
-				list = g_list_prepend(list, file_data_ref(sfd));
-				work2 = work2->next;
-				}
-			}
-
-		work = work->next;
-		}
-	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
-	g_list_free(slist);
-
-	return g_list_reverse(list);
-}
-
-GList *vflist_selection_get_list_by_index(ViewFile *vf)
-{
-	GtkTreeModel *store;
-	GtkTreeSelection *selection;
-	GList *slist;
-	GList *list = NULL;
-	GList *work;
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	slist = gtk_tree_selection_get_selected_rows(selection, &store);
-	work = slist;
-	while (work)
-		{
-		GtkTreePath *tpath = work->data;
-		FileData *fd;
-		GtkTreeIter iter;
-
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-
-		list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
-
-		work = work->next;
-		}
-	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
-	g_list_free(slist);
-
-	return g_list_reverse(list);
-}
-
-void vflist_select_all(ViewFile *vf)
-{
-	GtkTreeSelection *selection;
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_selection_select_all(selection);
-
-	VFLIST(vf)->select_fd = NULL;
-}
-
-void vflist_select_none(ViewFile *vf)
-{
-	GtkTreeSelection *selection;
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_selection_unselect_all(selection);
-}
-
-static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
-{
-	GtkTreePath *tpath;
-	gboolean result;
-
-	tpath = gtk_tree_model_get_path(store, iter);
-	result = gtk_tree_path_prev(tpath);
-	if (result)
-		gtk_tree_model_get_iter(store, iter, tpath);
-
-	gtk_tree_path_free(tpath);
-
-	return result;
-}
-
-static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
-{
-	if (!gtk_tree_model_get_iter_first(store, iter))
-		return FALSE;
-
-	while (TRUE)
-		{
-		GtkTreeIter next = *iter;
-
-		if (gtk_tree_model_iter_next(store, &next))
-			*iter = next;
-		else
-			break;
-		}
-
-	return TRUE;
-}
-
-void vflist_select_invert(ViewFile *vf)
-{
-	GtkTreeIter iter;
-	GtkTreeSelection *selection;
-	GtkTreeModel *store;
-	gboolean valid;
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-
-	/* Backward iteration prevents scrolling to the end of the list,
-	 * it scrolls to the first selected row instead. */
-	valid = tree_model_get_iter_last(store, &iter);
-
-	while (valid)
-		{
-		gboolean selected = gtk_tree_selection_iter_is_selected(selection, &iter);
-
-		if (selected)
-			gtk_tree_selection_unselect_iter(selection, &iter);
-		else
-			gtk_tree_selection_select_iter(selection, &iter);
-
-		valid = tree_model_iter_prev(store, &iter);
-		}
-}
-
-void vflist_select_by_fd(ViewFile *vf, FileData *fd)
-{
-	GtkTreeIter iter;
-
-	if (vflist_find_row(vf, fd, &iter) < 0) return;
-
-	tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
-
-	if (!vflist_row_is_selected(vf, fd))
-		{
-		GtkTreeSelection *selection;
-		GtkTreeModel *store;
-		GtkTreePath *tpath;
-
-		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-		gtk_tree_selection_unselect_all(selection);
-		gtk_tree_selection_select_iter(selection, &iter);
-		vflist_move_cursor(vf, &iter);
-
-		store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-		tpath = gtk_tree_model_get_path(store, &iter);
-		gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
-		gtk_tree_path_free(tpath);
-		}
-}
-
-static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
-{
-	GList *work;
-	FileData *fd = NULL;
-
-	if (sel_fd->parent) sel_fd = sel_fd->parent;
-	work = vf->list;
-
-	while (work)
-		{
-		gint match;
-		fd = work->data;
-		work = work->next;
-
-		match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
-
-		if (match >= 0) break;
-		}
-
-	if (fd) vflist_select_by_fd(vf, fd);
-
-}
-
-void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
-{
-	GtkTreeModel *store;
-	GtkTreeIter iter;
-	GtkTreeSelection *selection;
-	gboolean valid;
-	gint n = mark - 1;
-
-	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
-
-	store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-
-	valid = gtk_tree_model_get_iter_first(store, &iter);
-	while (valid)
-		{
-		FileData *fd;
-		gboolean mark_val, selected;
-		gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
-
-		mark_val = file_data_get_mark(fd, n);
-		selected = gtk_tree_selection_iter_is_selected(selection, &iter);
-
-		switch (mode)
-			{
-			case MTS_MODE_SET: selected = mark_val;
-				break;
-			case MTS_MODE_OR: selected = mark_val || selected;
-				break;
-			case MTS_MODE_AND: selected = mark_val && selected;
-				break;
-			case MTS_MODE_MINUS: selected = !mark_val && selected;
-				break;
-			}
-
-		if (selected)
-			gtk_tree_selection_select_iter(selection, &iter);
-		else
-			gtk_tree_selection_unselect_iter(selection, &iter);
-
-		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
-		}
-}
-
-void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
-{
-	GtkTreeModel *store;
-	GtkTreeSelection *selection;
-	GList *slist;
-	GList *work;
-	gint n = mark - 1;
-
-	g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	slist = gtk_tree_selection_get_selected_rows(selection, &store);
-	work = slist;
-	while (work)
-		{
-		GtkTreePath *tpath = work->data;
-		FileData *fd;
-		GtkTreeIter iter;
-
-		gtk_tree_model_get_iter(store, &iter, tpath);
-		gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
-
-		/* the change has a very limited range and the standard notification would trigger
-		   complete re-read of the directory - try to do only minimal update instead */
-		file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
-
-		switch (mode)
-			{
-			case STM_MODE_SET: file_data_set_mark(fd, n, 1);
-				break;
-			case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
-				break;
-			case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
-				break;
-			}
-
-		if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
-			{
-			vf_refresh_idle(vf);
-			}
-		else
-			{
-			/* mark functions can have various side effects - update all columns to be sure */
-			vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
-			/* mark functions can change sidecars too */
-			vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
-			}
-
-
-		file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
-
-		work = work->next;
-		}
-	g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
-	g_list_free(slist);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * core (population)
- *-----------------------------------------------------------------------------
- */
-
-static void vflist_listview_set_columns(GtkWidget *listview, gboolean thumb, gboolean multiline)
-{
-	GtkTreeViewColumn *column;
-	GtkCellRenderer *cell;
-	GList *list;
-
-	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_THUMB);
-	if (!column) return;
-
-	gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 4);
-
-	list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
-	if (!list) return;
-	cell = list->data;
-	g_list_free(list);
-
-	g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
-	gtk_tree_view_column_set_visible(column, thumb);
-
-	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_FORMATTED);
-	if (!column) return;
-	gtk_tree_view_set_expander_column(GTK_TREE_VIEW(listview), column);
-
-	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_SIZE);
-	if (!column) return;
-	gtk_tree_view_column_set_visible(column, !multiline);
-
-	column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), FILE_VIEW_COLUMN_DATE);
-	if (!column) return;
-	gtk_tree_view_column_set_visible(column, !multiline);
-}
-
-static gboolean vflist_is_multiline(ViewFile *vf)
-{
-	return (VFLIST(vf)->thumbs_enabled && options->thumbnails.max_height >= 48);
-}
-
-
-static void vflist_populate_view(ViewFile *vf, gboolean force)
-{
-	GtkTreeStore *store;
-	GList *selected;
-
-	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-
-	vf_thumb_stop(vf);
-
-	if (!vf->list)
-		{
-		vflist_store_clear(vf, FALSE);
-		vf_send_update(vf);
-		return;
-		}
-
-	vflist_listview_set_columns(vf->listview, VFLIST(vf)->thumbs_enabled, vflist_is_multiline(vf));
-
-	selected = vflist_selection_get_list(vf);
-
-	vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected, force);
-
-	if (selected && vflist_selection_count(vf, NULL) == 0)
-		{
-		/* all selected files disappeared */
-		vflist_select_closest(vf, selected->data);
-		}
-
-	filelist_free(selected);
-
-	vf_send_update(vf);
-	vf_thumb_update(vf);
-}
-
-gboolean vflist_refresh(ViewFile *vf)
-{
-	GList *old_list;
-	gboolean ret = TRUE;
-
-	old_list = vf->list;
-	vf->list = NULL;
-
-	DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
-	if (vf->dir_fd)
-		{
-		file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
-
-		ret = filelist_read(vf->dir_fd, &vf->list, NULL);
-
-		if (vf->marks_enabled)
-		        {
-		        // When marks are enabled, lock FileDatas so that we don't end up re-parsing XML
-		        // each time a mark is changed.
-		        file_data_lock_list(vf->list);
-		        }
-	        else
-			{
-			// FIXME: only do this when needed (aka when we just switched from
-			// FIXME: marks-enabled to marks-disabled)
-			file_data_unlock_list(vf->list);
-			}
-
-		vf->list = file_data_filter_marks_list(vf->list, vf_marks_get_filter(vf));
-		file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
-
-		DEBUG_1("%s vflist_refresh: sort", get_exec_time());
-		vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
-		}
-
-	DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
-
-	vflist_populate_view(vf, FALSE);
-
-	DEBUG_1("%s vflist_refresh: free filelist", get_exec_time());
-
-	filelist_free(old_list);
-	DEBUG_1("%s vflist_refresh: done", get_exec_time());
-
-	return ret;
-}
-
-
-
-/* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
-
-#define CELL_HEIGHT_OVERRIDE 512
-
-static void cell_renderer_height_override(GtkCellRenderer *renderer)
-{
-	GParamSpec *spec;
-
-	spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
-	if (spec && G_IS_PARAM_SPEC_INT(spec))
-		{
-		GParamSpecInt *spec_int;
-
-		spec_int = G_PARAM_SPEC_INT(spec);
-		if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
-		}
-}
-
-static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
-{
-	static GdkColor color;
-	static GtkWidget *done = NULL;
-
-	if (done != widget)
-		{
-		GtkStyle *style;
-
-		style = gtk_widget_get_style(widget);
-		memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
-		shift_color(&color, -1, 0);
-		done = widget;
-		}
-
-	return &color;
-}
-
-static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
-				     GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
-{
-	ViewFile *vf = data;
-	gboolean set;
-
-	gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
-	g_object_set(G_OBJECT(cell),
-		     "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
-		     "cell-background-set", set, NULL);
-}
-
-static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gboolean image, gboolean right_justify, gboolean expand)
-{
-	GtkTreeViewColumn *column;
-	GtkCellRenderer *renderer;
-
-	column = gtk_tree_view_column_new();
-	gtk_tree_view_column_set_title(column, title);
-	gtk_tree_view_column_set_min_width(column, 4);
-
-	if (!image)
-		{
-		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
-		renderer = gtk_cell_renderer_text_new();
-		if (right_justify)
-			{
-			g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
-			}
-		gtk_tree_view_column_pack_start(column, renderer, TRUE);
-		gtk_tree_view_column_add_attribute(column, renderer, "text", n);
-		if (expand)
-			gtk_tree_view_column_set_expand(column, TRUE);
-		}
-	else
-		{
-		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
-		renderer = gtk_cell_renderer_pixbuf_new();
-		cell_renderer_height_override(renderer);
-		gtk_tree_view_column_pack_start(column, renderer, TRUE);
-		gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
-		}
-
-	gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
-	g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
-	g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
-
-	gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
-}
-
-static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
-{
-	ViewFile *vf = data;
-	GtkTreeStore *store;
-	GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
-	GtkTreeIter iter;
-	FileData *fd;
-	gboolean marked;
-	guint col_idx;
-
-	store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
-	if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
-		return;
-
-	col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
-
-	g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
-
-	gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &marked, -1);
-	marked = !marked;
-
-	/* the change has a very limited range and the standard notification would trigger
-	   complete re-read of the directory - try to do only minimal update instead */
-	file_data_unregister_notify_func(vf_notify_cb, vf);
-	file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, marked);
-	if (!file_data_filter_marks(fd, vf_marks_get_filter(vf))) /* file no longer matches the filter -> remove it */
-		{
-		vf_refresh_idle(vf);
-		}
-	else
-		{
-		/* mark functions can have various side effects - update all columns to be sure */
-		vflist_setup_iter(vf, GTK_TREE_STORE(store), &iter, fd);
-		/* mark functions can change sidecars too */
-		vflist_setup_iter_recursive(vf, GTK_TREE_STORE(store), &iter, fd->sidecar_files, NULL, FALSE);
-		}
-	file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
-
-	gtk_tree_path_free(path);
-}
-
-static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
-{
-	GtkTreeViewColumn *column;
-	GtkCellRenderer *renderer;
-
-	renderer = gtk_cell_renderer_toggle_new();
-	column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
-
-	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
-	g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
-	g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
-
-	gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
-	gtk_tree_view_column_set_fixed_width(column, 22);
-	gtk_tree_view_column_set_visible(column, vf->marks_enabled);
-
-
-	g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
-}
-
-/*
- *-----------------------------------------------------------------------------
- * base
- *-----------------------------------------------------------------------------
- */
-
-gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd)
-{
-	gboolean ret;
-	if (!dir_fd) return FALSE;
-	if (vf->dir_fd == dir_fd) return TRUE;
-
-	file_data_unref(vf->dir_fd);
-	vf->dir_fd = file_data_ref(dir_fd);
-
-	/* force complete reload */
-	vflist_store_clear(vf, TRUE);
-
-	filelist_free(vf->list);
-	vf->list = NULL;
-
-	ret = vf_refresh(vf);
-	gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
-	return ret;
-}
-
-void vflist_destroy_cb(GtkWidget *widget, gpointer data)
-{
-	ViewFile *vf = data;
-
-	file_data_unregister_notify_func(vf_notify_cb, vf);
-
-	vflist_select_idle_cancel(vf);
-	vf_refresh_idle_cancel(vf);
-	vf_thumb_stop(vf);
-
-	filelist_free(vf->list);
-}
-
-ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
-{
-	GtkTreeStore *store;
-	GtkTreeSelection *selection;
-	GType flist_types[FILE_COLUMN_COUNT];
-	gint i;
-	gint column;
-
-	vf->info = g_new0(ViewFileInfoList, 1);
-
-	flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
-	flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
-	flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
-	flist_types[FILE_COLUMN_FORMATTED] = G_TYPE_STRING;
-	flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
-	flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
-	flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
-	flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
-	flist_types[FILE_COLUMN_EXPANDED] = G_TYPE_BOOLEAN;
-	flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
-	for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
-		flist_types[i] = G_TYPE_BOOLEAN;
-
-	store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
-
-	vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
-	g_object_unref(store);
-
-	g_signal_connect(G_OBJECT(vf->listview), "row-expanded",
-			 G_CALLBACK(vflist_expand_cb), vf);
-
-	g_signal_connect(G_OBJECT(vf->listview), "row-collapsed",
-			 G_CALLBACK(vflist_collapse_cb), vf);
-
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
-	gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
-	gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
-
-	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
-	gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
-
-	column = 0;
-
-	for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
-		{
-		vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
-		g_assert(column == FILE_VIEW_COLUMN_MARKS + i);
-		column++;
-		}
-
-	vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
-	g_assert(column == FILE_VIEW_COLUMN_THUMB);
-	column++;
-
-	vflist_listview_add_column(vf, FILE_COLUMN_FORMATTED, _("Name"), FALSE, FALSE, TRUE);
-	g_assert(column == FILE_VIEW_COLUMN_FORMATTED);
-	column++;
-
-	vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
-	g_assert(column == FILE_VIEW_COLUMN_SIZE);
-	column++;
-
-	vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
-	g_assert(column == FILE_VIEW_COLUMN_DATE);
-	column++;
-
-	file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
-	return vf;
-}
-
-void vflist_thumb_set(ViewFile *vf, gboolean enable)
-{
-	if (VFLIST(vf)->thumbs_enabled == enable) return;
-
-	VFLIST(vf)->thumbs_enabled = enable;
-
-	/* vflist_populate_view is better than vf_refresh:
-	   - no need to re-read the directory
-	   - force update because the formatted string has changed
-	*/
-	if (vf->layout)
-		{
-		vflist_populate_view(vf, TRUE);
-		gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview));
-		}
-}
-
-void vflist_marks_set(ViewFile *vf, gboolean enable)
-{
-	GList *columns, *work;
-
-	columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
-
-	work = columns;
-	while (work)
-		{
-		GtkTreeViewColumn *column = work->data;
-		gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
-		work = work->next;
-
-		if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
-			gtk_tree_view_column_set_visible(column, enable);
-		}
-
-	if (enable)
-		{
-		// Previously disabled, which means that vf->list is complete
-		file_data_lock_list(vf->list);
-		}
-	else
-		{
-		// Previously enabled, which means that vf->list is incomplete
-		}
-
-	g_list_free(columns);
-}
-
-/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/view_file_list.h	Thu Jun 29 11:05:59 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2004 John Ellis
- * Copyright (C) 2008 - 2016 The Geeqie Team
- *
- * Author: John Ellis
- *
- * 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 VIEW_FILE_LIST_H
-#define VIEW_FILE_LIST_H
-
-
-#include "filedata.h"
-
-gboolean vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data);
-gboolean vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
-gboolean vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
-
-void vflist_dnd_init(ViewFile *vf);
-
-void vflist_destroy_cb(GtkWidget *widget, gpointer data);
-ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd);
-
-gboolean vflist_set_fd(ViewFile *vf, FileData *dir_fd);
-gboolean vflist_refresh(ViewFile *vf);
-
-void vflist_thumb_set(ViewFile *vf, gboolean enable);
-void vflist_marks_set(ViewFile *vf, gboolean enable);
-void vflist_sort_set(ViewFile *vf, SortType type, gboolean ascend);
-
-GList *vflist_selection_get_one(ViewFile *vf, FileData *fd);
-GList *vflist_pop_menu_file_list(ViewFile *vf);
-void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data);
-void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data);
-void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data);
-void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data);
-void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data);
-
-FileData *vflist_index_get_data(ViewFile *vf, gint row);
-gint vflist_index_by_fd(ViewFile *vf, FileData *fd);
-guint vflist_count(ViewFile *vf, gint64 *bytes);
-GList *vflist_get_list(ViewFile *vf);
-
-gboolean vflist_index_is_selected(ViewFile *vf, gint row);
-guint vflist_selection_count(ViewFile *vf, gint64 *bytes);
-GList *vflist_selection_get_list(ViewFile *vf);
-GList *vflist_selection_get_list_by_index(ViewFile *vf);
-
-void vflist_select_all(ViewFile *vf);
-void vflist_select_none(ViewFile *vf);
-void vflist_select_invert(ViewFile *vf);
-void vflist_select_by_fd(ViewFile *vf, FileData *fd);
-
-void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode);
-void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode);
-
-void vflist_color_set(ViewFile *vf, FileData *fd, gboolean color_set);
-
-void vflist_thumb_progress_count(GList *list, gint *count, gint *done);
-void vflist_set_thumb_fd(ViewFile *vf, FileData *fd);
-FileData *vflist_thumb_next_fd(ViewFile *vf);
-void vflist_thumb_reset_all(ViewFile *vf);
-
-#endif
-/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */