Merge merge-requests '495' and '458'
authorKlaus Ethgen <Klaus@Ethgen.de>
Sat, 8 Jul 2017 09:24:19 +0000 (10:24 +0100)
committerKlaus Ethgen <Klaus@Ethgen.de>
Sat, 8 Jul 2017 09:24:19 +0000 (10:24 +0100)
* github/merge-requests/495:
  Avoid c99 feature
  *phew* commented and simplified.
  Hopefully make it not crash
  It compiles!
  Remove all references to "IconData"
  update .gitignore
  Refactor: move view_file implementations to their own subdirectory.

* github/merge-requests/458:
  Add the ability to use regular expressions for Pan View keyword filtering.
  Add pan filtering to all of the pan view modes
  Revamp pan view filtering to support different modes and grouping.
  Move filter code into pan-fiew-filter.{c,h}
  Adds a keyword filtering feature to Timeline PanView.
  Pull the search UI construction code out into a distinct function.
  Start moving pan view search code to its own module

24 files changed:
.gitignore
src/Makefile.am
src/layout_image.c
src/layout_util.c
src/pan-view/Makefile.am
src/pan-view/pan-calendar.c
src/pan-view/pan-folder.c
src/pan-view/pan-grid.c
src/pan-view/pan-timeline.c
src/pan-view/pan-types.h
src/pan-view/pan-view-filter.c [new file with mode: 0644]
src/pan-view/pan-view-filter.h [new file with mode: 0644]
src/pan-view/pan-view-search.c [new file with mode: 0644]
src/pan-view/pan-view-search.h [new file with mode: 0644]
src/pan-view/pan-view.c
src/pan-view/pan-view.h
src/typedefs.h
src/view_file.c
src/view_file/Makefile.am [new file with mode: 0644]
src/view_file/view_file_common.c [new file with mode: 0644]
src/view_file/view_file_icon.c [moved from src/view_file_icon.c with 77% similarity]
src/view_file/view_file_icon.h [moved from src/view_file_icon.h with 96% similarity]
src/view_file/view_file_list.c [moved from src/view_file_list.c with 99% similarity]
src/view_file/view_file_list.h [moved from src/view_file_list.h with 97% similarity]

index 4b906f6..8654fd2 100644 (file)
@@ -73,6 +73,10 @@ Makefile.in
 /src/pan-view/.deps
 /src/pan-view/.dirstamp
 
+# /src/view_file/
+/src/view_file/.deps
+/src/view_file/.dirstamp
+
 /build-stamp
 /debian/geeqie*
 /debian/files
index 3900a39..15bdf1b 100644 (file)
@@ -81,12 +81,14 @@ extra_SLIK = \
        $(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 @@ geeqie_SOURCES = \
        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           \
index 0872612..8289cb7 100644 (file)
@@ -1070,7 +1070,6 @@ void layout_image_alter_orientation(LayoutWindow *lw, AlterType type)
        GtkTreePath *tpath;
        FileData *fd_n;
        GtkTreeIter iter;
-       IconData *id;
 
        if (!lw || !lw->vf) return;
 
@@ -1089,8 +1088,7 @@ void layout_image_alter_orientation(LayoutWindow *lw, AlterType type)
                {
                if (lw->vf->type == FILEVIEW_ICON)
                        {
-                       id = work->data;
-                       fd_n = id->fd;
+                       fd_n = work->data;
                        work = work->next;
                        }
                else
@@ -1120,7 +1118,6 @@ void layout_image_rating(LayoutWindow *lw, const gchar *rating)
        GtkTreePath *tpath;
        FileData *fd_n;
        GtkTreeIter iter;
-       IconData *id;
 
        if (!lw || !lw->vf) return;
 
@@ -1139,8 +1136,7 @@ void layout_image_rating(LayoutWindow *lw, const gchar *rating)
                {
                if (lw->vf->type == FILEVIEW_ICON)
                        {
-                       id = work->data;
-                       fd_n = id->fd;
+                       fd_n = work->data;
                        work = work->next;
                        }
                else
index fc431c8..106f8dc 100644 (file)
@@ -463,7 +463,6 @@ static void layout_menu_write_rotate(GtkToggleAction *action, gpointer data, gbo
        GtkTreePath *tpath;
        FileData *fd_n;
        GtkTreeIter iter;
-       IconData *id;
        gchar *rotation;
        gchar *command;
        gint run_result;
@@ -489,8 +488,7 @@ static void layout_menu_write_rotate(GtkToggleAction *action, gpointer data, gbo
                {
                if (lw->vf->type == FILEVIEW_ICON)
                        {
-                       id = work->data;
-                       fd_n = id->fd;
+                       fd_n = work->data;
                        work = work->next;
                        }
                else
index 70c9423..2401b5e 100644 (file)
@@ -13,4 +13,9 @@ module_pan_view = \
        %D%/pan-util.c  \
        %D%/pan-util.h  \
        %D%/pan-view.c  \
-       %D%/pan-view.h
+       %D%/pan-view.h  \
+       %D%/pan-view-filter.c   \
+       %D%/pan-view-filter.h   \
+       %D%/pan-view-search.c   \
+       %D%/pan-view-search.h
+
index 91aa003..3400fbb 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "pan-util.h"
 #include "pan-view.h"
+#include "pan-view-filter.h"
 #include "pixbuf_util.h"
 
 #define PAN_CAL_POPUP_COLOR 220, 220, 220
@@ -200,6 +201,7 @@ void pan_calendar_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *he
        gint end_month = 0;
 
        list = pan_list_tree(dir_fd, SORT_NONE, TRUE, pw->ignore_symlinks);
+       pan_filter_fd_list(&list, pw->filter_ui->filter_elements);
 
        if (pw->cache_list && pw->exif_date_enable)
                {
index 65ac306..95748ee 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "pan-item.h"
 #include "pan-util.h"
+#include "pan-view-filter.h"
 
 static void pan_flower_size(PanWindow *pw, gint *width, gint *height)
 {
@@ -242,6 +243,8 @@ static FlowerGroup *pan_flower_group(PanWindow *pw, FileData *dir_fd, gint x, gi
        f = filelist_sort(f, SORT_NAME, TRUE);
        d = filelist_sort(d, SORT_NAME, TRUE);
 
+       pan_filter_fd_list(&f, pw->filter_ui->filter_elements);
+
        pi_box = pan_item_text_new(pw, x, y, dir_fd->path, PAN_TEXT_ATTR_NONE,
                                   PAN_TEXT_BORDER_SIZE,
                                   PAN_TEXT_COLOR, 255);
@@ -386,6 +389,8 @@ static void pan_folder_tree_path(PanWindow *pw, FileData *dir_fd,
        f = filelist_sort(f, SORT_NAME, TRUE);
        d = filelist_sort(d, SORT_NAME, TRUE);
 
+       pan_filter_fd_list(&f, pw->filter_ui->filter_elements);
+
        *x = PAN_BOX_BORDER + ((*level) * MAX(PAN_BOX_BORDER, PAN_THUMB_GAP));
 
        pi_box = pan_item_text_new(pw, *x, *y, dir_fd->path, PAN_TEXT_ATTR_NONE,
index b441b83..5d28e4b 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "pan-item.h"
 #include "pan-util.h"
+#include "pan-view-filter.h"
 
 void pan_grid_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *height)
 {
@@ -35,6 +36,7 @@ void pan_grid_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *height
        gint next_y;
 
        list = pan_list_tree(dir_fd, SORT_NAME, TRUE, pw->ignore_symlinks);
+       pan_filter_fd_list(&list, pw->filter_ui->filter_elements);
 
        grid_size = (gint)sqrt((gdouble)g_list_length(list));
        if (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE)
index 9a96420..1162795 100644 (file)
 #include "pan-item.h"
 #include "pan-util.h"
 #include "pan-view.h"
+#include "pan-view-filter.h"
 
 void pan_timeline_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *height)
 {
        GList *list;
        GList *work;
        gint x, y;
-       time_t tc;
+       time_t group_start_date;
        gint total;
        gint count;
        PanItem *pi_month = NULL;
@@ -41,6 +42,7 @@ void pan_timeline_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *he
        gint y_height;
 
        list = pan_list_tree(dir_fd, SORT_NONE, TRUE, pw->ignore_symlinks);
+       pan_filter_fd_list(&list, pw->filter_ui->filter_elements);
 
        if (pw->cache_list && pw->exif_date_enable)
                {
@@ -61,7 +63,8 @@ void pan_timeline_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *he
        day_start = month_start;
        x_width = 0;
        y_height = 0;
-       tc = 0;
+       group_start_date = 0;
+       // total and count are used to enforce a stride of PAN_GROUP_MAX thumbs.
        total = 0;
        count = 0;
        work = list;
@@ -73,13 +76,15 @@ void pan_timeline_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *he
                fd = work->data;
                work = work->next;
 
-               if (!pan_date_compare(fd->date, tc, PAN_DATE_LENGTH_DAY))
+               if (!pan_date_compare(fd->date, group_start_date, PAN_DATE_LENGTH_DAY))
                        {
+                       // FD starts a new day group.
                        GList *needle;
                        gchar *buf;
 
-                       if (!pan_date_compare(fd->date, tc, PAN_DATE_LENGTH_MONTH))
+                       if (!pan_date_compare(fd->date, group_start_date, PAN_DATE_LENGTH_MONTH))
                                {
+                               // FD starts a new month group.
                                pi_day = NULL;
 
                                if (pi_month)
@@ -114,7 +119,7 @@ void pan_timeline_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *he
 
                        if (pi_day) x = pi_day->x + pi_day->width + PAN_BOX_BORDER;
 
-                       tc = fd->date;
+                       group_start_date = fd->date;
                        total = 1;
                        count = 0;
 
@@ -124,7 +129,7 @@ void pan_timeline_compute(PanWindow *pw, FileData *dir_fd, gint *width, gint *he
                                FileData *nfd;
 
                                nfd = needle->data;
-                               if (pan_date_compare(nfd->date, tc, PAN_DATE_LENGTH_DAY))
+                               if (pan_date_compare(nfd->date, group_start_date, PAN_DATE_LENGTH_DAY))
                                        {
                                        needle = needle->next;
                                        total++;
index 5318b38..9fd8916 100644 (file)
@@ -169,6 +169,19 @@ struct _PanItem {
        gboolean queued;
 };
 
+typedef struct _PanViewSearchUi PanViewSearchUi;
+struct _PanViewSearchUi
+{
+       GtkWidget *search_box;
+       GtkWidget *search_entry;
+       GtkWidget *search_label;
+       GtkWidget *search_button;
+       GtkWidget *search_button_arrow;
+};
+
+// Defined in pan-view-filter.h
+typedef struct _PanViewFilterUi PanViewFilterUi;
+
 typedef struct _PanWindow PanWindow;
 struct _PanWindow
 {
@@ -182,11 +195,8 @@ struct _PanWindow
        GtkWidget *label_message;
        GtkWidget *label_zoom;
 
-       GtkWidget *search_box;
-       GtkWidget *search_entry;
-       GtkWidget *search_label;
-       GtkWidget *search_button;
-       GtkWidget *search_button_arrow;
+       PanViewSearchUi *search_ui;
+       PanViewFilterUi *filter_ui;
 
        GtkWidget *date_button;
 
diff --git a/src/pan-view/pan-view-filter.c b/src/pan-view/pan-view-filter.c
new file mode 100644 (file)
index 0000000..5865d66
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * 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 "pan-view-filter.h"
+
+#include "image.h"
+#include "metadata.h"
+#include "pan-item.h"
+#include "pan-util.h"
+#include "pan-view.h"
+#include "ui_fileops.h"
+#include "ui_tabcomp.h"
+#include "ui_misc.h"
+
+PanViewFilterUi *pan_filter_ui_new(PanWindow *pw)
+{
+       PanViewFilterUi *ui = g_new0(PanViewFilterUi, 1);
+       GtkWidget *combo;
+       GtkWidget *hbox;
+
+       /* Since we're using the GHashTable as a HashSet (in which key and value pointers
+        * are always identical), specifying key _and_ value destructor callbacks will
+        * cause a double-free.
+        */
+       {
+               GtkTreeIter iter;
+               ui->filter_mode_model = gtk_list_store_new(3, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING);
+               gtk_list_store_append(ui->filter_mode_model, &iter);
+               gtk_list_store_set(ui->filter_mode_model, &iter,
+                                  0, PAN_VIEW_FILTER_REQUIRE, 1, _("Require"), 2, _("R"), -1);
+               gtk_list_store_append(ui->filter_mode_model, &iter);
+               gtk_list_store_set(ui->filter_mode_model, &iter,
+                                  0, PAN_VIEW_FILTER_EXCLUDE, 1, _("Exclude"), 2, _("E"), -1);
+               gtk_list_store_append(ui->filter_mode_model, &iter);
+               gtk_list_store_set(ui->filter_mode_model, &iter,
+                                  0, PAN_VIEW_FILTER_INCLUDE, 1, _("Include"), 2, _("I"), -1);
+               gtk_list_store_append(ui->filter_mode_model, &iter);
+               gtk_list_store_set(ui->filter_mode_model, &iter,
+                                  0, PAN_VIEW_FILTER_GROUP, 1, _("Group"), 2, _("G"), -1);
+
+               ui->filter_mode_combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(ui->filter_mode_model));
+               gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(ui->filter_mode_combo), FALSE);
+               gtk_combo_box_set_active(GTK_COMBO_BOX(ui->filter_mode_combo), 0);
+
+               GtkCellRenderer *render = gtk_cell_renderer_text_new();
+               gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(ui->filter_mode_combo), render, TRUE);
+               gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(ui->filter_mode_combo), render, "text", 1, NULL);
+       }
+
+       // Build the actual filter UI.
+       ui->filter_box = gtk_hbox_new(FALSE, PREF_PAD_SPACE);
+       pref_spacer(ui->filter_box, 0);
+       pref_label_new(ui->filter_box, _("Keyword Filter:"));
+
+       gtk_box_pack_start(GTK_BOX(ui->filter_box), ui->filter_mode_combo, TRUE, TRUE, 0);
+       gtk_widget_show(ui->filter_mode_combo);
+
+       hbox = gtk_hbox_new(TRUE, PREF_PAD_SPACE);
+       gtk_box_pack_start(GTK_BOX(ui->filter_box), hbox, TRUE, TRUE, 0);
+       gtk_widget_show(hbox);
+
+       combo = tab_completion_new_with_history(&ui->filter_entry, "", "pan_view_filter", -1,
+                                               pan_filter_activate_cb, pw);
+       gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
+       gtk_widget_show(combo);
+
+       // TODO(xsdg): Figure out whether it's useful to keep this label around.
+       ui->filter_label = gtk_label_new("");
+       //gtk_box_pack_start(GTK_BOX(hbox), ui->filter_label, FALSE, FALSE, 0);
+       //gtk_widget_show(ui->filter_label);
+
+       ui->filter_kw_hbox = gtk_hbox_new(FALSE, PREF_PAD_SPACE);
+       gtk_box_pack_start(GTK_BOX(hbox), ui->filter_kw_hbox, TRUE, TRUE, 0);
+       gtk_widget_show(ui->filter_kw_hbox);
+
+       // Build the spin-button to show/hide the filter UI.
+       ui->filter_button = gtk_toggle_button_new();
+       gtk_button_set_relief(GTK_BUTTON(ui->filter_button), GTK_RELIEF_NONE);
+       gtk_button_set_focus_on_click(GTK_BUTTON(ui->filter_button), FALSE);
+       hbox = gtk_hbox_new(FALSE, PREF_PAD_GAP);
+       gtk_container_add(GTK_CONTAINER(ui->filter_button), hbox);
+       gtk_widget_show(hbox);
+       ui->filter_button_arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_NONE);
+       gtk_box_pack_start(GTK_BOX(hbox), ui->filter_button_arrow, FALSE, FALSE, 0);
+       gtk_widget_show(ui->filter_button_arrow);
+       pref_label_new(hbox, _("Filter"));
+
+       g_signal_connect(G_OBJECT(ui->filter_button), "clicked",
+                        G_CALLBACK(pan_filter_toggle_cb), pw);
+
+       return ui;
+}
+
+void pan_filter_ui_destroy(PanViewFilterUi **ui_ptr)
+{
+       if (ui_ptr == NULL || *ui_ptr == NULL) return;
+
+       // Note that g_clear_pointer handles already-NULL pointers.
+       //g_clear_pointer(&(*ui_ptr)->filter_kw_table, g_hash_table_destroy);
+
+       g_free(*ui_ptr);
+       *ui_ptr = NULL;
+}
+
+static void pan_filter_status(PanWindow *pw, const gchar *text)
+{
+       gtk_label_set_text(GTK_LABEL(pw->filter_ui->filter_label), (text) ? text : "");
+}
+
+static void pan_filter_kw_button_cb(GtkButton *widget, gpointer data)
+{
+       PanFilterCallbackState *cb_state = data;
+       PanWindow *pw = cb_state->pw;
+       PanViewFilterUi *ui = pw->filter_ui;
+
+       // TODO(xsdg): Fix filter element pointed object memory leak.
+       ui->filter_elements = g_list_delete_link(ui->filter_elements, cb_state->filter_element);
+       gtk_widget_destroy(GTK_WIDGET(widget));
+       g_free(cb_state);
+
+       pan_filter_status(pw, _("Removed keyword…"));
+       pan_layout_update(pw);
+}
+
+void pan_filter_activate_cb(const gchar *text, gpointer data)
+{
+       GtkWidget *kw_button;
+       PanWindow *pw = data;
+       PanViewFilterUi *ui = pw->filter_ui;
+       GtkTreeIter iter;
+
+       if (!text) return;
+
+       // Get all relevant state and reset UI.
+       gtk_combo_box_get_active_iter(GTK_COMBO_BOX(ui->filter_mode_combo), &iter);
+       gtk_entry_set_text(GTK_ENTRY(ui->filter_entry), "");
+       tab_completion_append_to_history(ui->filter_entry, text);
+
+       // Add new filter element.
+       PanViewFilterElement *element = g_new0(PanViewFilterElement, 1);
+       gtk_tree_model_get(GTK_TREE_MODEL(ui->filter_mode_model), &iter, 0, &element->mode, -1);
+       element->keyword = g_strdup(text);
+       if (g_strcmp0(text, g_regex_escape_string(text, -1)))
+               {
+               // It's an actual regex, so compile
+               element->kw_regex = g_regex_new(text, G_REGEX_ANCHORED | G_REGEX_OPTIMIZE, G_REGEX_MATCH_ANCHORED, NULL);
+               }
+       ui->filter_elements = g_list_append(ui->filter_elements, element);
+
+       // Get the short version of the mode value.
+       gchar *short_mode;
+       gtk_tree_model_get(GTK_TREE_MODEL(ui->filter_mode_model), &iter, 2, &short_mode, -1);
+
+       // Create the button.
+       // TODO(xsdg): Use MVC so that the button list is an actual representation of the GList
+       gchar *label = g_strdup_printf("(%s) %s", short_mode, text);
+       kw_button = gtk_button_new_with_label(label);
+       g_clear_pointer(&label, g_free);
+
+       gtk_box_pack_start(GTK_BOX(ui->filter_kw_hbox), kw_button, FALSE, FALSE, 0);
+       gtk_widget_show(kw_button);
+
+       PanFilterCallbackState *cb_state = g_new0(PanFilterCallbackState, 1);
+       cb_state->pw = pw;
+       cb_state->filter_element = g_list_last(ui->filter_elements);
+
+       g_signal_connect(G_OBJECT(kw_button), "clicked",
+                        G_CALLBACK(pan_filter_kw_button_cb), cb_state);
+
+       pan_layout_update(pw);
+}
+
+void pan_filter_activate(PanWindow *pw)
+{
+       gchar *text;
+
+       text = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->filter_ui->filter_entry)));
+       pan_filter_activate_cb(text, pw);
+       g_free(text);
+}
+
+void pan_filter_toggle_cb(GtkWidget *button, gpointer data)
+{
+       PanWindow *pw = data;
+       PanViewFilterUi *ui = pw->filter_ui;
+       gboolean visible;
+
+       visible = gtk_widget_get_visible(ui->filter_box);
+       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == visible) return;
+
+       if (visible)
+               {
+               gtk_widget_hide(ui->filter_box);
+               gtk_arrow_set(GTK_ARROW(ui->filter_button_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE);
+               }
+       else
+               {
+               gtk_widget_show(ui->filter_box);
+               gtk_arrow_set(GTK_ARROW(ui->filter_button_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+               gtk_widget_grab_focus(ui->filter_entry);
+               }
+}
+
+void pan_filter_toggle_visible(PanWindow *pw, gboolean enable)
+{
+       PanViewFilterUi *ui = pw->filter_ui;
+       if (pw->fs) return;
+
+       if (enable)
+               {
+               if (gtk_widget_get_visible(ui->filter_box))
+                       {
+                       gtk_widget_grab_focus(ui->filter_entry);
+                       }
+               else
+                       {
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ui->filter_button), TRUE);
+                       }
+               }
+       else
+               {
+               if (gtk_widget_get_visible(ui->filter_entry))
+                       {
+                       if (gtk_widget_has_focus(ui->filter_entry))
+                               {
+                               gtk_widget_grab_focus(GTK_WIDGET(pw->imd->widget));
+                               }
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ui->filter_button), FALSE);
+                       }
+               }
+}
+
+static gboolean pan_view_list_contains_kw_pattern(GList *haystack, PanViewFilterElement *filter, gchar **found_kw)
+{
+       if (filter->kw_regex)
+               {
+               // regex compile succeeded; attempt regex match.
+               GList *work = g_list_first(haystack);
+               while (work)
+                       {
+                       gchar *keyword = work->data;
+                       work = work->next;
+                       if (g_regex_match(filter->kw_regex, keyword, 0x0, NULL))
+                               {
+                               if (found_kw) *found_kw = keyword;
+                               return TRUE;
+                               }
+                       }
+               return FALSE;
+               }
+       else
+               {
+               // regex compile failed; fall back to exact string match.
+               GList *found_elem = g_list_find_custom(haystack, filter->keyword, (GCompareFunc)g_strcmp0);
+               if (found_elem && found_kw) *found_kw = found_elem->data;
+               return !!found_elem;
+               }
+}
+
+gboolean pan_filter_fd_list(GList **fd_list, GList *filter_elements)
+{
+       GList *work;
+       gboolean modified = FALSE;
+       GHashTable *seen_kw_table = NULL;
+
+       if (!fd_list || !*fd_list || !filter_elements) return modified;
+
+       // seen_kw_table is only valid in this scope, so don't take ownership of any strings.
+       seen_kw_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+
+       work = *fd_list;
+       while (work)
+               {
+               FileData *fd = work->data;
+               GList *last_work = work;
+               work = work->next;
+
+               // TODO(xsdg): OPTIMIZATION Do the search inside of metadata.c to avoid a
+               // bunch of string list copies.
+               GList *img_keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
+
+               // TODO(xsdg): OPTIMIZATION Determine a heuristic for when to linear-search the
+               // keywords list, and when to build a hash table for the image's keywords.
+               gboolean should_reject = FALSE;
+               gchar *group_kw = NULL;
+               GList *filter_element = filter_elements;
+               while (filter_element)
+                       {
+                       PanViewFilterElement *filter = filter_element->data;
+                       filter_element = filter_element->next;
+                       gchar *found_kw = NULL;
+                       gboolean has_kw = pan_view_list_contains_kw_pattern(img_keywords, filter, &found_kw);
+
+                       switch (filter->mode)
+                               {
+                               case PAN_VIEW_FILTER_REQUIRE:
+                                       should_reject |= !has_kw;
+                                       break;
+                               case PAN_VIEW_FILTER_EXCLUDE:
+                                       should_reject |= has_kw;
+                                       break;
+                               case PAN_VIEW_FILTER_INCLUDE:
+                                       if (has_kw) should_reject = FALSE;
+                                       break;
+                               case PAN_VIEW_FILTER_GROUP:
+                                       if (has_kw)
+                                               {
+                                               if (g_hash_table_contains(seen_kw_table, found_kw))
+                                                       {
+                                                       should_reject = TRUE;
+                                                       }
+                                               else if (group_kw == NULL)
+                                                       {
+                                                       group_kw = found_kw;
+                                                       }
+                                               }
+                                       break;
+                               }
+                       }
+
+               if (!should_reject && group_kw != NULL) g_hash_table_add(seen_kw_table, group_kw);
+
+               group_kw = NULL;  // group_kw references an item from img_keywords.
+               string_list_free(img_keywords);
+
+               if (should_reject)
+                       {
+                       *fd_list = g_list_delete_link(*fd_list, last_work);
+                       modified = TRUE;
+                       }
+               }
+
+       g_hash_table_destroy(seen_kw_table);
+       return modified;
+}
diff --git a/src/pan-view/pan-view-filter.h b/src/pan-view/pan-view-filter.h
new file mode 100644 (file)
index 0000000..f3e3e11
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef PAN_VIEW_PAN_VIEW_FILTER_H
+#define PAN_VIEW_PAN_VIEW_FILTER_H
+
+#include "main.h"
+#include "pan-types.h"
+
+typedef enum {
+       PAN_VIEW_FILTER_REQUIRE,
+       PAN_VIEW_FILTER_EXCLUDE,
+       PAN_VIEW_FILTER_INCLUDE,
+       PAN_VIEW_FILTER_GROUP
+} PanViewFilterMode;
+
+typedef struct _PanViewFilterElement PanViewFilterElement;
+struct _PanViewFilterElement
+{
+       PanViewFilterMode mode;
+       gchar *keyword;
+       GRegex *kw_regex;
+};
+
+typedef struct _PanFilterCallbackState PanFilterCallbackState;
+struct _PanFilterCallbackState
+{
+       PanWindow *pw;
+       GList *filter_element;
+};
+
+struct _PanViewFilterUi
+{
+       GtkWidget *filter_box;
+       GtkWidget *filter_entry;
+       GtkWidget *filter_label;
+       GtkWidget *filter_button;
+       GtkWidget *filter_button_arrow;
+       GtkWidget *filter_kw_hbox;
+       GtkListStore *filter_mode_model;
+       GtkWidget *filter_mode_combo;
+       GList *filter_elements;  // List of PanViewFilterElement.
+};
+
+void pan_filter_toggle_visible(PanWindow *pw, gboolean enable);
+void pan_filter_activate(PanWindow *pw);
+void pan_filter_activate_cb(const gchar *text, gpointer data);
+void pan_filter_toggle_cb(GtkWidget *button, gpointer data);
+
+// Creates a new PanViewFilterUi instance and returns it.
+PanViewFilterUi *pan_filter_ui_new(PanWindow *pw);
+
+// Destroys the specified PanViewFilterUi and sets the pointer to NULL.
+void pan_filter_ui_destroy(PanViewFilterUi **ui);
+
+gboolean pan_filter_fd_list(GList **fd_list, GList *filter_elements);
+
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
diff --git a/src/pan-view/pan-view-search.c b/src/pan-view/pan-view-search.c
new file mode 100644 (file)
index 0000000..5ddef13
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * 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 "pan-view-search.h"
+
+#include "image.h"
+#include "pan-calendar.h"
+#include "pan-item.h"
+#include "pan-util.h"
+#include "pan-view.h"
+#include "ui_tabcomp.h"
+#include "ui_misc.h"
+
+PanViewSearchUi *pan_search_ui_new(PanWindow *pw)
+{
+       PanViewSearchUi *ui = g_new0(PanViewSearchUi, 1);
+       GtkWidget *combo;
+       GtkWidget *hbox;
+
+       // Build the actual search UI.
+       ui->search_box = gtk_hbox_new(FALSE, PREF_PAD_SPACE);
+       pref_spacer(ui->search_box, 0);
+       pref_label_new(ui->search_box, _("Find:"));
+
+       hbox = gtk_hbox_new(TRUE, PREF_PAD_SPACE);
+       gtk_box_pack_start(GTK_BOX(ui->search_box), hbox, TRUE, TRUE, 0);
+       gtk_widget_show(hbox);
+
+       combo = tab_completion_new_with_history(&ui->search_entry, "", "pan_view_search", -1,
+                                               pan_search_activate_cb, pw);
+       gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
+       gtk_widget_show(combo);
+
+       ui->search_label = gtk_label_new("");
+       gtk_box_pack_start(GTK_BOX(hbox), ui->search_label, TRUE, TRUE, 0);
+       gtk_widget_show(ui->search_label);
+
+       // Build the spin-button to show/hide the search UI.
+       ui->search_button = gtk_toggle_button_new();
+       gtk_button_set_relief(GTK_BUTTON(ui->search_button), GTK_RELIEF_NONE);
+       gtk_button_set_focus_on_click(GTK_BUTTON(ui->search_button), FALSE);
+       hbox = gtk_hbox_new(FALSE, PREF_PAD_GAP);
+       gtk_container_add(GTK_CONTAINER(ui->search_button), hbox);
+       gtk_widget_show(hbox);
+       ui->search_button_arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_NONE);
+       gtk_box_pack_start(GTK_BOX(hbox), ui->search_button_arrow, FALSE, FALSE, 0);
+       gtk_widget_show(ui->search_button_arrow);
+       pref_label_new(hbox, _("Find"));
+
+       g_signal_connect(G_OBJECT(ui->search_button), "clicked",
+                        G_CALLBACK(pan_search_toggle_cb), pw);
+
+       return ui;
+}
+
+void pan_search_ui_destroy(PanViewSearchUi **ui_ptr)
+{
+       if (ui_ptr == NULL || *ui_ptr == NULL) return;
+
+       g_free(*ui_ptr);
+       *ui_ptr = NULL;
+}
+
+static void pan_search_status(PanWindow *pw, const gchar *text)
+{
+       gtk_label_set_text(GTK_LABEL(pw->search_ui->search_label), (text) ? text : "");
+}
+
+static gint pan_search_by_path(PanWindow *pw, const gchar *path)
+{
+       PanItem *pi;
+       GList *list;
+       GList *found;
+       PanItemType type;
+       gchar *buf;
+
+       type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
+
+       list = pan_item_find_by_path(pw, type, path, FALSE, FALSE);
+       if (!list) return FALSE;
+
+       found = g_list_find(list, pw->click_pi);
+       if (found && found->next)
+               {
+               found = found->next;
+               pi = found->data;
+               }
+       else
+               {
+               pi = list->data;
+               }
+
+       pan_info_update(pw, pi);
+       image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5);
+
+       buf = g_strdup_printf("%s ( %d / %d )",
+                             (path[0] == G_DIR_SEPARATOR) ? _("path found") : _("filename found"),
+                             g_list_index(list, pi) + 1,
+                             g_list_length(list));
+       pan_search_status(pw, buf);
+       g_free(buf);
+
+       g_list_free(list);
+
+       return TRUE;
+}
+
+static gboolean pan_search_by_partial(PanWindow *pw, const gchar *text)
+{
+       PanItem *pi;
+       GList *list;
+       GList *found;
+       PanItemType type;
+       gchar *buf;
+
+       type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
+
+       list = pan_item_find_by_path(pw, type, text, TRUE, FALSE);
+       if (!list) list = pan_item_find_by_path(pw, type, text, FALSE, TRUE);
+       if (!list)
+               {
+               gchar *needle;
+
+               needle = g_utf8_strdown(text, -1);
+               list = pan_item_find_by_path(pw, type, needle, TRUE, TRUE);
+               g_free(needle);
+               }
+       if (!list) return FALSE;
+
+       found = g_list_find(list, pw->click_pi);
+       if (found && found->next)
+               {
+               found = found->next;
+               pi = found->data;
+               }
+       else
+               {
+               pi = list->data;
+               }
+
+       pan_info_update(pw, pi);
+       image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5);
+
+       buf = g_strdup_printf("%s ( %d / %d )",
+                             _("partial match"),
+                             g_list_index(list, pi) + 1,
+                             g_list_length(list));
+       pan_search_status(pw, buf);
+       g_free(buf);
+
+       g_list_free(list);
+
+       return TRUE;
+}
+
+static gboolean valid_date_separator(gchar c)
+{
+       return (c == '/' || c == '-' || c == ' ' || c == '.' || c == ',');
+}
+
+static GList *pan_search_by_date_val(PanWindow *pw, PanItemType type,
+                                    gint year, gint month, gint day,
+                                    const gchar *key)
+{
+       GList *list = NULL;
+       GList *work;
+
+       work = g_list_last(pw->list_static);
+       while (work)
+               {
+               PanItem *pi;
+
+               pi = work->data;
+               work = work->prev;
+
+               if (pi->fd && (pi->type == type || type == PAN_ITEM_NONE) &&
+                   ((!key && !pi->key) || (key && pi->key && strcmp(key, pi->key) == 0)))
+                       {
+                       struct tm *tl;
+
+                       tl = localtime(&pi->fd->date);
+                       if (tl)
+                               {
+                               gint match;
+
+                               match = (tl->tm_year == year - 1900);
+                               if (match && month >= 0) match = (tl->tm_mon == month - 1);
+                               if (match && day > 0) match = (tl->tm_mday == day);
+
+                               if (match) list = g_list_prepend(list, pi);
+                               }
+                       }
+               }
+
+       return g_list_reverse(list);
+}
+
+static gboolean pan_search_by_date(PanWindow *pw, const gchar *text)
+{
+       PanItem *pi = NULL;
+       GList *list = NULL;
+       GList *found;
+       gint year;
+       gint month = -1;
+       gint day = -1;
+       gchar *ptr;
+       gchar *mptr;
+       struct tm *lt;
+       time_t t;
+       gchar *message;
+       gchar *buf;
+       gchar *buf_count;
+
+       if (!text) return FALSE;
+
+       ptr = (gchar *)text;
+       while (*ptr != '\0')
+               {
+               if (!g_unichar_isdigit(*ptr) && !valid_date_separator(*ptr)) return FALSE;
+               ptr++;
+               }
+
+       t = time(NULL);
+       if (t == -1) return FALSE;
+       lt = localtime(&t);
+       if (!lt) return FALSE;
+
+       if (valid_date_separator(*text))
+               {
+               year = -1;
+               mptr = (gchar *)text;
+               }
+       else
+               {
+               year = (gint)strtol(text, &mptr, 10);
+               if (mptr == text) return FALSE;
+               }
+
+       if (*mptr != '\0' && valid_date_separator(*mptr))
+               {
+               gchar *dptr;
+
+               mptr++;
+               month = strtol(mptr, &dptr, 10);
+               if (dptr == mptr)
+                       {
+                       if (valid_date_separator(*dptr))
+                               {
+                               month = lt->tm_mon + 1;
+                               dptr++;
+                               }
+                       else
+                               {
+                               month = -1;
+                               }
+                       }
+               if (dptr != mptr && *dptr != '\0' && valid_date_separator(*dptr))
+                       {
+                       gchar *eptr;
+                       dptr++;
+                       day = strtol(dptr, &eptr, 10);
+                       if (dptr == eptr)
+                               {
+                               day = lt->tm_mday;
+                               }
+                       }
+               }
+
+       if (year == -1)
+               {
+               year = lt->tm_year + 1900;
+               }
+       else if (year < 100)
+               {
+               if (year > 70)
+                       year+= 1900;
+               else
+                       year+= 2000;
+               }
+
+       if (year < 1970 ||
+           month < -1 || month == 0 || month > 12 ||
+           day < -1 || day == 0 || day > 31) return FALSE;
+
+       t = pan_date_to_time(year, month, day);
+       if (t < 0) return FALSE;
+
+       if (pw->layout == PAN_LAYOUT_CALENDAR)
+               {
+               list = pan_search_by_date_val(pw, PAN_ITEM_BOX, year, month, day, "day");
+               }
+       else
+               {
+               PanItemType type;
+
+               type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
+               list = pan_search_by_date_val(pw, type, year, month, day, NULL);
+               }
+
+       if (list)
+               {
+               found = g_list_find(list, pw->search_pi);
+               if (found && found->next)
+                       {
+                       found = found->next;
+                       pi = found->data;
+                       }
+               else
+                       {
+                       pi = list->data;
+                       }
+               }
+
+       pw->search_pi = pi;
+
+       if (pw->layout == PAN_LAYOUT_CALENDAR && pi && pi->type == PAN_ITEM_BOX)
+               {
+               pan_info_update(pw, NULL);
+               pan_calendar_update(pw, pi);
+               image_scroll_to_point(pw->imd,
+                                     pi->x + pi->width / 2,
+                                     pi->y + pi->height / 2, 0.5, 0.5);
+               }
+       else if (pi)
+               {
+               pan_info_update(pw, pi);
+               image_scroll_to_point(pw->imd,
+                                     pi->x - PAN_BOX_BORDER * 5 / 2,
+                                     pi->y, 0.0, 0.5);
+               }
+
+       if (month > 0)
+               {
+               buf = pan_date_value_string(t, PAN_DATE_LENGTH_MONTH);
+               if (day > 0)
+                       {
+                       gchar *tmp;
+                       tmp = buf;
+                       buf = g_strdup_printf("%d %s", day, tmp);
+                       g_free(tmp);
+                       }
+               }
+       else
+               {
+               buf = pan_date_value_string(t, PAN_DATE_LENGTH_YEAR);
+               }
+
+       if (pi)
+               {
+               buf_count = g_strdup_printf("( %d / %d )",
+                                           g_list_index(list, pi) + 1,
+                                           g_list_length(list));
+               }
+       else
+               {
+               buf_count = g_strdup_printf("(%s)", _("no match"));
+               }
+
+       message = g_strdup_printf("%s %s %s", _("Date:"), buf, buf_count);
+       g_free(buf);
+       g_free(buf_count);
+       pan_search_status(pw, message);
+       g_free(message);
+
+       g_list_free(list);
+
+       return TRUE;
+}
+
+void pan_search_activate_cb(const gchar *text, gpointer data)
+{
+       PanWindow *pw = data;
+
+       if (!text) return;
+
+       tab_completion_append_to_history(pw->search_ui->search_entry, text);
+
+       if (pan_search_by_path(pw, text)) return;
+
+       if ((pw->layout == PAN_LAYOUT_TIMELINE ||
+            pw->layout == PAN_LAYOUT_CALENDAR) &&
+           pan_search_by_date(pw, text))
+               {
+               return;
+               }
+
+       if (pan_search_by_partial(pw, text)) return;
+
+       pan_search_status(pw, _("no match"));
+}
+
+void pan_search_activate(PanWindow *pw)
+{
+       gchar *text;
+
+       text = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->search_ui->search_entry)));
+       pan_search_activate_cb(text, pw);
+       g_free(text);
+}
+
+void pan_search_toggle_cb(GtkWidget *button, gpointer data)
+{
+       PanWindow *pw = data;
+       PanViewSearchUi *ui = pw->search_ui;
+       gboolean visible;
+
+       visible = gtk_widget_get_visible(ui->search_box);
+       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == visible) return;
+
+       if (visible)
+               {
+               gtk_widget_hide(ui->search_box);
+               gtk_arrow_set(GTK_ARROW(ui->search_button_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE);
+               }
+       else
+               {
+               gtk_widget_show(ui->search_box);
+               gtk_arrow_set(GTK_ARROW(ui->search_button_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+               gtk_widget_grab_focus(ui->search_entry);
+               }
+}
+
+void pan_search_toggle_visible(PanWindow *pw, gboolean enable)
+{
+       PanViewSearchUi *ui = pw->search_ui;
+       if (pw->fs) return;
+
+       if (enable)
+               {
+               if (gtk_widget_get_visible(ui->search_box))
+                       {
+                       gtk_widget_grab_focus(ui->search_entry);
+                       }
+               else
+                       {
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ui->search_button), TRUE);
+                       }
+               }
+       else
+               {
+               if (gtk_widget_get_visible(ui->search_entry))
+                       {
+                       if (gtk_widget_has_focus(ui->search_entry))
+                               {
+                               gtk_widget_grab_focus(GTK_WIDGET(pw->imd->widget));
+                               }
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ui->search_button), FALSE);
+                       }
+               }
+}
diff --git a/src/pan-view/pan-view-search.h b/src/pan-view/pan-view-search.h
new file mode 100644 (file)
index 0000000..88784b7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef PAN_VIEW_PAN_VIEW_SEARCH_H
+#define PAN_VIEW_PAN_VIEW_SEARCH_H
+
+#include "main.h"
+#include "pan-types.h"
+
+void pan_search_toggle_visible(PanWindow *pw, gboolean enable);
+void pan_search_activate(PanWindow *pw);
+void pan_search_activate_cb(const gchar *text, gpointer data);
+void pan_search_toggle_cb(GtkWidget *button, gpointer data);
+
+// Creates a new PanViewSearchUi instance and returns it.
+PanViewSearchUi *pan_search_ui_new(PanWindow *pw);
+
+// Destroys the specified PanViewSearchUi and sets the pointer to NULL.
+void pan_search_ui_destroy(PanViewSearchUi **ui);
+
+#endif
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index db70b65..59c4cc0 100644 (file)
@@ -38,6 +38,8 @@
 #include "pan-item.h"
 #include "pan-timeline.h"
 #include "pan-util.h"
+#include "pan-view-filter.h"
+#include "pan-view-search.h"
 #include "pixbuf-renderer.h"
 #include "pixbuf_util.h"
 #include "thumb.h"
@@ -78,9 +80,6 @@ static void pan_layout_update_idle(PanWindow *pw);
 
 static void pan_fullscreen_toggle(PanWindow *pw, gboolean force_off);
 
-static void pan_search_toggle_visible(PanWindow *pw, gboolean enable);
-static void pan_search_activate(PanWindow *pw);
-
 static void pan_window_close(PanWindow *pw);
 
 static GtkWidget *pan_popup_menu(PanWindow *pw);
@@ -1072,7 +1071,7 @@ static void pan_layout_update_idle(PanWindow *pw)
                }
 }
 
-static void pan_layout_update(PanWindow *pw)
+void pan_layout_update(PanWindow *pw)
 {
        pan_window_message(pw, _("Sorting images..."));
        pan_layout_update_idle(pw);
@@ -1134,7 +1133,8 @@ static gboolean pan_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, g
        imd_widget = gtk_container_get_focus_child(GTK_CONTAINER(pw->imd->widget));
        focused = (pw->fs || (imd_widget && gtk_widget_has_focus(imd_widget)));
        on_entry = (gtk_widget_has_focus(pw->path_entry) ||
-                   gtk_widget_has_focus(pw->search_entry));
+                   gtk_widget_has_focus(pw->search_ui->search_entry) ||
+                   gtk_widget_has_focus(pw->filter_ui->filter_entry));
 
        if (focused)
                {
@@ -1248,6 +1248,7 @@ static gboolean pan_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, g
 
                if (stop_signal) return stop_signal;
 
+               // Don't steal characters from entry boxes.
                if (!on_entry)
                        {
                        stop_signal = TRUE;
@@ -1326,7 +1327,7 @@ static void pan_info_add_exif(PanTextAlignment *ta, FileData *fd)
 }
 
 
-static void pan_info_update(PanWindow *pw, PanItem *pi)
+void pan_info_update(PanWindow *pw, PanItem *pi)
 {
        PanTextAlignment *ta;
        PanItem *pbox;
@@ -1450,399 +1451,6 @@ static void pan_info_update(PanWindow *pw, PanItem *pi)
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- * search
- *-----------------------------------------------------------------------------
- */
-
-static void pan_search_status(PanWindow *pw, const gchar *text)
-{
-       gtk_label_set_text(GTK_LABEL(pw->search_label), (text) ? text : "");
-}
-
-static gint pan_search_by_path(PanWindow *pw, const gchar *path)
-{
-       PanItem *pi;
-       GList *list;
-       GList *found;
-       PanItemType type;
-       gchar *buf;
-
-       type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
-
-       list = pan_item_find_by_path(pw, type, path, FALSE, FALSE);
-       if (!list) return FALSE;
-
-       found = g_list_find(list, pw->click_pi);
-       if (found && found->next)
-               {
-               found = found->next;
-               pi = found->data;
-               }
-       else
-               {
-               pi = list->data;
-               }
-
-       pan_info_update(pw, pi);
-       image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5);
-
-       buf = g_strdup_printf("%s ( %d / %d )",
-                             (path[0] == G_DIR_SEPARATOR) ? _("path found") : _("filename found"),
-                             g_list_index(list, pi) + 1,
-                             g_list_length(list));
-       pan_search_status(pw, buf);
-       g_free(buf);
-
-       g_list_free(list);
-
-       return TRUE;
-}
-
-static gboolean pan_search_by_partial(PanWindow *pw, const gchar *text)
-{
-       PanItem *pi;
-       GList *list;
-       GList *found;
-       PanItemType type;
-       gchar *buf;
-
-       type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
-
-       list = pan_item_find_by_path(pw, type, text, TRUE, FALSE);
-       if (!list) list = pan_item_find_by_path(pw, type, text, FALSE, TRUE);
-       if (!list)
-               {
-               gchar *needle;
-
-               needle = g_utf8_strdown(text, -1);
-               list = pan_item_find_by_path(pw, type, needle, TRUE, TRUE);
-               g_free(needle);
-               }
-       if (!list) return FALSE;
-
-       found = g_list_find(list, pw->click_pi);
-       if (found && found->next)
-               {
-               found = found->next;
-               pi = found->data;
-               }
-       else
-               {
-               pi = list->data;
-               }
-
-       pan_info_update(pw, pi);
-       image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5);
-
-       buf = g_strdup_printf("%s ( %d / %d )",
-                             _("partial match"),
-                             g_list_index(list, pi) + 1,
-                             g_list_length(list));
-       pan_search_status(pw, buf);
-       g_free(buf);
-
-       g_list_free(list);
-
-       return TRUE;
-}
-
-static gboolean valid_date_separator(gchar c)
-{
-       return (c == '/' || c == '-' || c == ' ' || c == '.' || c == ',');
-}
-
-static GList *pan_search_by_date_val(PanWindow *pw, PanItemType type,
-                                    gint year, gint month, gint day,
-                                    const gchar *key)
-{
-       GList *list = NULL;
-       GList *work;
-
-       work = g_list_last(pw->list_static);
-       while (work)
-               {
-               PanItem *pi;
-
-               pi = work->data;
-               work = work->prev;
-
-               if (pi->fd && (pi->type == type || type == PAN_ITEM_NONE) &&
-                   ((!key && !pi->key) || (key && pi->key && strcmp(key, pi->key) == 0)))
-                       {
-                       struct tm *tl;
-
-                       tl = localtime(&pi->fd->date);
-                       if (tl)
-                               {
-                               gint match;
-
-                               match = (tl->tm_year == year - 1900);
-                               if (match && month >= 0) match = (tl->tm_mon == month - 1);
-                               if (match && day > 0) match = (tl->tm_mday == day);
-
-                               if (match) list = g_list_prepend(list, pi);
-                               }
-                       }
-               }
-
-       return g_list_reverse(list);
-}
-
-static gboolean pan_search_by_date(PanWindow *pw, const gchar *text)
-{
-       PanItem *pi = NULL;
-       GList *list = NULL;
-       GList *found;
-       gint year;
-       gint month = -1;
-       gint day = -1;
-       gchar *ptr;
-       gchar *mptr;
-       struct tm *lt;
-       time_t t;
-       gchar *message;
-       gchar *buf;
-       gchar *buf_count;
-
-       if (!text) return FALSE;
-
-       ptr = (gchar *)text;
-       while (*ptr != '\0')
-               {
-               if (!g_unichar_isdigit(*ptr) && !valid_date_separator(*ptr)) return FALSE;
-               ptr++;
-               }
-
-       t = time(NULL);
-       if (t == -1) return FALSE;
-       lt = localtime(&t);
-       if (!lt) return FALSE;
-
-       if (valid_date_separator(*text))
-               {
-               year = -1;
-               mptr = (gchar *)text;
-               }
-       else
-               {
-               year = (gint)strtol(text, &mptr, 10);
-               if (mptr == text) return FALSE;
-               }
-
-       if (*mptr != '\0' && valid_date_separator(*mptr))
-               {
-               gchar *dptr;
-
-               mptr++;
-               month = strtol(mptr, &dptr, 10);
-               if (dptr == mptr)
-                       {
-                       if (valid_date_separator(*dptr))
-                               {
-                               month = lt->tm_mon + 1;
-                               dptr++;
-                               }
-                       else
-                               {
-                               month = -1;
-                               }
-                       }
-               if (dptr != mptr && *dptr != '\0' && valid_date_separator(*dptr))
-                       {
-                       gchar *eptr;
-                       dptr++;
-                       day = strtol(dptr, &eptr, 10);
-                       if (dptr == eptr)
-                               {
-                               day = lt->tm_mday;
-                               }
-                       }
-               }
-
-       if (year == -1)
-               {
-               year = lt->tm_year + 1900;
-               }
-       else if (year < 100)
-               {
-               if (year > 70)
-                       year+= 1900;
-               else
-                       year+= 2000;
-               }
-
-       if (year < 1970 ||
-           month < -1 || month == 0 || month > 12 ||
-           day < -1 || day == 0 || day > 31) return FALSE;
-
-       t = pan_date_to_time(year, month, day);
-       if (t < 0) return FALSE;
-
-       if (pw->layout == PAN_LAYOUT_CALENDAR)
-               {
-               list = pan_search_by_date_val(pw, PAN_ITEM_BOX, year, month, day, "day");
-               }
-       else
-               {
-               PanItemType type;
-
-               type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
-               list = pan_search_by_date_val(pw, type, year, month, day, NULL);
-               }
-
-       if (list)
-               {
-               found = g_list_find(list, pw->search_pi);
-               if (found && found->next)
-                       {
-                       found = found->next;
-                       pi = found->data;
-                       }
-               else
-                       {
-                       pi = list->data;
-                       }
-               }
-
-       pw->search_pi = pi;
-
-       if (pw->layout == PAN_LAYOUT_CALENDAR && pi && pi->type == PAN_ITEM_BOX)
-               {
-               pan_info_update(pw, NULL);
-               pan_calendar_update(pw, pi);
-               image_scroll_to_point(pw->imd,
-                                     pi->x + pi->width / 2,
-                                     pi->y + pi->height / 2, 0.5, 0.5);
-               }
-       else if (pi)
-               {
-               pan_info_update(pw, pi);
-               image_scroll_to_point(pw->imd,
-                                     pi->x - PAN_BOX_BORDER * 5 / 2,
-                                     pi->y, 0.0, 0.5);
-               }
-
-       if (month > 0)
-               {
-               buf = pan_date_value_string(t, PAN_DATE_LENGTH_MONTH);
-               if (day > 0)
-                       {
-                       gchar *tmp;
-                       tmp = buf;
-                       buf = g_strdup_printf("%d %s", day, tmp);
-                       g_free(tmp);
-                       }
-               }
-       else
-               {
-               buf = pan_date_value_string(t, PAN_DATE_LENGTH_YEAR);
-               }
-
-       if (pi)
-               {
-               buf_count = g_strdup_printf("( %d / %d )",
-                                           g_list_index(list, pi) + 1,
-                                           g_list_length(list));
-               }
-       else
-               {
-               buf_count = g_strdup_printf("(%s)", _("no match"));
-               }
-
-       message = g_strdup_printf("%s %s %s", _("Date:"), buf, buf_count);
-       g_free(buf);
-       g_free(buf_count);
-       pan_search_status(pw, message);
-       g_free(message);
-
-       g_list_free(list);
-
-       return TRUE;
-}
-
-static void pan_search_activate_cb(const gchar *text, gpointer data)
-{
-       PanWindow *pw = data;
-
-       if (!text) return;
-
-       tab_completion_append_to_history(pw->search_entry, text);
-
-       if (pan_search_by_path(pw, text)) return;
-
-       if ((pw->layout == PAN_LAYOUT_TIMELINE ||
-            pw->layout == PAN_LAYOUT_CALENDAR) &&
-           pan_search_by_date(pw, text))
-               {
-               return;
-               }
-
-       if (pan_search_by_partial(pw, text)) return;
-
-       pan_search_status(pw, _("no match"));
-}
-
-static void pan_search_activate(PanWindow *pw)
-{
-       gchar *text;
-
-       text = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->search_entry)));
-       pan_search_activate_cb(text, pw);
-       g_free(text);
-}
-
-static void pan_search_toggle_cb(GtkWidget *button, gpointer data)
-{
-       PanWindow *pw = data;
-       gboolean visible;
-
-       visible = gtk_widget_get_visible(pw->search_box);
-       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == visible) return;
-
-       if (visible)
-               {
-               gtk_widget_hide(pw->search_box);
-               gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE);
-               }
-       else
-               {
-               gtk_widget_show(pw->search_box);
-               gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
-               gtk_widget_grab_focus(pw->search_entry);
-               }
-}
-
-static void pan_search_toggle_visible(PanWindow *pw, gboolean enable)
-{
-       if (pw->fs) return;
-
-       if (enable)
-               {
-               if (gtk_widget_get_visible(pw->search_box))
-                       {
-                       gtk_widget_grab_focus(pw->search_entry);
-                       }
-               else
-                       {
-                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), TRUE);
-                       }
-               }
-       else
-               {
-               if (gtk_widget_get_visible(pw->search_entry))
-                       {
-                       if (gtk_widget_has_focus(pw->search_entry))
-                               {
-                               gtk_widget_grab_focus(GTK_WIDGET(pw->imd->widget));
-                               }
-                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), FALSE);
-                       }
-               }
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  * main window
@@ -2129,6 +1737,8 @@ static void pan_window_close(PanWindow *pw)
                }
 
        pan_fullscreen_toggle(pw, TRUE);
+       pan_search_ui_destroy(&pw->search_ui);
+       pan_filter_ui_destroy(&pw->filter_ui);
        gtk_widget_destroy(pw->window);
 
        pan_window_items_free(pw);
@@ -2274,24 +1884,12 @@ static void pan_window_new_real(FileData *dir_fd)
 
        /* find bar */
 
-       pw->search_box = gtk_hbox_new(FALSE, PREF_PAD_SPACE);
-       gtk_box_pack_start(GTK_BOX(vbox), pw->search_box, FALSE, FALSE, 2);
+       pw->search_ui = pan_search_ui_new(pw);
+       gtk_box_pack_start(GTK_BOX(vbox), pw->search_ui->search_box, FALSE, FALSE, 2);
 
-       pref_spacer(pw->search_box, 0);
-       pref_label_new(pw->search_box, _("Find:"));
-
-       hbox = gtk_hbox_new(TRUE, PREF_PAD_SPACE);
-       gtk_box_pack_start(GTK_BOX(pw->search_box), hbox, TRUE, TRUE, 0);
-       gtk_widget_show(hbox);
-
-       combo = tab_completion_new_with_history(&pw->search_entry, "", "pan_view_search", -1,
-                                               pan_search_activate_cb, pw);
-       gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
-       gtk_widget_show(combo);
-
-       pw->search_label = gtk_label_new("");
-       gtk_box_pack_start(GTK_BOX(hbox), pw->search_label, TRUE, TRUE, 0);
-       gtk_widget_show(pw->search_label);
+    /* filter bar */
+    pw->filter_ui = pan_filter_ui_new(pw);
+    gtk_box_pack_start(GTK_BOX(vbox), pw->filter_ui->filter_box, FALSE, FALSE, 2);
 
        /* status bar */
 
@@ -2320,21 +1918,13 @@ static void pan_window_new_real(FileData *dir_fd)
        gtk_container_add(GTK_CONTAINER(frame), pw->label_zoom);
        gtk_widget_show(pw->label_zoom);
 
-       pw->search_button = gtk_toggle_button_new();
-       gtk_button_set_relief(GTK_BUTTON(pw->search_button), GTK_RELIEF_NONE);
-       gtk_button_set_focus_on_click(GTK_BUTTON(pw->search_button), FALSE);
-       hbox = gtk_hbox_new(FALSE, PREF_PAD_GAP);
-       gtk_container_add(GTK_CONTAINER(pw->search_button), hbox);
-       gtk_widget_show(hbox);
-       pw->search_button_arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_NONE);
-       gtk_box_pack_start(GTK_BOX(hbox), pw->search_button_arrow, FALSE, FALSE, 0);
-       gtk_widget_show(pw->search_button_arrow);
-       pref_label_new(hbox, _("Find"));
-
-       gtk_box_pack_end(GTK_BOX(box), pw->search_button, FALSE, FALSE, 0);
-       gtk_widget_show(pw->search_button);
-       g_signal_connect(G_OBJECT(pw->search_button), "clicked",
-                        G_CALLBACK(pan_search_toggle_cb), pw);
+       // Add the "Find" button to the status bar area.
+       gtk_box_pack_end(GTK_BOX(box), pw->search_ui->search_button, FALSE, FALSE, 0);
+       gtk_widget_show(pw->search_ui->search_button);
+
+       // Add the "Filter" button to the status bar area.
+       gtk_box_pack_end(GTK_BOX(box), pw->filter_ui->filter_button, FALSE, FALSE, 0);
+       gtk_widget_show(pw->filter_ui->filter_button);
 
        g_signal_connect(G_OBJECT(pw->window), "delete_event",
                         G_CALLBACK(pan_window_delete_cb), pw);
index 7a7ddc7..a17c6ab 100644 (file)
@@ -25,6 +25,7 @@
 #include "main.h"
 #include "pan-types.h"
 
+void pan_layout_update(PanWindow *pw);
 GList *pan_layout_intersect(PanWindow *pw, gint x, gint y, gint width, gint height);
 void pan_layout_resize(PanWindow *pw);
 
@@ -32,6 +33,7 @@ void pan_cache_sync_date(PanWindow *pw, GList *list);
 
 GList *pan_cache_sort(GList *list, SortType method, gboolean ascend);
 
+void pan_info_update(PanWindow *pw, PanItem *pi);
 
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
index f7725f2..9d7db51 100644 (file)
@@ -252,6 +252,13 @@ typedef enum {
 
 #define MAX_SPLIT_IMAGES 4
 
+typedef enum {
+       SELECTION_NONE          = 0,
+       SELECTION_SELECTED      = 1 << 0,
+       SELECTION_PRELIGHT      = 1 << 1,
+       SELECTION_FOCUS         = 1 << 2
+} SelectionType;
+
 typedef struct _ImageLoader ImageLoader;
 typedef struct _ThumbLoader ThumbLoader;
 
@@ -575,6 +582,8 @@ struct _FileData {
        GHashTable *modified_xmp; // hash table which contains unwritten xmp metadata in format: key->list of string values
        GList *cached_metadata;
        gint rating;
+
+       SelectionType selected;  // Used by view_file_icon.
 };
 
 struct _LayoutOptions
@@ -823,6 +832,7 @@ struct _ViewDirInfoTree
 struct _ViewFile
 {
        FileViewType type;
+       // TODO(xsdg): Turn this into a union (see VFLIST and VFICON from view_file.h).
        gpointer info;
 
        GtkWidget *widget;
@@ -876,20 +886,6 @@ struct _ViewFileInfoList
        guint select_idle_id; /* event source id */
 };
 
-typedef enum {
-       SELECTION_NONE          = 0,
-       SELECTION_SELECTED      = 1 << 0,
-       SELECTION_PRELIGHT      = 1 << 1,
-       SELECTION_FOCUS         = 1 << 2
-} SelectionType;
-
-typedef struct _IconData IconData;
-struct _IconData
-{
-       SelectionType selected;
-       FileData *fd;
-};
-
 struct _ViewFileInfoIcon
 {
        /* table stuff */
@@ -897,15 +893,15 @@ struct _ViewFileInfoIcon
        gint rows;
 
        GList *selection;
-       struct _IconData *prev_selection;
+       FileData *prev_selection;
 
        GtkWidget *tip_window;
        guint tip_delay_id; /* event source id */
-       struct _IconData *tip_id;
+       FileData *tip_fd;
 
-       struct _IconData *click_id;
+       FileData *click_fd;
 
-       struct _IconData *focus_id;
+       FileData *focus_fd;
        gint focus_row;
        gint focus_column;
 
index 7fc5017..cd4cf09 100644 (file)
@@ -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"
 
 /*
  *-----------------------------------------------------------------------------
@@ -555,7 +555,7 @@ GtkWidget *vf_pop_menu(ViewFile *vf)
                active = (VFLIST(vf)->click_fd != NULL);
                break;
        case FILEVIEW_ICON:
-               active = (VFICON(vf)->click_id != NULL);
+               active = (VFICON(vf)->click_fd != NULL);
                break;
        }
 
diff --git a/src/view_file/Makefile.am b/src/view_file/Makefile.am
new file mode 100644 (file)
index 0000000..6837e72
--- /dev/null
@@ -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
diff --git a/src/view_file/view_file_common.c b/src/view_file/view_file_common.c
new file mode 100644 (file)
index 0000000..959aa66
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  This file is a part of Geeqie project (http://www.geeqie.org/).
+ *  Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ */
+
+guint vfcommon_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);
+}
+
similarity index 77%
rename from src/view_file_icon.c
rename to src/view_file/view_file_icon.c
index 52e13e9..6fbc7d2 100644 (file)
@@ -60,61 +60,10 @@ enum {
        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_selection_remove(ViewFile *vf, FileData *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_set_focus(ViewFile *vf, FileData *fd);
 static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gboolean force);
 
 
@@ -131,23 +80,23 @@ GList *vficon_selection_get_one(ViewFile *vf, FileData *fd)
 
 GList *vficon_pop_menu_file_list(ViewFile *vf)
 {
-       if (!VFICON(vf)->click_id) return NULL;
+       if (!VFICON(vf)->click_fd) return NULL;
 
-       if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+       if (VFICON(vf)->click_fd->selected & SELECTION_SELECTED)
                {
                return vf_selection_get_list(vf);
                }
 
-       return vficon_selection_get_one(vf, VFICON(vf)->click_id->fd);
+       return vficon_selection_get_one(vf, VFICON(vf)->click_fd);
 }
 
 void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data)
 {
        ViewFile *vf = data;
 
-       if (!VFICON(vf)->click_id) return;
+       if (!VFICON(vf)->click_fd) return;
 
-       if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+       if (VFICON(vf)->click_fd->selected & SELECTION_SELECTED)
                {
                GList *list;
 
@@ -157,7 +106,7 @@ void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data)
                }
        else
                {
-               view_window_new(VFICON(vf)->click_id->fd);
+               view_window_new(VFICON(vf)->click_fd);
                }
 }
 
@@ -185,8 +134,8 @@ void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
 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;
+       vficon_selection_remove(vf, VFICON(vf)->click_fd, SELECTION_PRELIGHT, NULL);
+       VFICON(vf)->click_fd = NULL;
        vf->popup = NULL;
 }
 
@@ -196,15 +145,15 @@ void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data)
  *-------------------------------------------------------------------
  */
 
-static void vficon_send_layout_select(ViewFile *vf, IconData *id)
+static void vficon_send_layout_select(ViewFile *vf, FileData *fd)
 {
        FileData *read_ahead_fd = NULL;
        FileData *sel_fd;
        FileData *cur_fd;
 
-       if (!vf->layout || !id || !id->fd) return;
+       if (!vf->layout || !fd) return;
 
-       sel_fd = id->fd;
+       sel_fd = fd;
 
        cur_fd = layout_image_get_fd(vf->layout);
        if (sel_fd == cur_fd) return; /* no change */
@@ -213,7 +162,7 @@ static void vficon_send_layout_select(ViewFile *vf, IconData *id)
                {
                gint row;
 
-               row = g_list_index(vf->list, id);
+               row = g_list_index(vf->list, fd);
                if (row > vficon_index_by_fd(vf, cur_fd) &&
                    (guint) (row + 1) < vf_count(vf, NULL))
                        {
@@ -257,11 +206,11 @@ static gint vficon_get_icon_width(ViewFile *vf)
  *-------------------------------------------------------------------
  */
 
-static gboolean vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint *col)
+static gboolean vficon_find_position(ViewFile *vf, FileData *fd, gint *row, gint *col)
 {
        gint n;
 
-       n = g_list_index(vf->list, id);
+       n = g_list_index(vf->list, fd);
 
        if (n < 0) return FALSE;
 
@@ -271,20 +220,20 @@ static gboolean vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint
        return TRUE;
 }
 
-static gboolean vficon_find_iter(ViewFile *vf, IconData *id, GtkTreeIter *iter, gint *column)
+static gboolean vficon_find_iter(ViewFile *vf, FileData *fd, 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 (!vficon_find_position(vf, fd, &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)
+static FileData *vficon_find_data(ViewFile *vf, gint row, gint col, GtkTreeIter *iter)
 {
        GtkTreeModel *store;
        GtkTreeIter p;
@@ -307,7 +256,7 @@ static IconData *vficon_find_data(ViewFile *vf, gint row, gint col, GtkTreeIter
        return NULL;
 }
 
-static IconData *vficon_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
+static FileData *vficon_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTreeIter *iter)
 {
        GtkTreePath *tpath;
        GtkTreeViewColumn *column;
@@ -346,21 +295,19 @@ static void vficon_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str,
        gint column;
        GList *list;
        guint toggled_mark;
-       IconData *id;
+       FileData *fd;
 
        store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
-       if (!path || !gtk_tree_model_get_iter(store, &row, path))
-               return;
+       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)
+       fd = g_list_nth_data(list, column);
+       if (fd)
                {
-               FileData *fd = id->fd;
                file_data_set_mark(fd, toggled_mark, !file_data_get_mark(fd, toggled_mark));
                }
 }
@@ -394,14 +341,14 @@ static void tip_show(ViewFile *vf)
        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_fd = vficon_find_data_by_coord(vf, x, y, NULL);
+       if (!VFICON(vf)->tip_fd) 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);
+       label = gtk_label_new(VFICON(vf)->tip_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);
@@ -473,7 +420,7 @@ static void tip_unschedule(ViewFile *vf)
                }
 }
 
-static void tip_update(ViewFile *vf, IconData *id)
+static void tip_update(ViewFile *vf, FileData *fd)
 {
 #if GTK_CHECK_VERSION(3,0,0)
        GdkDisplay *display = gdk_display_get_default();
@@ -492,13 +439,13 @@ static void tip_update(ViewFile *vf, IconData *id)
 #endif
                gtk_window_move(GTK_WINDOW(VFICON(vf)->tip_window), x + 16, y + 16);
 
-               if (id != VFICON(vf)->tip_id)
+               if (fd != VFICON(vf)->tip_fd)
                        {
                        GtkWidget *label;
 
-                       VFICON(vf)->tip_id = id;
+                       VFICON(vf)->tip_fd = fd;
 
-                       if (!VFICON(vf)->tip_id)
+                       if (!VFICON(vf)->tip_fd)
                                {
                                tip_hide(vf);
                                tip_schedule(vf);
@@ -506,7 +453,7 @@ static void tip_update(ViewFile *vf, IconData *id)
                                }
 
                        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);
+                       gtk_label_set_text(GTK_LABEL(label), VFICON(vf)->tip_fd->name);
                        }
                }
        else
@@ -528,15 +475,15 @@ static void vficon_dnd_get(GtkWidget *widget, GdkDragContext *context,
        ViewFile *vf = data;
        GList *list = NULL;
 
-       if (!VFICON(vf)->click_id) return;
+       if (!VFICON(vf)->click_fd) return;
 
-       if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+       if (VFICON(vf)->click_fd->selected & SELECTION_SELECTED)
                {
                list = vf_selection_get_list(vf);
                }
        else
                {
-               list = g_list_append(NULL, file_data_ref(VFICON(vf)->click_id->fd));
+               list = g_list_append(NULL, file_data_ref(VFICON(vf)->click_fd));
                }
 
        if (!list) return;
@@ -551,11 +498,10 @@ static void vficon_drag_data_received(GtkWidget *entry_widget, GdkDragContext *c
        ViewFile *vf = data;
 
        if (info == TARGET_TEXT_PLAIN) {
-               IconData *id = vficon_find_data_by_coord(vf, x, y, NULL);
+               FileData *fd = vficon_find_data_by_coord(vf, x, y, NULL);
 
-               if (id && id->fd) {
+               if (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);
 
@@ -572,16 +518,16 @@ static void vficon_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointe
 
        tip_unschedule(vf);
 
-       if (VFICON(vf)->click_id && VFICON(vf)->click_id->fd->thumb_pixbuf)
+       if (VFICON(vf)->click_fd && VFICON(vf)->click_fd->thumb_pixbuf)
                {
                gint items;
 
-               if (VFICON(vf)->click_id->selected & SELECTION_SELECTED)
+               if (VFICON(vf)->click_fd->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);
+               dnd_set_drag_icon(widget, context, VFICON(vf)->click_fd->thumb_pixbuf, items);
                }
 }
 
@@ -589,7 +535,7 @@ static void vficon_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer
 {
        ViewFile *vf = data;
 
-       vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
+       vficon_selection_remove(vf, VFICON(vf)->click_fd, SELECTION_PRELIGHT, NULL);
 
        if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE)
                {
@@ -624,16 +570,15 @@ void vficon_dnd_init(ViewFile *vf)
  *-------------------------------------------------------------------
  */
 
-static void vficon_selection_set(ViewFile *vf, IconData *id, SelectionType value, GtkTreeIter *iter)
+static void vficon_selection_set(ViewFile *vf, FileData *fd, SelectionType value, GtkTreeIter *iter)
 {
        GtkTreeModel *store;
        GList *list;
 
-       if (!id) return;
-
+       if (!fd) return;
 
-       if (id->selected == value) return;
-       id->selected = value;
+       if (fd->selected == value) return;
+       fd->selected = value;
 
        store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
        if (iter)
@@ -645,7 +590,7 @@ static void vficon_selection_set(ViewFile *vf, IconData *id, SelectionType value
                {
                GtkTreeIter row;
 
-               if (vficon_find_iter(vf, id, &row, NULL))
+               if (vficon_find_iter(vf, fd, &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);
@@ -653,18 +598,18 @@ static void vficon_selection_set(ViewFile *vf, IconData *id, SelectionType value
                }
 }
 
-static void vficon_selection_add(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
+static void vficon_selection_add(ViewFile *vf, FileData *fd, SelectionType mask, GtkTreeIter *iter)
 {
-       if (!id) return;
+       if (!fd) return;
 
-       vficon_selection_set(vf, id, id->selected | mask, iter);
+       vficon_selection_set(vf, fd, fd->selected | mask, iter);
 }
 
-static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter)
+static void vficon_selection_remove(ViewFile *vf, FileData *fd, SelectionType mask, GtkTreeIter *iter)
 {
-       if (!id) return;
+       if (!fd) return;
 
-       vficon_selection_set(vf, id, id->selected & ~mask, iter);
+       vficon_selection_set(vf, fd, fd->selected & ~mask, iter);
 }
 
 void vficon_marks_set(ViewFile *vf, gint enable)
@@ -687,12 +632,12 @@ static void vficon_verify_selections(ViewFile *vf)
        work = VFICON(vf)->selection;
        while (work)
                {
-               IconData *id = work->data;
+               FileData *fd = work->data;
                work = work->next;
 
-               if (vficon_index_by_id(vf, id) >= 0) continue;
+               if (vficon_index_by_fd(vf, fd) >= 0) continue;
 
-               VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
+               VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, fd);
                }
 }
 
@@ -706,11 +651,11 @@ void vficon_select_all(ViewFile *vf)
        work = vf->list;
        while (work)
                {
-               IconData *id = work->data;
+               FileData *fd = work->data;
                work = work->next;
 
-               VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
-               vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
+               VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, fd);
+               vficon_selection_add(vf, fd, SELECTION_SELECTED, NULL);
                }
 
        vf_send_update(vf);
@@ -723,10 +668,10 @@ void vficon_select_none(ViewFile *vf)
        work = VFICON(vf)->selection;
        while (work)
                {
-               IconData *id = work->data;
+               FileData *fd = work->data;
                work = work->next;
 
-               vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
+               vficon_selection_remove(vf, fd, SELECTION_SELECTED, NULL);
                }
 
        g_list_free(VFICON(vf)->selection);
@@ -742,61 +687,61 @@ void vficon_select_invert(ViewFile *vf)
        work = vf->list;
        while (work)
                {
-               IconData *id = work->data;
+               FileData *fd = work->data;
                work = work->next;
 
-               if (id->selected & SELECTION_SELECTED)
+               if (fd->selected & SELECTION_SELECTED)
                        {
-                       VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
-                       vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
+                       VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, fd);
+                       vficon_selection_remove(vf, fd, SELECTION_SELECTED, NULL);
                        }
                else
                        {
-                       VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
-                       vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
+                       VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, fd);
+                       vficon_selection_add(vf, fd, SELECTION_SELECTED, NULL);
                        }
                }
 
        vf_send_update(vf);
 }
 
-static void vficon_select(ViewFile *vf, IconData *id)
+static void vficon_select(ViewFile *vf, FileData *fd)
 {
-       VFICON(vf)->prev_selection = id;
+       VFICON(vf)->prev_selection = fd;
 
-       if (!id || id->selected & SELECTION_SELECTED) return;
+       if (!fd || fd->selected & SELECTION_SELECTED) return;
 
-       VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id);
-       vficon_selection_add(vf, id, SELECTION_SELECTED, NULL);
+       VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, fd);
+       vficon_selection_add(vf, fd, SELECTION_SELECTED, NULL);
 
        vf_send_update(vf);
 }
 
-static void vficon_unselect(ViewFile *vf, IconData *id)
+static void vficon_unselect(ViewFile *vf, FileData *fd)
 {
-       VFICON(vf)->prev_selection = id;
+       VFICON(vf)->prev_selection = fd;
 
-       if (!id || !(id->selected & SELECTION_SELECTED) ) return;
+       if (!fd || !(fd->selected & SELECTION_SELECTED) ) return;
 
-       VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id);
-       vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL);
+       VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, fd);
+       vficon_selection_remove(vf, fd, SELECTION_SELECTED, NULL);
 
        vf_send_update(vf);
 }
 
-static void vficon_select_util(ViewFile *vf, IconData *id, gboolean select)
+static void vficon_select_util(ViewFile *vf, FileData *fd, gboolean select)
 {
        if (select)
                {
-               vficon_select(vf, id);
+               vficon_select(vf, fd);
                }
        else
                {
-               vficon_unselect(vf, id);
+               vficon_unselect(vf, fd);
                }
 }
 
-static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *end, gboolean select)
+static void vficon_select_region_util(ViewFile *vf, FileData *start, FileData *end, gboolean select)
 {
        gint row1, col1;
        gint row2, col2;
@@ -811,20 +756,19 @@ static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *e
        if (!options->collections.rectangular_selection)
                {
                GList *work;
-               IconData *id;
 
                if (g_list_index(vf->list, start) > g_list_index(vf->list, end))
                        {
-                       id = start;
+                       FileData *tmp = start;
                        start = end;
-                       end = id;
+                       end = tmp;
                        }
 
                work = g_list_find(vf->list, start);
                while (work)
                        {
-                       id = work->data;
-                       vficon_select_util(vf, id, select);
+                       FileData *fd = work->data;
+                       vficon_select_util(vf, fd, select);
 
                        if (work->data != end)
                                work = work->next;
@@ -834,6 +778,7 @@ static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *e
                return;
                }
 
+       // rectangular_selection==true.
        if (row2 < row1)
                {
                t = row1;
@@ -853,19 +798,19 @@ static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *e
                {
                for (j = col1; j <= col2; j++)
                        {
-                       IconData *id = vficon_find_data(vf, i, j, NULL);
-                       if (id) vficon_select_util(vf, id, select);
+                       FileData *fd = vficon_find_data(vf, i, j, NULL);
+                       if (fd) vficon_select_util(vf, fd, select);
                        }
                }
 }
 
 gboolean vficon_index_is_selected(ViewFile *vf, gint row)
 {
-       IconData *id = g_list_nth_data(vf->list, row);
+       FileData *fd = g_list_nth_data(vf->list, row);
 
-       if (!id) return FALSE;
+       if (!fd) return FALSE;
 
-       return (id->selected & SELECTION_SELECTED);
+       return (fd->selected & SELECTION_SELECTED);
 }
 
 guint vficon_selection_count(ViewFile *vf, gint64 *bytes)
@@ -878,8 +823,7 @@ guint vficon_selection_count(ViewFile *vf, gint64 *bytes)
                work = VFICON(vf)->selection;
                while (work)
                        {
-                       IconData *id = work->data;
-                       FileData *fd = id->fd;
+                       FileData *fd = work->data;
                        g_assert(fd->magick == FD_MAGICK);
                        b += fd->size;
 
@@ -900,8 +844,7 @@ GList *vficon_selection_get_list(ViewFile *vf)
        work = VFICON(vf)->selection;
        while (work)
                {
-               IconData *id = work->data;
-               FileData *fd = id->fd;
+               FileData *fd = work->data;
                g_assert(fd->magick == FD_MAGICK);
 
                list = g_list_prepend(list, file_data_ref(fd));
@@ -937,33 +880,18 @@ GList *vficon_selection_get_list_by_index(ViewFile *vf)
        return g_list_reverse(list);
 }
 
-static void vficon_select_by_id(ViewFile *vf, IconData *id)
+void vficon_select_by_fd(ViewFile *vf, FileData *fd)
 {
-       if (!id) return;
+       if (!fd) return;
+       if (!g_list_find(vf->list, fd)) return;
 
-       if (!(id->selected & SELECTION_SELECTED))
+       if (!(fd->selected & SELECTION_SELECTED))
                {
                vf_select_none(vf);
-               vficon_select(vf, id);
+               vficon_select(vf, fd);
                }
 
-       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);
+       vficon_set_focus(vf, fd);
 }
 
 void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
@@ -976,14 +904,13 @@ void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
        work = vf->list;
        while (work)
                {
-               IconData *id = work->data;
-               FileData *fd = id->fd;
+               FileData *fd = work->data;
                gboolean mark_val, selected;
 
                g_assert(fd->magick == FD_MAGICK);
 
                mark_val = file_data_get_mark(fd, n);
-               selected = (id->selected & SELECTION_SELECTED);
+               selected = fd->selected & SELECTION_SELECTED;
 
                switch (mode)
                        {
@@ -997,7 +924,7 @@ void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
                                break;
                        }
 
-               vficon_select_util(vf, id, selected);
+               vficon_select_util(vf, fd, selected);
 
                work = work->next;
                }
@@ -1034,7 +961,7 @@ void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
 static void vficon_select_closest(ViewFile *vf, FileData *sel_fd)
 {
        GList *work;
-       IconData *id = NULL;
+       FileData *fd = NULL;
 
        if (sel_fd->parent) sel_fd = sel_fd->parent;
        work = vf->list;
@@ -1042,10 +969,8 @@ static void vficon_select_closest(ViewFile *vf, FileData *sel_fd)
        while (work)
                {
                gint match;
-               FileData *fd;
 
-               id = work->data;
-               fd = id->fd;
+               fd = work->data;
                work = work->next;
 
                match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
@@ -1053,10 +978,10 @@ static void vficon_select_closest(ViewFile *vf, FileData *sel_fd)
                if (match >= 0) break;
                }
 
-       if (id)
+       if (fd)
                {
-               vficon_select(vf, id);
-               vficon_send_layout_select(vf, id);
+               vficon_select(vf, fd);
+               vficon_send_layout_select(vf, fd);
                }
 }
 
@@ -1150,46 +1075,46 @@ static void vficon_move_focus(ViewFile *vf, gint row, gint col, gboolean relativ
        vficon_set_focus(vf, vficon_find_data(vf, new_row, new_col, NULL));
 }
 
-static void vficon_set_focus(ViewFile *vf, IconData *id)
+static void vficon_set_focus(ViewFile *vf, FileData *fd)
 {
        GtkTreeIter iter;
        gint row, col;
 
-       if (g_list_find(vf->list, VFICON(vf)->focus_id))
+       if (g_list_find(vf->list, VFICON(vf)->focus_fd))
                {
-               if (id == VFICON(vf)->focus_id)
+               if (fd == VFICON(vf)->focus_fd)
                        {
                        /* ensure focus row col are correct */
-                       vficon_find_position(vf, VFICON(vf)->focus_id, &VFICON(vf)->focus_row, &VFICON(vf)->focus_column);
+                       vficon_find_position(vf, VFICON(vf)->focus_fd, &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))
+                       if (vficon_find_iter(vf, VFICON(vf)->focus_fd, &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);
+               vficon_selection_remove(vf, VFICON(vf)->focus_fd, SELECTION_FOCUS, NULL);
                }
 
-       if (!vficon_find_position(vf, id, &row, &col))
+       if (!vficon_find_position(vf, fd, &row, &col))
                {
-               VFICON(vf)->focus_id = NULL;
+               VFICON(vf)->focus_fd = NULL;
                VFICON(vf)->focus_row = -1;
                VFICON(vf)->focus_column = -1;
                return;
                }
 
-       VFICON(vf)->focus_id = id;
+       VFICON(vf)->focus_fd = fd;
        VFICON(vf)->focus_row = row;
        VFICON(vf)->focus_column = col;
-       vficon_selection_add(vf, VFICON(vf)->focus_id, SELECTION_FOCUS, NULL);
+       vficon_selection_add(vf, VFICON(vf)->focus_fd, SELECTION_FOCUS, NULL);
 
-       if (vficon_find_iter(vf, VFICON(vf)->focus_id, &iter, NULL))
+       if (vficon_find_iter(vf, VFICON(vf)->focus_fd, &iter, NULL))
                {
                GtkTreePath *tpath;
                GtkTreeViewColumn *column;
@@ -1241,7 +1166,7 @@ static void vfi_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push
        GtkTreePath *tpath;
        gint cw, ch;
 
-       if (!vficon_find_iter(vf, VFICON(vf)->click_id, &iter, &column)) return;
+       if (!vficon_find_iter(vf, VFICON(vf)->click_fd, &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);
@@ -1255,7 +1180,7 @@ gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
        ViewFile *vf = data;
        gint focus_row = 0;
        gint focus_col = 0;
-       IconData *id;
+       FileData *fd;
        gboolean stop_signal;
 
        stop_signal = TRUE;
@@ -1288,38 +1213,38 @@ gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
                        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)
+                       fd = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+                       if (fd)
                                {
-                               VFICON(vf)->click_id = id;
+                               VFICON(vf)->click_fd = fd;
                                if (event->state & GDK_CONTROL_MASK)
                                        {
                                        gint selected;
 
-                                       selected = id->selected & SELECTION_SELECTED;
+                                       selected = fd->selected & SELECTION_SELECTED;
                                        if (selected)
                                                {
-                                               vficon_unselect(vf, id);
+                                               vficon_unselect(vf, fd);
                                                }
                                        else
                                                {
-                                               vficon_select(vf, id);
-                                               vficon_send_layout_select(vf, id);
+                                               vficon_select(vf, fd);
+                                               vficon_send_layout_select(vf, fd);
                                                }
                                        }
                                else
                                        {
                                        vf_select_none(vf);
-                                       vficon_select(vf, id);
-                                       vficon_send_layout_select(vf, id);
+                                       vficon_select(vf, fd);
+                                       vficon_send_layout_select(vf, fd);
                                        }
                                }
                        break;
                case GDK_KEY_Menu:
-                       id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
-                       VFICON(vf)->click_id = id;
+                       fd = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+                       VFICON(vf)->click_fd = fd;
 
-                       vficon_selection_add(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
+                       vficon_selection_add(vf, VFICON(vf)->click_fd, SELECTION_PRELIGHT, NULL);
                        tip_unschedule(vf);
 
                        vf->popup = vf_pop_menu(vf);
@@ -1332,38 +1257,38 @@ gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
 
        if (focus_row != 0 || focus_col != 0)
                {
-               IconData *new_id;
-               IconData *old_id;
+               FileData *new_fd;
+               FileData *old_fd;
 
-               old_id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
+               old_fd = 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);
+               new_fd = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL);
 
-               if (new_id != old_id)
+               if (new_fd != old_fd)
                        {
                        if (event->state & GDK_SHIFT_MASK)
                                {
                                if (!options->collections.rectangular_selection)
                                        {
-                                       vficon_select_region_util(vf, old_id, new_id, FALSE);
+                                       vficon_select_region_util(vf, old_fd, new_fd, FALSE);
                                        }
                                else
                                        {
-                                       vficon_select_region_util(vf, VFICON(vf)->click_id, old_id, FALSE);
+                                       vficon_select_region_util(vf, VFICON(vf)->click_fd, old_fd, FALSE);
                                        }
-                               vficon_select_region_util(vf, VFICON(vf)->click_id, new_id, TRUE);
-                               vficon_send_layout_select(vf, new_id);
+                               vficon_select_region_util(vf, VFICON(vf)->click_fd, new_fd, TRUE);
+                               vficon_send_layout_select(vf, new_fd);
                                }
                        else if (event->state & GDK_CONTROL_MASK)
                                {
-                               VFICON(vf)->click_id = new_id;
+                               VFICON(vf)->click_fd = new_fd;
                                }
                        else
                                {
-                               VFICON(vf)->click_id = new_id;
+                               VFICON(vf)->click_fd = new_fd;
                                vf_select_none(vf);
-                               vficon_select(vf, new_id);
-                               vficon_send_layout_select(vf, new_id);
+                               vficon_select(vf, new_fd);
+                               vficon_send_layout_select(vf, new_fd);
                                }
                        }
                }
@@ -1385,10 +1310,10 @@ gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat
 static gboolean vficon_motion_cb(GtkWidget *widget, GdkEventMotion *event, gpointer data)
 {
        ViewFile *vf = data;
-       IconData *id;
+       FileData *fd;
 
-       id = vficon_find_data_by_coord(vf, (gint)event->x, (gint)event->y, NULL);
-       tip_update(vf, id);
+       fd = vficon_find_data_by_coord(vf, (gint)event->x, (gint)event->y, NULL);
+       tip_update(vf, fd);
 
        return FALSE;
 }
@@ -1397,14 +1322,14 @@ gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer dat
 {
        ViewFile *vf = data;
        GtkTreeIter iter;
-       IconData *id;
+       FileData *fd;
 
        tip_unschedule(vf);
 
-       id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
+       fd = 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);
+       VFICON(vf)->click_fd = fd;
+       vficon_selection_add(vf, VFICON(vf)->click_fd, SELECTION_PRELIGHT, &iter);
 
        switch (bevent->button)
                {
@@ -1414,10 +1339,9 @@ gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer dat
                                gtk_widget_grab_focus(vf->listview);
                                }
 
-                       if (bevent->type == GDK_2BUTTON_PRESS &&
-                           vf->layout)
+                       if (bevent->type == GDK_2BUTTON_PRESS && vf->layout)
                                {
-                               vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, &iter);
+                               vficon_selection_remove(vf, VFICON(vf)->click_fd, SELECTION_PRELIGHT, &iter);
                                layout_image_full_screen_start(vf->layout);
                                }
                        break;
@@ -1436,43 +1360,43 @@ gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer d
 {
        ViewFile *vf = data;
        GtkTreeIter iter;
-       IconData *id = NULL;
+       FileData *fd = 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);
+               fd = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter);
                }
 
-       if (VFICON(vf)->click_id)
+       if (VFICON(vf)->click_fd)
                {
-               vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL);
+               vficon_selection_remove(vf, VFICON(vf)->click_fd, SELECTION_PRELIGHT, NULL);
                }
 
-       if (!id || VFICON(vf)->click_id != id) return TRUE;
+       if (!fd || VFICON(vf)->click_fd != fd) return TRUE;
 
-       was_selected = !!(id->selected & SELECTION_SELECTED);
+       was_selected = !!(fd->selected & SELECTION_SELECTED);
 
        switch (bevent->button)
                {
                case MOUSE_BUTTON_LEFT:
                        {
-                       vficon_set_focus(vf, id);
+                       vficon_set_focus(vf, fd);
 
                        if (bevent->state & GDK_CONTROL_MASK)
                                {
                                gboolean select;
 
-                               select = !(id->selected & SELECTION_SELECTED);
+                               select = !(fd->selected & SELECTION_SELECTED);
                                if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection)
                                        {
-                                       vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, select);
+                                       vficon_select_region_util(vf, VFICON(vf)->prev_selection, fd, select);
                                        }
                                else
                                        {
-                                       vficon_select_util(vf, id, select);
+                                       vficon_select_util(vf, fd, select);
                                        }
                                }
                        else
@@ -1481,11 +1405,11 @@ gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer d
 
                                if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection)
                                        {
-                                       vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, TRUE);
+                                       vficon_select_region_util(vf, VFICON(vf)->prev_selection, fd, TRUE);
                                        }
                                else
                                        {
-                                       vficon_select_util(vf, id, TRUE);
+                                       vficon_select_util(vf, fd, TRUE);
                                        was_selected = FALSE;
                                        }
                                }
@@ -1493,16 +1417,16 @@ gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer d
                        break;
                case MOUSE_BUTTON_MIDDLE:
                        {
-                       vficon_select_util(vf, id, !(id->selected & SELECTION_SELECTED));
+                       vficon_select_util(vf, fd, !(fd->selected & SELECTION_SELECTED));
                        }
                        break;
                default:
                        break;
                }
 
-       if (!was_selected && (id->selected & SELECTION_SELECTED))
+       if (!was_selected && (fd->selected & SELECTION_SELECTED))
                {
-               vficon_send_layout_select(vf, id);
+               vficon_send_layout_select(vf, fd);
                }
 
        return TRUE;
@@ -1566,7 +1490,7 @@ static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_positio
        GtkTreeModel *store;
        GtkTreePath *tpath;
        GList *work;
-       IconData *visible_id = NULL;
+       FileData *visible_fd = NULL;
        gint r, c;
        gboolean valid;
        GtkTreeIter iter;
@@ -1585,7 +1509,7 @@ static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_positio
                gtk_tree_path_free(tpath);
 
                gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1);
-               if (list) visible_id = list->data;
+               if (list) visible_fd = list->data;
                }
 
 
@@ -1648,20 +1572,20 @@ static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_positio
 
                while (list)
                        {
-                       IconData *id;
+                       FileData *fd;
 
                        if (work)
                                {
-                               id = work->data;
+                               fd = work->data;
                                work = work->next;
                                c++;
                                }
                        else
                                {
-                               id = NULL;
+                               fd = NULL;
                                }
 
-                       list->data = id;
+                       list->data = fd;
                        list = list->next;
                        }
                if (valid) valid = gtk_tree_model_iter_next(store, &iter);
@@ -1679,7 +1603,7 @@ static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_positio
 
        VFICON(vf)->rows = r;
 
-       if (visible_id &&
+       if (visible_fd &&
            gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
                {
                GtkTreeIter iter;
@@ -1689,8 +1613,8 @@ static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_positio
                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))
+               if (g_list_find(list, visible_fd) == NULL &&
+                   vficon_find_iter(vf, visible_fd, &iter, NULL))
                        {
                        tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE);
                        }
@@ -1756,8 +1680,7 @@ void vficon_thumb_progress_count(GList *list, gint *count, gint *done)
        GList *work = list;
        while (work)
                {
-               IconData *id = work->data;
-               FileData *fd = id->fd;
+               FileData *fd = work->data;
                work = work->next;
 
                if (fd->thumb_pixbuf) (*done)++;
@@ -1771,7 +1694,8 @@ void vficon_set_thumb_fd(ViewFile *vf, FileData *fd)
        GtkTreeIter iter;
        GList *list;
 
-       if (!vficon_find_iter(vf, vficon_icon_data(vf, fd), &iter, NULL)) return;
+       if (!g_list_find(vf->list, fd)) return;
+       if (!vficon_find_iter(vf, fd, &iter, NULL)) return;
 
        store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
 
@@ -1779,12 +1703,12 @@ void vficon_set_thumb_fd(ViewFile *vf, FileData *fd)
        gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1);
 }
 
-
+/* Returns the next fd without a loaded pixbuf, so the thumb-loader can load the pixbuf for it. */
 FileData *vficon_thumb_next_fd(ViewFile *vf)
 {
        GtkTreePath *tpath;
-       FileData *fd = NULL;
 
+       /* First see if there are visible files that don't have a loaded thumb... */
        if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
                {
                GtkTreeModel *store;
@@ -1794,40 +1718,36 @@ FileData *vficon_thumb_next_fd(ViewFile *vf)
                store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
                gtk_tree_model_get_iter(store, &iter, tpath);
                gtk_tree_path_free(tpath);
+               tpath = NULL;
 
-               while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
+               while (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)
+                       // TODO(xsdg): for loop here.
+                       for (; list; list = list->next)
                                {
-                               IconData *id = list->data;
-                               if (id && !id->fd->thumb_pixbuf) fd = id->fd;
-                               list = list->next;
+                               FileData *fd = list->data;
+                               if (fd && !fd->thumb_pixbuf) return fd;
                                }
 
                        valid = gtk_tree_model_iter_next(store, &iter);
                        }
                }
 
-       /* then find first undone */
-
-       if (!fd)
+       /* Then iterate through the entire list to load all of them. */
+       GList *work;
+       for (work = vf->list; work; work = work->next)
                {
-               GList *work = vf->list;
-               while (work && !fd)
-                       {
-                       IconData *id = work->data;
-                       FileData *fd_p = id->fd;
-                       work = work->next;
+               FileData *fd = work->data;
 
-                       if (!fd_p->thumb_pixbuf) fd = fd_p;
-                       }
+               // Note: This implementation differs from view_file_list.c because sidecar files are not
+               // distinct list elements here, as they are in the list view.
+               if (!fd->thumb_pixbuf) return fd;
                }
 
-       return fd;
+       return NULL;
 }
 
 void vficon_thumb_reset_all(ViewFile *vf)
@@ -1836,8 +1756,7 @@ void vficon_thumb_reset_all(ViewFile *vf)
 
        while (work)
                {
-               IconData *id = work->data;
-               FileData *fd = id->fd;
+               FileData *fd = work->data;
                if (fd->thumb_pixbuf)
                        {
                        g_object_unref(fd->thumb_pixbuf);
@@ -1856,10 +1775,10 @@ void vficon_thumb_reset_all(ViewFile *vf)
 
 FileData *vficon_index_get_data(ViewFile *vf, gint row)
 {
-       IconData *id;
+       FileData *fd;
 
-       id = g_list_nth_data(vf->list, row);
-       return id ? id->fd : NULL;
+       fd = g_list_nth_data(vf->list, row);
+       return fd ? fd : NULL;
 }
 
 
@@ -1873,8 +1792,7 @@ gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd)
        work = vf->list;
        while (work)
                {
-               IconData *id = work->data;
-               FileData *fd = id->fd;
+               FileData *fd = work->data;
                if (fd == in_fd) return p;
                work = work->next;
                p++;
@@ -1883,25 +1801,6 @@ gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd)
        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)
@@ -1912,8 +1811,7 @@ guint vficon_count(ViewFile *vf, gint64 *bytes)
                work = vf->list;
                while (work)
                        {
-                       IconData *id = work->data;
-                       FileData *fd = id->fd;
+                       FileData *fd = work->data;
                        work = work->next;
 
                        b += fd->size;
@@ -1933,8 +1831,7 @@ GList *vficon_get_list(ViewFile *vf)
        work = vf->list;
        while (work)
                {
-               IconData *id = work->data;
-               FileData *fd = id->fd;
+               FileData *fd = work->data;
                work = work->next;
 
                list = g_list_prepend(list, file_data_ref(fd));
@@ -1952,13 +1849,13 @@ GList *vficon_get_list(ViewFile *vf)
 static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
 {
        gboolean ret = TRUE;
-       GList *work, *work_fd;
-       IconData *focus_id;
-       GList *new_filelist = NULL;
+       GList *work, *new_work;
+       FileData *focus_fd;
        FileData *first_selected = NULL;
-       GList *new_iconlist = NULL;
+       GList *new_filelist = NULL;
+       GList *new_fd_list = NULL;
 
-       focus_id = VFICON(vf)->focus_id;
+       focus_fd = VFICON(vf)->focus_fd;
 
        if (vf->dir_fd)
                {
@@ -1966,44 +1863,39 @@ static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
                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 */
+       vf->list = filelist_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;
+               first_selected = VFICON(vf)->selection->data;
                file_data_ref(first_selected);
                g_list_free(VFICON(vf)->selection);
                VFICON(vf)->selection = NULL;
-
-
                }
 
-       /* check for same files from old_list */
+       /* iterate old list and new list, looking for differences */
        work = vf->list;
-       work_fd = new_filelist;
-       while (work || work_fd)
+       new_work = new_filelist;
+       while (work || new_work)
                {
-               IconData *id = NULL;
                FileData *fd = NULL;
                FileData *new_fd = NULL;
                gint match;
 
-               if (work && work_fd)
+               if (work && new_work)
                        {
-                       id = work->data;
-                       fd = id->fd;
-
-                       new_fd = work_fd->data;
+                       fd = work->data;
+                       new_fd = new_work->data;
 
                        if (fd == new_fd)
                                {
                                /* not changed, go to next */
                                work = work->next;
-                               work_fd = work_fd->next;
-                               if (id->selected & SELECTION_SELECTED)
+                               new_work = new_work->next;
+                               if (fd->selected & SELECTION_SELECTED)
                                        {
-                                       VFICON(vf)->selection = g_list_prepend(VFICON(vf)->selection, id);
+                                       VFICON(vf)->selection = g_list_prepend(VFICON(vf)->selection, fd);
                                        }
                                continue;
                                }
@@ -2013,13 +1905,14 @@ static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
                        }
                else if (work)
                        {
-                       id = work->data;
-                       fd = id->fd;
+                       /* old item was deleted */
+                       fd = work->data;
                        match = -1;
                        }
-               else /* work_fd */
+               else
                        {
-                       new_fd = work_fd->data;
+                       /* new item was added */
+                       new_fd = new_work->data;
                        match = 1;
                        }
 
@@ -2028,32 +1921,33 @@ static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
                        /* 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;
+                       if (fd == VFICON(vf)->prev_selection) VFICON(vf)->prev_selection = NULL;
+                       if (fd == VFICON(vf)->click_fd) VFICON(vf)->click_fd = 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);
+                       file_data_ref(new_fd);
+                       new_fd->selected = SELECTION_NONE;
                        if (work)
-                               vf->list = g_list_insert_before(vf->list, work, id);
+                               {
+                               vf->list = g_list_insert_before(vf->list, work, new_fd);
+                               }
                        else
-                               new_iconlist = g_list_prepend(new_iconlist, id); /* it is faster to append all new entries together later */
+                               {
+                               /* it is faster to append all new entries together later */
+                               new_fd_list = g_list_prepend(new_fd_list, new_fd);
+                               }
 
-                       work_fd = work_fd->next;
+                       new_work = new_work->next;
                        }
-
                }
 
-       if (new_iconlist)
+       if (new_fd_list)
                {
-               vf->list = g_list_concat(vf->list, g_list_reverse(new_iconlist));
+               vf->list = g_list_concat(vf->list, g_list_reverse(new_fd_list));
                }
 
        VFICON(vf)->selection = g_list_reverse(VFICON(vf)->selection);
@@ -2070,9 +1964,9 @@ static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position)
        file_data_unref(first_selected);
 
        /* attempt to keep focus on same icon when refreshing */
-       if (focus_id && g_list_find(vf->list, focus_id))
+       if (focus_fd && g_list_find(vf->list, focus_fd))
                {
-               vficon_set_focus(vf, focus_id);
+               vficon_set_focus(vf, focus_fd);
                }
 
        return ret;
@@ -2100,7 +1994,7 @@ static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer
                                GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
 {
        GList *list;
-       IconData *id;
+       FileData *fd;
        ColumnData *cd = data;
        ViewFile *vf = cd->vf;
 
@@ -2108,9 +2002,9 @@ static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer
 
        gtk_tree_model_get(tree_model, iter, FILE_COLUMN_POINTER, &list, -1);
 
-       id = g_list_nth_data(list, cd->number);
+       fd = g_list_nth_data(list, cd->number);
 
-       if (id)
+       if (fd)
                {
                GdkColor color_fg;
                GdkColor color_bg;
@@ -2119,23 +2013,23 @@ static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer
                gchar *link;
                GtkStateType state = GTK_STATE_NORMAL;
 
-               g_assert(id->fd->magick == FD_MAGICK);
+               g_assert(fd->magick == FD_MAGICK);
 
-               link = islink(id->fd->path) ? GQ_LINK_STR : "";
-               if (id->fd->sidecar_files)
+               link = islink(fd->path) ? GQ_LINK_STR : "";
+               if (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);
+                       gchar *sidecars = file_data_sc_list_to_string(fd);
+                       name_sidecars = g_strdup_printf("%s%s %s", link, 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);
+                       gchar *disabled_grouping = fd->disable_grouping ? _(" [NO GROUPING]") : "";
+                       name_sidecars = g_strdup_printf("%s%s%s", link, fd->name, disabled_grouping);
                        }
 
                style = gtk_widget_get_style(vf->listview);
-               if (id->selected & SELECTION_SELECTED)
+               if (fd->selected & SELECTION_SELECTED)
                        {
                        state = GTK_STATE_SELECTED;
                        }
@@ -2143,20 +2037,20 @@ static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer
                memcpy(&color_fg, &style->text[state], sizeof(color_fg));
                memcpy(&color_bg, &style->base[state], sizeof(color_bg));
 
-               if (id->selected & SELECTION_PRELIGHT)
+               if (fd->selected & SELECTION_PRELIGHT)
                        {
                        shift_color(&color_bg, -1, 0);
                        }
 
-               g_object_set(cell,      "pixbuf", id->fd->thumb_pixbuf,
+               g_object_set(cell,      "pixbuf", fd->thumb_pixbuf,
                                        "text", name_sidecars,
-                                       "marks", file_data_get_marks(id->fd),
+                                       "marks", file_data_get_marks(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);
+                                       "has-focus", (VFICON(vf)->focus_fd == fd), NULL);
                g_free(name_sidecars);
                }
        else
@@ -2220,13 +2114,13 @@ gboolean vficon_set_fd(ViewFile *vf, FileData *dir_fd)
        g_list_free(VFICON(vf)->selection);
        VFICON(vf)->selection = NULL;
 
-       iconlist_free(vf->list);
+       g_list_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(vf)->focus_fd = NULL;
        vficon_move_focus(vf, 0, 0, FALSE);
 
        return ret;
@@ -2244,7 +2138,7 @@ void vficon_destroy_cb(GtkWidget *widget, gpointer data)
 
        vf_thumb_cleanup(vf);
 
-       iconlist_free(vf->list);
+       g_list_free(vf->list);
        g_list_free(VFICON(vf)->selection);
 }
 
similarity index 96%
rename from src/view_file_icon.h
rename to src/view_file/view_file_icon.h
index 086491b..0ca75b5 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef VIEW_FILE_ICON_H
-#define VIEW_FILE_ICON_H
+#ifndef VIEW_FILE_VIEW_FILE_ICON_H
+#define VIEW_FILE_VIEW_FILE_ICON_H
+
+#include "filedata.h"
 
 gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data);
 gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
similarity index 99%
rename from src/view_file_list.c
rename to src/view_file/view_file_list.c
index bee6bfc..38be2a9 100644 (file)
@@ -1102,6 +1102,7 @@ FileData *vflist_thumb_next_fd(ViewFile *vf)
                store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
                gtk_tree_model_get_iter(store, &iter, tpath);
                gtk_tree_path_free(tpath);
+               tpath = NULL;
 
                while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
                        {
similarity index 97%
rename from src/view_file_list.h
rename to src/view_file/view_file_list.h
index ca9e75d..38bc829 100644 (file)
@@ -19,9 +19,8 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef VIEW_FILE_LIST_H
-#define VIEW_FILE_LIST_H
-
+#ifndef VIEW_FILE_VIEW_FILE_LIST_H
+#define VIEW_FILE_VIEW_FILE_LIST_H
 
 #include "filedata.h"