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