/*----------------------------------------------------------------------------* * .---. * * PornView (_,/\ \ * * photo/movie collection viewer and manager (`a a( ) * * trem0r ) \= ) ( * * (c) 2002 (.--' '--.) * * / (_)^(_) \ * *----------------------------------------------------------------------------*/ #include "pornview.h" #include "dirtree.h" #include "clist_edit.h" #include "dialogs.h" #include "file_utils.h" #include "menu.h" #include "pixbuf_utils.h" #include "string_utils.h" #include "dirview.h" #include "browser.h" #include "prefs.h" #include "pixmaps/refresh.xpm" #include "pixmaps/up.xpm" #include "pixmaps/down.xpm" #include "pixmaps/left.xpm" #include "pixmaps/right.xpm" #include "pixmaps/dotfile.xpm" #define min(a, b) (((a)<(b))?(a):(b)) DirView *dirview = NULL; static void cb_dirview_refresh_dir_tree (GtkWidget * widget, DirView * dv); static void cb_dirview_mkdir (void); static void cb_dirview_rename_dir (void); static void cb_dirview_delete_dir (void); static GtkItemFactoryEntry dirview_popup_items[] = { {N_("/_Refresh"), NULL, cb_dirview_refresh_dir_tree, 0, NULL}, {"/---", NULL, NULL, 0, ""}, {N_("/_Make Directory"), NULL, cb_dirview_mkdir, 0, NULL}, {N_("/Re_name Directory"), NULL, cb_dirview_rename_dir, 0, NULL}, {N_("/_Delete Directory"), NULL, cb_dirview_delete_dir, 0, NULL}, {NULL, NULL, NULL, 0, NULL} }; /* *------------------------------------------------------------------- * callback functions *------------------------------------------------------------------- */ static void dirview_update_toolbar (DirView * dv); static void dirview_make_visible (DirView * dv, GtkCTreeNode * node); static gint cb_dirview_button_press_event (GtkWidget * widget, GdkEventButton * event, gpointer data) { DirView *dv = data; if (event->type == GDK_BUTTON_PRESS && event->button == 3) { GtkWidget *dirview_popup, *menuitem; GtkItemFactory *ifactory; GtkCTreeNode *node; DirTreeNode *dirnode; gint n_menu_items; gchar *path, *parent, *node_text; gboolean expanded, is_leaf; node = GTK_CLIST (dv->dirtree)->selection->data; if (!node) return FALSE; gtk_ctree_get_node_info (GTK_CTREE (dv->dirtree), node, &node_text, NULL, NULL, NULL, NULL, NULL, &is_leaf, &expanded); dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dv->dirtree), node); /* * create popup menu */ n_menu_items = sizeof (dirview_popup_items) / sizeof (dirview_popup_items[0]) - 1; dirview_popup = menu_create_items (NULL, dirview_popup_items, n_menu_items, "", dv); /* * set sensitive */ ifactory = gtk_item_factory_from_widget (dirview_popup); if (!strcmp (node_text, ".") || !strcmp (node_text, "..")) { menuitem = gtk_item_factory_get_item (ifactory, "/Make Directory"); gtk_widget_set_sensitive (menuitem, FALSE); } if (!iswritable (dirnode->path)) { menuitem = gtk_item_factory_get_item (ifactory, "/Make Directory"); gtk_widget_set_sensitive (menuitem, FALSE); } path = g_strdup (dirnode->path); if (path[strlen (path) - 1] == '/') path[strlen (path) - 1] = '\0'; parent = g_dirname (path); if (!parent || !strcmp (parent, ".") || !iswritable (parent) || !strcmp (node_text, ".") || !strcmp (node_text, "..")) { menuitem = gtk_item_factory_get_item (ifactory, "/Rename Directory"); gtk_widget_set_sensitive (menuitem, FALSE); menuitem = gtk_item_factory_get_item (ifactory, "/Delete Directory"); gtk_widget_set_sensitive (menuitem, FALSE); } g_free (path); g_free (parent); /* * popup menu */ gtk_menu_popup (GTK_MENU (dirview_popup), NULL, NULL, NULL, NULL, 0, 0); #ifdef USE_GTK2 gtk_object_ref (GTK_OBJECT (dirview_popup)); gtk_object_sink (GTK_OBJECT (dirview_popup)); #endif gtk_widget_unref (dirview_popup); } return FALSE; } static gint cb_dirview_button_release_event (GtkWidget * widget, GdkEventButton * event, DirView * dv) { dirview_update_toolbar (dv); return FALSE; } static gboolean cb_dirview_key_press (GtkWidget * widget, GdkEventKey * event, DirView * dv) { guint keyval; GtkCTreeNode *node; GList *sel_list; keyval = event->keyval; sel_list = GTK_CLIST (dv->dirtree)->selection; if (!sel_list) return FALSE; node = sel_list->data; switch (keyval) { case GDK_space: dirtree_freeze (GTK_CTREE (dv->dirtree)); gtk_ctree_toggle_expansion (GTK_CTREE (dv->dirtree), node); dirtree_thaw (GTK_CTREE (dv->dirtree)); break; case GDK_Right: dirtree_freeze (GTK_CTREE (dv->dirtree)); gtk_ctree_expand (GTK_CTREE (dv->dirtree), node); dirtree_thaw (GTK_CTREE (dv->dirtree)); break; case GDK_Left: dirtree_freeze (GTK_CTREE (dv->dirtree)); gtk_ctree_collapse (GTK_CTREE (dv->dirtree), node); dirtree_thaw (GTK_CTREE (dv->dirtree)); break; } dirview_update_toolbar (dv); return FALSE; } static void cb_dirview_select_file (GtkWidget * widget, gchar * path, DirView * dv) { if (dv->lock_select) return; dirview_update_toolbar (dv); browser_select_dir (path); } static void cb_dirview_refresh_dir_tree (GtkWidget * widget, DirView * dv) { GtkCTreeNode *parent; gchar *node_text; gboolean expanded, is_leaf; browser->last_path = g_string_assign (browser->last_path, ""); parent = GTK_CLIST (dirview->dirtree)->selection->data; gtk_ctree_get_node_info (GTK_CTREE (dirview->dirtree), parent, &node_text, NULL, NULL, NULL, NULL, NULL, &is_leaf, &expanded); if (!strcmp (node_text, "..")) { parent = (GTK_CTREE_ROW (parent))->parent; if (!parent) return; parent = (GTK_CTREE_ROW (parent))->parent; if (!parent) return; dirview_make_visible (dirview, parent); } else if (!strcmp (node_text, ".")) { parent = (GTK_CTREE_ROW (parent))->parent; if (!parent) return; dirview_make_visible (dirview, parent); } dirtree_freeze (DIRTREE (dirview->dirtree)); dirtree_refresh_node (DIRTREE (dirview->dirtree), parent); dirtree_refresh_tree ((DirTree *) dirview->dirtree, parent, TRUE); dirtree_thaw (DIRTREE (dirview->dirtree)); dirview_update_toolbar (dirview); } static void cb_dirview_expand (GtkWidget * widget, DirView * dv) { GList *sel_list; GtkCTreeNode *node; sel_list = GTK_CLIST (dv->dirtree)->selection; if (!sel_list) return; node = sel_list->data; dirtree_freeze (GTK_CTREE (dv->dirtree)); gtk_ctree_expand (GTK_CTREE (dv->dirtree), node); dirtree_thaw (GTK_CTREE (dv->dirtree)); dirview_update_toolbar (dirview); } static void cb_dirview_collapse (GtkWidget * widget, DirView * dv) { GList *sel_list; GtkCTreeNode *node; sel_list = GTK_CLIST (dv->dirtree)->selection; if (!sel_list) return; node = sel_list->data; dirtree_freeze (GTK_CTREE (dv->dirtree)); gtk_ctree_collapse (GTK_CTREE (dv->dirtree), node); dirtree_thaw (GTK_CTREE (dv->dirtree)); dirview_update_toolbar (dirview); } static void cb_dirview_down (GtkWidget * widget, DirView * dv) { GtkCTreeNode *node; GList *sel_list; sel_list = GTK_CLIST (dv->dirtree)->selection; if (!sel_list) return; node = sel_list->data; node = GTK_CTREE_NODE_NEXT (node); if (node != NULL) { dirtree_freeze (GTK_CTREE (dv->dirtree)); gtk_ctree_select (GTK_CTREE (dv->dirtree), node); GTK_CLIST (dv->dirtree)->focus_row = GTK_CLIST (dv->dirtree)->rows - g_list_length ((GList *) node); dirtree_thaw (GTK_CTREE (dv->dirtree)); dirview_scroll_center (); dirview_update_toolbar (dirview); } } static void cb_dirview_up (GtkWidget * widget, DirView * dv) { GtkCTreeNode *node; GList *sel_list; sel_list = GTK_CLIST (dv->dirtree)->selection; if (!sel_list) return; node = sel_list->data; node = GTK_CTREE_NODE_PREV (node); if (node != NULL) { dirtree_freeze (GTK_CTREE (dv->dirtree)); gtk_ctree_select (GTK_CTREE (dv->dirtree), node); GTK_CLIST (dv->dirtree)->focus_row = GTK_CLIST (dv->dirtree)->rows - g_list_length ((GList *) node); dirtree_thaw (GTK_CTREE (dv->dirtree)); dirview_scroll_center (); dirview_update_toolbar (dirview); } } static void cb_dirview_show_dotfile (GtkWidget * widget, DirView * dv) { dv->lock_select = TRUE; if (DIRTREE (dv->dirtree)->show_dotfile) DIRTREE (dv->dirtree)->show_dotfile = FALSE; else DIRTREE (dv->dirtree)->show_dotfile = TRUE; cb_dirview_refresh_dir_tree (widget, dv); dv->lock_select = FALSE; } /* * make directory */ static gint cb_dirview_rename_node (ClistEditData * ced, const gchar * old, const gchar * new, gpointer data); static void cb_dirview_mkdir (void) { GtkCTreeNode *node; DirTreeNode *dirnode; gboolean success; gint row; gchar *path; gchar *new_path; node = GTK_CLIST (dirview->dirtree)->selection->data; if (!node) return; dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dirview->dirtree), node); if (!dirnode) return; if (!iswritable (dirnode->path)) { gchar *message = NULL; message = g_strdup_printf ("%s \"%s\".", _("Permission denied"), g_basename (dirnode->path)); dialog_message (_("Error"), message, browser->window); g_free (message); return; } path = g_strconcat (dirnode->path, "/", _("new folder"), NULL); new_path = unique_filename (path, NULL, NULL, FALSE); success = makedir (new_path); dirtree_freeze (DIRTREE (dirview->dirtree)); dirtree_refresh_node (DIRTREE (dirview->dirtree), node); dirtree_refresh_tree (DIRTREE (dirview->dirtree), node, FALSE); node = dirtree_find_file (DIRTREE (dirview->dirtree), node, g_basename (new_path)); dirtree_refresh_tree (DIRTREE (dirview->dirtree), node, TRUE); dirview_scroll_center (); dirtree_thaw (DIRTREE (dirview->dirtree)); row = g_list_position (GTK_CLIST (dirview->dirtree)->row_list, (GList *) node); if (row < 0) return; dirview_make_visible (dirview, node); gtk_ctree_node_moveto (GTK_CTREE (dirview->dirtree), node, 0, 0.0, 0.0); clist_edit_by_row (GTK_CLIST (dirview->dirtree), row, 0, cb_dirview_rename_node, dirview); g_free (path); g_free (new_path); } /* * rename directory */ static gint timer_refresh; static gchar *refresh_dir = NULL; static int cb_dirview_refresh_timer_proc (gpointer data) { GtkCTreeNode *parent; GtkCTreeNode *node = data; parent = (GTK_CTREE_ROW (node))->parent; dirtree_freeze (DIRTREE (dirview->dirtree)); if (parent) dirtree_refresh_tree (DIRTREE (dirview->dirtree), parent, FALSE); if (refresh_dir) { node = dirtree_find_file (DIRTREE (dirview->dirtree), parent, refresh_dir); dirtree_refresh_tree (DIRTREE (dirview->dirtree), node, TRUE); g_free (refresh_dir); refresh_dir = NULL; } dirview_scroll_center (); dirtree_thaw (DIRTREE (dirview->dirtree)); return FALSE; } static gint cb_dirview_rename_node (ClistEditData * ced, const gchar * old, const gchar * new, gpointer data) { DirView *dv = data; DirTreeNode *dirnode; GtkCTreeNode *node; gchar *src_path; gchar *dest_path; node = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), (guint) ced->row); if (!node) return FALSE; dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dv->dirtree), node); if (!dirnode) return FALSE; src_path = g_strdup (dirnode->path); if (src_path[strlen (src_path) - 1] == '/') src_path[strlen (src_path) - 1] = '\0'; dest_path = g_strconcat (g_dirname (src_path), "/", new, NULL); if (rename (src_path, dest_path) < 0) { gchar *message = NULL; message = g_strdup_printf ("%s \"%s\".\n%s", _("Faild to rename directory"), g_basename (src_path), g_strerror (errno)); dialog_message (_("Error"), message, browser->window); g_free (message); } else { refresh_dir = g_strdup (new); timer_refresh = gtk_timeout_add (100, cb_dirview_refresh_timer_proc, node); } g_free (src_path); g_free (dest_path); return FALSE; } static void cb_dirview_rename_dir (void) { GtkCTreeNode *node; DirTreeNode *dirnode; gboolean exist; struct stat st; gint row; node = GTK_CLIST (dirview->dirtree)->selection->data; if (!node) return; dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dirview->dirtree), node); if (!dirnode) return; /* * check for direcotry exist */ exist = !lstat (dirnode->path, &st); if (!exist) { gchar *message = NULL; message = g_strdup_printf ("%s \"%s\".", _("Directory not exist"), g_basename (dirnode->path)); dialog_message (_("Error"), message, browser->window); g_free (message); return; } row = g_list_position (GTK_CLIST (dirview->dirtree)->row_list, (GList *) node); if (row < 0) return; dirview_make_visible (dirview, node); gtk_ctree_node_moveto (GTK_CTREE (dirview->dirtree), node, 0, 0.0, 0.0); clist_edit_by_row (GTK_CLIST (dirview->dirtree), row, 0, cb_dirview_rename_node, dirview); return; } /* * delete directory */ static void cb_dirview_delete_dir (void) { GtkCTreeNode *node, *parent; DirTreeNode *dirnode; gboolean exist; struct stat st; ConfirmType action; gchar *path = NULL; gchar *message = NULL; node = GTK_CLIST (dirview->dirtree)->selection->data; if (!node) return; dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dirview->dirtree), node); if (!dirnode) return; /* * check direcotry exist or not */ exist = !lstat (dirnode->path, &st); if (!exist) { message = g_strdup_printf ("%s \"%s\".", _("Directory not exist"), g_basename (dirnode->path)); dialog_message (_("Error"), message, browser->window); g_free (message); return; } /* * confirm */ message = g_strdup_printf ("%s \"%s\" ?", _("Delete directory"), g_basename (dirnode->path)); action = dialog_confirm (_("Confirm Deleting Directory"), message, browser->window); g_free (message); if (action != CONFIRM_YES) return; path = g_strdup (dirnode->path); if (path[strlen (path) - 1] == '/') path[strlen (path) - 1] = '\0'; if (rmdir (path) < 0) { message = g_strdup_printf ("%s \"%s\".\n%s", _("Faild to delete directory"), g_basename (path), g_strerror (errno)); dialog_message (_("Error"), message, browser->window); g_free (message); g_free (path); return; } g_free (path); /* * refresh dir tree */ parent = (GTK_CTREE_ROW (node))->parent; if (!parent) return; dirtree_freeze (DIRTREE (dirview->dirtree)); dirtree_refresh_node (DIRTREE (dirview->dirtree), parent); dirtree_refresh_tree (DIRTREE (dirview->dirtree), parent, TRUE); dirview_make_visible (dirview, parent); dirtree_thaw (DIRTREE (dirview->dirtree)); } /* *------------------------------------------------------------------- * private functions *------------------------------------------------------------------- */ static void dirview_make_visible (DirView * dv, GtkCTreeNode * node) { GtkCTreeNode *parent; parent = GTK_CTREE_ROW (node)->parent; gtk_clist_freeze (GTK_CLIST (dv->dirtree)); while (parent) { if (!GTK_CTREE_ROW (parent)->expanded) { gtk_ctree_expand (GTK_CTREE (dv->dirtree), parent); } parent = GTK_CTREE_ROW (parent)->parent; } /* * the realized test is a hack, otherwise the scrollbar is incorrect at start up */ if (GTK_WIDGET_REALIZED (dv->dirtree) && gtk_ctree_node_is_visible (GTK_CTREE (dv->dirtree), node) != GTK_VISIBILITY_FULL) { gtk_ctree_node_moveto (GTK_CTREE (dv->dirtree), node, 0, 0, 0.0); } gtk_clist_thaw (GTK_CLIST (dv->dirtree)); } static GtkWidget * dirview_create_toolbar (DirView * dv) { GtkWidget *toolbar; GtkWidget *iconw; g_return_val_if_fail (dv, NULL); #ifdef USE_GTK2 toolbar = gtk_toolbar_new (); #else toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_ICONS); gtk_toolbar_set_button_relief (GTK_TOOLBAR (toolbar), GTK_RELIEF_NONE); gtk_toolbar_set_space_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_SPACE_LINE); gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 16); #endif /* * refresh */ iconw = pixbuf_create_pixmap_from_xpm_data (refresh_xpm); dv->toolbar_refresh_btn = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Refresh"), NULL, iconw, GTK_SIGNAL_FUNC (cb_dirview_refresh_dir_tree), dv); /* * up */ iconw = pixbuf_create_pixmap_from_xpm_data (up_xpm); dv->toolbar_up_btn = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Up"), NULL, iconw, GTK_SIGNAL_FUNC (cb_dirview_up), dv); /* * down */ iconw = pixbuf_create_pixmap_from_xpm_data (down_xpm); dv->toolbar_down_btn = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Down"), NULL, iconw, GTK_SIGNAL_FUNC (cb_dirview_down), dv); /* * collapse */ iconw = pixbuf_create_pixmap_from_xpm_data (left_xpm); dv->toolbar_collapse_btn = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Collapse"), NULL, iconw, GTK_SIGNAL_FUNC (cb_dirview_collapse), dv); /* * expand */ iconw = pixbuf_create_pixmap_from_xpm_data (right_xpm); dv->toolbar_expand_btn = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Expand"), NULL, iconw, GTK_SIGNAL_FUNC (cb_dirview_expand), dv); /* * show/hide dotfile */ iconw = pixbuf_create_pixmap_from_xpm_data (dotfile_xpm); dv->toolbar_show_dotfile_btn = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), NULL, _("Show/Hide dotfile"), NULL, iconw, GTK_SIGNAL_FUNC (cb_dirview_show_dotfile), dv); gtk_widget_show_all (toolbar); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS); return toolbar; } static void dirview_update_toolbar (DirView * dv) { GtkCTreeNode *node; GList *sel_list; gboolean is_leaf, expanded; gint current, len; sel_list = GTK_CLIST (dv->dirtree)->selection; if (!sel_list) return; node = sel_list->data; len = GTK_CLIST (GTK_CTREE (dv->dirtree))->rows; current = len - g_list_length ((GList *) node); if (current == 0) { gtk_widget_set_sensitive (dv->toolbar_up_btn, FALSE); gtk_widget_set_sensitive (dv->toolbar_down_btn, TRUE); } else if (current == (len - 1)) { gtk_widget_set_sensitive (dv->toolbar_up_btn, TRUE); gtk_widget_set_sensitive (dv->toolbar_down_btn, FALSE); } else { gtk_widget_set_sensitive (dv->toolbar_up_btn, TRUE); gtk_widget_set_sensitive (dv->toolbar_down_btn, TRUE); } gtk_ctree_get_node_info (GTK_CTREE (dv->dirtree), node, NULL, NULL, NULL, NULL, NULL, NULL, &is_leaf, &expanded); gtk_widget_set_sensitive (dv->toolbar_expand_btn, !is_leaf); gtk_widget_set_sensitive (dv->toolbar_collapse_btn, !is_leaf); if (is_leaf) return; if (expanded) { gtk_widget_set_sensitive (dv->toolbar_expand_btn, FALSE); gtk_widget_set_sensitive (dv->toolbar_collapse_btn, TRUE); } else { gtk_widget_set_sensitive (dv->toolbar_expand_btn, TRUE); gtk_widget_set_sensitive (dv->toolbar_collapse_btn, FALSE); } } /* *------------------------------------------------------------------- * public functions *------------------------------------------------------------------- */ void dirview_create (const gchar * start_path, GtkWidget * parent_win) { dirview = g_new0 (DirView, 1); /* * main vbox */ dirview->container = gtk_vbox_new (FALSE, 0); gtk_widget_ref (dirview->container); gtk_object_set_data_full (GTK_OBJECT (parent_win), "dirview_container", dirview->container, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (dirview->container); /* * toolbar */ dirview->toolbar_eventbox = gtk_event_box_new (); gtk_container_set_border_width (GTK_CONTAINER (dirview->toolbar_eventbox), 1); gtk_box_pack_start (GTK_BOX (dirview->container), dirview->toolbar_eventbox, FALSE, FALSE, 0); gtk_widget_show (dirview->toolbar_eventbox); dirview->toolbar = dirview_create_toolbar (dirview); gtk_container_add (GTK_CONTAINER (dirview->toolbar_eventbox), dirview->toolbar); /* * scrolled window */ dirview->scroll_win = gtk_scrolled_window_new (NULL, NULL); gtk_container_set_border_width (GTK_CONTAINER (dirview->scroll_win), 1); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dirview->scroll_win), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (dirview->container), dirview->scroll_win, TRUE, TRUE, 0); gtk_widget_show (dirview->scroll_win); /* * dirtree */ dirview->dirtree = dirtree_new (parent_win, start_path, conf.scan_dir, conf.check_hlinks, conf.show_dotfile, conf.dirtree_line_style, conf.dirtree_expander_style); gtk_container_add (GTK_CONTAINER (dirview->scroll_win), dirview->dirtree); gtk_widget_set_usize (GTK_WIDGET (dirview->scroll_win), conf.dirtree_width, conf.dirtree_height); gtk_widget_show (dirview->dirtree); /* * callback singnals */ gtk_signal_connect (GTK_OBJECT (dirview->dirtree), "button_press_event", GTK_SIGNAL_FUNC (cb_dirview_button_press_event), dirview); gtk_signal_connect (GTK_OBJECT (dirview->dirtree), "button_release_event", GTK_SIGNAL_FUNC (cb_dirview_button_release_event), dirview); gtk_signal_connect (GTK_OBJECT (dirview->dirtree), "key_press_event", GTK_SIGNAL_FUNC (cb_dirview_key_press), dirview); gtk_signal_connect (GTK_OBJECT (dirview->dirtree), "select_file", GTK_SIGNAL_FUNC (cb_dirview_select_file), dirview); gtk_widget_show (dirview->scroll_win); dirview_update_toolbar (dirview); } void dirview_scroll_center (void) { GtkAdjustment *vadj; gfloat pos; vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (dirview->scroll_win)); pos = (vadj->upper * GTK_CLIST (DIRTREE (dirview->dirtree))->focus_row) / (gfloat) GTK_CLIST (dirview->dirtree)->rows; gtk_adjustment_set_value (vadj, min (vadj->upper - vadj->page_size, pos)); } void dirview_destroy (void) { gtk_widget_destroy (dirview->dirtree); g_free (dirview); dirview = NULL; }