Merge few more vdlist/vdtree functions.
[geeqie.git] / src / view_dir_list.c
1 /*
2  * Geeqie
3  * (C) 2004 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12 #include "main.h"
13 #include "view_dir_list.h"
14
15 #include "dnd.h"
16 #include "dupe.h"
17 #include "filelist.h"
18 #include "layout.h"
19 #include "layout_image.h"
20 #include "layout_util.h"
21 #include "utilops.h"
22 #include "ui_bookmark.h"
23 #include "ui_fileops.h"
24 #include "ui_menu.h"
25 #include "ui_tree_edit.h"
26 #include "view_dir.h"
27
28 #include <gdk/gdkkeysyms.h> /* for keyboard values */
29
30
31 #define VDLIST_PAD 4
32
33 #define VDLIST_INFO(_vd_, _part_) (((ViewDirInfoList *)(_vd_->info))->_part_)
34
35
36 static gint vdlist_auto_scroll_notify_cb(GtkWidget *widget, gint x, gint y, gpointer data);
37
38 /*
39  *-----------------------------------------------------------------------------
40  * misc
41  *-----------------------------------------------------------------------------
42  */
43
44 gint vdlist_find_row(ViewDir *vd, FileData *fd, GtkTreeIter *iter)
45 {
46         GtkTreeModel *store;
47         gint valid;
48         gint row = 0;
49
50         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view));
51         valid = gtk_tree_model_get_iter_first(store, iter);
52         while (valid)
53                 {
54                 FileData *fd_n;
55                 gtk_tree_model_get(GTK_TREE_MODEL(store), iter, DIR_COLUMN_POINTER, &fd_n, -1);
56                 if (fd_n == fd) return row;
57
58                 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter);
59                 row++;
60                 }
61
62         return -1;
63 }
64
65
66 FileData *vdlist_row_by_path(ViewDir *vd, const gchar *path, gint *row)
67 {
68         GList *work;
69         gint n;
70
71         if (!path)
72                 {
73                 if (row) *row = -1;
74                 return NULL;
75                 }
76
77         n = 0;
78         work = VDLIST_INFO(vd, list);
79         while (work)
80                 {
81                 FileData *fd = work->data;
82                 if (strcmp(fd->path, path) == 0)
83                         {
84                         if (row) *row = n;
85                         return fd;
86                         }
87                 work = work->next;
88                 n++;
89                 }
90
91         if (row) *row = -1;
92         return NULL;
93 }
94
95 /*
96  *-----------------------------------------------------------------------------
97  * dnd
98  *-----------------------------------------------------------------------------
99  */
100
101 static GtkTargetEntry vdlist_dnd_drop_types[] = {
102         { "text/uri-list", 0, TARGET_URI_LIST }
103 };
104 static gint vdlist_dnd_drop_types_count = 1;
105
106 static void vdlist_dest_set(ViewDir *vd, gint enable)
107 {
108         if (enable)
109                 {
110                 gtk_drag_dest_set(vd->view,
111                                   GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
112                                   vdlist_dnd_drop_types, vdlist_dnd_drop_types_count,
113                                   GDK_ACTION_MOVE | GDK_ACTION_COPY);
114                 }
115         else
116                 {
117                 gtk_drag_dest_unset(vd->view);
118                 }
119 }
120
121 static void vdlist_dnd_get(GtkWidget *widget, GdkDragContext *context,
122                            GtkSelectionData *selection_data, guint info,
123                            guint time, gpointer data)
124 {
125         ViewDir *vd = data;
126         GList *list;
127         gchar *text = NULL;
128         gint length = 0;
129
130         if (!vd->click_fd) return;
131
132         switch (info)
133                 {
134                 case TARGET_URI_LIST:
135                 case TARGET_TEXT_PLAIN:
136                         list = g_list_prepend(NULL, vd->click_fd);
137                         text = uri_text_from_filelist(list, &length, (info == TARGET_TEXT_PLAIN));
138                         g_list_free(list);
139                         break;
140                 }
141         if (text)
142                 {
143                 gtk_selection_data_set (selection_data, selection_data->target,
144                                 8, (guchar *)text, length);
145                 g_free(text);
146                 }
147 }
148
149 static void vdlist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
150 {
151         ViewDir *vd = data;
152
153         vd_color_set(vd, vd->click_fd, TRUE);
154         vdlist_dest_set(vd, FALSE);
155 }
156
157 static void vdlist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
158 {
159         ViewDir *vd = data;
160
161         vd_color_set(vd, vd->click_fd, FALSE);
162
163         if (context->action == GDK_ACTION_MOVE)
164                 {
165                 vdlist_refresh(vd);
166                 }
167         vdlist_dest_set(vd, TRUE);
168 }
169
170 static void vdlist_dnd_drop_receive(GtkWidget *widget,
171                                     GdkDragContext *context, gint x, gint y,
172                                     GtkSelectionData *selection_data, guint info,
173                                     guint time, gpointer data)
174 {
175         ViewDir *vd = data;
176         GtkTreePath *tpath;
177         GtkTreeIter iter;
178         FileData *fd = NULL;
179
180         vd->click_fd = NULL;
181
182         if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), x, y,
183                                           &tpath, NULL, NULL, NULL))
184                 {
185                 GtkTreeModel *store;
186
187                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
188                 gtk_tree_model_get_iter(store, &iter, tpath);
189                 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &fd, -1);
190                 gtk_tree_path_free(tpath);
191                 }
192
193         if (!fd) return;
194
195         if (info == TARGET_URI_LIST)
196                 {
197                 GList *list;
198                 gint active;
199
200                 list = uri_filelist_from_text((gchar *)selection_data->data, TRUE);
201                 if (!list) return;
202
203                 active = access_file(fd->path, W_OK | X_OK);
204
205                 vd_color_set(vd, fd, TRUE);
206                 vd->popup = vd_drop_menu(vd, active);
207                 gtk_menu_popup(GTK_MENU(vd->popup), NULL, NULL, NULL, NULL, 0, time);
208
209                 vd->drop_fd = fd;
210                 vd->drop_list = list;
211                 }
212 }
213
214 #if 0
215 static gint vdlist_get_row_visibility(ViewDir *vd, FileData *fd)
216 {
217         GtkTreeModel *store;
218         GtkTreeViewColumn *column;
219         GtkTreePath *tpath;
220         GtkTreeIter iter;
221
222         GdkRectangle vrect;
223         GdkRectangle crect;
224
225         if (!fd || vd_find_row(vd, fd, &iter) < 0) return 0;
226
227         column = gtk_tree_view_get_column(GTK_TREE_VIEW(vd->view), 0);
228         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view));
229         tpath = gtk_tree_model_get_path(store, &iter);
230
231         gtk_tree_view_get_visible_rect(GTK_TREE_VIEW(vd->view), &vrect);
232         gtk_tree_view_get_cell_area(GTK_TREE_VIEW(vd->view), tpath, column, &crect);
233 printf("window: %d + %d; cell: %d + %d\n", vrect.y, vrect.height, crect.y, crect.height);
234         gtk_tree_path_free(tpath);
235
236         if (crect.y + crect.height < vrect.y) return -1;
237         if (crect.y > vrect.y + vrect.height) return 1;
238         return 0;
239 }
240 #endif
241
242 static void vdlist_scroll_to_row(ViewDir *vd, FileData *fd, gfloat y_align)
243 {
244         GtkTreeIter iter;
245
246         if (GTK_WIDGET_REALIZED(vd->view) &&
247             vd_find_row(vd, fd, &iter) >= 0)
248                 {
249                 GtkTreeModel *store;
250                 GtkTreePath *tpath;
251
252                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view));
253                 tpath = gtk_tree_model_get_path(store, &iter);
254                 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vd->view), tpath, NULL, TRUE, y_align, 0.0);
255                 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vd->view), tpath, NULL, FALSE);
256                 gtk_tree_path_free(tpath);
257
258                 if (!GTK_WIDGET_HAS_FOCUS(vd->view)) gtk_widget_grab_focus(vd->view);
259                 }
260 }
261
262 static void vdlist_drop_update(ViewDir *vd, gint x, gint y)
263 {
264         GtkTreePath *tpath;
265         GtkTreeIter iter;
266         FileData *fd = NULL;
267
268         if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vd->view), x, y,
269                                           &tpath, NULL, NULL, NULL))
270                 {
271                 GtkTreeModel *store;
272
273                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view));
274                 gtk_tree_model_get_iter(store, &iter, tpath);
275                 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &fd, -1);
276                 gtk_tree_path_free(tpath);
277                 }
278
279         if (fd != vd->drop_fd)
280                 {
281                 vd_color_set(vd, vd->drop_fd, FALSE);
282                 vd_color_set(vd, fd, TRUE);
283                 }
284
285         vd->drop_fd = fd;
286 }
287
288 static void vdlist_dnd_drop_scroll_cancel(ViewDir *vd)
289 {
290         if (vd->drop_scroll_id != -1) g_source_remove(vd->drop_scroll_id);
291         vd->drop_scroll_id = -1;
292 }
293
294 static gint vdlist_auto_scroll_idle_cb(gpointer data)
295 {
296         ViewDir *vd = data;
297
298         if (vd->drop_fd)
299                 {
300                 GdkWindow *window;
301                 gint x, y;
302                 gint w, h;
303
304                 window = vd->view->window;
305                 gdk_window_get_pointer(window, &x, &y, NULL);
306                 gdk_drawable_get_size(window, &w, &h);
307                 if (x >= 0 && x < w && y >= 0 && y < h)
308                         {
309                         vdlist_drop_update(vd, x, y);
310                         }
311                 }
312
313         vd->drop_scroll_id = -1;
314         return FALSE;
315 }
316
317 static gint vdlist_auto_scroll_notify_cb(GtkWidget *widget, gint x, gint y, gpointer data)
318 {
319         ViewDir *vd = data;
320
321         if (!vd->drop_fd || vd->drop_list) return FALSE;
322
323         if (vd->drop_scroll_id == -1) vd->drop_scroll_id = g_idle_add(vdlist_auto_scroll_idle_cb, vd);
324
325         return TRUE;
326 }
327
328 static gint vdlist_dnd_drop_motion(GtkWidget *widget, GdkDragContext *context,
329                                    gint x, gint y, guint time, gpointer data)
330 {
331         ViewDir *vd = data;
332
333         vd->click_fd = NULL;
334
335         if (gtk_drag_get_source_widget(context) == vd->view)
336                 {
337                 /* from same window */
338                 gdk_drag_status(context, 0, time);
339                 return TRUE;
340                 }
341         else
342                 {
343                 gdk_drag_status(context, context->suggested_action, time);
344                 }
345
346         vdlist_drop_update(vd, x, y);
347
348         if (vd->drop_fd)
349                 {
350                 GtkAdjustment *adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(vd->view));
351                 widget_auto_scroll_start(vd->view, adj, -1, -1, vdlist_auto_scroll_notify_cb, vd);
352                 }
353
354         return FALSE;
355 }
356
357 static void vdlist_dnd_drop_leave(GtkWidget *widget, GdkDragContext *context, guint time, gpointer data)
358 {
359         ViewDir *vd = data;
360
361         if (vd->drop_fd != vd->click_fd) vd_color_set(vd, vd->drop_fd, FALSE);
362
363         vd->drop_fd = NULL;
364 }
365
366 static void vdlist_dnd_init(ViewDir *vd)
367 {
368         gtk_drag_source_set(vd->view, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
369                             dnd_file_drag_types, dnd_file_drag_types_count,
370                             GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
371         g_signal_connect(G_OBJECT(vd->view), "drag_data_get",
372                          G_CALLBACK(vdlist_dnd_get), vd);
373         g_signal_connect(G_OBJECT(vd->view), "drag_begin",
374                          G_CALLBACK(vdlist_dnd_begin), vd);
375         g_signal_connect(G_OBJECT(vd->view), "drag_end",
376                          G_CALLBACK(vdlist_dnd_end), vd);
377
378         vdlist_dest_set(vd, TRUE);
379         g_signal_connect(G_OBJECT(vd->view), "drag_data_received",
380                          G_CALLBACK(vdlist_dnd_drop_receive), vd);
381         g_signal_connect(G_OBJECT(vd->view), "drag_motion",
382                          G_CALLBACK(vdlist_dnd_drop_motion), vd);
383         g_signal_connect(G_OBJECT(vd->view), "drag_leave",
384                          G_CALLBACK(vdlist_dnd_drop_leave), vd);
385 }
386
387 /*
388  *-----------------------------------------------------------------------------
389  * main
390  *-----------------------------------------------------------------------------
391  */ 
392
393 static void vdlist_select_row(ViewDir *vd, FileData *fd)
394 {
395         if (fd && vd->select_func)
396                 {
397                 gchar *path;
398
399                 path = g_strdup(fd->path);
400                 vd->select_func(vd, path, vd->select_data);
401                 g_free(path);
402                 }
403 }
404
405 const gchar *vdlist_row_get_path(ViewDir *vd, gint row)
406 {
407         FileData *fd;
408
409         fd = g_list_nth_data(VDLIST_INFO(vd, list), row);
410
411         if (fd) return fd->path;
412
413         return NULL;
414 }
415
416 static void vdlist_populate(ViewDir *vd)
417 {
418         GtkListStore *store;
419         GList *work;
420
421         store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view)));
422         gtk_list_store_clear(store);
423
424         work = VDLIST_INFO(vd, list);
425         while (work)
426                 {
427                 FileData *fd;
428                 GtkTreeIter iter;
429                 GdkPixbuf *pixbuf;
430
431                 fd = work->data;
432
433                 if (access_file(fd->path, R_OK | X_OK) && fd->name)
434                         {
435                         if (fd->name[0] == '.' && fd->name[1] == '\0')
436                                 {
437                                 pixbuf = vd->pf->open;
438                                 }
439                         else if (fd->name[0] == '.' && fd->name[1] == '.' && fd->name[2] == '\0')
440                                 {
441                                 pixbuf = vd->pf->parent;
442                                 }
443                         else
444                                 {
445                                 pixbuf = vd->pf->close;
446                                 }
447                         }
448                 else
449                         {
450                         pixbuf = vd->pf->deny;
451                         }
452
453                 gtk_list_store_append(store, &iter);
454                 gtk_list_store_set(store, &iter,
455                                    DIR_COLUMN_POINTER, fd,
456                                    DIR_COLUMN_ICON, pixbuf,
457                                    DIR_COLUMN_NAME, fd->name, -1);
458
459                 work = work->next;
460                 }
461
462         vd->click_fd = NULL;
463         vd->drop_fd = NULL;
464 }
465
466 gint vdlist_set_path(ViewDir *vd, const gchar *path)
467 {
468         gint ret;
469         FileData *fd;
470         gchar *old_path = NULL;
471         gchar *filepath;
472
473         if (!path) return FALSE;
474         if (vd->path && strcmp(path, vd->path) == 0) return TRUE;
475
476         if (vd->path)
477                 {
478                 gchar *base;
479
480                 base = remove_level_from_path(vd->path);
481                 if (strcmp(base, path) == 0)
482                         {
483                         old_path = g_strdup(filename_from_path(vd->path));
484                         }
485                 g_free(base);
486                 }
487
488         g_free(vd->path);
489         vd->path = g_strdup(path);
490
491         filelist_free(VDLIST_INFO(vd, list));
492         VDLIST_INFO(vd, list) = NULL;
493
494         ret = filelist_read(vd->path, NULL, &VDLIST_INFO(vd, list));
495
496         VDLIST_INFO(vd, list) = filelist_sort(VDLIST_INFO(vd, list), SORT_NAME, TRUE);
497
498         /* add . and .. */
499
500         if (strcmp(vd->path, "/") != 0)
501                 {
502                 filepath = g_strconcat(vd->path, "/", "..", NULL); 
503                 fd = file_data_new_simple(filepath);
504                 VDLIST_INFO(vd, list) = g_list_prepend(VDLIST_INFO(vd, list), fd);
505                 g_free(filepath);
506                 }
507         
508         if (options->file_filter.show_dot_directory)
509                 {
510                 filepath = g_strconcat(vd->path, "/", ".", NULL); 
511                 fd = file_data_new_simple(filepath);
512                 VDLIST_INFO(vd, list) = g_list_prepend(VDLIST_INFO(vd, list), fd);
513                 g_free(filepath);
514         }
515
516         vdlist_populate(vd);
517
518         if (old_path)
519                 {
520                 /* scroll to make last path visible */
521                 FileData *found = NULL;
522                 GList *work;
523
524                 work = VDLIST_INFO(vd, list);
525                 while (work && !found)
526                         {
527                         FileData *fd = work->data;
528                         if (strcmp(old_path, fd->name) == 0) found = fd;
529                         work = work->next;
530                         }
531
532                 if (found) vdlist_scroll_to_row(vd, found, 0.5);
533
534                 g_free(old_path);
535                 return ret;
536                 }
537
538         if (GTK_WIDGET_REALIZED(vd->view))
539                 {
540                 gtk_tree_view_scroll_to_point(GTK_TREE_VIEW(vd->view), 0, 0);
541                 }
542
543         return ret;
544 }
545
546 void vdlist_refresh(ViewDir *vd)
547 {
548         gchar *path;
549
550         path = g_strdup(vd->path);
551         vd->path = NULL;
552         vdlist_set_path(vd, path);
553         g_free(path);
554 }
555
556 static void vdlist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
557 {
558         ViewDir *vd = data;
559         GtkTreeModel *store;
560         GtkTreeIter iter;
561         GtkTreePath *tpath;
562         gint cw, ch;
563
564         if (vd_find_row(vd, vd->click_fd, &iter) < 0) return;
565         store = gtk_tree_view_get_model(GTK_TREE_VIEW(vd->view));
566         tpath = gtk_tree_model_get_path(store, &iter);
567         tree_view_get_cell_clamped(GTK_TREE_VIEW(vd->view), tpath, 0, TRUE, x, y, &cw, &ch);
568         gtk_tree_path_free(tpath);
569         *y += ch;
570         popup_menu_position_clamp(menu, x, y, 0);
571 }
572
573 static gint vdlist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
574 {
575         ViewDir *vd = data;
576         GtkTreePath *tpath;
577         
578         if (event->keyval != GDK_Menu) return FALSE;
579
580         gtk_tree_view_get_cursor(GTK_TREE_VIEW(vd->view), &tpath, NULL);
581         if (tpath)
582                 {
583                 GtkTreeModel *store;
584                 GtkTreeIter iter;
585
586                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
587                 gtk_tree_model_get_iter(store, &iter, tpath);
588                 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &vd->click_fd, -1);
589                 
590                 gtk_tree_path_free(tpath);
591                 }
592         else
593                 {
594                 vd->click_fd = NULL;
595                 }
596
597         vd_color_set(vd, vd->click_fd, TRUE);
598
599         vd->popup = vd_pop_menu(vd, vd->click_fd);
600
601         gtk_menu_popup(GTK_MENU(vd->popup), NULL, NULL, vdlist_menu_position_cb, vd, 0, GDK_CURRENT_TIME);
602
603         return TRUE;
604 }
605
606 static gint vdlist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
607 {
608         ViewDir *vd = data;
609         GtkTreePath *tpath;
610         GtkTreeIter iter;
611         FileData *fd = NULL;
612
613         if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
614                                           &tpath, NULL, NULL, NULL))
615                 {
616                 GtkTreeModel *store;
617
618                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
619                 gtk_tree_model_get_iter(store, &iter, tpath);
620                 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &fd, -1);
621                 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
622                 gtk_tree_path_free(tpath);
623                 }
624
625         vd->click_fd = fd;
626         vd_color_set(vd, vd->click_fd, TRUE);
627
628         if (bevent->button == 3)
629                 {
630                 vd->popup = vd_pop_menu(vd, vd->click_fd);
631                 gtk_menu_popup(GTK_MENU(vd->popup), NULL, NULL, NULL, NULL,
632                                bevent->button, bevent->time);
633                 }
634
635         return TRUE;
636 }
637
638 static gint vdlist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
639 {
640         ViewDir *vd = data;
641         GtkTreePath *tpath;
642         GtkTreeIter iter;
643         FileData *fd = NULL;
644
645         vd_color_set(vd, vd->click_fd, FALSE);
646
647         if (bevent->button != 1) return TRUE;
648
649         if ((bevent->x != 0 || bevent->y != 0) &&
650             gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
651                                           &tpath, NULL, NULL, NULL))
652                 {
653                 GtkTreeModel *store;
654
655                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
656                 gtk_tree_model_get_iter(store, &iter, tpath);
657                 gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &fd, -1);
658                 gtk_tree_path_free(tpath);
659                 }
660
661         if (fd && vd->click_fd == fd)
662                 {
663                 vdlist_select_row(vd, vd->click_fd);
664                 }
665
666         return TRUE;
667 }
668
669 static void vdlist_select_cb(GtkTreeView *tview, GtkTreePath *tpath, GtkTreeViewColumn *column, gpointer data)
670 {
671         ViewDir *vd = data;
672         GtkTreeModel *store;
673         GtkTreeIter iter;
674         FileData *fd;
675
676         store = gtk_tree_view_get_model(tview);
677         gtk_tree_model_get_iter(store, &iter, tpath);
678         gtk_tree_model_get(store, &iter, DIR_COLUMN_POINTER, &fd, -1);
679
680         vdlist_select_row(vd, fd);
681 }
682
683 static GdkColor *vdlist_color_shifted(GtkWidget *widget)
684 {
685         static GdkColor color;
686         static GtkWidget *done = NULL;
687
688         if (done != widget)
689                 {
690                 GtkStyle *style;
691                 
692                 style = gtk_widget_get_style(widget);
693                 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
694                 shift_color(&color, -1, 0);
695                 done = widget;
696                 }
697
698         return &color;
699 }
700
701 static void vdlist_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
702                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
703 {
704         ViewDir *vd = data;
705         gboolean set;
706
707         gtk_tree_model_get(tree_model, iter, DIR_COLUMN_COLOR, &set, -1);
708         g_object_set(G_OBJECT(cell),
709                      "cell-background-gdk", vdlist_color_shifted(vd->view),
710                      "cell-background-set", set, NULL);
711 }
712
713 static void vdlist_destroy_cb(GtkWidget *widget, gpointer data)
714 {
715         ViewDir *vd = data;
716
717         vdlist_dnd_drop_scroll_cancel(vd);
718         widget_auto_scroll_stop(vd->view);
719
720         filelist_free(VDLIST_INFO(vd, list));
721 }
722
723 ViewDir *vdlist_new(ViewDir *vd, const gchar *path)
724 {
725         GtkListStore *store;
726         GtkTreeSelection *selection;
727         GtkTreeViewColumn *column;
728         GtkCellRenderer *renderer;
729
730         vd->info = g_new0(ViewDirInfoList, 1);
731         vd->type = DIRVIEW_LIST;
732         vd->widget_destroy_cb = vdlist_destroy_cb;
733
734         VDLIST_INFO(vd, list) = NULL;
735
736         store = gtk_list_store_new(4, G_TYPE_POINTER, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN);
737         vd->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
738         g_object_unref(store);
739
740         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vd->view), FALSE);
741         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vd->view), FALSE);
742         g_signal_connect(G_OBJECT(vd->view), "row_activated",
743
744                          G_CALLBACK(vdlist_select_cb), vd);
745
746         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vd->view));
747         gtk_tree_selection_set_mode(selection, GTK_SELECTION_NONE);
748
749         column = gtk_tree_view_column_new();
750         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
751
752         renderer = gtk_cell_renderer_pixbuf_new();
753         gtk_tree_view_column_pack_start(column, renderer, FALSE);
754         gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", DIR_COLUMN_ICON);
755         gtk_tree_view_column_set_cell_data_func(column, renderer, vdlist_color_cb, vd, NULL);
756
757         renderer = gtk_cell_renderer_text_new();
758         gtk_tree_view_column_pack_start(column, renderer, TRUE);
759         gtk_tree_view_column_add_attribute(column, renderer, "text", DIR_COLUMN_NAME);
760         gtk_tree_view_column_set_cell_data_func(column, renderer, vdlist_color_cb, vd, NULL);
761
762         gtk_tree_view_append_column(GTK_TREE_VIEW(vd->view), column);
763
764         g_signal_connect(G_OBJECT(vd->view), "key_press_event",
765                            G_CALLBACK(vdlist_press_key_cb), vd);
766         gtk_container_add(GTK_CONTAINER(vd->widget), vd->view);
767         gtk_widget_show(vd->view);
768
769         vdlist_dnd_init(vd);
770
771         g_signal_connect(G_OBJECT(vd->view), "button_press_event",
772                          G_CALLBACK(vdlist_press_cb), vd);
773         g_signal_connect(G_OBJECT(vd->view), "button_release_event",
774                          G_CALLBACK(vdlist_release_cb), vd);
775
776         if (path) vdlist_set_path(vd, path);
777
778         return vd;
779 }