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