From 8ad0d469deb8c143d4a1d3075944ca15c9ca5e04 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Sun, 21 Oct 2018 11:32:53 +0100 Subject: [PATCH] Fix #642: If a folder is a link, use an icon to indicate it is a link https://github.com/BestImageViewer/geeqie/issues/642 There is no stock icon for a folder as a link. The icon used is not particularly appropriate, but its meaning should be clear. The target path is shown as a tooltip. --- src/typedefs.h | 1 + src/view_dir.c | 3 ++ src/view_dir.h | 1 + src/view_dir_list.c | 23 ++++++++- src/view_dir_tree.c | 117 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 136 insertions(+), 9 deletions(-) diff --git a/src/typedefs.h b/src/typedefs.h index 4664dc68..b31ca33a 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -992,6 +992,7 @@ struct _PixmapFolders GdkPixbuf *open; GdkPixbuf *deny; GdkPixbuf *parent; + GdkPixbuf *link; }; struct _SecureSaveInfo { diff --git a/src/view_dir.c b/src/view_dir.c index 8ae22cc8..f671beaf 100644 --- a/src/view_dir.c +++ b/src/view_dir.c @@ -49,6 +49,8 @@ static PixmapFolders *folder_icons_new(GtkWidget *widget) pf->open = gtk_widget_render_icon(widget, GTK_STOCK_OPEN, size, NULL); pf->deny = gtk_widget_render_icon(widget, GTK_STOCK_STOP, size, NULL); pf->parent = gtk_widget_render_icon(widget, GTK_STOCK_GO_UP, size, NULL); + /* FIXME: this is not a suitable icon */ + pf->link = gtk_widget_render_icon(widget, GTK_STOCK_REDO, size, NULL); #else /* GQView legacy icons */ pf->close = pixbuf_inline(PIXBUF_INLINE_FOLDER_CLOSED); @@ -67,6 +69,7 @@ static void folder_icons_free(PixmapFolders *pf) g_object_unref(pf->open); g_object_unref(pf->deny); g_object_unref(pf->parent); + g_object_unref(pf->link); g_free(pf); } diff --git a/src/view_dir.h b/src/view_dir.h index 07ebf1f0..724b11a1 100644 --- a/src/view_dir.h +++ b/src/view_dir.h @@ -27,6 +27,7 @@ enum { DIR_COLUMN_NAME, DIR_COLUMN_COLOR, DIR_COLUMN_DATE, + DIR_COLUMN_LINK, DIR_COLUMN_COUNT }; diff --git a/src/view_dir_list.c b/src/view_dir_list.c index a125f47b..f752d1fe 100644 --- a/src/view_dir_list.c +++ b/src/view_dir_list.c @@ -149,6 +149,7 @@ static gboolean vdlist_populate(ViewDir *vd, gboolean clear) FileData *fd; SortType sort_type = SORT_NAME; gboolean sort_ascend = TRUE; + gchar *link; old_list = VDLIST(vd)->list; @@ -190,7 +191,11 @@ static gboolean vdlist_populate(ViewDir *vd, gboolean clear) if (access_file(fd->path, R_OK | X_OK) && fd->name) { - if (fd->name[0] == '.' && fd->name[1] == '\0') + if (islink(fd->path)) + { + pixbuf = vd->pf->link; + } + else if (fd->name[0] == '.' && fd->name[1] == '\0') { pixbuf = vd->pf->open; } @@ -237,6 +242,15 @@ static gboolean vdlist_populate(ViewDir *vd, gboolean clear) match = -1; } + if (islink(fd->path)) + { + link = realpath(fd->path, NULL); + } + else + { + link = NULL; + } + if (match < 0) { GtkTreeIter new; @@ -254,6 +268,7 @@ static gboolean vdlist_populate(ViewDir *vd, gboolean clear) DIR_COLUMN_POINTER, fd, DIR_COLUMN_ICON, pixbuf, DIR_COLUMN_NAME, fd->name, + DIR_COLUMN_LINK, link, DIR_COLUMN_DATE, date, -1); @@ -268,6 +283,7 @@ static gboolean vdlist_populate(ViewDir *vd, gboolean clear) gtk_list_store_set(store, &iter, DIR_COLUMN_ICON, pixbuf, DIR_COLUMN_NAME, fd->name, + DIR_COLUMN_LINK, link, DIR_COLUMN_DATE, date, -1); @@ -292,6 +308,7 @@ static gboolean vdlist_populate(ViewDir *vd, gboolean clear) vd->drop_fd = NULL; filelist_free(old_list); + g_free(link); return ret; } @@ -433,7 +450,7 @@ ViewDir *vdlist_new(ViewDir *vd, FileData *dir_fd) vd->type = DIRVIEW_LIST; - store = gtk_list_store_new(5, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING); + store = gtk_list_store_new(6, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING); vd->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); @@ -463,6 +480,8 @@ ViewDir *vdlist_new(ViewDir *vd, FileData *dir_fd) gtk_tree_view_append_column(GTK_TREE_VIEW(vd->view), column); + gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(vd->view), DIR_COLUMN_LINK); + return vd; } /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/src/view_dir_tree.c b/src/view_dir_tree.c index a90a9db9..009639c1 100644 --- a/src/view_dir_tree.c +++ b/src/view_dir_tree.c @@ -133,6 +133,8 @@ static void vdtree_expand_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean expan { GtkTreeModel *store; GtkTreePath *tpath; + NodeData *nd; + FileData *fd = NULL; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); tpath = gtk_tree_model_get_path(store, iter); @@ -143,7 +145,18 @@ static void vdtree_expand_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean expan that the iter is populated */ g_signal_handlers_block_by_func(G_OBJECT(vd->view), vdtree_row_expanded, vd); gtk_tree_view_expand_row(GTK_TREE_VIEW(vd->view), tpath, FALSE); - vdtree_icon_set_by_iter(vd, iter, vd->pf->open); + gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); + fd = (nd) ? nd->fd : NULL; + + if (fd && islink(fd->path)) + { + vdtree_icon_set_by_iter(vd, iter, vd->pf->link); + } + else + { + vdtree_icon_set_by_iter(vd, iter, vd->pf->open); + } + g_signal_handlers_unblock_by_func(G_OBJECT(vd->view), vdtree_row_expanded, vd); } else @@ -379,12 +392,20 @@ static void vdtree_add_by_data(ViewDir *vd, FileData *fd, GtkTreeIter *parent) GdkPixbuf *pixbuf; NodeData *end; GtkTreeIter empty; + gchar *link = NULL; if (!fd) return; if (access_file(fd->path, R_OK | X_OK)) { - pixbuf = vd->pf->close; + if (islink(fd->path)) + { + pixbuf = vd->pf->link; + } + else + { + pixbuf = vd->pf->close; + } } else { @@ -397,11 +418,21 @@ static void vdtree_add_by_data(ViewDir *vd, FileData *fd, GtkTreeIter *parent) nd->expanded = FALSE; nd->last_update = time(NULL); + if (islink(fd->path)) + { + link = realpath(fd->path, NULL); + } + else + { + link = NULL; + } + store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view))); gtk_tree_store_append(store, &child, parent); gtk_tree_store_set(store, &child, DIR_COLUMN_POINTER, nd, DIR_COLUMN_ICON, pixbuf, DIR_COLUMN_NAME, nd->fd->name, + DIR_COLUMN_LINK, link, DIR_COLUMN_COLOR, FALSE, -1); /* all nodes are created with an "empty" node, so that the expander is shown @@ -429,6 +460,8 @@ static void vdtree_add_by_data(ViewDir *vd, FileData *fd, GtkTreeIter *parent) } gtk_tree_path_free(tpath); } + + g_free(link); } gboolean vdtree_populate_path_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean force, FileData *target_fd) @@ -441,6 +474,7 @@ gboolean vdtree_populate_path_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean f GtkTreeIter child; NodeData *nd; gboolean add_hidden = FALSE; + gchar *link = NULL; store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)); gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); @@ -542,6 +576,18 @@ gboolean vdtree_populate_path_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean f } gtk_tree_store_set(GTK_TREE_STORE(store), &child, DIR_COLUMN_NAME, fd->name, -1); + + if (islink(fd->path)) + { + link = realpath(fd->path, NULL); + } + else + { + link = NULL; + } + + gtk_tree_store_set(GTK_TREE_STORE(store), &child, DIR_COLUMN_LINK, link, -1); + cnd->version = fd->version; old = g_list_remove(old, cnd); file_data_unref(fd); @@ -577,6 +623,8 @@ gboolean vdtree_populate_path_by_iter(ViewDir *vd, GtkTreeIter *iter, gboolean f nd->expanded = TRUE; nd->last_update = current_time; + g_free(link); + return TRUE; } @@ -783,7 +831,15 @@ gboolean vdtree_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer dat if (fd) { vdtree_populate_path_by_iter(vd, &iter, FALSE, vd->dir_fd); - vdtree_icon_set_by_iter(vd, &iter, vd->pf->open); + + if (islink(fd->path)) + { + vdtree_icon_set_by_iter(vd, &iter, vd->pf->link); + } + else + { + vdtree_icon_set_by_iter(vd, &iter, vd->pf->open); + } } break; } @@ -822,6 +878,7 @@ gboolean vdtree_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer dat GtkTreeViewColumn *column; GtkTreeIter iter; NodeData *nd = NULL; + FileData *fd; if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y, &tpath, &column, NULL, NULL)) @@ -846,7 +903,16 @@ gboolean vdtree_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer dat !gtk_tree_view_row_expanded(GTK_TREE_VIEW(vd->view), tpath)) { vdtree_populate_path_by_iter(vd, &iter, FALSE, vd->dir_fd); - vdtree_icon_set_by_iter(vd, &iter, vd->pf->open); + + fd = (nd) ? nd->fd : NULL; + if (fd && islink(fd->path)) + { + vdtree_icon_set_by_iter(vd, &iter, vd->pf->link); + } + else + { + vdtree_icon_set_by_iter(vd, &iter, vd->pf->open); + } } gtk_tree_path_free(tpath); @@ -872,16 +938,51 @@ gboolean vdtree_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer dat static void vdtree_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *tpath, gpointer data) { ViewDir *vd = data; + GtkTreeModel *store; + NodeData *nd = NULL; + FileData *fd; + + gtk_tree_view_set_tooltip_column(treeview, DIR_COLUMN_LINK); vdtree_populate_path_by_iter(vd, iter, FALSE, NULL); - vdtree_icon_set_by_iter(vd, iter, vd->pf->open); + store = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); + + gtk_tree_model_get_iter(store, iter, tpath); + gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); + + fd = (nd) ? nd->fd : NULL; + if (fd && islink(fd->path)) + { + vdtree_icon_set_by_iter(vd, iter, vd->pf->link); + } + else + { + vdtree_icon_set_by_iter(vd, iter, vd->pf->open); + } } static void vdtree_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *tpath, gpointer data) { ViewDir *vd = data; + GtkTreeModel *store; + NodeData *nd = NULL; + FileData *fd; + + vdtree_populate_path_by_iter(vd, iter, FALSE, NULL); + store = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); - vdtree_icon_set_by_iter(vd, iter, vd->pf->close); + gtk_tree_model_get_iter(store, iter, tpath); + gtk_tree_model_get(store, iter, DIR_COLUMN_POINTER, &nd, -1); + + fd = (nd) ? nd->fd : NULL; + if (fd && islink(fd->path)) + { + vdtree_icon_set_by_iter(vd, iter, vd->pf->link); + } + else + { + vdtree_icon_set_by_iter(vd, iter, vd->pf->close); + } } static gint vdtree_sort_cb(GtkTreeModel *store, GtkTreeIter *a, GtkTreeIter *b, gpointer data) @@ -958,7 +1059,7 @@ ViewDir *vdtree_new(ViewDir *vd, FileData *dir_fd) vd->dnd_drop_leave_func = vdtree_dnd_drop_expand_cancel; vd->dnd_drop_update_func = vdtree_dnd_drop_expand; - store = gtk_tree_store_new(4, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); + store = gtk_tree_store_new(6, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING); vd->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); @@ -987,6 +1088,8 @@ ViewDir *vdtree_new(ViewDir *vd, FileData *dir_fd) gtk_tree_view_append_column(GTK_TREE_VIEW(vd->view), column); + gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(vd->view), DIR_COLUMN_LINK); + vdtree_setup_root(vd); g_signal_connect(G_OBJECT(vd->view), "row_expanded", -- 2.20.1