1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * GImageView
5  * Copyright (C) 2001 Takuro Ashie
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * $Id: dirview.c,v 1.81 2004/09/21 08:44:31 makeinu Exp $
22  */
23 
24 /*
25  * These codes are mostly taken from G-thumB.
26  * G-thumB code Copyright (C) 1999-2000 MIZUNO Takehiko <mizuno@bigfoot.com>
27  */
28 
29 #include "dirview.h"
30 
31 #ifndef ENABLE_TREEVIEW
32 
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <dirent.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 #include <gdk/gdkkeysyms.h>
40 
41 #include "gimageview.h"
42 #include "charset.h"
43 #include "dirview_priv.h"
44 #include "dnd.h"
45 #include "fileload.h"
46 #include "fileutil.h"
47 #include "gfileutil.h"
48 #include "gtk2-compat.h"
49 #include "gtk_prop.h"
50 #include "gtkutils.h"
51 #include "gimv_icon_stock.h"
52 #include "gimv_thumb_win.h"
53 #include "menu.h"
54 #include "prefs.h"
55 
56 
57 /* for auto-scroll and auto-expand at drag */
58 #define SCROLL_EDGE 20
59 typedef gboolean (*desirable_fn) (DirView *dv, gint x, gint y);
60 typedef gboolean (*scroll_fn)    (gpointer data);
61 
62 
63 typedef enum {
64    DirNodeScannedFlag = 1 << 0,
65    DirNodeOpenedFlag  = 1 << 1
66 } DirNodeFlags;
67 
68 
69 typedef struct DirNode_Tag
70 {
71    DirNodeFlags flags;
72    gboolean scanned;
73    gchar *path;
74 } DirNode;
75 
76 
77 /* private functions */
78 static gint          comp_func_dirnode         (gconstpointer   node_data,
79                                                 gconstpointer   comp_data);
80 static GtkCTreeNode *dirview_find_directory    (DirView        *dv,
81                                                 const gchar    *path);
82 
83 static void     dirview_create_ctree           (DirView        *dv);
84 static void     adjust_ctree                   (GtkWidget      *widget,
85                                                 GtkCTreeNode   *node);
86 GtkCTreeNode   *dirview_insert_dummy_node      (DirView        *dv,
87                                                 GtkCTreeNode   *parent);
88 GtkCTreeNode   *dirview_insert_node            (DirView        *dv,
89                                                 GtkCTreeNode   *parent,
90                                                 const gchar    *path);
91 static void     expand_dir                     (DirView        *dv,
92                                                 GtkCTreeNode   *parent);
93 static GList   *get_expanded_list              (DirView        *dv);
94 static void     refresh_dir_tree               (DirView        *dv,
95                                                 GtkCTreeNode   *parent);
96 static void     dirview_popup_menu             (DirView        *dv,
97                                                 GtkCTreeNode   *node,
98                                                 GdkEventButton *event);
99 static gboolean dirview_button_action          (DirView        *dv,
100                                                 GdkEventButton *event,
101                                                 gint            num);
102 
103 /* for drag motion */
104 static void     dirview_setup_drag_scroll      (DirView        *dv,
105                                                 gint            x,
106                                                 gint            y,
107                                                 desirable_fn    desirable,
108                                                 scroll_fn       scroll);
109 static void     dirview_cancel_drag_scroll     (DirView        *dv);
110 static gboolean dirview_scrolling_is_desirable (DirView        *dv,
111                                                 gint            x,
112                                                 gint            y);
113 static gboolean timeout_dirview_scroll         (gpointer        data);
114 static gint     timeout_auto_expand_directory  (gpointer        data);
115 
116 
117 /* callback functions */
118 static void     cb_dirtree_destroy             (GtkWidget      *widget,
119                                                 DirView        *dv);
120 static void     cb_dirview_destroyed           (GtkWidget      *widget,
121                                                 DirView        *dv);
122 static void     cb_node_destroy                (gpointer        data);
123 static void     cb_expand                      (GtkWidget      *widget,
124                                                 GtkCTreeNode   *parent,
125                                                 DirView        *dv);
126 static void     cb_collapse                    (GtkWidget      *widget,
127                                                 GtkCTreeNode   *parent,
128                                                 DirView        *dv);
129 static gboolean  cb_button_press               (GtkWidget      *widget,
130                                                 GdkEventButton *event,
131                                                 DirView        *dv);
132 static gboolean  cb_button_release             (GtkWidget      *widget,
133                                                 GdkEventButton *event,
134                                                 DirView        *dv);
135 static gboolean cb_key_press                   (GtkWidget      *widget,
136                                                 GdkEventKey    *event,
137                                                 DirView        *dv);
138 
139 /* callback functions for popup menu */
140 static void     cb_open_thumbnail              (DirView        *dv,
141                                                 ScanSubDirType  scan_subdir,
142                                                 GtkWidget      *menuitem);
143 static void     cb_go_to_here                  (DirView        *dv,
144                                                 guint           action,
145                                                 GtkWidget      *menuitem);
146 static void     cb_refresh_dir_tree            (DirView        *dv,
147                                                 guint           action,
148                                                 GtkWidget      *menuitem);
149 static void     cb_file_property               (DirView        *tv,
150                                                 guint           action,
151                                                 GtkWidget      *menuitem);
152 static void     cb_mkdir                       (DirView        *dv,
153                                                 guint           action,
154                                                 GtkWidget      *menuitem);
155 static void     cb_rename_dir                  (DirView        *dv,
156                                                 guint           action,
157                                                 GtkWidget      *menuitem);
158 static void     cb_delete_dir                  (DirView        *dv,
159                                                 guint           action,
160                                                 GtkWidget      *menuitem);
161 
162 /* callback functions for toolbar buttons */
163 static void     cb_home_button                 (GtkWidget      *widget,
164                                                 DirView        *dv);
165 static void     cb_up_button                   (GtkWidget      *widget,
166                                                 DirView        *dv);
167 static void     cb_refresh_button              (GtkWidget      *widget,
168                                                 DirView        *dv);
169 static void     cb_dotfile_button              (GtkWidget      *widget,
170                                                 DirView        *dv);
171 
172 /* callback functions for DnD */
173 static void     cb_drag_motion                 (GtkWidget      *dirtree,
174                                                 GdkDragContext *context,
175                                                 gint            x,
176                                                 gint            y,
177                                                 gint            time,
178                                                 gpointer        data);
179 static void     cb_drag_leave                  (GtkWidget      *dirtree,
180                                                 GdkDragContext *context,
181                                                 guint           time,
182                                                 gpointer        data);
183 static void     cb_drag_data_get               (GtkWidget      *widget,
184                                                 GdkDragContext *context,
185                                                 GtkSelectionData *seldata,
186                                                 guint info,
187                                                 guint time,
188                                                 gpointer data);
189 static void     cb_drag_data_received          (GtkWidget      *dirtree,
190                                                 GdkDragContext *context,
191                                                 gint            x,
192                                                 gint            y,
193                                                 GtkSelectionData *seldata,
194                                                 guint           info,
195                                                 guint32         time,
196                                                 gpointer        data);
197 static void     cb_drag_end                    (GtkWidget      *dirtree,
198                                                 GdkDragContext *context,
199                                                 gpointer        data);
200 static void     cb_com_swap_drag_data_received (GtkWidget      *widget,
201                                                 GdkDragContext *context,
202                                                 gint            x,
203                                                 gint            y,
204                                                 GtkSelectionData *seldata,
205                                                 guint           info,
206                                                 guint           time,
207                                                 gpointer        data);
208 
209 
210 static GtkItemFactoryEntry dirview_popup_items [] =
211 {
212    {N_("/_Load Thumbnail"),                        NULL, cb_open_thumbnail, SCAN_SUB_DIR_NONE,     NULL},
213    {N_("/Load Thumbnail re_cursively"),            NULL, cb_open_thumbnail, SCAN_SUB_DIR,          NULL},
214    {N_("/Load Thumbnail recursively in _one tab"), NULL, cb_open_thumbnail, SCAN_SUB_DIR_ONE_TAB,  NULL},
215    {N_("/---"),                         NULL, NULL,                0,     "<Separator>"},
216    {N_("/_Go to here"),                 NULL, cb_go_to_here,       0,     NULL},
217    {N_("/_Refresh Tree"),               NULL, cb_refresh_dir_tree, 0,     NULL},
218    {N_("/---"),                         NULL, NULL,                0,     "<Separator>"},
219    {N_("/_Property..."),                NULL, cb_file_property,    0,     NULL},
220    {N_("/---"),                         NULL, NULL,                0,     "<Separator>"},
221    {N_("/_Make Directory..."),          NULL, cb_mkdir,            0,     NULL},
222    {N_("/Re_name Directory..."),        NULL, cb_rename_dir,       0,     NULL},
223    {N_("/_Delete Directory..."),        NULL, cb_delete_dir,       0,     NULL},
224    {NULL, NULL, NULL, 0, NULL},
225 };
226 
227 
228 extern GtkItemFactoryEntry dnd_file_popup_items [];
229 
230 
231 /******************************************************************************
232  *
233  *   Private functions
234  *
235  ******************************************************************************/
236 static gint
comp_func_dirnode(gconstpointer node_data,gconstpointer comp_data)237 comp_func_dirnode (gconstpointer node_data, gconstpointer comp_data)
238 {
239    const DirNode *dirnode = node_data;
240    const gchar *node_path;
241    const gchar *comp_path = comp_data;
242 
243    g_return_val_if_fail (comp_path && *comp_path, -1);
244 
245    if (!dirnode) return -1;
246 
247    node_path = dirnode->path;
248    if (!node_path || !*node_path) return -1;
249 
250    return strcmp (node_path, comp_path);
251 }
252 
253 
254 static GtkCTreeNode *
dirview_find_directory(DirView * dv,const gchar * path)255 dirview_find_directory (DirView *dv, const gchar *path)
256 {
257    GtkCTreeNode *parent, *node;
258 
259    g_return_val_if_fail (dv, NULL);
260    g_return_val_if_fail (path && path, NULL);
261 
262    parent = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), 0);
263    if (!parent) return NULL;
264    node = gtk_ctree_find_by_row_data_custom (GTK_CTREE (dv->dirtree),
265                                              parent,
266                                              (gpointer) path,
267                                              comp_func_dirnode);
268    return node;
269 }
270 
271 
272 /*
273  *  dirview_create_ctree:
274  *     @ create a new GtkCTree widget.
275  *
276  *  dv : Pointer to the DirView struct.
277  */
278 static void
dirview_create_ctree(DirView * dv)279 dirview_create_ctree (DirView *dv)
280 {
281    GtkWidget *dirtree;
282    GtkCTreeNode *root_node;
283    gchar *root_dir;
284 
285    g_return_if_fail (dv);
286 
287    root_dir = add_slash (dv->root_dir);
288    g_free (dv->root_dir);
289    dv->root_dir = root_dir;
290 
291    dirtree = dv->dirtree = gtk_ctree_new (1,0);
292    gtk_clist_set_column_auto_resize (GTK_CLIST (dirtree), 0, TRUE);
293    gtk_clist_set_selection_mode (GTK_CLIST (dirtree), GTK_SELECTION_BROWSE);
294    gtk_ctree_set_line_style (GTK_CTREE (dirtree), conf.dirview_line_style);
295    gtk_ctree_set_expander_style (GTK_CTREE (dirtree), conf.dirview_expander_style);
296    gtk_clist_set_row_height (GTK_CLIST (dirtree), 18);
297 
298    gtk_container_add (GTK_CONTAINER (dv->scroll_win), dirtree);
299 
300    gtk_signal_connect (GTK_OBJECT (dirtree), "tree_expand",
301                        GTK_SIGNAL_FUNC (cb_expand), dv);
302    gtk_signal_connect (GTK_OBJECT (dirtree), "tree_collapse",
303                        GTK_SIGNAL_FUNC (cb_collapse), dv);
304 
305    gtk_signal_connect (GTK_OBJECT (dirtree),"button_press_event",
306                        GTK_SIGNAL_FUNC (cb_button_press), dv);
307    gtk_signal_connect (GTK_OBJECT (dirtree),"button_release_event",
308                        GTK_SIGNAL_FUNC (cb_button_release), dv);
309 
310    gtk_signal_connect (GTK_OBJECT(dirtree), "key-press-event",
311                        GTK_SIGNAL_FUNC (cb_key_press), dv);
312 
313    gtk_signal_connect (GTK_OBJECT (dv->dirtree), "destroy",
314                        GTK_SIGNAL_FUNC (cb_dirtree_destroy), dv);
315 
316    /* for drag file list */
317    dnd_src_set  (dirtree, dnd_types_uri, dnd_types_uri_num);
318    dnd_dest_set (dirtree, dnd_types_archive, dnd_types_archive_num);
319    gtk_signal_connect (GTK_OBJECT (dirtree), "drag_motion",
320                        GTK_SIGNAL_FUNC (cb_drag_motion), dv);
321    gtk_signal_connect (GTK_OBJECT (dirtree), "drag_leave",
322                        GTK_SIGNAL_FUNC (cb_drag_leave), dv);
323    gtk_signal_connect (GTK_OBJECT (dirtree), "drag_data_get",
324                        GTK_SIGNAL_FUNC (cb_drag_data_get), dv);
325    gtk_signal_connect (GTK_OBJECT (dirtree), "drag_data_received",
326                        GTK_SIGNAL_FUNC (cb_drag_data_received), dv);
327    gtk_signal_connect (GTK_OBJECT (dirtree), "drag_end",
328                        GTK_SIGNAL_FUNC (cb_drag_end), dv);
329 
330    root_node = dirview_insert_node (dv, NULL, dv->root_dir);
331    if (root_dir)
332       gtk_ctree_expand (GTK_CTREE (dirtree), root_node);
333 
334    gtk_widget_show (dirtree);
335 }
336 
337 
338 /*
339  *  adjust_ctree:
340  *     @ set position of viewport
341  *
342  *  dirtree : ctree widget.
343  *  parent  : ctree node that contain direcotry to expand.
344  */
345 static void
adjust_ctree(GtkWidget * dirtree,GtkCTreeNode * node)346 adjust_ctree (GtkWidget *dirtree, GtkCTreeNode *node)
347 {
348    gint row = GTK_CLIST (dirtree)->rows - g_list_length ((GList*)node);
349 
350    GTK_CLIST (dirtree)->focus_row = row;
351    gtk_ctree_select (GTK_CTREE (dirtree), node);
352 
353    gtk_clist_freeze (GTK_CLIST (dirtree));
354    if (gtk_ctree_node_is_visible (GTK_CTREE (dirtree), node) != GTK_VISIBILITY_FULL)
355       gtk_ctree_node_moveto (GTK_CTREE (dirtree), node, 0, 0, 0);
356    gtk_clist_thaw (GTK_CLIST (dirtree));
357 }
358 
359 
360 /*
361  *  dirview_insert_dummy_node:
362  *     @ insert dummy node to display expander.
363  *
364  *  dv     : Pointer to the Dir View struct.
365  *  parnt  : Parent node to insert dummy node.
366  *  Return : Pointer to the new GtkCTreeNode.
367  */
368 GtkCTreeNode *
dirview_insert_dummy_node(DirView * dv,GtkCTreeNode * parent)369 dirview_insert_dummy_node (DirView *dv, GtkCTreeNode *parent)
370 {
371    GtkCTreeNode *node = NULL;
372    gchar *dummy = "dummy", *node_text;
373    DirNode *dirdata;
374    gboolean is_leaf, expanded;
375 
376    dirdata = gtk_ctree_node_get_row_data (GTK_CTREE (dv->dirtree), parent);
377    gtk_ctree_get_node_info (GTK_CTREE (dv->dirtree), parent, &node_text, NULL,
378                             NULL, NULL, NULL, NULL, &is_leaf, &expanded);
379 
380    if (!expanded && !(dirdata->flags & DirNodeScannedFlag)
381        && !GTK_CTREE_ROW (parent)->children
382        && strcmp (node_text, ".") && strcmp (node_text, ".."))
383    {
384       gtk_ctree_insert_node (GTK_CTREE (dv->dirtree),
385                              parent, NULL, &dummy,
386                              4, NULL, NULL, NULL, NULL, FALSE, FALSE);
387    }
388 
389    return node;
390 }
391 
392 
393 /*
394  *  dirview_insert_node:
395  *     @ insert new node to the dirview.
396  *
397  *  dv     : Pointer to the Dir View struct.
398  *  parnt  : Parent node to insert new node.
399  *  path   : Dir name to insert.
400  *  Return : Pointer to the new GtkCTreeNode.
401  */
402 GtkCTreeNode *
dirview_insert_node(DirView * dv,GtkCTreeNode * parent,const gchar * path)403 dirview_insert_node (DirView *dv, GtkCTreeNode *parent, const gchar *path)
404 {
405    GtkCTreeNode *node = NULL;
406    DirNode *dirnode;
407    GimvIcon *folder, *ofolder;
408    gchar *dir, *internal_str;
409    const gchar *filename, *text;
410 
411    g_return_val_if_fail (dv && path, NULL);
412 
413    dir = remove_slash (path);
414    filename = g_basename (dir);
415 
416    if (isdir (path)
417        && (!(!dv->show_dotfile && (filename[0] == '.'))
418            || (conf.dirview_show_current_dir && !strcmp (filename, "."))
419            || (conf.dirview_show_parent_dir  && !strcmp (filename, ".."))
420            || !parent))
421    {
422       dirnode = g_new0 (DirNode, 1);
423       dirnode->flags = 0;
424       if (!strcmp(filename, ".") || !strcmp(filename, "..")) {
425          gchar *tmpstr = relpath2abs (path);
426          dirnode->path = add_slash (tmpstr);
427          g_free (tmpstr);
428       } else {
429          dirnode->path = add_slash (path);
430       }
431 
432       if (parent)
433          text = filename;
434       else
435          text = path;
436 
437       if (islink (path))
438          folder = gimv_icon_stock_get_icon ("folder-link");
439       else if (!strcmp (filename, "."))
440          folder = gimv_icon_stock_get_icon ("folder-go");
441       else if (!strcmp (filename, ".."))
442          folder = gimv_icon_stock_get_icon ("folder-up");
443       else if (access(path, R_OK))
444          folder = gimv_icon_stock_get_icon ("folder-lock");
445       else
446          folder = gimv_icon_stock_get_icon ("folder");
447 
448       if (islink (path))
449          ofolder = gimv_icon_stock_get_icon ("folder-link-open");
450       else
451          ofolder = gimv_icon_stock_get_icon ("folder-open");
452 
453       internal_str = charset_to_internal (text, conf.charset_filename,
454                                           conf.charset_auto_detect_fn,
455                                           conf.charset_filename_mode);
456 
457       node = gtk_ctree_insert_node (GTK_CTREE (dv->dirtree), parent,
458                                     NULL, (gchar **) &internal_str, 4,
459                                     folder->pixmap, folder->mask,
460                                     ofolder->pixmap, ofolder->mask,
461                                     FALSE, FALSE);
462 
463       g_free (internal_str);
464 
465       gtk_ctree_node_set_row_data_full (GTK_CTREE (dv->dirtree), node,
466                                         dirnode, cb_node_destroy);
467 
468       /* set expander */
469       if (!access(path, R_OK))
470          dirview_insert_dummy_node (dv, node);
471 
472       /* set mark */
473       if (gimv_thumb_view_find_opened_dir (dirnode->path)) {
474          dirview_set_opened_mark (dv, dirnode->path);
475       }
476    }
477 
478    g_free (dir);
479 
480    return node;
481 }
482 
483 
484 /*
485  *  expand_dir:
486  *     @ Expand specified direcotry tree.
487  *
488  *  dv      : Pointer to the DirView struct.
489  *  parent  : ctree node that contain direcotry to expand.
490  */
491 static void
expand_dir(DirView * dv,GtkCTreeNode * parent)492 expand_dir (DirView *dv, GtkCTreeNode *parent)
493 {
494    GtkWidget *dirtree;
495    DirNode *parent_dirnode;
496    DIR *dir;
497    struct dirent *dirent;
498    gchar *path;
499 
500    g_return_if_fail (dv);
501 
502    dirtree = dv->dirtree;
503    if (!dirtree) return;
504 
505    parent_dirnode = gtk_ctree_node_get_row_data(GTK_CTREE(dirtree), parent);
506 
507    dir = opendir (parent_dirnode->path);
508    if (dir) {
509       while ((dirent = readdir(dir))) {
510          path = g_strconcat (parent_dirnode->path, dirent->d_name, NULL);
511          if (isdir (path))
512             dirview_insert_node (dv, parent, path);
513          g_free (path);
514       }
515       closedir (dir);
516       gtk_ctree_sort_node (GTK_CTREE(dirtree), parent);
517    }
518 
519    parent_dirnode->flags |= DirNodeScannedFlag;
520 }
521 
522 
523 GList *
get_expanded_list(DirView * dv)524 get_expanded_list (DirView *dv)
525 {
526    GList *list = NULL;
527    GtkCTreeNode *node;
528    gchar *text;
529    gboolean is_leaf, expanded;
530    DirNode *dirnode;
531 
532    g_return_val_if_fail (dv, NULL);
533    g_return_val_if_fail (dv->dirtree, NULL);
534 
535    node = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), 0);
536    for (; node; node = GTK_CTREE_NODE_NEXT (node)) {
537       gtk_ctree_get_node_info (GTK_CTREE (dv->dirtree), node, &text, NULL,
538                                NULL, NULL, NULL, NULL, &is_leaf, &expanded);
539 
540       if (expanded) {
541          dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dv->dirtree), node);
542          list = g_list_append (list, g_strdup (dirnode->path));
543       }
544    }
545 
546    return list;
547 }
548 
549 
550 /*
551  *  refresh_dir_tree:
552  *     @ Refresh sub direcotry list.
553  *
554  *  dv      : Pointer to the DirView struct.
555  *  parent  : ctree node that contain direcotry to refresh.
556  */
557 static void
refresh_dir_tree(DirView * dv,GtkCTreeNode * parent)558 refresh_dir_tree (DirView *dv,  GtkCTreeNode *parent)
559 {
560    GList *expand_list, *node;
561    GtkCTreeNode *treenode;
562    gchar *root_dir, *selected_path;
563 
564    g_return_if_fail (dv);
565 
566    selected_path = dirview_get_selected_path (dv);
567    if (!selected_path) selected_path = g_strdup (dv->root_dir);
568 
569    /* get expanded directory list */
570    expand_list = get_expanded_list (dv);
571 
572    /* replace root node */
573    root_dir = g_strdup (dv->root_dir);
574    dirview_change_root (dv, root_dir);
575    g_free (root_dir);
576 
577    /* restore expanded directory */
578    for (node = expand_list; node; node = g_list_next (node)) {
579       dirview_expand_dir (dv, node->data, FALSE);
580    }
581 
582    /* restore selection */
583    treenode = dirview_find_directory (dv, selected_path);
584    if (treenode)
585       adjust_ctree (dv->dirtree, treenode);
586 
587    g_list_foreach (expand_list, (GFunc) g_free, NULL);
588    g_list_free (expand_list);
589 
590    g_free (selected_path);
591 }
592 
593 
594 static void
dirview_popup_menu(DirView * dv,GtkCTreeNode * node,GdkEventButton * event)595 dirview_popup_menu (DirView *dv, GtkCTreeNode *node,  GdkEventButton *event)
596 {
597    GtkWidget *dirview_popup, *menuitem;
598    GtkItemFactory *ifactory;
599    DirNode *dirnode;
600    gint n_menu_items;
601    gchar *path, *parent, *node_text;
602    gboolean expanded, is_leaf;
603    GtkMenuPositionFunc pos_fn = NULL;
604    guint button;
605    guint32 time;
606 
607    g_return_if_fail (dv);
608    g_return_if_fail (dv->dirtree);
609 
610    if (!node) {
611       GList *sel_list;
612       sel_list = GTK_CLIST (dv->dirtree)->selection;
613       if (!sel_list) return;
614 
615       node = sel_list->data;
616    }
617 
618    if (event) {
619       button = event->button;
620       time = event->time;
621    } else {
622       button = 0;
623       time = GDK_CURRENT_TIME;
624       pos_fn = menu_calc_popup_position;
625    }
626 
627    gtk_ctree_get_node_info (GTK_CTREE (dv->dirtree), node, &node_text, NULL,
628                             NULL, NULL, NULL, NULL, &is_leaf, &expanded);
629    dirnode = gtk_ctree_node_get_row_data(GTK_CTREE(dv->dirtree), node);
630 
631    if (dv->popup_menu) {
632       gtk_widget_unref (dv->popup_menu);
633       dv->popup_menu = NULL;
634    }
635 
636    n_menu_items = sizeof(dirview_popup_items)
637       / sizeof(dirview_popup_items[0]) -  1;
638    dirview_popup = menu_create_items(NULL, dirview_popup_items,
639                                      n_menu_items, "<DirViewPop>", dv);
640 
641    /* set sensitive */
642    ifactory = gtk_item_factory_from_widget (dirview_popup);
643 
644    if (!strcmp (node_text, ".") || !strcmp (node_text, ".."))
645    {
646       menuitem = gtk_item_factory_get_item (ifactory, "/Refresh Tree");
647       gtk_widget_set_sensitive (menuitem, FALSE);
648       menuitem = gtk_item_factory_get_item (ifactory, "/Make Directory...");
649       gtk_widget_set_sensitive (menuitem, FALSE);
650    }
651 
652    if (!iswritable (dirnode->path)) {
653       menuitem = gtk_item_factory_get_item (ifactory, "/Make Directory...");
654       gtk_widget_set_sensitive (menuitem, FALSE);
655    }
656 
657    path = g_strdup (dirnode->path);
658    if (path [strlen (path) - 1] == '/')
659       path [strlen (path) - 1] = '\0';
660    parent = g_dirname (path);
661 
662    if (!parent || !strcmp (parent, ".") || !iswritable (parent)
663        || !strcmp (node_text, ".") || !strcmp (node_text, ".."))
664    {
665       menuitem = gtk_item_factory_get_item (ifactory, "/Rename Directory...");
666       gtk_widget_set_sensitive (menuitem, FALSE);
667       menuitem = gtk_item_factory_get_item (ifactory, "/Delete Directory...");
668       gtk_widget_set_sensitive (menuitem, FALSE);
669    }
670 
671    g_free (path);
672    g_free (parent);
673 
674    /* popup menu */
675    gtk_menu_popup(GTK_MENU (dirview_popup), NULL, NULL,
676                   pos_fn, dv->dirtree->window, button, time);
677 
678    dv->popup_menu = dirview_popup;
679 
680 #ifdef USE_GTK2
681    gtk_object_ref (GTK_OBJECT (dv->popup_menu));
682    gtk_object_sink (GTK_OBJECT (dv->popup_menu));
683 #endif
684 }
685 
686 
687 typedef struct ButtonActionData_Tag
688 {
689    DirView *dv;
690    gchar   *path, *label;
691    gint     action_num;
692 } ButtonActionData;
693 
694 
695 static void
free_button_action_data(ButtonActionData * data)696 free_button_action_data (ButtonActionData *data)
697 {
698    g_free (data->path);
699    g_free (data->label);
700    g_free (data);
701 }
702 
703 
704 static gboolean
idle_dirview_button_action(gpointer data)705 idle_dirview_button_action (gpointer data)
706 {
707    ButtonActionData *bdata = data;
708    DirView *dv = bdata->dv;
709    gchar *path = bdata->path, *label = bdata->label;
710 
711    dv->priv->button_action_id = 0;
712 
713    switch (abs (bdata->action_num)) {
714    case MouseActLoadThumb:
715       if (!strcmp (label, ".") || !strcmp (label, "..")) {
716          dirview_change_root (dv, path);
717       } else {
718          open_dir_images (path, dv->tw, NULL, LOAD_CACHE, SCAN_SUB_DIR_NONE);
719       }
720       break;
721    case MouseActLoadThumbRecursive:
722       if (!strcmp (label, ".") || !strcmp (label, "..")) {
723          dirview_change_root (dv, path);
724       } else {
725          open_dir_images (path, dv->tw, NULL, LOAD_CACHE, SCAN_SUB_DIR);
726       }
727       break;
728    case MouseActLoadThumbRecursiveInOneTab:
729       if (!strcmp (label, ".") || !strcmp (label, "..")) {
730          dirview_change_root (dv, path);
731       } else {
732          open_dir_images (path, dv->tw, NULL, LOAD_CACHE, SCAN_SUB_DIR_ONE_TAB);
733       }
734       break;
735    case MouseActChangeTop:
736       dirview_change_root (dv, path);
737       break;
738    default:
739       break;
740    }
741 
742    free_button_action_data (bdata);
743 
744    return FALSE;
745 }
746 
747 
748 static gboolean
dirview_button_action(DirView * dv,GdkEventButton * event,gint num)749 dirview_button_action (DirView *dv, GdkEventButton *event, gint num)
750 {
751    GimvThumbWin *tw;
752    GtkWidget *dirtree;
753    GtkCTreeNode *node;
754    DirNode *dirnode;
755    gchar *node_text;
756    gint row;
757    gboolean is_leaf, expanded, retval = FALSE;
758 
759    g_return_val_if_fail (dv, FALSE);
760 
761    dirtree = dv->dirtree;
762    tw = dv->tw;
763 
764    gtk_clist_get_selection_info(GTK_CLIST(dirtree),
765                                 event->x, event->y, &row, NULL);
766    node = gtk_ctree_node_nth(GTK_CTREE(dirtree), row);
767    if (!node) return FALSE;
768 
769    gtk_ctree_get_node_info (GTK_CTREE (dirtree), node, &node_text, NULL,
770                             NULL, NULL, NULL, NULL, &is_leaf, &expanded);
771 
772    gtk_clist_freeze(GTK_CLIST(dirtree));
773    gtk_ctree_select(GTK_CTREE(dirtree), node);
774    GTK_CLIST(dirtree)->focus_row = row;
775    gtk_clist_thaw(GTK_CLIST(dirtree));
776    dirnode = gtk_ctree_node_get_row_data(GTK_CTREE(dirtree), node);
777 
778    switch (abs(num)) {
779    case MouseActLoadThumb:
780    case MouseActLoadThumbRecursive:
781    case MouseActLoadThumbRecursiveInOneTab:
782    case MouseActChangeTop:
783    {
784       ButtonActionData *data = g_new0 (ButtonActionData, 1);
785 
786       data->dv         = dv;
787       data->path       = g_strdup (dirnode->path);
788       data->label      = g_strdup (node_text);
789       data->action_num = num;
790 
791       dv->priv->button_action_id
792          = gtk_idle_add (idle_dirview_button_action, data);
793 
794       return FALSE;
795       break;
796    }
797    case MouseActPopupMenu:
798       dirview_popup_menu (dv, node, event);
799       if (num > 0) retval = TRUE;
800       break;
801    default:
802       break;
803    }
804 
805    return retval;
806 }
807 
808 
809 
810 /******************************************************************************
811  *
812  *   for drag motion related functions
813  *
814  ******************************************************************************/
815 /*
816  *  dirview_setup_drag_scroll:
817  *     @ set timer for auto scroll.
818  *
819  *  dv        : Pointer to the DirView struct.
820  *  x         : X position of mouse cursor.
821  *  y         : Y positoon of mouse cursor.
822  *  desirable :
823  *  scroll    : time out function for auto scroll.
824  */
825 static void
dirview_setup_drag_scroll(DirView * dv,gint x,gint y,desirable_fn desirable,scroll_fn scroll)826 dirview_setup_drag_scroll (DirView *dv, gint x, gint y,
827                            desirable_fn desirable, scroll_fn scroll)
828 {
829    dirview_cancel_drag_scroll (dv);
830 
831    dv->priv->drag_motion_x = x;
832    dv->priv->drag_motion_y = y;
833 
834    if ((* desirable) (dv, x, y))
835       dv->priv->scroll_timer_id
836          = gtk_timeout_add (conf.dirview_auto_scroll_time,
837                             scroll, dv);
838 }
839 
840 
841 /*
842  *  dirview_cancel_drag_scroll:
843  *     @ remove timer for auto scroll..
844  *
845  *  dv : Pointer to the DirView struct.
846  */
847 static void
dirview_cancel_drag_scroll(DirView * dv)848 dirview_cancel_drag_scroll (DirView *dv)
849 {
850    g_return_if_fail (dv);
851 
852    if (dv->priv->scroll_timer_id){
853       gtk_timeout_remove (dv->priv->scroll_timer_id);
854       dv->priv->scroll_timer_id = 0;
855    }
856 }
857 
858 
859 /*
860  *  dirview_scrolling_is_desirable:
861  *     @ If the cursor is in a position close to either edge (top or bottom)
862  *     @ and there is possible to scroll the window, this routine returns
863  *     @ true.
864  *
865  *  dv     : Pointer to the DirView struct for scrolling.
866  *  x      : X position of mouse cursor.
867  *  y      : Y position of mouse cursor.
868  *  Return : possiblilty of scrolling (TRUE or FALSE).
869  */
870 static gboolean
dirview_scrolling_is_desirable(DirView * dv,gint x,gint y)871 dirview_scrolling_is_desirable (DirView *dv, gint x, gint y)
872 {
873    GtkCTree *dirtree;
874    GtkAdjustment *vadj;
875 
876    dirtree = GTK_CTREE (dv->dirtree);
877 
878    vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (dv->scroll_win));
879 
880    if (y < SCROLL_EDGE) {
881       if (vadj->value > vadj->lower)
882          return TRUE;
883    } else {
884       if (y > (vadj->page_size - SCROLL_EDGE)){
885          if (vadj->value < vadj->upper - vadj->page_size)
886             return TRUE;
887       }
888    }
889 
890    return FALSE;
891 }
892 
893 
894 /*
895  *  timeout_dirview_scroll:
896  *     @ Timer callback to scroll the tree.
897  *
898  *  data   : Pointer to the DirView struct.
899  *  Return : TRUE
900  */
901 static gboolean
timeout_dirview_scroll(gpointer data)902 timeout_dirview_scroll (gpointer data)
903 {
904    DirView *dv = data;
905    GtkAdjustment *vadj;
906    gfloat vpos;
907 
908    vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (dv->scroll_win));
909 
910    if (dv->priv->drag_motion_y < SCROLL_EDGE) {
911       vpos = vadj->value - vadj->step_increment;
912       if (vpos < vadj->lower)
913          vpos = vadj->lower;
914 
915       gtk_adjustment_set_value (vadj, vpos);
916    } else {
917       vpos = vadj->value + vadj->step_increment;
918       if (vpos > vadj->upper - vadj->page_size)
919          vpos = vadj->upper - vadj->page_size;
920 
921       gtk_adjustment_set_value (vadj, vpos);
922    }
923 
924    return TRUE;
925 }
926 
927 
928 /*
929  *  timeout_auto_expand_directory:
930  *     @ This routine is invoked in a delayed fashion if the user
931  *     @ keeps the drag cursor still over the widget.
932  *
933  *  data   : Pointer to the DirView struct.
934  *  Retuan : FALSE
935  */
936 static gint
timeout_auto_expand_directory(gpointer data)937 timeout_auto_expand_directory (gpointer data)
938 {
939    DirView *dv = data;
940    GtkCTreeNode *node;
941 
942    g_return_val_if_fail (dv, FALSE);
943 
944    node = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree),
945                               dv->priv->drag_tree_row);
946    if (!node) {
947       dv->priv->auto_expand_timeout_id = 0;
948       return FALSE;
949    }
950 
951    if (!GTK_CTREE_ROW (node)->expanded) {
952       gtk_ctree_expand (GTK_CTREE (dv->dirtree), node);
953    }
954 
955    return FALSE;
956 }
957 
958 
959 
960 /******************************************************************************
961  *
962  *   Callback functions
963  *
964  ******************************************************************************/
965 static void
cb_dirtree_destroy(GtkWidget * widget,DirView * dv)966 cb_dirtree_destroy (GtkWidget *widget, DirView *dv)
967 {
968    g_return_if_fail (dv);
969 
970    dv->dirtree = NULL;
971 }
972 
973 
974 static void
cb_dirview_destroyed(GtkWidget * widget,DirView * dv)975 cb_dirview_destroyed (GtkWidget *widget, DirView *dv)
976 {
977    g_return_if_fail (dv);
978 
979    dirview_cancel_drag_scroll (dv);
980 
981    if (dv->priv->button_action_id)
982       gtk_idle_remove (dv->priv->button_action_id);
983    dv->priv->button_action_id = 0;
984 
985    if (dv->priv->swap_com_id)
986       gtk_idle_remove (dv->priv->swap_com_id);
987    dv->priv->swap_com_id = 0;
988 
989    if (dv->priv->change_root_id)
990       gtk_idle_remove (dv->priv->change_root_id);
991    dv->priv->change_root_id = 0;
992 
993    gtk_widget_destroy (dv->dirtree);
994 
995    g_free (dv->root_dir);
996    g_free (dv->priv);
997    g_free (dv);
998 }
999 
1000 
1001 static void
cb_node_destroy(gpointer data)1002 cb_node_destroy (gpointer data)
1003 {
1004    DirNode *node = data;
1005    g_free (node->path);
1006    g_free (node);
1007 }
1008 
1009 
1010 static void
cb_expand(GtkWidget * dirtree,GtkCTreeNode * parent,DirView * dv)1011 cb_expand (GtkWidget *dirtree, GtkCTreeNode *parent, DirView *dv)
1012 {
1013    GtkCTreeNode *node;
1014    DirNode *dirnode;
1015 
1016    g_return_if_fail (dv);
1017 
1018    if (!GTK_CTREE_ROW (parent)->children) return;
1019 
1020    dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dirtree), parent);
1021 
1022    if (!(dirnode->flags & DirNodeScannedFlag)) {
1023       gtk_clist_freeze (GTK_CLIST (dirtree));
1024 
1025       node = gtk_ctree_find_by_row_data (GTK_CTREE (dirtree), parent, NULL);
1026       gtk_ctree_remove_node (GTK_CTREE (dirtree), node);
1027 
1028       expand_dir (dv, parent);
1029 
1030       gtk_clist_thaw (GTK_CLIST (dirtree));
1031    }
1032 }
1033 
1034 
1035 static void
cb_collapse(GtkWidget * dirtree,GtkCTreeNode * parent,DirView * dv)1036 cb_collapse (GtkWidget *dirtree, GtkCTreeNode *parent, DirView *dv)
1037 {
1038    g_return_if_fail (dv && parent);
1039 }
1040 
1041 
1042 static gboolean
cb_button_press(GtkWidget * widget,GdkEventButton * event,DirView * dv)1043 cb_button_press (GtkWidget *widget, GdkEventButton *event, DirView *dv)
1044 {
1045    gint num;
1046 
1047    g_return_val_if_fail (dv, TRUE);
1048    g_return_val_if_fail (event, TRUE);
1049 
1050    num = prefs_mouse_get_num_from_event (event, conf.dirview_mouse_button);
1051    if (event->type == GDK_2BUTTON_PRESS) {
1052       dv->priv->button_2pressed_queue = num;
1053    } else if (num > 0) {
1054       return dirview_button_action (dv, event, num);
1055    }
1056 
1057    return FALSE;
1058 }
1059 
1060 
1061 static gboolean
cb_button_release(GtkWidget * widget,GdkEventButton * event,DirView * dv)1062 cb_button_release (GtkWidget *widget, GdkEventButton *event, DirView *dv)
1063 {
1064    gint num;
1065 
1066    g_return_val_if_fail (dv, FALSE);
1067    g_return_val_if_fail (event, FALSE);
1068 
1069    if (dv->priv->button_2pressed_queue) {
1070       num = dv->priv->button_2pressed_queue;
1071       if (num > 0)
1072          num = 0 - num;
1073       dv->priv->button_2pressed_queue = 0;
1074    } else {
1075       num = prefs_mouse_get_num_from_event (event, conf.dirview_mouse_button);
1076    }
1077    if (num < 0)
1078       return dirview_button_action (dv, event, num);
1079 
1080    return FALSE;
1081 }
1082 
1083 
1084 static gboolean
cb_key_press(GtkWidget * widget,GdkEventKey * event,DirView * dv)1085 cb_key_press (GtkWidget *widget, GdkEventKey *event, DirView *dv)
1086 {
1087    guint keyval, popup_key;
1088    GdkModifierType modval, popup_mod;
1089    GtkCTreeNode *node;
1090    GList *sel_list;
1091    DirNode *dirnode;
1092    gchar *node_text;
1093    gboolean expanded, is_leaf;
1094 
1095    g_return_val_if_fail (dv, FALSE);
1096 
1097    keyval = event->keyval;
1098    modval = event->state;
1099 
1100    sel_list = GTK_CLIST (dv->dirtree)->selection;
1101    if (!sel_list) return FALSE;
1102    node = sel_list->data;
1103    gtk_ctree_get_node_info (GTK_CTREE (widget), node, &node_text, NULL,
1104                             NULL, NULL, NULL, NULL, &is_leaf, &expanded);
1105 
1106    dirnode = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
1107    if (!dirnode) return FALSE;
1108 
1109    if (akey.common_popup_menu || *akey.common_popup_menu)
1110       gtk_accelerator_parse (akey.common_popup_menu, &popup_key, &popup_mod);
1111    else
1112       return FALSE;
1113 
1114    if (keyval == popup_key && (!popup_mod || (modval & popup_mod))) {
1115       dirview_popup_menu (dv, NULL, NULL);
1116    } else {
1117       switch (keyval) {
1118       case GDK_KP_Enter:
1119       case GDK_Return:
1120       case GDK_ISO_Enter:
1121          if (!strcmp (node_text, ".") || !strcmp (node_text, "..")) {
1122             dirview_change_root (dv, dirnode->path);
1123          } else {
1124             open_dir_images (dirnode->path, dv->tw, NULL,
1125                              LOAD_CACHE, conf.scan_dir_recursive);
1126          }
1127          break;
1128       case GDK_space:
1129          gtk_ctree_toggle_expansion (GTK_CTREE (widget), node);
1130          break;
1131       case GDK_Right:
1132          if (modval & GDK_CONTROL_MASK) {
1133             dirview_change_root (dv, dirnode->path);
1134          } else {
1135             gtk_ctree_expand (GTK_CTREE (widget), node);
1136          }
1137          return TRUE;
1138          break;
1139       case GDK_Left:
1140          if (modval & GDK_CONTROL_MASK) {
1141             dirview_change_root_to_parent (dv);
1142          } else {
1143             gtk_ctree_collapse (GTK_CTREE (widget), node);
1144          }
1145          return TRUE;
1146          break;
1147       case GDK_Up:
1148          if (modval & GDK_CONTROL_MASK)
1149             dirview_change_root_to_parent (dv);
1150          return TRUE;
1151          break;
1152       case GDK_Down:
1153          if (modval & GDK_CONTROL_MASK)
1154             dirview_change_root (dv, dirnode->path);
1155          return TRUE;
1156       }
1157    }
1158 
1159    return FALSE;
1160 }
1161 
1162 
1163 
1164 /******************************************************************************
1165  *
1166  *   Callback functions for popup menu
1167  *
1168  ******************************************************************************/
1169 static void
cb_open_thumbnail(DirView * dv,ScanSubDirType scan_subdir,GtkWidget * menuitem)1170 cb_open_thumbnail (DirView *dv, ScanSubDirType scan_subdir, GtkWidget *menuitem)
1171 {
1172    gchar *path;
1173 
1174    path = dirview_get_selected_path (dv);
1175    if (!path) return;
1176 
1177    open_dir_images (path, dv->tw, NULL, LOAD_CACHE, scan_subdir);
1178 
1179    g_free (path);
1180 }
1181 
1182 
1183 static void
cb_go_to_here(DirView * dv,guint action,GtkWidget * menuitem)1184 cb_go_to_here (DirView *dv, guint action, GtkWidget *menuitem)
1185 {
1186    gchar *path;
1187 
1188    path = dirview_get_selected_path (dv);
1189    if (!path) return;
1190 
1191    dirview_change_root (dv, path);
1192 
1193    g_free (path);
1194 }
1195 
1196 
1197 static void
cb_refresh_dir_tree(DirView * dv,guint action,GtkWidget * menuitem)1198 cb_refresh_dir_tree (DirView *dv, guint action, GtkWidget *menuitem)
1199 {
1200    refresh_dir_tree (dv, NULL);
1201 }
1202 
1203 static void
cb_file_property(DirView * dv,guint action,GtkWidget * menuitem)1204 cb_file_property (DirView *dv, guint action, GtkWidget *menuitem)
1205 {
1206    GimvImageInfo *info;
1207    gchar *path, *tmpstr;
1208 
1209    g_return_if_fail (dv);
1210 
1211    tmpstr = dirview_get_selected_path (dv);
1212    if (!tmpstr) return;
1213 
1214    path = remove_slash (tmpstr);
1215    g_free(tmpstr);
1216 
1217    info = gimv_image_info_get (path);
1218    if (!info) {
1219       g_free (path);
1220       return;
1221    }
1222 
1223    dlg_prop_from_image_info (info, 0);
1224 
1225    gimv_image_info_unref (info);
1226    g_free (path);
1227 }
1228 
1229 
1230 static void
cb_mkdir(DirView * dv,guint action,GtkWidget * menuitem)1231 cb_mkdir (DirView *dv, guint action, GtkWidget *menuitem)
1232 {
1233    GtkCTreeNode *node;
1234    DirNode *dirnode;
1235    gboolean success;
1236 
1237    g_return_if_fail (dv);
1238    node = GTK_CLIST (dv->dirtree)->selection->data;
1239    if (!node) return;
1240 
1241    dirnode = gtk_ctree_node_get_row_data (GTK_CTREE(dv->dirtree), node);
1242    if (!dirnode) return;
1243 
1244    success = make_dir_dialog
1245       (dirnode->path, GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
1246 
1247    if (success) {
1248       refresh_dir_tree (dv, node);
1249    }
1250 }
1251 
1252 
1253 static void
cb_rename_dir(DirView * dv,guint action,GtkWidget * menuitem)1254 cb_rename_dir (DirView *dv, guint action, GtkWidget *menuitem)
1255 {
1256    GtkCTreeNode *node, *parent;
1257    DirNode *dirnode;
1258    gboolean success;
1259 
1260    g_return_if_fail (dv);
1261    node = GTK_CLIST (dv->dirtree)->selection->data;
1262    if (!node) return;
1263 
1264    dirnode = gtk_ctree_node_get_row_data (GTK_CTREE(dv->dirtree), node);
1265    if (!dirnode) return;
1266 
1267    success = rename_dir_dialog
1268       (dirnode->path, GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
1269 
1270    if (success) {
1271       parent = (GTK_CTREE_ROW (node))->parent;
1272       if (parent)
1273          refresh_dir_tree (dv, parent);
1274    }
1275 }
1276 
1277 
1278 static void
cb_delete_dir(DirView * dv,guint action,GtkWidget * menuitem)1279 cb_delete_dir (DirView *dv, guint action, GtkWidget *menuitem)
1280 {
1281    GtkCTreeNode *node, *parent;
1282    DirNode *dirnode;
1283    gchar *path;
1284 
1285    g_return_if_fail (dv);
1286    node = GTK_CLIST (dv->dirtree)->selection->data;
1287    if (!node) return;
1288 
1289    dirnode = gtk_ctree_node_get_row_data (GTK_CTREE(dv->dirtree), node);
1290    if (!dirnode) return;
1291 
1292    path = remove_slash (dirnode->path);
1293 
1294    delete_dir (path, GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
1295    g_free (path);
1296 
1297    /* refresh dir tree */
1298    parent = (GTK_CTREE_ROW (node))->parent;
1299    if (parent)
1300       refresh_dir_tree (dv, parent);
1301 }
1302 
1303 
1304 
1305 /******************************************************************************
1306  *
1307  *   Callback functions for toolbar buttons.
1308  *
1309  ******************************************************************************/
1310 static void
cb_home_button(GtkWidget * widget,DirView * dv)1311 cb_home_button (GtkWidget *widget, DirView *dv)
1312 {
1313    g_return_if_fail (dv);
1314 
1315    dirview_go_home (dv);
1316 }
1317 
1318 
1319 static void
cb_up_button(GtkWidget * widget,DirView * dv)1320 cb_up_button (GtkWidget *widget, DirView *dv)
1321 {
1322    dirview_change_root_to_parent (dv);
1323 }
1324 
1325 
1326 static void
cb_refresh_button(GtkWidget * widget,DirView * dv)1327 cb_refresh_button (GtkWidget *widget, DirView *dv)
1328 {
1329    GtkCTreeNode *parent;
1330 
1331    g_return_if_fail (dv);
1332 
1333    parent = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), 0);
1334    if (parent)
1335       refresh_dir_tree (dv, parent);
1336 }
1337 
1338 
1339 static void
cb_dotfile_button(GtkWidget * widget,DirView * dv)1340 cb_dotfile_button (GtkWidget *widget, DirView *dv)
1341 {
1342    GtkCTreeNode *parent;
1343 
1344    g_return_if_fail (widget && dv);
1345 
1346    dv->show_dotfile = !dv->show_dotfile;
1347 
1348    parent = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), 0);
1349    refresh_dir_tree (dv, parent);
1350 }
1351 
1352 
1353 
1354 /******************************************************************************
1355  *
1356  *   Callback functions for DnD
1357  *
1358  ******************************************************************************/
1359 static void
cb_drag_motion(GtkWidget * dirtree,GdkDragContext * context,gint x,gint y,gint time,gpointer data)1360 cb_drag_motion (GtkWidget *dirtree, GdkDragContext *context,
1361                 gint x, gint y, gint time, gpointer data)
1362 {
1363    DirView *dv = data;
1364    GtkCTreeNode *node;
1365    DirNode *node_data;
1366    gint row, on_row;
1367 
1368    g_return_if_fail (dv);
1369 
1370    /* Set up auto-scrolling */
1371    if (conf.dirview_auto_scroll)
1372       dirview_setup_drag_scroll (dv, x, y,
1373                                  dirview_scrolling_is_desirable,
1374                                  timeout_dirview_scroll);
1375 
1376    if (!GTK_CLIST (dirtree)->selection) return;
1377 
1378    on_row = gtk_clist_get_selection_info (GTK_CLIST (dirtree), x, y, &row, NULL);
1379 
1380    /* Remove the auto-expansion timeout if we are on the blank area of the
1381     * tree or on a row different from the previous one.
1382     */
1383    if ((!on_row || row != dv->priv->drag_tree_row)
1384        && dv->priv->auto_expand_timeout_id != 0)
1385    {
1386       gtk_timeout_remove (dv->priv->auto_expand_timeout_id);
1387       dv->priv->auto_expand_timeout_id = 0;
1388    }
1389 
1390    if (on_row) {
1391       node = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), row);
1392       node_data = gtk_ctree_node_get_row_data (GTK_CTREE (dirtree),
1393                                                gtk_ctree_node_nth (GTK_CTREE (dirtree),
1394                                                                    row));
1395 
1396       /* hilight row under cursor */
1397       if (node_data && dv->priv->hilit_dir != row) {
1398          if (dv->priv->hilit_dir != -1) {
1399             /*
1400               gtk_clist_set_foreground (GTK_CLIST (dirtree), dv->hilit_dir,
1401               &(dirtree->style->fg[GTK_STATE_NORMAL]));
1402             */
1403             gtk_clist_set_background (GTK_CLIST (dirtree), dv->priv->hilit_dir,
1404                                       &(dirtree->style->base[GTK_STATE_NORMAL]));
1405          }
1406 
1407          dv->priv->hilit_dir = row;
1408 
1409          /*
1410            gtk_clist_set_foreground (GTK_CLIST (dirtree), dv->hilit_dir,
1411            &(dirtree->style->fg[GTK_STATE_PRELIGHT]));
1412          */
1413          gtk_clist_set_background (GTK_CLIST (dirtree), dv->priv->hilit_dir,
1414                                    &(dirtree->style->bg[GTK_STATE_PRELIGHT]));
1415       }
1416 
1417       /* Install the timeout handler for auto-expansion */
1418       if (conf.dirview_auto_expand && row != dv->priv->drag_tree_row) {
1419          dv->priv->auto_expand_timeout_id
1420             = gtk_timeout_add (conf.dirview_auto_expand_time,
1421                                timeout_auto_expand_directory,
1422                                dv);
1423          dv->priv->drag_tree_row = row;
1424       }
1425    }
1426 }
1427 
1428 
1429 static void
cb_drag_leave(GtkWidget * dirtree,GdkDragContext * context,guint time,gpointer data)1430 cb_drag_leave (GtkWidget *dirtree, GdkDragContext *context, guint time,
1431                gpointer data)
1432 {
1433    DirView *dv = data;
1434 
1435    dirview_cancel_drag_scroll (dv);
1436 
1437    /*
1438      gtk_clist_set_foreground (GTK_CLIST (dirtree), dv->hilit_dir,
1439      &(dirtree->style->fg[GTK_STATE_NORMAL]));
1440    */
1441    gtk_clist_set_background (GTK_CLIST (dirtree), dv->priv->hilit_dir,
1442                              &(dirtree->style->base[GTK_STATE_NORMAL]));
1443    dv->priv->hilit_dir = -1;
1444 
1445    /* remove auto expand handler */
1446    if (dv->priv->auto_expand_timeout_id != 0) {
1447       gtk_timeout_remove (dv->priv->auto_expand_timeout_id);
1448       dv->priv->auto_expand_timeout_id = 0;
1449    }
1450 
1451    dv->priv->drag_tree_row = -1;
1452 }
1453 
1454 
1455 static void
cb_drag_data_get(GtkWidget * dirtree,GdkDragContext * context,GtkSelectionData * seldata,guint info,guint time,gpointer data)1456 cb_drag_data_get (GtkWidget *dirtree,
1457                   GdkDragContext *context,
1458                   GtkSelectionData *seldata,
1459                   guint info,
1460                   guint time,
1461                   gpointer data)
1462 {
1463    DirView *dv = data;
1464    GtkCTreeNode *node;
1465    DirNode *dirnode;
1466    gchar *uri, *tmpstr;
1467 
1468    g_return_if_fail (dv && dirtree);
1469 
1470    dirview_cancel_drag_scroll (dv);
1471 
1472    node = GTK_CLIST (dirtree)->selection->data;
1473    if (!node) return;
1474 
1475    dirnode = gtk_ctree_node_get_row_data(GTK_CTREE(dirtree), node);
1476    g_return_if_fail (dirnode);
1477 
1478    tmpstr = remove_slash (dirnode->path);
1479 
1480    uri = g_strconcat ("file://", tmpstr, "\r\n", NULL);
1481 
1482    gtk_selection_data_set(seldata, seldata->target,
1483                           8, uri, strlen(uri));
1484    g_free (tmpstr);
1485    g_free (uri);
1486 }
1487 
1488 
1489 static void
cb_drag_data_received(GtkWidget * dirtree,GdkDragContext * context,gint x,gint y,GtkSelectionData * seldata,guint info,guint32 time,gpointer data)1490 cb_drag_data_received (GtkWidget *dirtree,
1491                        GdkDragContext *context,
1492                        gint x, gint y,
1493                        GtkSelectionData *seldata,
1494                        guint info,
1495                        guint32 time,
1496                        gpointer data)
1497 {
1498    gint row;
1499    DirNode *node;
1500    DirView *dv = data;
1501    GtkCTreeNode *parent;
1502 
1503    g_return_if_fail (dv);
1504 
1505    dirview_cancel_drag_scroll (dv);
1506 
1507    if (!GTK_CLIST (dirtree)->selection) return;
1508 
1509    gtk_clist_get_selection_info (GTK_CLIST (dirtree), x, y, &row, NULL);
1510    parent = gtk_ctree_node_nth (GTK_CTREE (dirtree), row);
1511    node = gtk_ctree_node_get_row_data (GTK_CTREE (dirtree), parent);
1512 
1513    if (node) {
1514       if (iswritable (node->path)) {
1515          dnd_file_operation (node->path, context, seldata, time, dv->tw);
1516          parent = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), 0);
1517          refresh_dir_tree (dv, parent);
1518       } else {
1519          gchar error_message[BUF_SIZE], *dir_internal;
1520 
1521          dir_internal = charset_to_internal (node->path,
1522                                              conf.charset_filename,
1523                                              conf.charset_auto_detect_fn,
1524                                              conf.charset_filename_mode);
1525          g_snprintf (error_message, BUF_SIZE,
1526                      _("Permission denied: %s"),
1527                      dir_internal);
1528          gtkutil_message_dialog
1529             (_("Error!!"), error_message,
1530              GTK_WINDOW(gtk_widget_get_toplevel(dv->container)));
1531 
1532          g_free (dir_internal);
1533       }
1534    }
1535 }
1536 
1537 
1538 static void
cb_drag_end(GtkWidget * dirtree,GdkDragContext * context,gpointer data)1539 cb_drag_end (GtkWidget *dirtree, GdkDragContext *context, gpointer data)
1540 {
1541    DirView *dv = data;
1542    GtkCTreeNode *parent;
1543 
1544    g_return_if_fail (dirtree && dv);
1545 
1546    dirview_cancel_drag_scroll (dv);
1547 
1548    parent = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), 0);
1549 
1550    /* refresh_dir_tree (dv, parent); */
1551 }
1552 
1553 
1554 static void
cb_toolbar_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)1555 cb_toolbar_drag_begin (GtkWidget *widget,
1556                        GdkDragContext *context,
1557                        gpointer data)
1558 {
1559    GdkColormap *colormap;
1560    GimvIcon *icon;
1561 
1562    icon = gimv_icon_stock_get_icon ("paper");
1563    colormap = gdk_colormap_get_system ();
1564    gtk_drag_set_icon_pixmap (context, colormap,
1565                              icon->pixmap, icon->mask,
1566                              0, 0);
1567 }
1568 
1569 
1570 static void
cb_toolbar_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * seldata,guint info,guint time,gpointer data)1571 cb_toolbar_drag_data_get (GtkWidget *widget,
1572                           GdkDragContext *context,
1573                           GtkSelectionData *seldata,
1574                           guint info,
1575                           guint time,
1576                           gpointer data)
1577 {
1578    switch (info) {
1579    case TARGET_GIMV_COMPONENT:
1580       gtk_selection_data_set(seldata, seldata->target,
1581                              8, "dummy", strlen("dummy"));
1582       break;
1583    }
1584 }
1585 
1586 
1587 typedef struct SwapCom_Tag
1588 {
1589    GimvThumbWin *tw;
1590    gint src;
1591    gint dest;
1592 } SwapCom;
1593 
1594 
1595 static gint
idle_thumbwin_swap_component(gpointer data)1596 idle_thumbwin_swap_component (gpointer data)
1597 {
1598    SwapCom *swap = data;
1599    gimv_thumb_win_swap_component (swap->tw, swap->src, swap->dest);
1600    return FALSE;
1601 }
1602 
1603 
1604 static void
cb_com_swap_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * seldata,guint info,guint time,gpointer data)1605 cb_com_swap_drag_data_received (GtkWidget *widget,
1606                                 GdkDragContext *context,
1607                                 gint x, gint y,
1608                                 GtkSelectionData *seldata,
1609                                 guint info,
1610                                 guint time,
1611                                 gpointer data)
1612 {
1613    GimvThumbWin *tw = data;
1614    GtkWidget *src_widget;
1615    gpointer p;
1616    gint src, dest;
1617 
1618    switch (info) {
1619    case TARGET_GIMV_COMPONENT:
1620       src_widget = gtk_drag_get_source_widget (context);
1621       if (gdk_window_get_toplevel (src_widget->window)
1622           != gdk_window_get_toplevel (widget->window))
1623       {
1624          return;
1625       }
1626 
1627       p = gtk_object_get_data (GTK_OBJECT (src_widget), "gimv-component");
1628       src = GPOINTER_TO_INT (p);
1629       if (!src) return;
1630 
1631       p = gtk_object_get_data (GTK_OBJECT (widget), "gimv-component");
1632       dest = GPOINTER_TO_INT (p);
1633       if (!dest) return;
1634 
1635       {
1636          SwapCom *swap = g_new0 (SwapCom, 1);
1637          swap->tw = tw;
1638          swap->src = src;
1639          swap->dest = dest;
1640          /* to avoid gtk's bug, exec redraw after exit this callback function */
1641          gtk_idle_add_full (GTK_PRIORITY_REDRAW,
1642                             idle_thumbwin_swap_component, NULL, swap,
1643                             (GtkDestroyNotify) g_free);
1644       }
1645 
1646       break;
1647 
1648    default:
1649       break;
1650    }
1651 }
1652 
1653 
1654 
1655 /******************************************************************************
1656  *
1657  *   Public  functions
1658  *
1659  ******************************************************************************/
1660 /*
1661  *  dirview_change_root:
1662  *     @ Change top directory.
1663  *
1664  *   dirtree   : GtkCtree widget.
1665  *   root_drir : path to change.
1666 
1667 */
1668 void
dirview_change_root(DirView * dv,const gchar * root_dir)1669 dirview_change_root (DirView *dv, const gchar *root_dir)
1670 {
1671    gchar *dest_dir;
1672    GtkCTreeNode *root_node;
1673 
1674    g_return_if_fail (dv && root_dir);
1675 
1676    dest_dir = add_slash (root_dir);
1677 
1678    if (!isdir (dest_dir)) {
1679       g_free (dest_dir);
1680       return;
1681    }
1682 
1683    g_free (dv->root_dir);
1684    dv->root_dir = dest_dir;
1685 
1686    gtk_clist_clear (GTK_CLIST (dv->dirtree));
1687 
1688    root_node = dirview_insert_node (dv, NULL, dv->root_dir);
1689    if (!root_node) return;
1690 
1691    /* set opened mark */
1692    if (gimv_thumb_view_find_opened_dir (dv->root_dir)) {
1693       dirview_set_opened_mark (dv, dv->root_dir);
1694    }
1695 
1696    gtk_ctree_expand (GTK_CTREE (dv->dirtree), root_node);
1697 
1698    adjust_ctree (dv->dirtree, root_node);
1699 }
1700 
1701 
1702 void
dirview_change_root_to_parent(DirView * dv)1703 dirview_change_root_to_parent (DirView *dv)
1704 {
1705    gchar *end;
1706    gchar *root;
1707 
1708    g_return_if_fail (dv);
1709 
1710    root = g_strdup (dv->root_dir);
1711    end = strrchr (root, '/');
1712    if (end && end != root) *end = '\0';
1713    end = strrchr (root, '/');
1714    if (end) *(end + 1) = '\0';
1715 
1716    dirview_change_dir (dv, root);
1717 
1718    g_free (root);
1719 }
1720 
1721 
1722 /*
1723  *  dirview_change_dir:
1724  *     @ Change selection to specified directory.
1725  *
1726  *   dirtree : GtkCtree widget:
1727  *   str     : path to change.
1728  */
1729 void
dirview_change_dir(DirView * dv,const gchar * str)1730 dirview_change_dir (DirView *dv, const gchar *str)
1731 {
1732    GtkWidget *dirtree;
1733    GtkCTreeNode *node;
1734    gchar *path, *row, *ptr;
1735    gboolean is_leaf, expanded;
1736    size_t length;
1737 
1738    g_return_if_fail (dv);
1739 
1740    dirtree = dv->dirtree;
1741 
1742    path = add_slash (str);
1743 
1744    if (!isdir (path)) {
1745       g_free (path);
1746       return;
1747    }
1748 
1749    ptr = path;
1750 
1751    /* FIXME */
1752    /* if selected path in directory view is same as str, adjust to it */
1753    /* END FIXME */
1754 
1755    /* get root node */
1756    node = gtk_ctree_node_nth (GTK_CTREE (dirtree), 0);
1757    gtk_ctree_get_node_info (GTK_CTREE (dirtree), node, &row, NULL,
1758                             NULL, NULL, NULL, NULL, &is_leaf, &expanded);
1759 
1760    /* if root node is specified directory, adjust to root */
1761    if (!(strcmp (ptr, row))) {
1762       g_free (path);
1763       adjust_ctree (dirtree, node);
1764       return;
1765    }
1766 
1767    if (!is_leaf && !expanded)
1768       gtk_ctree_expand (GTK_CTREE (dirtree), node);
1769 
1770    /* get first child */
1771    node = GTK_CTREE_ROW(node)->children;
1772    if (!node) {
1773       g_free (path);
1774       dirview_change_root (dv, str);
1775       return;
1776    }
1777 
1778    /*
1779     *  if specified directory string is shorter than root node's one,
1780     *  change top direcotry.
1781     */
1782    length = strlen (dv->root_dir);
1783    if (strlen (ptr) >= length) {
1784       ptr = ptr + length;
1785    } else {
1786       g_free (path);
1787       dirview_change_root (dv, str);
1788       return;
1789    }
1790 
1791    /* search children */
1792    gtk_clist_freeze (GTK_CLIST (dirtree));
1793    while (TRUE) {
1794       gtk_ctree_get_node_info (GTK_CTREE (dirtree), node, &row, NULL,
1795                                NULL, NULL, NULL, NULL, &is_leaf, &expanded);
1796       if (!strncmp (row, ptr, strlen (row)) && *(ptr+strlen (row)) == '/' ) {
1797          ptr = ptr + strlen (row) + 1;
1798          while (*ptr == '/')
1799             ptr++;
1800          if (!is_leaf && GTK_CTREE_ROW (node)->children && !expanded) {
1801             gtk_ctree_expand(GTK_CTREE (dirtree), node);
1802          }
1803          if (!(ptr && *ptr))
1804             break;
1805          if (!(node = GTK_CTREE_ROW (node)->children))
1806             break;
1807       } else if (!(node = GTK_CTREE_ROW (node)->sibling)) {
1808          break;
1809       }
1810    }
1811    gtk_clist_thaw (GTK_CLIST (dirtree));
1812 
1813    g_free (path);
1814 
1815    if (node) {
1816       adjust_ctree (dirtree, node);
1817    } else {
1818       dirview_change_root (dv, str);
1819    }
1820 }
1821 
1822 
1823 /*
1824  *  dirview_go_home:
1825  *     @ Change top directory to home directory.
1826  *
1827  *  dv : Pointer to the DirView struct.
1828  */
1829 void
dirview_go_home(DirView * dv)1830 dirview_go_home (DirView *dv)
1831 {
1832    const gchar *home = g_getenv ("HOME");
1833 
1834    dirview_change_root (dv, home);
1835    dirview_change_dir (dv, home);
1836 }
1837 
1838 
1839 void
dirview_refresh_list(DirView * dv)1840 dirview_refresh_list (DirView *dv)
1841 {
1842    GtkCTreeNode *parent;
1843 
1844    g_return_if_fail (dv);
1845 
1846    parent = gtk_ctree_node_nth (GTK_CTREE (dv->dirtree), 0);
1847    if (parent)
1848       refresh_dir_tree (dv, parent);
1849 }
1850 
1851 
1852 gchar *
dirview_get_selected_path(DirView * dv)1853 dirview_get_selected_path (DirView *dv)
1854 {
1855    DirNode *dirnode;
1856    GtkCTreeNode *node;
1857 
1858    g_return_val_if_fail (dv, NULL);
1859    g_return_val_if_fail (dv->dirtree, NULL);
1860    if (!GTK_CLIST(dv->dirtree)->selection) return NULL;
1861 
1862    node =  GTK_CLIST (dv->dirtree)->selection->data;
1863    if (!node) return NULL;
1864 
1865    dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dv->dirtree), node);
1866    if (!dirnode) return NULL;
1867 
1868    return g_strdup (dirnode->path);
1869 }
1870 
1871 
1872 void
dirview_expand_dir(DirView * dv,const gchar * dir,gboolean open_all)1873 dirview_expand_dir (DirView *dv, const gchar *dir, gboolean open_all)
1874 {
1875    GtkCTreeNode *node;
1876 
1877    g_return_if_fail (dv);
1878    g_return_if_fail (dir && *dir);
1879 
1880    node = dirview_find_directory (dv, dir);
1881    if (!node) return;
1882 
1883    if (open_all)
1884       gtk_ctree_expand_recursive (GTK_CTREE (dv->dirtree), node);
1885    else
1886       gtk_ctree_expand (GTK_CTREE (dv->dirtree), node);
1887 }
1888 
1889 
1890 gboolean
dirview_set_opened_mark(DirView * dv,const gchar * path)1891 dirview_set_opened_mark (DirView *dv, const gchar *path)
1892 {
1893    GtkCTreeNode *node;
1894    DirNode *dirnode;
1895 
1896    g_return_val_if_fail (dv, FALSE);
1897    g_return_val_if_fail (path && path, FALSE);
1898 
1899    node = dirview_find_directory (dv, path);
1900 
1901    if (!node) return FALSE;
1902 
1903    dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dv->dirtree), node);
1904    dirnode->flags |= DirNodeOpenedFlag;
1905 
1906    gtk_ctree_node_set_foreground (GTK_CTREE (dv->dirtree), node,
1907                                   &dv->dirtree->style->fg[GTK_STATE_ACTIVE]);
1908 
1909    return TRUE;
1910 }
1911 
1912 
1913 gboolean
dirview_unset_opened_mark(DirView * dv,const gchar * path)1914 dirview_unset_opened_mark (DirView *dv, const gchar *path)
1915 {
1916    GtkCTreeNode *node;
1917    DirNode *dirnode;
1918 
1919    g_return_val_if_fail (dv, FALSE);
1920    g_return_val_if_fail (path && path, FALSE);
1921 
1922    node = dirview_find_directory (dv, path);
1923 
1924    if (!node) return FALSE;
1925 
1926    dirnode = gtk_ctree_node_get_row_data (GTK_CTREE (dv->dirtree), node);
1927    dirnode->flags &= ~DirNodeOpenedFlag;
1928 
1929    gtk_ctree_node_set_foreground (GTK_CTREE (dv->dirtree), node,
1930                                   &dv->dirtree->style->fg[GTK_STATE_NORMAL]);
1931 
1932    return TRUE;
1933 }
1934 
1935 
1936 /*
1937  *  dirview_show_toolbar:
1938  *     @
1939  *
1940  *  dv : Pointer to the DirView struct.
1941  */
1942 void
dirview_show_toolbar(DirView * dv)1943 dirview_show_toolbar (DirView *dv)
1944 {
1945    g_return_if_fail (dv);
1946 
1947    dv->show_toolbar = TRUE;
1948    gtk_widget_show (dv->toolbar_eventbox);
1949 }
1950 
1951 
1952 /*
1953  *  dirview_hide_toolbar:
1954  *     @
1955  *
1956  *  dv : Pointer to the DirView struct.
1957  */
1958 void
dirview_hide_toolbar(DirView * dv)1959 dirview_hide_toolbar (DirView *dv)
1960 {
1961    g_return_if_fail (dv);
1962 
1963    dv->show_toolbar = FALSE;
1964    gtk_widget_hide (dv->toolbar_eventbox);
1965 }
1966 
1967 
1968 /*
1969  *  dirview_create_toolbar:
1970  *     @
1971  *
1972  *  dv : Pointer to the DirView struct.
1973  */
1974 static GtkWidget *
dirview_create_toolbar(DirView * dv)1975 dirview_create_toolbar (DirView *dv)
1976 {
1977    GtkWidget *toolbar;
1978    GtkWidget *button;
1979    GtkWidget *iconw;
1980 
1981    g_return_val_if_fail (dv, NULL);
1982 
1983    toolbar = gtkutil_create_toolbar ();
1984 
1985    /* file open button */
1986    iconw = gimv_icon_stock_get_widget ("small_home");
1987    button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
1988                                      _("Home"),
1989                                      _("Home"),
1990                                      _("Home"),
1991                                      iconw,
1992                                      GTK_SIGNAL_FUNC (cb_home_button),
1993                                      dv);
1994 
1995    /* preference button */
1996    iconw = gimv_icon_stock_get_widget ("small_up");
1997    button = gtk_toolbar_append_item (GTK_TOOLBAR (toolbar),
1998                                      _("Up"),
1999                                      _("Up"),
2000                                      _("Up"),
2001                                      iconw,
2002                                      GTK_SIGNAL_FUNC (cb_up_button),
2003                                      dv);
2004 
2005    /* refresh button */
2006    iconw = gimv_icon_stock_get_widget ("small_refresh");
2007    button = gtk_toolbar_append_item(GTK_TOOLBAR (toolbar),
2008                                     _("Refresh"),
2009                                     _("Refresh"),
2010                                     _("Refresh"),
2011                                     iconw,
2012                                     GTK_SIGNAL_FUNC (cb_refresh_button),
2013                                     dv);
2014 
2015    /* preference button */
2016    iconw = gimv_icon_stock_get_widget ("dotfile");
2017    button = gtk_toolbar_append_item(GTK_TOOLBAR (toolbar),
2018                                     _("Dotfile"),
2019                                     _("Show/Hide dotfile"),
2020                                     _("Show/Hide dotfile"),
2021                                     iconw,
2022                                     GTK_SIGNAL_FUNC (cb_dotfile_button),
2023                                     dv);
2024 
2025    gtk_widget_show_all (toolbar);
2026    gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
2027 
2028    return toolbar;
2029 }
2030 
2031 
2032 static gint
idle_change_root(gpointer data)2033 idle_change_root (gpointer data)
2034 {
2035    DirView *dv = data;
2036 
2037    g_return_val_if_fail (dv, FALSE);
2038 
2039    dv->priv->change_root_id = 0;
2040 
2041    dirview_change_root (dv, dv->root_dir);
2042    dirview_change_dir (dv, dv->root_dir);
2043    /*
2044    if (dv)
2045    dirview_go_home (dv);
2046    */
2047 
2048    return FALSE;
2049 }
2050 
2051 
2052 /******************************************************************************
2053  *
2054  *   dirview_create:
2055  *      @ create directory view widget.
2056  *
2057  *   tw     :
2058  *   Return : directory view packed container widget.
2059  *
2060  ******************************************************************************/
2061 DirView *
dirview_create(const gchar * root_dir,GtkWidget * parent_win,GimvThumbWin * tw)2062 dirview_create (const gchar *root_dir, GtkWidget *parent_win, GimvThumbWin *tw)
2063 {
2064    DirView *dv;
2065    GtkWidget *eventbox;
2066    const gchar *home = g_getenv ("HOME");
2067 
2068    dv       = g_new0 (DirView, 1);
2069    dv->priv = g_new0 (DirViewPrivate, 1);
2070 
2071    if (root_dir)
2072       dv->root_dir = g_strdup (root_dir);
2073    else
2074       dv->root_dir = g_strdup (home);
2075 
2076    dv->popup_menu        = NULL;
2077    dv->tw                = tw;
2078    dv->show_toolbar      = conf.dirview_show_toolbar;
2079    dv->show_dotfile      = conf.dirview_show_dotfile;
2080    dv->priv->hilit_dir        = -1;
2081    dv->priv->scroll_timer_id  = 0;
2082    dv->priv->button_action_id = 0;
2083    dv->priv->swap_com_id      = 0;
2084    dv->priv->change_root_id   = 0;
2085 
2086    /* main vbox */
2087    dv->container = gtk_vbox_new (FALSE, 0);
2088    gtk_widget_set_name (dv->container, "DirView");
2089    gtk_widget_show (dv->container);
2090 
2091    dnd_dest_set (dv->container, dnd_types_component, dnd_types_component_num);
2092    gtk_object_set_data (GTK_OBJECT (dv->container),
2093                         "gimv-component",
2094                         GINT_TO_POINTER (GIMV_COM_DIR_VIEW));
2095    gtk_signal_connect (GTK_OBJECT (dv->container), "drag_data_received",
2096                        GTK_SIGNAL_FUNC (cb_com_swap_drag_data_received), dv->tw);
2097 
2098    /* toolbar */
2099    eventbox = dv->toolbar_eventbox = gtk_event_box_new ();
2100    gtk_container_set_border_width (GTK_CONTAINER (eventbox), 1);
2101    gtk_box_pack_start (GTK_BOX (dv->container), eventbox, FALSE, FALSE, 0);
2102    gtk_widget_show (eventbox);
2103 
2104    dv->toolbar = dirview_create_toolbar (dv);
2105    gtk_container_add (GTK_CONTAINER (eventbox), dv->toolbar);
2106 
2107    if (!dv->show_toolbar)
2108       gtk_widget_hide (dv->toolbar_eventbox);
2109 
2110    dnd_src_set  (eventbox, dnd_types_component, dnd_types_component_num);
2111    gtk_object_set_data (GTK_OBJECT (eventbox),
2112                         "gimv-component",
2113                         GINT_TO_POINTER (GIMV_COM_DIR_VIEW));
2114    gtk_signal_connect (GTK_OBJECT (eventbox), "drag_begin",
2115                        GTK_SIGNAL_FUNC (cb_toolbar_drag_begin), tw);
2116    gtk_signal_connect (GTK_OBJECT (eventbox), "drag_data_get",
2117                        GTK_SIGNAL_FUNC (cb_toolbar_drag_data_get), tw);
2118 
2119    /* scrolled window */
2120    dv->scroll_win = gtk_scrolled_window_new (NULL, NULL);
2121    gtk_container_set_border_width (GTK_CONTAINER (dv->scroll_win), 1);
2122    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dv->scroll_win),
2123                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2124    gtk_box_pack_start(GTK_BOX(dv->container), dv->scroll_win, TRUE, TRUE, 0);
2125    gtk_signal_connect (GTK_OBJECT (dv->scroll_win), "destroy",
2126                        GTK_SIGNAL_FUNC (cb_dirview_destroyed), dv);
2127    gtk_widget_show (dv->scroll_win);
2128 
2129    /* ctree */
2130    dirview_create_ctree (dv);
2131 
2132    dv->priv->change_root_id = gtk_idle_add (idle_change_root, dv);
2133    /* dirview_go_home (dirtree); */
2134 
2135    return dv;
2136 }
2137 
2138 #endif /* ENABLE_TREEVIEW */
2139