X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fview_file_icon.c;h=52e13e9c3cd1f3c2ef1317b664597b07d68d711f;hb=2d3cd230c26931eec9fc02f2f76d72f7bfe5e1c4;hp=9ac7608c259ea85efb2dbd9d148c1b8e2f1044cc;hpb=5cacdd949c21b1c5b989b62eb48d91e094ef3e89;p=geeqie.git diff --git a/src/view_file_icon.c b/src/view_file_icon.c index 9ac7608c..52e13e9c 100644 --- a/src/view_file_icon.c +++ b/src/view_file_icon.c @@ -1,43 +1,50 @@ /* - * Geeqie - * (C) 2006 John Ellis - * Copyright (C) 2008 The Geeqie Team + * Copyright (C) 2006 John Ellis + * Copyright (C) 2008 - 2016 The Geeqie Team * * Author: John Ellis * - * This software is released under the GNU General Public License (GNU GPL). - * Please read the included file COPYING for more information. - * This software comes with no warranty of any kind, use at your own risk! + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "main.h" #include "view_file_icon.h" +#include "bar.h" #include "cellrenderericon.h" #include "collect.h" #include "collect-io.h" #include "collect-table.h" -#include "debug.h" #include "dnd.h" #include "editors.h" #include "img-view.h" -#include "info.h" -#include "filelist.h" +#include "filedata.h" #include "layout.h" #include "layout_image.h" #include "menu.h" +#include "metadata.h" #include "thumb.h" #include "utilops.h" -#include "ui_bookmark.h" #include "ui_fileops.h" #include "ui_menu.h" #include "ui_tree_edit.h" - +#include "uri_utils.h" +#include "view_file.h" #include /* for keyboard values */ -#define VFICON_INFO_POINTER(_vf_) ((ViewFileInfoIcon *)(_vf_->info)) -#define VFICON_INFO(_vf_, _part_) (VFICON_INFO_POINTER(_vf_)->_part_) /* between these, the icon width is increased by thumb_max_width / 2 */ #define THUMB_MIN_ICON_WIDTH 128 @@ -53,21 +60,6 @@ enum { FILE_COLUMN_COUNT }; -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; - gint row; - FileData *fd; -}; - static gint vficon_index_by_id(ViewFile *vf, IconData *in_id); static IconData *vficon_icon_data(ViewFile *vf, FileData *fd) @@ -86,37 +78,6 @@ static IconData *vficon_icon_data(ViewFile *vf, FileData *fd) return id; } - -static gint iconlist_read(const gchar *path, GList **list) -{ - GList *temp; - GList *work; - - if (!filelist_read(path, &temp, NULL)) return FALSE; - - work = temp; - while (work) - { - FileData *fd; - IconData *id; - - fd = work->data; - g_assert(fd->magick == 0x12345678); - id = g_new0(IconData, 1); - - id->selected = SELECTION_NONE; - id->row = -1; - id->fd = fd; - - work->data = id; - work = work->next; - } - - *list = temp; - - return TRUE; -} - static void iconlist_free(GList *list) { GList *work = list; @@ -132,18 +93,19 @@ static void iconlist_free(GList *list) } -gint iconlist_sort_file_cb(void *a, void *b) +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, gint ascend) + +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, gint ascend) +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); } @@ -151,10 +113,9 @@ GList *iconlist_insert_sort(GList *list, IconData *id, SortType method, gint asc static void vficon_toggle_filenames(ViewFile *vf); static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType mask, GtkTreeIter *iter); -static void vficon_move_focus(ViewFile *vf, gint row, gint col, gint relative); +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_thumb_update(ViewFile *vf); -static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gint force); +static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gboolean force); /* @@ -163,224 +124,78 @@ static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gint force *----------------------------------------------------------------------------- */ -static GList *vficon_pop_menu_file_list(ViewFile *vf) +GList *vficon_selection_get_one(ViewFile *vf, FileData *fd) { - if (!VFICON_INFO(vf, click_id)) return NULL; - - if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED) - { - return vficon_selection_get_list(vf); - } - - return g_list_append(NULL, file_data_ref(VFICON_INFO(vf, click_id)->fd)); + return g_list_prepend(filelist_copy(fd->sidecar_files), file_data_ref(fd)); } -static void vficon_pop_menu_edit_cb(GtkWidget *widget, gpointer data) +GList *vficon_pop_menu_file_list(ViewFile *vf) { - ViewFile *vf; - gint n; - GList *list; - - vf = submenu_item_get_data(widget); - n = GPOINTER_TO_INT(data); - - if (!vf) return; + if (!VFICON(vf)->click_id) return NULL; - list = vficon_pop_menu_file_list(vf); - start_editor_from_filelist(n, list); - filelist_free(list); -} - -static void vficon_pop_menu_info_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf = data; + if (VFICON(vf)->click_id->selected & SELECTION_SELECTED) + { + return vf_selection_get_list(vf); + } - info_window_new(NULL, vficon_pop_menu_file_list(vf), NULL); + return vficon_selection_get_one(vf, VFICON(vf)->click_id->fd); } -static void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data) +void vficon_pop_menu_view_cb(GtkWidget *widget, gpointer data) { ViewFile *vf = data; - if (!VFICON_INFO(vf, click_id)) return; + if (!VFICON(vf)->click_id) return; - if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED) + if (VFICON(vf)->click_id->selected & SELECTION_SELECTED) { GList *list; - list = vficon_selection_get_list(vf); + list = vf_selection_get_list(vf); view_window_new_from_list(list); filelist_free(list); } else { - view_window_new(VFICON_INFO(vf, click_id)->fd); - } -} - -static void vficon_pop_menu_copy_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf = data; - - file_util_copy(NULL, vficon_pop_menu_file_list(vf), NULL, vf->listview); -} - -static void vficon_pop_menu_move_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf = data; - - file_util_move(NULL, vficon_pop_menu_file_list(vf), NULL, vf->listview); -} - -static void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf = data; - - file_util_rename(NULL, vficon_pop_menu_file_list(vf), vf->listview); -} - -static void vficon_pop_menu_delete_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf = data; - - file_util_delete(NULL, vficon_pop_menu_file_list(vf), vf->listview); -} - -static void vficon_pop_menu_copy_path_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf = data; - - file_util_copy_path_list_to_clipboard(vficon_pop_menu_file_list(vf)); -} - -static void vficon_pop_menu_sort_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf; - SortType type; - - if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return; - - vf = submenu_item_get_data(widget); - if (!vf) return; - - type = (SortType)GPOINTER_TO_INT(data); - - if (vf->layout) - { - layout_sort_set(vf->layout, type, vf->sort_ascend); - } - else - { - vficon_sort_set(vf, type, vf->sort_ascend); - } -} - -static void vficon_pop_menu_sort_ascend_cb(GtkWidget *widget, gpointer data) -{ - ViewFile *vf = data; - - if (vf->layout) - { - layout_sort_set(vf->layout, vf->sort_method, !vf->sort_ascend); - } - else - { - vficon_sort_set(vf, vf->sort_method, !vf->sort_ascend); + view_window_new(VFICON(vf)->click_id->fd); } } -static void vficon_pop_menu_list_cb(GtkWidget *widget, gpointer data) +void vficon_pop_menu_rename_cb(GtkWidget *widget, gpointer data) { ViewFile *vf = data; - if (vf->layout) layout_views_set(vf->layout, vf->layout->dir_view_type, FALSE); + file_util_rename(NULL, vf_pop_menu_file_list(vf), vf->listview); } -static void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data) +void vficon_pop_menu_show_names_cb(GtkWidget *widget, gpointer data) { ViewFile *vf = data; vficon_toggle_filenames(vf); } -static void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data) +void vficon_pop_menu_refresh_cb(GtkWidget *widget, gpointer data) { ViewFile *vf = data; - vficon_refresh(vf); + vf_refresh(vf); } -static void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data) +void vficon_popup_destroy_cb(GtkWidget *widget, gpointer data) { ViewFile *vf = data; - vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL); - VFICON_INFO(vf, click_id) = NULL; + vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL); + VFICON(vf)->click_id = NULL; vf->popup = NULL; } -static GtkWidget *vficon_pop_menu(ViewFile *vf, gint active) -{ - GtkWidget *menu; - GtkWidget *item; - GtkWidget *submenu; - - menu = popup_menu_short_lived(); - - g_signal_connect(G_OBJECT(menu), "destroy", - G_CALLBACK(vficon_popup_destroy_cb), vf); - - submenu_add_edit(menu, &item, G_CALLBACK(vficon_pop_menu_edit_cb), vf); - gtk_widget_set_sensitive(item, active); - - menu_item_add_stock_sensitive(menu, _("_Properties"), GTK_STOCK_PROPERTIES, active, - G_CALLBACK(vficon_pop_menu_info_cb), vf); - - menu_item_add_stock_sensitive(menu, _("View in _new window"), GTK_STOCK_NEW, active, - G_CALLBACK(vficon_pop_menu_view_cb), vf); - menu_item_add_divider(menu); - - menu_item_add_stock_sensitive(menu, _("_Copy..."), GTK_STOCK_COPY, active, - G_CALLBACK(vficon_pop_menu_copy_cb), vf); - menu_item_add_sensitive(menu, _("_Move..."), active, - G_CALLBACK(vficon_pop_menu_move_cb), vf); - menu_item_add_sensitive(menu, _("_Rename..."), active, - G_CALLBACK(vficon_pop_menu_rename_cb), vf); - menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, active, - G_CALLBACK(vficon_pop_menu_delete_cb), vf); - if (options->show_copy_path) - menu_item_add_sensitive(menu, _("_Copy path"), active, - G_CALLBACK(vficon_pop_menu_copy_path_cb), vf); - menu_item_add_divider(menu); - - submenu = submenu_add_sort(NULL, G_CALLBACK(vficon_pop_menu_sort_cb), vf, - FALSE, FALSE, TRUE, vf->sort_method); - menu_item_add_divider(submenu); - menu_item_add_check(submenu, _("Ascending"), vf->sort_ascend, - G_CALLBACK(vficon_pop_menu_sort_ascend_cb), vf); - - item = menu_item_add(menu, _("_Sort"), NULL, NULL); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); - - menu_item_add_check(menu, _("View as _icons"), TRUE, - G_CALLBACK(vficon_pop_menu_list_cb), vf); - menu_item_add_check(menu, _("Show filename _text"), VFICON_INFO(vf, show_text), - G_CALLBACK(vficon_pop_menu_show_names_cb), vf); - menu_item_add_stock(menu, _("Re_fresh"), GTK_STOCK_REFRESH, G_CALLBACK(vficon_pop_menu_refresh_cb), vf); - - return menu; -} - /* *------------------------------------------------------------------- * signals *------------------------------------------------------------------- */ -static void vficon_send_update(ViewFile *vf) -{ - if (vf->func_status) vf->func_status(vf, vf->data_status); -} - static void vficon_send_layout_select(ViewFile *vf, IconData *id) { FileData *read_ahead_fd = NULL; @@ -400,13 +215,13 @@ static void vficon_send_layout_select(ViewFile *vf, IconData *id) row = g_list_index(vf->list, id); if (row > vficon_index_by_fd(vf, cur_fd) && - row + 1 < vficon_count(vf, NULL)) + (guint) (row + 1) < vf_count(vf, NULL)) { - read_ahead_fd = vficon_index_get_data(vf, row + 1); + read_ahead_fd = vf_index_get_data(vf, row + 1); } else if (row > 0) { - read_ahead_fd = vficon_index_get_data(vf, row - 1); + read_ahead_fd = vf_index_get_data(vf, row - 1); } } @@ -415,17 +230,19 @@ static void vficon_send_layout_select(ViewFile *vf, IconData *id) static void vficon_toggle_filenames(ViewFile *vf) { - VFICON_INFO(vf, show_text) = !VFICON_INFO(vf, show_text); - options->show_icon_names = VFICON_INFO(vf, show_text); + GtkAllocation allocation; + VFICON(vf)->show_text = !VFICON(vf)->show_text; + options->show_icon_names = VFICON(vf)->show_text; - vficon_populate_at_new_size(vf, vf->listview->allocation.width, vf->listview->allocation.height, TRUE); + gtk_widget_get_allocation(vf->listview, &allocation); + vficon_populate_at_new_size(vf, allocation.width, allocation.height, TRUE); } static gint vficon_get_icon_width(ViewFile *vf) { gint width; - if (!VFICON_INFO(vf, show_text)) return options->thumbnails.max_width; + if (!VFICON(vf)->show_text) return options->thumbnails.max_width; width = options->thumbnails.max_width + options->thumbnails.max_width / 2; if (width < THUMB_MIN_ICON_WIDTH) width = THUMB_MIN_ICON_WIDTH; @@ -440,7 +257,7 @@ static gint vficon_get_icon_width(ViewFile *vf) *------------------------------------------------------------------- */ -static gint vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint *col) +static gboolean vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint *col) { gint n; @@ -448,13 +265,13 @@ static gint vficon_find_position(ViewFile *vf, IconData *id, gint *row, gint *co if (n < 0) return FALSE; - *row = n / VFICON_INFO(vf, columns); - *col = n - (*row * VFICON_INFO(vf, columns)); + *row = n / VFICON(vf)->columns; + *col = n - (*row * VFICON(vf)->columns); return TRUE; } -static gint vficon_find_iter(ViewFile *vf, IconData *id, GtkTreeIter *iter, gint *column) +static gboolean vficon_find_iter(ViewFile *vf, IconData *id, GtkTreeIter *iter, gint *column) { GtkTreeModel *store; gint row, col; @@ -520,6 +337,35 @@ static IconData *vficon_find_data_by_coord(ViewFile *vf, gint x, gint y, GtkTree return NULL; } +static void vficon_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data) +{ + ViewFile *vf = data; + GtkTreeModel *store; + GtkTreePath *path = gtk_tree_path_new_from_string(path_str); + GtkTreeIter row; + gint column; + GList *list; + guint toggled_mark; + IconData *id; + + store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); + if (!path || !gtk_tree_model_get_iter(store, &row, path)) + return; + + gtk_tree_model_get(store, &row, FILE_COLUMN_POINTER, &list, -1); + + column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_number")); + g_object_get(G_OBJECT(cell), "toggled_mark", &toggled_mark, NULL); + + id = g_list_nth_data(list, column); + if (id) + { + FileData *fd = id->fd; + file_data_set_mark(fd, toggled_mark, !file_data_get_mark(fd, toggled_mark)); + } +} + + /* *------------------------------------------------------------------- * tooltip type window @@ -530,53 +376,73 @@ static void tip_show(ViewFile *vf) { GtkWidget *label; gint x, y; +#if GTK_CHECK_VERSION(3,0,0) + GdkDisplay *display; + GdkDeviceManager *device_manager; + GdkDevice *device; +#endif - if (VFICON_INFO(vf, tip_window)) return; + if (VFICON(vf)->tip_window) return; +#if GTK_CHECK_VERSION(3,0,0) + device_manager = gdk_display_get_device_manager(gdk_window_get_display( + gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)))); + device = gdk_device_manager_get_client_pointer(device_manager); + gdk_window_get_device_position(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)), + device, &x, &y, NULL); +#else gdk_window_get_pointer(gtk_tree_view_get_bin_window(GTK_TREE_VIEW(vf->listview)), &x, &y, NULL); +#endif - VFICON_INFO(vf, tip_id) = vficon_find_data_by_coord(vf, x, y, NULL); - if (!VFICON_INFO(vf, tip_id)) return; + VFICON(vf)->tip_id = vficon_find_data_by_coord(vf, x, y, NULL); + if (!VFICON(vf)->tip_id) return; - VFICON_INFO(vf, tip_window) = gtk_window_new(GTK_WINDOW_POPUP); - gtk_window_set_resizable(GTK_WINDOW(VFICON_INFO(vf, tip_window)), FALSE); - gtk_container_set_border_width(GTK_CONTAINER(VFICON_INFO(vf, tip_window)), 2); + 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_INFO(vf, tip_id)->fd->name); + label = gtk_label_new(VFICON(vf)->tip_id->fd->name); - g_object_set_data(G_OBJECT(VFICON_INFO(vf, tip_window)), "tip_label", label); - gtk_container_add(GTK_CONTAINER(VFICON_INFO(vf, tip_window)), label); + g_object_set_data(G_OBJECT(VFICON(vf)->tip_window), "tip_label", label); + gtk_container_add(GTK_CONTAINER(VFICON(vf)->tip_window), label); gtk_widget_show(label); +#if GTK_CHECK_VERSION(3,0,0) + display = gdk_display_get_default(); + device_manager = gdk_display_get_device_manager(display); + device = gdk_device_manager_get_client_pointer(device_manager); + gdk_device_get_position(device, NULL, &x, &y); +#else gdk_window_get_pointer(NULL, &x, &y, NULL); +#endif - if (!GTK_WIDGET_REALIZED(VFICON_INFO(vf, tip_window))) gtk_widget_realize(VFICON_INFO(vf, tip_window)); - gtk_window_move(GTK_WINDOW(VFICON_INFO(vf, tip_window)), x + 16, y + 16); - gtk_widget_show(VFICON_INFO(vf, tip_window)); + if (!gtk_widget_get_realized(VFICON(vf)->tip_window)) gtk_widget_realize(VFICON(vf)->tip_window); + gtk_window_move(GTK_WINDOW(VFICON(vf)->tip_window), x + 16, y + 16); + gtk_widget_show(VFICON(vf)->tip_window); } static void tip_hide(ViewFile *vf) { - if (VFICON_INFO(vf, tip_window)) gtk_widget_destroy(VFICON_INFO(vf, tip_window)); - VFICON_INFO(vf, tip_window) = NULL; + if (VFICON(vf)->tip_window) gtk_widget_destroy(VFICON(vf)->tip_window); + VFICON(vf)->tip_window = NULL; } -static gint tip_schedule_cb(gpointer data) +static gboolean tip_schedule_cb(gpointer data) { ViewFile *vf = data; GtkWidget *window; - if (VFICON_INFO(vf, tip_delay_id) == -1) return FALSE; + if (!VFICON(vf)->tip_delay_id) return FALSE; window = gtk_widget_get_toplevel(vf->listview); - if (GTK_WIDGET_SENSITIVE(window) && - GTK_WINDOW(window)->has_focus) + if (gtk_widget_get_sensitive(window) && + gtk_window_has_toplevel_focus(GTK_WINDOW(window))) { tip_show(vf); } - VFICON_INFO(vf, tip_delay_id) = -1; + VFICON(vf)->tip_delay_id = 0; return FALSE; } @@ -584,15 +450,15 @@ static void tip_schedule(ViewFile *vf) { tip_hide(vf); - if (VFICON_INFO(vf, tip_delay_id) != -1) + if (VFICON(vf)->tip_delay_id) { - g_source_remove(VFICON_INFO(vf, tip_delay_id)); - VFICON_INFO(vf, tip_delay_id) = -1; + g_source_remove(VFICON(vf)->tip_delay_id); + VFICON(vf)->tip_delay_id = 0; } - if (!VFICON_INFO(vf, show_text)) + if (!VFICON(vf)->show_text) { - VFICON_INFO(vf, tip_delay_id) = g_timeout_add(VFICON_TIP_DELAY, tip_schedule_cb, vf); + VFICON(vf)->tip_delay_id = g_timeout_add(VFICON_TIP_DELAY, tip_schedule_cb, vf); } } @@ -600,34 +466,47 @@ static void tip_unschedule(ViewFile *vf) { tip_hide(vf); - if (VFICON_INFO(vf, tip_delay_id) != -1) g_source_remove(VFICON_INFO(vf, tip_delay_id)); - VFICON_INFO(vf, tip_delay_id) = -1; + if (VFICON(vf)->tip_delay_id) + { + g_source_remove(VFICON(vf)->tip_delay_id); + VFICON(vf)->tip_delay_id = 0; + } } static void tip_update(ViewFile *vf, IconData *id) { - if (VFICON_INFO(vf, tip_window)) +#if GTK_CHECK_VERSION(3,0,0) + GdkDisplay *display = gdk_display_get_default(); + GdkDeviceManager *device_manager = gdk_display_get_device_manager(display); + GdkDevice *device = gdk_device_manager_get_client_pointer(device_manager); +#endif + + if (VFICON(vf)->tip_window) { gint x, y; +#if GTK_CHECK_VERSION(3,0,0) + gdk_device_get_position(device, NULL, &x, &y); +#else gdk_window_get_pointer(NULL, &x, &y, NULL); - gtk_window_move(GTK_WINDOW(VFICON_INFO(vf, tip_window)), x + 16, y + 16); +#endif + gtk_window_move(GTK_WINDOW(VFICON(vf)->tip_window), x + 16, y + 16); - if (id != VFICON_INFO(vf, tip_id)) + if (id != VFICON(vf)->tip_id) { GtkWidget *label; - VFICON_INFO(vf, tip_id) = id; + VFICON(vf)->tip_id = id; - if (!VFICON_INFO(vf, tip_id)) + if (!VFICON(vf)->tip_id) { tip_hide(vf); tip_schedule(vf); return; } - label = g_object_get_data(G_OBJECT(VFICON_INFO(vf, tip_window)), "tip_label"); - gtk_label_set_text(GTK_LABEL(label), VFICON_INFO(vf, tip_id)->fd->name); + label = g_object_get_data(G_OBJECT(VFICON(vf)->tip_window), "tip_label"); + gtk_label_set_text(GTK_LABEL(label), VFICON(vf)->tip_id->fd->name); } } else @@ -648,29 +527,43 @@ static void vficon_dnd_get(GtkWidget *widget, GdkDragContext *context, { ViewFile *vf = data; GList *list = NULL; - gchar *uri_text = NULL; - gint total; - if (!VFICON_INFO(vf, click_id)) return; + if (!VFICON(vf)->click_id) return; - if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED) + if (VFICON(vf)->click_id->selected & SELECTION_SELECTED) { - list = vficon_selection_get_list(vf); + list = vf_selection_get_list(vf); } else { - list = g_list_append(NULL, file_data_ref(VFICON_INFO(vf, click_id)->fd)); + list = g_list_append(NULL, file_data_ref(VFICON(vf)->click_id->fd)); } if (!list) return; - uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN)); + uri_selection_data_set_uris_from_filelist(selection_data, list); filelist_free(list); +} + +static void vficon_drag_data_received(GtkWidget *entry_widget, GdkDragContext *context, + int x, int y, GtkSelectionData *selection, + guint info, guint time, gpointer data) +{ + ViewFile *vf = data; + + if (info == TARGET_TEXT_PLAIN) { + IconData *id = vficon_find_data_by_coord(vf, x, y, NULL); - DEBUG_1(uri_text); + if (id && id->fd) { + /* Add keywords to file */ + FileData *fd = id->fd; + gchar *str = (gchar *) gtk_selection_data_get_text(selection); + GList *kw_list = string_to_keywords_list(str); - gtk_selection_data_set(selection_data, selection_data->target, - 8, (guchar *)uri_text, total); - g_free(uri_text); + metadata_append_list(fd, KEYWORD_KEY, kw_list); + string_list_free(kw_list); + g_free(str); + } + } } static void vficon_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data) @@ -679,16 +572,16 @@ static void vficon_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointe tip_unschedule(vf); - if (VFICON_INFO(vf, click_id) && VFICON_INFO(vf, click_id)->fd->pixbuf) + if (VFICON(vf)->click_id && VFICON(vf)->click_id->fd->thumb_pixbuf) { gint items; - if (VFICON_INFO(vf, click_id)->selected & SELECTION_SELECTED) - items = g_list_length(VFICON_INFO(vf, selection)); + if (VFICON(vf)->click_id->selected & SELECTION_SELECTED) + items = g_list_length(VFICON(vf)->selection); else items = 1; - dnd_set_drag_icon(widget, context, VFICON_INFO(vf, click_id)->fd->pixbuf, items); + dnd_set_drag_icon(widget, context, VFICON(vf)->click_id->fd->thumb_pixbuf, items); } } @@ -696,11 +589,11 @@ static void vficon_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer { ViewFile *vf = data; - vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL); + vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL); - if (context->action == GDK_ACTION_MOVE) + if (gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE) { - vficon_refresh(vf); + vf_refresh(vf); } tip_unschedule(vf); @@ -711,12 +604,18 @@ void vficon_dnd_init(ViewFile *vf) gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, dnd_file_drag_types, dnd_file_drag_types_count, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); + gtk_drag_dest_set(vf->listview, GTK_DEST_DEFAULT_ALL, + dnd_file_drag_types, dnd_file_drag_types_count, + GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); + g_signal_connect(G_OBJECT(vf->listview), "drag_data_get", G_CALLBACK(vficon_dnd_get), vf); g_signal_connect(G_OBJECT(vf->listview), "drag_begin", G_CALLBACK(vficon_dnd_begin), vf); g_signal_connect(G_OBJECT(vf->listview), "drag_end", G_CALLBACK(vficon_dnd_end), vf); + g_signal_connect(G_OBJECT(vf->listview), "drag_data_received", + G_CALLBACK(vficon_drag_data_received), vf); } /* @@ -768,6 +667,13 @@ static void vficon_selection_remove(ViewFile *vf, IconData *id, SelectionType ma vficon_selection_set(vf, id, id->selected & ~mask, iter); } +void vficon_marks_set(ViewFile *vf, gint enable) +{ + GtkAllocation allocation; + gtk_widget_get_allocation(vf->listview, &allocation); + vficon_populate_at_new_size(vf, allocation.width, allocation.height, TRUE); +} + /* *------------------------------------------------------------------- * selections @@ -778,7 +684,7 @@ static void vficon_verify_selections(ViewFile *vf) { GList *work; - work = VFICON_INFO(vf, selection); + work = VFICON(vf)->selection; while (work) { IconData *id = work->data; @@ -786,7 +692,7 @@ static void vficon_verify_selections(ViewFile *vf) if (vficon_index_by_id(vf, id) >= 0) continue; - VFICON_INFO(vf, selection) = g_list_remove(VFICON_INFO(vf, selection), id); + VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id); } } @@ -794,27 +700,27 @@ void vficon_select_all(ViewFile *vf) { GList *work; - g_list_free(VFICON_INFO(vf, selection)); - VFICON_INFO(vf, selection) = NULL; + g_list_free(VFICON(vf)->selection); + VFICON(vf)->selection = NULL; work = vf->list; while (work) { IconData *id = work->data; work = work->next; - - VFICON_INFO(vf, selection) = g_list_append(VFICON_INFO(vf, selection), id); + + VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id); vficon_selection_add(vf, id, SELECTION_SELECTED, NULL); } - vficon_send_update(vf); + vf_send_update(vf); } void vficon_select_none(ViewFile *vf) { GList *work; - work = VFICON_INFO(vf, selection); + work = VFICON(vf)->selection; while (work) { IconData *id = work->data; @@ -823,37 +729,62 @@ void vficon_select_none(ViewFile *vf) vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL); } - g_list_free(VFICON_INFO(vf, selection)); - VFICON_INFO(vf, selection) = NULL; + g_list_free(VFICON(vf)->selection); + VFICON(vf)->selection = NULL; + + vf_send_update(vf); +} + +void vficon_select_invert(ViewFile *vf) +{ + GList *work; + + work = vf->list; + while (work) + { + IconData *id = work->data; + work = work->next; + + if (id->selected & SELECTION_SELECTED) + { + VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id); + vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL); + } + else + { + VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id); + vficon_selection_add(vf, id, SELECTION_SELECTED, NULL); + } + } - vficon_send_update(vf); + vf_send_update(vf); } static void vficon_select(ViewFile *vf, IconData *id) { - VFICON_INFO(vf, prev_selection) = id; + VFICON(vf)->prev_selection = id; if (!id || id->selected & SELECTION_SELECTED) return; - VFICON_INFO(vf, selection) = g_list_append(VFICON_INFO(vf, selection), id); + VFICON(vf)->selection = g_list_append(VFICON(vf)->selection, id); vficon_selection_add(vf, id, SELECTION_SELECTED, NULL); - vficon_send_update(vf); + vf_send_update(vf); } static void vficon_unselect(ViewFile *vf, IconData *id) { - VFICON_INFO(vf, prev_selection) = id; + VFICON(vf)->prev_selection = id; if (!id || !(id->selected & SELECTION_SELECTED) ) return; - VFICON_INFO(vf, selection) = g_list_remove(VFICON_INFO(vf, selection), id); + VFICON(vf)->selection = g_list_remove(VFICON(vf)->selection, id); vficon_selection_remove(vf, id, SELECTION_SELECTED, NULL); - vficon_send_update(vf); + vf_send_update(vf); } -static void vficon_select_util(ViewFile *vf, IconData *id, gint select) +static void vficon_select_util(ViewFile *vf, IconData *id, gboolean select) { if (select) { @@ -865,7 +796,7 @@ static void vficon_select_util(ViewFile *vf, IconData *id, gint select) } } -static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *end, gint select) +static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *end, gboolean select) { gint row1, col1; gint row2, col2; @@ -875,7 +806,7 @@ static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *e if (!vficon_find_position(vf, start, &row1, &col1) || !vficon_find_position(vf, end, &row2, &col2) ) return; - VFICON_INFO(vf, prev_selection) = end; + VFICON(vf)->prev_selection = end; if (!options->collections.rectangular_selection) { @@ -928,7 +859,7 @@ static void vficon_select_region_util(ViewFile *vf, IconData *start, IconData *e } } -gint vficon_index_is_selected(ViewFile *vf, gint row) +gboolean vficon_index_is_selected(ViewFile *vf, gint row) { IconData *id = g_list_nth_data(vf->list, row); @@ -937,19 +868,19 @@ gint vficon_index_is_selected(ViewFile *vf, gint row) return (id->selected & SELECTION_SELECTED); } -gint vficon_selection_count(ViewFile *vf, gint64 *bytes) +guint vficon_selection_count(ViewFile *vf, gint64 *bytes) { if (bytes) { gint64 b = 0; GList *work; - work = VFICON_INFO(vf, selection); + work = VFICON(vf)->selection; while (work) { IconData *id = work->data; FileData *fd = id->fd; - g_assert(fd->magick == 0x12345678); + g_assert(fd->magick == FD_MAGICK); b += fd->size; work = work->next; @@ -958,23 +889,31 @@ gint vficon_selection_count(ViewFile *vf, gint64 *bytes) *bytes = b; } - return g_list_length(VFICON_INFO(vf, selection)); + return g_list_length(VFICON(vf)->selection); } GList *vficon_selection_get_list(ViewFile *vf) { GList *list = NULL; - GList *work; + GList *work, *work2; - work = VFICON_INFO(vf, selection); + work = VFICON(vf)->selection; while (work) { IconData *id = work->data; FileData *fd = id->fd; - g_assert(fd->magick == 0x12345678); + g_assert(fd->magick == FD_MAGICK); list = g_list_prepend(list, file_data_ref(fd)); + work2 = fd->sidecar_files; + while (work2) + { + fd = work2->data; + list = g_list_prepend(list, file_data_ref(fd)); + work2 = work2->next; + } + work = work->next; } @@ -988,7 +927,7 @@ GList *vficon_selection_get_list_by_index(ViewFile *vf) GList *list = NULL; GList *work; - work = VFICON_INFO(vf, selection); + work = VFICON(vf)->selection; while (work) { list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, work->data))); @@ -1004,7 +943,7 @@ static void vficon_select_by_id(ViewFile *vf, IconData *id) if (!(id->selected & SELECTION_SELECTED)) { - vficon_select_none(vf); + vf_select_none(vf); vficon_select(vf, id); } @@ -1030,6 +969,9 @@ void vficon_select_by_fd(ViewFile *vf, FileData *fd) void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode) { GList *work; + gint n = mark - 1; + + g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE); work = vf->list; while (work) @@ -1038,20 +980,20 @@ void vficon_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode) FileData *fd = id->fd; gboolean mark_val, selected; - g_assert(fd->magick == 0x12345678); + g_assert(fd->magick == FD_MAGICK); - mark_val = fd->marks[mark]; + mark_val = file_data_get_mark(fd, n); selected = (id->selected & SELECTION_SELECTED); switch (mode) { case MTS_MODE_SET: selected = mark_val; break; - case MTS_MODE_OR: selected = mark_val | selected; + case MTS_MODE_OR: selected = mark_val || selected; break; - case MTS_MODE_AND: selected = mark_val & selected; + case MTS_MODE_AND: selected = mark_val && selected; break; - case MTS_MODE_MINUS: selected = !mark_val & selected; + case MTS_MODE_MINUS: selected = !mark_val && selected; break; } @@ -1065,10 +1007,11 @@ void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode) { GList *slist; GList *work; + gint n = mark -1; - g_assert(mark >= 0 && mark < FILEDATA_MARKS_SIZE); + g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE); - slist = vficon_selection_get_list(vf); + slist = vf_selection_get_list(vf); work = slist; while (work) { @@ -1076,19 +1019,47 @@ void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode) switch (mode) { - case STM_MODE_SET: fd->marks[mark] = 1; + case STM_MODE_SET: file_data_set_mark(fd, n, 1); break; - case STM_MODE_RESET: fd->marks[mark] = 0; + case STM_MODE_RESET: file_data_set_mark(fd, n, 0); break; - case STM_MODE_TOGGLE: fd->marks[mark] = !fd->marks[mark]; + case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n)); break; } - work = work->next; } filelist_free(slist); } +static void vficon_select_closest(ViewFile *vf, FileData *sel_fd) +{ + GList *work; + IconData *id = NULL; + + if (sel_fd->parent) sel_fd = sel_fd->parent; + work = vf->list; + + while (work) + { + gint match; + FileData *fd; + + id = work->data; + fd = id->fd; + work = work->next; + + match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend); + + if (match >= 0) break; + } + + if (id) + { + vficon_select(vf, id); + vficon_send_layout_select(vf, id); + } +} + /* *------------------------------------------------------------------- @@ -1096,19 +1067,19 @@ void vficon_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode) *------------------------------------------------------------------- */ -static void vficon_move_focus(ViewFile *vf, gint row, gint col, gint relative) +static void vficon_move_focus(ViewFile *vf, gint row, gint col, gboolean relative) { gint new_row; gint new_col; if (relative) { - new_row = VFICON_INFO(vf, focus_row); - new_col = VFICON_INFO(vf, focus_column); + new_row = VFICON(vf)->focus_row; + new_col = VFICON(vf)->focus_column; new_row += row; if (new_row < 0) new_row = 0; - if (new_row >= VFICON_INFO(vf, rows)) new_row = VFICON_INFO(vf, rows) - 1; + if (new_row >= VFICON(vf)->rows) new_row = VFICON(vf)->rows - 1; while (col != 0) { @@ -1128,23 +1099,23 @@ static void vficon_move_focus(ViewFile *vf, gint row, gint col, gint relative) if (new_row > 0) { new_row--; - new_col = VFICON_INFO(vf, columns) - 1; + new_col = VFICON(vf)->columns - 1; } else { new_col = 0; } } - if (new_col >= VFICON_INFO(vf, columns)) + if (new_col >= VFICON(vf)->columns) { - if (new_row < VFICON_INFO(vf, rows) - 1) + if (new_row < VFICON(vf)->rows - 1) { new_row++; new_col = 0; } else { - new_col = VFICON_INFO(vf, columns) - 1; + new_col = VFICON(vf)->columns - 1; } } } @@ -1154,25 +1125,25 @@ static void vficon_move_focus(ViewFile *vf, gint row, gint col, gint relative) new_row = row; new_col = col; - if (new_row >= VFICON_INFO(vf, rows)) + if (new_row >= VFICON(vf)->rows) { - if (VFICON_INFO(vf, rows) > 0) - new_row = VFICON_INFO(vf, rows) - 1; + if (VFICON(vf)->rows > 0) + new_row = VFICON(vf)->rows - 1; else new_row = 0; - new_col = VFICON_INFO(vf, columns) - 1; + new_col = VFICON(vf)->columns - 1; } - if (new_col >= VFICON_INFO(vf, columns)) new_col = VFICON_INFO(vf, columns) - 1; + if (new_col >= VFICON(vf)->columns) new_col = VFICON(vf)->columns - 1; } - if (new_row == VFICON_INFO(vf, rows) - 1) + if (new_row == VFICON(vf)->rows - 1) { gint l; /* if we moved beyond the last image, go to the last image */ l = g_list_length(vf->list); - if (VFICON_INFO(vf, rows) > 1) l -= (VFICON_INFO(vf, rows) - 1) * VFICON_INFO(vf, columns); + if (VFICON(vf)->rows > 1) l -= (VFICON(vf)->rows - 1) * VFICON(vf)->columns; if (new_col >= l) new_col = l - 1; } @@ -1184,31 +1155,41 @@ static void vficon_set_focus(ViewFile *vf, IconData *id) GtkTreeIter iter; gint row, col; - if (g_list_find(vf->list, VFICON_INFO(vf, focus_id))) + if (g_list_find(vf->list, VFICON(vf)->focus_id)) { - if (id == VFICON_INFO(vf, focus_id)) + if (id == VFICON(vf)->focus_id) { /* ensure focus row col are correct */ - vficon_find_position(vf, VFICON_INFO(vf, focus_id), &VFICON_INFO(vf, focus_row), &VFICON_INFO(vf, focus_column)); + vficon_find_position(vf, VFICON(vf)->focus_id, &VFICON(vf)->focus_row, &VFICON(vf)->focus_column); +#if GTK_CHECK_VERSION(3,0,0) +/* FIXME: Refer to issue #467 on Github. The thumbnail position is not + * preserved when the icon view is refreshed. Caused by an unknown call from + * the idle loop. This patch hides the problem. + */ + if (vficon_find_iter(vf, VFICON(vf)->focus_id, &iter, NULL)) + { + tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE); + } +#endif return; } - vficon_selection_remove(vf, VFICON_INFO(vf, focus_id), SELECTION_FOCUS, NULL); + vficon_selection_remove(vf, VFICON(vf)->focus_id, SELECTION_FOCUS, NULL); } if (!vficon_find_position(vf, id, &row, &col)) { - VFICON_INFO(vf, focus_id) = NULL; - VFICON_INFO(vf, focus_row) = -1; - VFICON_INFO(vf, focus_column) = -1; + VFICON(vf)->focus_id = NULL; + VFICON(vf)->focus_row = -1; + VFICON(vf)->focus_column = -1; return; } - VFICON_INFO(vf, focus_id) = id; - VFICON_INFO(vf, focus_row) = row; - VFICON_INFO(vf, focus_column) = col; - vficon_selection_add(vf, VFICON_INFO(vf, focus_id), SELECTION_FOCUS, NULL); + VFICON(vf)->focus_id = id; + VFICON(vf)->focus_row = row; + VFICON(vf)->focus_column = col; + vficon_selection_add(vf, VFICON(vf)->focus_id, SELECTION_FOCUS, NULL); - if (vficon_find_iter(vf, VFICON_INFO(vf, focus_id), &iter, NULL)) + if (vficon_find_iter(vf, VFICON(vf)->focus_id, &iter, NULL)) { GtkTreePath *tpath; GtkTreeViewColumn *column; @@ -1225,25 +1206,6 @@ static void vficon_set_focus(ViewFile *vf, IconData *id) } } -static void vficon_update_focus(ViewFile *vf) -{ - gint new_row = 0; - gint new_col = 0; - - if (VFICON_INFO(vf, focus_id) && vficon_find_position(vf, VFICON_INFO(vf, focus_id), &new_row, &new_col)) - { - /* first find the old focus, if it exists and is valid */ - } - else - { - /* (try to) stay where we were */ - new_row = VFICON_INFO(vf, focus_row); - new_col = VFICON_INFO(vf, focus_column); - } - - vficon_move_focus(vf, new_row, new_col, FALSE); -} - /* used to figure the page up/down distances */ static gint page_height(ViewFile *vf) { @@ -1253,10 +1215,10 @@ static gint page_height(ViewFile *vf) gint ret; adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(vf->listview)); - page_size = (gint)adj->page_increment; + page_size = (gint)gtk_adjustment_get_page_increment(adj); row_height = options->thumbnails.max_height + THUMB_BORDER_PADDING * 2; - if (VFICON_INFO(vf, show_text)) row_height += options->thumbnails.max_height / 3; + if (VFICON(vf)->show_text) row_height += options->thumbnails.max_height / 3; ret = page_size / row_height; if (ret < 1) ret = 1; @@ -1279,7 +1241,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_INFO(vf, click_id), &iter, &column)) return; + if (!vficon_find_iter(vf, VFICON(vf)->click_id, &iter, &column)) return; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); tpath = gtk_tree_model_get_path(store, &iter); tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, column, FALSE, x, y, &cw, &ch); @@ -1288,48 +1250,48 @@ static void vfi_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push popup_menu_position_clamp(menu, x, y, 0); } -gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) +gboolean vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) { ViewFile *vf = data; gint focus_row = 0; gint focus_col = 0; IconData *id; - gint stop_signal; + gboolean stop_signal; stop_signal = TRUE; switch (event->keyval) { - case GDK_Left: case GDK_KP_Left: + case GDK_KEY_Left: case GDK_KEY_KP_Left: focus_col = -1; break; - case GDK_Right: case GDK_KP_Right: + case GDK_KEY_Right: case GDK_KEY_KP_Right: focus_col = 1; break; - case GDK_Up: case GDK_KP_Up: + case GDK_KEY_Up: case GDK_KEY_KP_Up: focus_row = -1; break; - case GDK_Down: case GDK_KP_Down: + case GDK_KEY_Down: case GDK_KEY_KP_Down: focus_row = 1; break; - case GDK_Page_Up: case GDK_KP_Page_Up: + case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up: focus_row = -page_height(vf); break; - case GDK_Page_Down: case GDK_KP_Page_Down: + case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down: focus_row = page_height(vf); break; - case GDK_Home: case GDK_KP_Home: - focus_row = -VFICON_INFO(vf, focus_row); - focus_col = -VFICON_INFO(vf, focus_column); + case GDK_KEY_Home: case GDK_KEY_KP_Home: + focus_row = -VFICON(vf)->focus_row; + focus_col = -VFICON(vf)->focus_column; break; - case GDK_End: case GDK_KP_End: - focus_row = VFICON_INFO(vf, rows) - 1 - VFICON_INFO(vf, focus_row); - focus_col = VFICON_INFO(vf, columns) - 1 - VFICON_INFO(vf, focus_column); + case GDK_KEY_End: case GDK_KEY_KP_End: + focus_row = VFICON(vf)->rows - 1 - VFICON(vf)->focus_row; + focus_col = VFICON(vf)->columns - 1 - VFICON(vf)->focus_column; break; - case GDK_space: - id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL); + case GDK_KEY_space: + id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL); if (id) { - VFICON_INFO(vf, click_id) = id; + VFICON(vf)->click_id = id; if (event->state & GDK_CONTROL_MASK) { gint selected; @@ -1347,20 +1309,20 @@ gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) } else { - vficon_select_none(vf); + vf_select_none(vf); vficon_select(vf, id); vficon_send_layout_select(vf, id); } } break; - case GDK_Menu: - id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL); - VFICON_INFO(vf, click_id) = id; + case GDK_KEY_Menu: + id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL); + VFICON(vf)->click_id = id; - vficon_selection_add(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL); + vficon_selection_add(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL); tip_unschedule(vf); - vf->popup = vficon_pop_menu(vf, (id != NULL)); + vf->popup = vf_pop_menu(vf); gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vfi_menu_position_cb, vf, 0, GDK_CURRENT_TIME); break; default: @@ -1373,9 +1335,9 @@ gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) IconData *new_id; IconData *old_id; - old_id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL); + old_id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL); vficon_move_focus(vf, focus_row, focus_col, TRUE); - new_id = vficon_find_data(vf, VFICON_INFO(vf, focus_row), VFICON_INFO(vf, focus_column), NULL); + new_id = vficon_find_data(vf, VFICON(vf)->focus_row, VFICON(vf)->focus_column, NULL); if (new_id != old_id) { @@ -1387,19 +1349,19 @@ gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) } else { - vficon_select_region_util(vf, VFICON_INFO(vf, click_id), old_id, FALSE); + vficon_select_region_util(vf, VFICON(vf)->click_id, old_id, FALSE); } - vficon_select_region_util(vf, VFICON_INFO(vf, click_id), new_id, TRUE); + vficon_select_region_util(vf, VFICON(vf)->click_id, new_id, TRUE); vficon_send_layout_select(vf, new_id); } else if (event->state & GDK_CONTROL_MASK) { - VFICON_INFO(vf, click_id) = new_id; + VFICON(vf)->click_id = new_id; } else { - VFICON_INFO(vf, click_id) = new_id; - vficon_select_none(vf); + VFICON(vf)->click_id = new_id; + vf_select_none(vf); vficon_select(vf, new_id); vficon_send_layout_select(vf, new_id); } @@ -1408,9 +1370,6 @@ gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) if (stop_signal) { -#if 0 - g_signal_stop_emission_by_name(GTK_OBJECT(widget), "key_press_event"); -#endif tip_unschedule(vf); } @@ -1423,18 +1382,18 @@ gint vficon_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) *------------------------------------------------------------------- */ -static gint vficon_motion_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) +static gboolean vficon_motion_cb(GtkWidget *widget, GdkEventMotion *event, gpointer data) { ViewFile *vf = data; IconData *id; - id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, NULL); + id = vficon_find_data_by_coord(vf, (gint)event->x, (gint)event->y, NULL); tip_update(vf, id); return FALSE; } -gint vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) +gboolean vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) { ViewFile *vf = data; GtkTreeIter iter; @@ -1444,42 +1403,41 @@ gint vficon_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter); - VFICON_INFO(vf, click_id) = id; - vficon_selection_add(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, &iter); + VFICON(vf)->click_id = id; + vficon_selection_add(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, &iter); switch (bevent->button) { case MOUSE_BUTTON_LEFT: - if (!GTK_WIDGET_HAS_FOCUS(vf->listview)) + if (!gtk_widget_has_focus(vf->listview)) { gtk_widget_grab_focus(vf->listview); } -#if 0 + if (bevent->type == GDK_2BUTTON_PRESS && vf->layout) { - vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, &iter); + vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, &iter); layout_image_full_screen_start(vf->layout); } -#endif break; case MOUSE_BUTTON_RIGHT: - vf->popup = vficon_pop_menu(vf, (id != NULL)); + vf->popup = vf_pop_menu(vf); gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL, bevent->button, bevent->time); break; default: break; } - return TRUE; + return FALSE; } -gint vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) +gboolean vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) { ViewFile *vf = data; GtkTreeIter iter; IconData *id = NULL; - gint was_selected; + gboolean was_selected; tip_schedule(vf); @@ -1488,14 +1446,14 @@ gint vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) id = vficon_find_data_by_coord(vf, (gint)bevent->x, (gint)bevent->y, &iter); } - if (VFICON_INFO(vf, click_id)) + if (VFICON(vf)->click_id) { - vficon_selection_remove(vf, VFICON_INFO(vf, click_id), SELECTION_PRELIGHT, NULL); + vficon_selection_remove(vf, VFICON(vf)->click_id, SELECTION_PRELIGHT, NULL); } - if (!id || VFICON_INFO(vf, click_id) != id) return TRUE; + if (!id || VFICON(vf)->click_id != id) return TRUE; - was_selected = (id->selected & SELECTION_SELECTED); + was_selected = !!(id->selected & SELECTION_SELECTED); switch (bevent->button) { @@ -1505,12 +1463,12 @@ gint vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) if (bevent->state & GDK_CONTROL_MASK) { - gint select; + gboolean select; select = !(id->selected & SELECTION_SELECTED); - if ((bevent->state & GDK_SHIFT_MASK) && VFICON_INFO(vf, prev_selection)) + if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection) { - vficon_select_region_util(vf, VFICON_INFO(vf, prev_selection), id, select); + vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, select); } else { @@ -1519,11 +1477,11 @@ gint vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) } else { - vficon_select_none(vf); + vf_select_none(vf); - if ((bevent->state & GDK_SHIFT_MASK) && VFICON_INFO(vf, prev_selection)) + if ((bevent->state & GDK_SHIFT_MASK) && VFICON(vf)->prev_selection) { - vficon_select_region_util(vf, VFICON_INFO(vf, prev_selection), id, TRUE); + vficon_select_region_util(vf, VFICON(vf)->prev_selection, id, TRUE); } else { @@ -1550,7 +1508,7 @@ gint vficon_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) return TRUE; } -static gint vficon_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data) +static gboolean vficon_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data) { ViewFile *vf = data; @@ -1569,6 +1527,10 @@ static gboolean vficon_destroy_node_cb(GtkTreeModel *store, GtkTreePath *tpath, GList *list; gtk_tree_model_get(store, iter, FILE_COLUMN_POINTER, &list, -1); + + /* it seems that gtk_list_store_clear may call some callbacks + that use the column. Set the pointer to NULL to be safe. */ + gtk_list_store_set(GTK_LIST_STORE(store), iter, FILE_COLUMN_POINTER, NULL, -1); g_list_free(list); return FALSE; @@ -1584,31 +1546,13 @@ static void vficon_clear_store(ViewFile *vf) gtk_list_store_clear(GTK_LIST_STORE(store)); } -static void vficon_set_thumb(ViewFile *vf, FileData *fd, GdkPixbuf *pb) -{ - GtkTreeModel *store; - GtkTreeIter iter; - GList *list; - - if (!vficon_find_iter(vf, vficon_icon_data(vf, fd), &iter, NULL)) return; - - store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); - - if (pb) g_object_ref(pb); - if (fd->pixbuf) g_object_unref(fd->pixbuf); - fd->pixbuf = pb; - - gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); - gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1); -} - static GList *vficon_add_row(ViewFile *vf, GtkTreeIter *iter) { GtkListStore *store; GList *list = NULL; gint i; - for (i = 0; i < VFICON_INFO(vf, columns); i++) list = g_list_prepend(list, NULL); + for (i = 0; i < VFICON(vf)->columns; i++) list = g_list_prepend(list, NULL); store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview))); gtk_list_store_append(store, iter); @@ -1617,19 +1561,21 @@ static GList *vficon_add_row(ViewFile *vf, GtkTreeIter *iter) return list; } -static void vficon_populate(ViewFile *vf, gint resize, gint keep_position) +static void vficon_populate(ViewFile *vf, gboolean resize, gboolean keep_position) { GtkTreeModel *store; GtkTreePath *tpath; - gint row; GList *work; IconData *visible_id = NULL; + gint r, c; + gboolean valid; + GtkTreeIter iter; vficon_verify_selections(vf); store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); - if (keep_position && GTK_WIDGET_REALIZED(vf->listview) && + if (keep_position && gtk_widget_get_realized(vf->listview) && gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL)) { GtkTreeIter iter; @@ -1642,13 +1588,14 @@ static void vficon_populate(ViewFile *vf, gint resize, gint keep_position) if (list) visible_id = list->data; } - vficon_clear_store(vf); if (resize) { gint i; gint thumb_width; + vficon_clear_store(vf); + thumb_width = vficon_get_icon_width(vf); for (i = 0; i < VFICON_MAX_COLUMNS; i++) @@ -1658,10 +1605,10 @@ static void vficon_populate(ViewFile *vf, gint resize, gint keep_position) GList *list; column = gtk_tree_view_get_column(GTK_TREE_VIEW(vf->listview), i); - gtk_tree_view_column_set_visible(column, (i < VFICON_INFO(vf, columns))); + gtk_tree_view_column_set_visible(column, (i < VFICON(vf)->columns)); gtk_tree_view_column_set_fixed_width(column, thumb_width + (THUMB_BORDER_PADDING * 6)); - list = gtk_tree_view_column_get_cell_renderers(column); + list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column)); cell = (list) ? list->data : NULL; g_list_free(list); @@ -1669,108 +1616,37 @@ static void vficon_populate(ViewFile *vf, gint resize, gint keep_position) { g_object_set(G_OBJECT(cell), "fixed_width", thumb_width, "fixed_height", options->thumbnails.max_height, - "show_text", VFICON_INFO(vf, show_text), NULL); + "show_text", VFICON(vf)->show_text, + "show_marks", vf->marks_enabled, + "num_marks", FILEDATA_MARKS_SIZE, + NULL); } } - if (GTK_WIDGET_REALIZED(vf->listview)) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview)); + if (gtk_widget_get_realized(vf->listview)) gtk_tree_view_columns_autosize(GTK_TREE_VIEW(vf->listview)); } - row = -1; + r = -1; + c = 0; + + valid = gtk_tree_model_iter_children(store, &iter, NULL); + work = vf->list; while (work) { GList *list; - GtkTreeIter iter; - - row++; + r++; + c = 0; + if (valid) + { + gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); + gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1); + } + else + { + list = vficon_add_row(vf, &iter); + } - list = vficon_add_row(vf, &iter); - while (work && list) - { - IconData *id; - - id = work->data; - id->row = row; - - list->data = work->data; - list = list->next; - work = work->next; - } - } - - if (visible_id && - gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL)) - { - GtkTreeIter iter; - GList *list; - - gtk_tree_model_get_iter(store, &iter, tpath); - gtk_tree_path_free(tpath); - - gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); - if (g_list_find(list, visible_id) == NULL && - vficon_find_iter(vf, visible_id, &iter, NULL)) - { - tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE); - } - } - - VFICON_INFO(vf, rows) = row + 1; - - vficon_send_update(vf); - vficon_thumb_update(vf); -} - -static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gint force) -{ - gint new_cols; - gint thumb_width; - - thumb_width = vficon_get_icon_width(vf); - - new_cols = w / (thumb_width + (THUMB_BORDER_PADDING * 6)); - if (new_cols < 1) new_cols = 1; - - if (!force && new_cols == VFICON_INFO(vf, columns)) return; - - VFICON_INFO(vf, columns) = new_cols; - - vficon_populate(vf, TRUE, TRUE); - - DEBUG_1("col tab pop cols=%d rows=%d", VFICON_INFO(vf, columns), VFICON_INFO(vf, rows)); -} - -static void vficon_sync(ViewFile *vf) -{ - GtkTreeModel *store; - GtkTreeIter iter; - GList *work; - gint r, c; - - if (VFICON_INFO(vf, rows) == 0) return; - - store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); - - r = -1; - c = 0; - - work = vf->list; - while (work) - { - GList *list; - r++; - c = 0; - if (gtk_tree_model_iter_nth_child(store, &iter, NULL, r)) - { - gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); - gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1); - } - else - { - list = vficon_add_row(vf, &iter); - } - - while (list) + while (list) { IconData *id; @@ -1779,8 +1655,6 @@ static void vficon_sync(ViewFile *vf) id = work->data; work = work->next; c++; - - id->row = r; } else { @@ -1790,43 +1664,60 @@ static void vficon_sync(ViewFile *vf) list->data = id; list = list->next; } + if (valid) valid = gtk_tree_model_iter_next(store, &iter); } r++; - while (gtk_tree_model_iter_nth_child(store, &iter, NULL, r)) + while (valid) { GList *list; gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); - gtk_list_store_remove(GTK_LIST_STORE(store), &iter); + valid = gtk_list_store_remove(GTK_LIST_STORE(store), &iter); g_list_free(list); } - VFICON_INFO(vf, rows) = r; + VFICON(vf)->rows = r; - vficon_update_focus(vf); -} + if (visible_id && + gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL)) + { + GtkTreeIter iter; + GList *list; -static gint vficon_sync_idle_cb(gpointer data) -{ - ViewFile *vf = data; + gtk_tree_model_get_iter(store, &iter, tpath); + gtk_tree_path_free(tpath); - if (VFICON_INFO(vf, sync_idle_id) == -1) return FALSE; - VFICON_INFO(vf, sync_idle_id) = -1; + gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); + if (g_list_find(list, visible_id) == NULL && + vficon_find_iter(vf, visible_id, &iter, NULL)) + { + tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, FALSE); + } + } - vficon_sync(vf); - return FALSE; + + vf_send_update(vf); + vf_thumb_update(vf); } -static void vficon_sync_idle(ViewFile *vf) +static void vficon_populate_at_new_size(ViewFile *vf, gint w, gint h, gboolean force) { - if (VFICON_INFO(vf, sync_idle_id) == -1) - { - /* high priority, the view needs to be resynced before a redraw - * may contain invalid pointers at this time - */ - VFICON_INFO(vf, sync_idle_id) = g_idle_add_full(G_PRIORITY_HIGH, vficon_sync_idle_cb, vf, NULL); - } + gint new_cols; + gint thumb_width; + + thumb_width = vficon_get_icon_width(vf); + + new_cols = w / (thumb_width + (THUMB_BORDER_PADDING * 6)); + if (new_cols < 1) new_cols = 1; + + if (!force && new_cols == VFICON(vf)->columns) return; + + VFICON(vf)->columns = new_cols; + + vficon_populate(vf, TRUE, TRUE); + + DEBUG_1("col tab pop cols=%d rows=%d", VFICON(vf)->columns, VFICON(vf)->rows); } static void vficon_sized_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data) @@ -1842,7 +1733,7 @@ static void vficon_sized_cb(GtkWidget *widget, GtkAllocation *allocation, gpoint *----------------------------------------------------------------------------- */ -void vficon_sort_set(ViewFile *vf, SortType type, gint ascend) +void vficon_sort_set(ViewFile *vf, SortType type, gboolean ascend) { if (vf->sort_method == type && vf->sort_ascend == ascend) return; @@ -1851,8 +1742,7 @@ void vficon_sort_set(ViewFile *vf, SortType type, gint ascend) if (!vf->list) return; - vf->list = iconlist_sort(vf->list, vf->sort_method, vf->sort_ascend); - vficon_sync(vf); + vf_refresh(vf); } /* @@ -1861,87 +1751,45 @@ void vficon_sort_set(ViewFile *vf, SortType type, gint ascend) *----------------------------------------------------------------------------- */ -static gint vficon_thumb_next(ViewFile *vf); - -static void vficon_thumb_status(ViewFile *vf, gdouble val, const gchar *text) +void vficon_thumb_progress_count(GList *list, gint *count, gint *done) { - if (vf->func_thumb_status) + GList *work = list; + while (work) { - vf->func_thumb_status(vf, val, text, vf->data_thumb_status); - } -} - -static void vficon_thumb_cleanup(ViewFile *vf) -{ - vficon_thumb_status(vf, 0.0, NULL); - - vf->thumbs_count = 0; - vf->thumbs_running = FALSE; - - thumb_loader_free(vf->thumbs_loader); - vf->thumbs_loader = NULL; - - vf->thumbs_filedata = NULL; -} + IconData *id = work->data; + FileData *fd = id->fd; + work = work->next; -static void vficon_thumb_stop(ViewFile *vf) -{ - if (vf->thumbs_running) vficon_thumb_cleanup(vf); + if (fd->thumb_pixbuf) (*done)++; + (*count)++; + } } -static void vficon_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd) +void vficon_set_thumb_fd(ViewFile *vf, FileData *fd) { - GdkPixbuf *pixbuf; - - if (!fd) return; - - pixbuf = thumb_loader_get_pixbuf(tl, TRUE); - vficon_set_thumb(vf, fd, pixbuf); - g_object_unref(pixbuf); - - vficon_thumb_status(vf, (gdouble)(vf->thumbs_count) / g_list_length(vf->list), _("Loading thumbs...")); -} + GtkTreeModel *store; + GtkTreeIter iter; + GList *list; -static void vficon_thumb_error_cb(ThumbLoader *tl, gpointer data) -{ - ViewFile *vf = data; + if (!vficon_find_iter(vf, vficon_icon_data(vf, fd), &iter, NULL)) return; - if (vf->thumbs_filedata && vf->thumbs_loader == tl) - { - vficon_thumb_do(vf, tl, vf->thumbs_filedata); - } + store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); - while (vficon_thumb_next(vf)); + gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); + gtk_list_store_set(GTK_LIST_STORE(store), &iter, FILE_COLUMN_POINTER, list, -1); } -static void vficon_thumb_done_cb(ThumbLoader *tl, gpointer data) -{ - ViewFile *vf = data; - - if (vf->thumbs_filedata && vf->thumbs_loader == tl) - { - vficon_thumb_do(vf, tl, vf->thumbs_filedata); - } - - while (vficon_thumb_next(vf)); -} -static gint vficon_thumb_next(ViewFile *vf) +FileData *vficon_thumb_next_fd(ViewFile *vf) { GtkTreePath *tpath; FileData *fd = NULL; - if (!GTK_WIDGET_REALIZED(vf->listview)) - { - vficon_thumb_status(vf, 0.0, NULL); - return FALSE; - } - if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL)) { GtkTreeModel *store; GtkTreeIter iter; - gint valid = TRUE; + gboolean valid = TRUE; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); gtk_tree_model_get_iter(store, &iter, tpath); @@ -1956,7 +1804,7 @@ static gint vficon_thumb_next(ViewFile *vf) while (!fd && list) { IconData *id = list->data; - if (id && !id->fd->pixbuf) fd = id->fd; + if (id && !id->fd->thumb_pixbuf) fd = id->fd; list = list->next; } @@ -1975,51 +1823,30 @@ static gint vficon_thumb_next(ViewFile *vf) FileData *fd_p = id->fd; work = work->next; - if (!fd_p->pixbuf) fd = fd_p; + if (!fd_p->thumb_pixbuf) fd = fd_p; } } - if (!fd) - { - /* done */ - vficon_thumb_cleanup(vf); - return FALSE; - } - - vf->thumbs_count++; - - vf->thumbs_filedata = fd; - - thumb_loader_free(vf->thumbs_loader); + return fd; +} - vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height); - thumb_loader_set_callbacks(vf->thumbs_loader, - vficon_thumb_done_cb, - vficon_thumb_error_cb, - NULL, - vf); +void vficon_thumb_reset_all(ViewFile *vf) +{ + GList *work = vf->list; - if (!thumb_loader_start(vf->thumbs_loader, fd->path)) + while (work) { - /* set icon to unknown, continue */ - DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path); - vficon_thumb_do(vf, vf->thumbs_loader, fd); - - return TRUE; + IconData *id = work->data; + FileData *fd = id->fd; + if (fd->thumb_pixbuf) + { + g_object_unref(fd->thumb_pixbuf); + fd->thumb_pixbuf = NULL; + } + work = work->next; } - - return FALSE; } -static void vficon_thumb_update(ViewFile *vf) -{ - vficon_thumb_stop(vf); - - vficon_thumb_status(vf, 0.0, _("Loading thumbs...")); - vf->thumbs_running = TRUE; - - while (vficon_thumb_next(vf)); -} /* *----------------------------------------------------------------------------- @@ -2035,36 +1862,6 @@ FileData *vficon_index_get_data(ViewFile *vf, gint row) return id ? id->fd : NULL; } -gchar *vficon_index_get_path(ViewFile *vf, gint row) -{ - FileData *fd; - IconData *id; - - id = g_list_nth_data(vf->list, row); - fd = id ? id->fd : NULL; - - return (fd ? fd->path : NULL); -} - -gint vficon_index_by_path(ViewFile *vf, const gchar *path) -{ - gint p = 0; - GList *work; - - if (!path) return -1; - - work = vf->list; - while (work) - { - IconData *id = work->data; - FileData *fd = id->fd; - if (strcmp(path, fd->path) == 0) return p; - work = work->next; - p++; - } - - return -1; -} gint vficon_index_by_fd(ViewFile *vf, FileData *in_fd) { @@ -2105,7 +1902,7 @@ static gint vficon_index_by_id(ViewFile *vf, IconData *in_id) return -1; } -gint vficon_count(ViewFile *vf, gint64 *bytes) +guint vficon_count(ViewFile *vf, gint64 *bytes) { if (bytes) { @@ -2152,78 +1949,136 @@ GList *vficon_get_list(ViewFile *vf) *----------------------------------------------------------------------------- */ -static gint vficon_refresh_real(ViewFile *vf, gint keep_position) +static gboolean vficon_refresh_real(ViewFile *vf, gboolean keep_position) { - gint ret = TRUE; - GList *old_list; - GList *work; + gboolean ret = TRUE; + GList *work, *work_fd; IconData *focus_id; + GList *new_filelist = NULL; + FileData *first_selected = NULL; + GList *new_iconlist = NULL; - focus_id = VFICON_INFO(vf, focus_id); + focus_id = VFICON(vf)->focus_id; - old_list = vf->list; - vf->list = NULL; + if (vf->dir_fd) + { + ret = filelist_read(vf->dir_fd, &new_filelist, NULL); + new_filelist = file_data_filter_marks_list(new_filelist, vf_marks_get_filter(vf)); + } + + vf->list = iconlist_sort(vf->list, vf->sort_method, vf->sort_ascend); /* the list might not be sorted if there were renames */ + new_filelist = filelist_sort(new_filelist, vf->sort_method, vf->sort_ascend); - if (vf->path) + if (VFICON(vf)->selection) { - ret = iconlist_read(vf->path, &vf->list); + first_selected = ((IconData *)(VFICON(vf)->selection->data))->fd; + file_data_ref(first_selected); + g_list_free(VFICON(vf)->selection); + VFICON(vf)->selection = NULL; + + } /* check for same files from old_list */ - work = old_list; - while (work) + work = vf->list; + work_fd = new_filelist; + while (work || work_fd) { - IconData *id = work->data; - FileData *fd = id->fd; - GList *needle = vf->list; + IconData *id = NULL; + FileData *fd = NULL; + FileData *new_fd = NULL; + gint match; - while (needle) + if (work && work_fd) { - IconData *idn = needle->data; - FileData *fdn = idn->fd; + id = work->data; + fd = id->fd; - if (fdn == fd) + new_fd = work_fd->data; + + if (fd == new_fd) { - /* swap, to retain old thumb, selection */ - needle->data = id; - work->data = idn; - needle = NULL; + /* not changed, go to next */ + work = work->next; + work_fd = work_fd->next; + if (id->selected & SELECTION_SELECTED) + { + VFICON(vf)->selection = g_list_prepend(VFICON(vf)->selection, id); + } + continue; } + + match = filelist_sort_compare_filedata_full(fd, new_fd, vf->sort_method, vf->sort_ascend); + if (match == 0) g_warning("multiple fd for the same path"); + } + else if (work) + { + id = work->data; + fd = id->fd; + match = -1; + } + else /* work_fd */ + { + new_fd = work_fd->data; + match = 1; + } + + if (match < 0) + { + /* file no longer exists, delete from vf->list */ + GList *to_delete = work; + work = work->next; + if (id == VFICON(vf)->prev_selection) VFICON(vf)->prev_selection = NULL; + if (id == VFICON(vf)->click_id) VFICON(vf)->click_id = NULL; + file_data_unref(fd); + g_free(id); + vf->list = g_list_delete_link(vf->list, to_delete); + } + else + { + /* new file, add to vf->list */ + id = g_new0(IconData, 1); + + id->selected = SELECTION_NONE; + id->fd = file_data_ref(new_fd); + if (work) + vf->list = g_list_insert_before(vf->list, work, id); else - { - needle = needle->next; - } + new_iconlist = g_list_prepend(new_iconlist, id); /* it is faster to append all new entries together later */ + + work_fd = work_fd->next; } - work = work->next; } - vf->list = iconlist_sort(vf->list, vf->sort_method, vf->sort_ascend); - - work = old_list; - while (work) + if (new_iconlist) { - IconData *id = work->data; - work = work->next; - - if (id == VFICON_INFO(vf, prev_selection)) VFICON_INFO(vf, prev_selection) = NULL; - if (id == VFICON_INFO(vf, click_id)) VFICON_INFO(vf, click_id) = NULL; + vf->list = g_list_concat(vf->list, g_list_reverse(new_iconlist)); } + VFICON(vf)->selection = g_list_reverse(VFICON(vf)->selection); + + filelist_free(new_filelist); + vficon_populate(vf, TRUE, keep_position); + if (first_selected && !VFICON(vf)->selection) + { + /* all selected files disappeared */ + vficon_select_closest(vf, first_selected); + } + file_data_unref(first_selected); + /* attempt to keep focus on same icon when refreshing */ if (focus_id && g_list_find(vf->list, focus_id)) { vficon_set_focus(vf, focus_id); } - iconlist_free(old_list); - return ret; } -gint vficon_refresh(ViewFile *vf) +gboolean vficon_refresh(ViewFile *vf) { return vficon_refresh_real(vf, TRUE); } @@ -2244,62 +2099,74 @@ struct _ColumnData static void vficon_cell_data_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { - ColumnData *cd = data; - ViewFile *vf; - GtkStyle *style; GList *list; - GdkColor color_fg; - GdkColor color_bg; IconData *id; + ColumnData *cd = data; + ViewFile *vf = cd->vf; - vf = cd->vf; + if (!GQV_IS_CELL_RENDERER_ICON(cell)) return; gtk_tree_model_get(tree_model, iter, FILE_COLUMN_POINTER, &list, -1); id = g_list_nth_data(list, cd->number); - if (id) g_assert(id->fd->magick == 0x12345678); - - style = gtk_widget_get_style(vf->listview); - if (id && id->selected & SELECTION_SELECTED) - { - memcpy(&color_fg, &style->text[GTK_STATE_SELECTED], sizeof(color_fg)); - memcpy(&color_bg, &style->base[GTK_STATE_SELECTED], sizeof(color_bg)); - } - else + if (id) { - memcpy(&color_fg, &style->text[GTK_STATE_NORMAL], sizeof(color_fg)); - memcpy(&color_bg, &style->base[GTK_STATE_NORMAL], sizeof(color_bg)); - } + GdkColor color_fg; + GdkColor color_bg; + GtkStyle *style; + gchar *name_sidecars; + gchar *link; + GtkStateType state = GTK_STATE_NORMAL; - if (id && id->selected & SELECTION_PRELIGHT) - { -#if 0 - shift_color(&color_fg, -1, 0); -#endif - shift_color(&color_bg, -1, 0); - } + g_assert(id->fd->magick == FD_MAGICK); - if (GQV_IS_CELL_RENDERER_ICON(cell)) - { - if (id) + link = islink(id->fd->path) ? GQ_LINK_STR : ""; + if (id->fd->sidecar_files) { - g_object_set(cell, "pixbuf", id->fd->pixbuf, - "text", id->fd->name, - "cell-background-gdk", &color_bg, - "cell-background-set", TRUE, - "foreground-gdk", &color_fg, - "foreground-set", TRUE, - "has-focus", (VFICON_INFO(vf, focus_id) == id), NULL); + gchar *sidecars = file_data_sc_list_to_string(id->fd); + name_sidecars = g_strdup_printf("%s%s %s", link, id->fd->name, sidecars); + g_free(sidecars); } else { - g_object_set(cell, "pixbuf", NULL, - "text", NULL, - "cell-background-set", FALSE, - "foreground-set", FALSE, - "has-focus", FALSE, NULL); + gchar *disabled_grouping = id->fd->disable_grouping ? _(" [NO GROUPING]") : ""; + name_sidecars = g_strdup_printf("%s%s%s", link, id->fd->name, disabled_grouping); + } + + style = gtk_widget_get_style(vf->listview); + if (id->selected & SELECTION_SELECTED) + { + state = GTK_STATE_SELECTED; } + + memcpy(&color_fg, &style->text[state], sizeof(color_fg)); + memcpy(&color_bg, &style->base[state], sizeof(color_bg)); + + if (id->selected & SELECTION_PRELIGHT) + { + shift_color(&color_bg, -1, 0); + } + + g_object_set(cell, "pixbuf", id->fd->thumb_pixbuf, + "text", name_sidecars, + "marks", file_data_get_marks(id->fd), + "show_marks", vf->marks_enabled, + "cell-background-gdk", &color_bg, + "cell-background-set", TRUE, + "foreground-gdk", &color_fg, + "foreground-set", TRUE, + "has-focus", (VFICON(vf)->focus_id == id), NULL); + g_free(name_sidecars); + } + else + { + g_object_set(cell, "pixbuf", NULL, + "text", NULL, + "show_marks", FALSE, + "cell-background-set", FALSE, + "foreground-set", FALSE, + "has-focus", FALSE, NULL); } } @@ -2322,6 +2189,7 @@ static void vficon_append_column(ViewFile *vf, gint n) "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); g_object_set_data(G_OBJECT(column), "column_number", GINT_TO_POINTER(n)); + g_object_set_data(G_OBJECT(renderer), "column_number", GINT_TO_POINTER(n)); cd = g_new0(ColumnData, 1); cd->vf = vf; @@ -2329,6 +2197,8 @@ static void vficon_append_column(ViewFile *vf, gint n) gtk_tree_view_column_set_cell_data_func(column, renderer, vficon_cell_data_cb, cd, g_free); gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column); + + g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vficon_mark_toggled_cb), vf); } /* @@ -2337,18 +2207,18 @@ static void vficon_append_column(ViewFile *vf, gint n) *----------------------------------------------------------------------------- */ -gint vficon_set_path(ViewFile *vf, const gchar *path) +gboolean vficon_set_fd(ViewFile *vf, FileData *dir_fd) { - gint ret; + gboolean ret; - if (!path) return FALSE; - if (vf->path && strcmp(path, vf->path) == 0) return TRUE; + if (!dir_fd) return FALSE; + if (vf->dir_fd == dir_fd) return TRUE; - g_free(vf->path); - vf->path = g_strdup(path); + file_data_unref(vf->dir_fd); + vf->dir_fd = file_data_ref(dir_fd); - g_list_free(VFICON_INFO(vf, selection)); - VFICON_INFO(vf, selection) = NULL; + g_list_free(VFICON(vf)->selection); + VFICON(vf)->selection = NULL; iconlist_free(vf->list); vf->list = NULL; @@ -2356,7 +2226,7 @@ gint vficon_set_path(ViewFile *vf, const gchar *path) /* NOTE: populate will clear the store for us */ ret = vficon_refresh_real(vf, FALSE); - VFICON_INFO(vf, focus_id) = NULL; + VFICON(vf)->focus_id = NULL; vficon_move_focus(vf, 0, 0, FALSE); return ret; @@ -2366,17 +2236,19 @@ void vficon_destroy_cb(GtkWidget *widget, gpointer data) { ViewFile *vf = data; - if (VFICON_INFO(vf, sync_idle_id) != -1) g_source_remove(VFICON_INFO(vf, sync_idle_id)); + vf_refresh_idle_cancel(vf); + + file_data_unregister_notify_func(vf_notify_cb, vf); tip_unschedule(vf); - vficon_thumb_cleanup(vf); + vf_thumb_cleanup(vf); iconlist_free(vf->list); - g_list_free(VFICON_INFO(vf, selection)); + g_list_free(VFICON(vf)->selection); } -ViewFile *vficon_new(ViewFile *vf, const gchar *path) +ViewFile *vficon_new(ViewFile *vf, FileData *dir_fd) { GtkListStore *store; GtkTreeSelection *selection; @@ -2384,19 +2256,7 @@ ViewFile *vficon_new(ViewFile *vf, const gchar *path) vf->info = g_new0(ViewFileInfoIcon, 1); - VFICON_INFO(vf, selection) = NULL; - VFICON_INFO(vf, prev_selection) = NULL; - - VFICON_INFO(vf, tip_window) = NULL; - VFICON_INFO(vf, tip_delay_id) = -1; - - VFICON_INFO(vf, focus_row) = 0; - VFICON_INFO(vf, focus_column) = 0; - VFICON_INFO(vf, focus_id) = NULL; - - VFICON_INFO(vf, show_text) = options->show_icon_names; - - VFICON_INFO(vf, sync_idle_id) = -1; + VFICON(vf)->show_text = options->show_icon_names; store = gtk_list_store_new(1, G_TYPE_POINTER); vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); @@ -2429,256 +2289,12 @@ ViewFile *vficon_new(ViewFile *vf, const gchar *path) g_signal_connect(G_OBJECT(vf->listview), "leave_notify_event", G_CALLBACK(vficon_leave_cb), vf); - /* force VFICON_INFO(vf, columns) to be at least 1 (sane) - this will be corrected in the size_cb */ + /* force VFICON(vf)->columns to be at least 1 (sane) - this will be corrected in the size_cb */ vficon_populate_at_new_size(vf, 1, 1, FALSE); - return vf; -} - -/* - *----------------------------------------------------------------------------- - * maintenance (for rename, move, remove) - *----------------------------------------------------------------------------- - */ - -static gint vficon_maint_find_closest(ViewFile *vf, gint row, gint count, GList *ignore_list) -{ - GList *list = NULL; - GList *work; - gint rev = row - 1; - - row++; - - work = ignore_list; - while (work) - { - FileData *fd = work->data; - gint f = vficon_index_by_fd(vf, fd); - g_assert(fd->magick == 0x12345678); - - if (f >= 0) list = g_list_prepend(list, GINT_TO_POINTER(f)); - work = work->next; - } - - while (list) - { - gint c = TRUE; - - work = list; - while (work && c) - { - gpointer p = work->data; - - work = work->next; - if (row == GPOINTER_TO_INT(p)) - { - row++; - c = FALSE; - } - if (rev == GPOINTER_TO_INT(p)) - { - rev--; - c = FALSE; - } - if (!c) list = g_list_remove(list, p); - } - - if (c && list) - { - g_list_free(list); - list = NULL; - } - } + file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM); - if (row > count - 1) - { - if (rev < 0) - return -1; - else - return rev; - } - else - { - return row; - } -} - -gint vficon_maint_renamed(ViewFile *vf, FileData *fd) -{ - gint ret = FALSE; - gint row; - gchar *source_base; - gchar *dest_base; - IconData *id = vficon_icon_data(vf, fd); - - if (!id) return FALSE; - - row = vficon_index_by_id(vf, id); - if (row < 0) return FALSE; - - source_base = remove_level_from_path(fd->change->source); - dest_base = remove_level_from_path(fd->change->dest); - - if (strcmp(source_base, dest_base) == 0) - { - vf->list = g_list_remove(vf->list, id); - vf->list = iconlist_insert_sort(vf->list, id, vf->sort_method, vf->sort_ascend); - - vficon_sync_idle(vf); - ret = TRUE; - } - else - { - ret = vficon_maint_removed(vf, fd, NULL); - } - - g_free(source_base); - g_free(dest_base); - - return ret; -} - -gint vficon_maint_removed(ViewFile *vf, FileData *fd, GList *ignore_list) -{ - gint row; - gint new_row = -1; - GtkTreeModel *store; - GtkTreeIter iter; - IconData *id = vficon_icon_data(vf, fd); - - if (!id) return FALSE; - - row = g_list_index(vf->list, id); - if (row < 0) return FALSE; - - if ((id->selected & SELECTION_SELECTED) && - layout_image_get_collection(vf->layout, NULL) == NULL) - { - vficon_unselect(vf, id); - - if (!VFICON_INFO(vf, selection)) - { - gint n; - - n = vficon_count(vf, NULL); - if (ignore_list) - { - new_row = vficon_maint_find_closest(vf, row, n, ignore_list); - DEBUG_1("row = %d, closest is %d", row, new_row); - } - else - { - if (row + 1 < n) - { - new_row = row + 1; - } - else if (row > 0) - { - new_row = row - 1; - } - } - } - else if (ignore_list) - { - GList *work; - - work = VFICON_INFO(vf, selection); - while (work) - { - IconData *ignore_id; - FileData *ignore_fd; - GList *tmp; - gint match = FALSE; - - ignore_id = work->data; - ignore_fd = ignore_id->fd; - g_assert(ignore_fd->magick == 0x12345678); - work = work->next; - - tmp = ignore_list; - while (tmp && !match) - { - FileData *ignore_list_fd = tmp->data; - g_assert(ignore_list_fd->magick == 0x12345678); - tmp = tmp->next; - - if (ignore_list_fd == ignore_fd) - { - match = TRUE; - } - } - - if (!match) - { - new_row = g_list_index(vf->list, ignore_id); - work = NULL; - } - } - - if (new_row == -1) - { - /* selection all ignored, use closest */ - new_row = vficon_maint_find_closest(vf, row, vficon_count(vf, NULL), ignore_list); - } - } - else - { - new_row = g_list_index(vf->list, VFICON_INFO(vf, selection)->data); - } - - if (new_row >= 0) - { - IconData *idn = g_list_nth_data(vf->list, new_row); - - vficon_select(vf, idn); - vficon_send_layout_select(vf, idn); - } - } - - /* Thumb loader check */ - if (fd == vf->thumbs_filedata) vf->thumbs_filedata = NULL; - if (vf->thumbs_count > 0) vf->thumbs_count--; - - if (VFICON_INFO(vf, prev_selection) == id) VFICON_INFO(vf, prev_selection) = NULL; - if (VFICON_INFO(vf, click_id) == id) VFICON_INFO(vf, click_id) = NULL; - - /* remove pointer to this fd from grid */ - store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)); - if (id->row >= 0 && - gtk_tree_model_iter_nth_child(store, &iter, NULL, id->row)) - { - GList *list; - - gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &list, -1); - list = g_list_find(list, id); - if (list) list->data = NULL; - } - - vf->list = g_list_remove(vf->list, id); - file_data_unref(fd); - g_free(id); - - vficon_sync_idle(vf); - vficon_send_update(vf); - - return TRUE; + return vf; } -gint vficon_maint_moved(ViewFile *vf, FileData *fd, GList *ignore_list) -{ - gint ret = FALSE; - gchar *buf; - - if (!fd->change->source || !vf->path) return FALSE; - - buf = remove_level_from_path(fd->change->source); - - if (strcmp(buf, vf->path) == 0) - { - ret = vficon_maint_removed(vf, fd, ignore_list); - } - - g_free(buf); - - return ret; -} +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */