1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4 * Copyright (C) 2000, 2001 Eazel, Inc
5 * Copyright (C) 2002 Anders Carlsson
6 * Copyright (C) 2002 Darin Adler
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
21 * Boston, MA 02110-1335, USA.
22 *
23 * Authors:
24 * Maciej Stachowiak <mjs@eazel.com>
25 * Anders Carlsson <andersca@gnu.org>
26 * Darin Adler <darin@bentspoon.com>
27 */
28
29 /* fm-tree-view.c - tree sidebar panel
30 */
31
32 #include <config.h>
33
34 #include "nemo-tree-sidebar.h"
35
36 #include "nemo-tree-sidebar-model.h"
37 #include "nemo-properties-window.h"
38 #include "nemo-window-slot.h"
39
40 #include <libnemo-private/nemo-clipboard.h>
41 #include <libnemo-private/nemo-clipboard-monitor.h>
42 #include <libnemo-private/nemo-desktop-icon-file.h>
43 #include <libnemo-private/nemo-file-attributes.h>
44 #include <libnemo-private/nemo-file-operations.h>
45 #include <libnemo-private/nemo-file-utilities.h>
46 #include <libnemo-private/nemo-global-preferences.h>
47 #include <libnemo-private/nemo-icon-names.h>
48 #include <libnemo-private/nemo-program-choosing.h>
49 #include <libnemo-private/nemo-tree-view-drag-dest.h>
50 #include <libnemo-private/nemo-module.h>
51 #include <libnemo-private/nemo-action-manager.h>
52 #include <libnemo-private/nemo-action.h>
53
54 #include <string.h>
55 #include <eel/eel-gtk-extensions.h>
56 #include <gtk/gtk.h>
57 #include <glib/gi18n.h>
58 #include <gio/gio.h>
59
60 #define DEBUG_FLAG NEMO_DEBUG_LIST_VIEW
61 #include <libnemo-private/nemo-debug.h>
62
63 typedef struct {
64 GObject parent;
65 } FMTreeViewProvider;
66
67 typedef struct {
68 GObjectClass parent;
69 } FMTreeViewProviderClass;
70
71
72 struct FMTreeViewDetails {
73 NemoWindow *window;
74 GtkTreeView *tree_widget;
75 GtkTreeModelSort *sort_model;
76 FMTreeModel *child_model;
77
78 GVolumeMonitor *volume_monitor;
79
80 NemoFile *activation_file;
81 NemoWindowOpenFlags activation_flags;
82
83 NemoTreeViewDragDest *drag_dest;
84
85 char *selection_location;
86 gboolean selecting;
87
88 guint show_selection_idle_id;
89 gulong clipboard_handler_id;
90
91 GtkWidget *popup;
92 GtkWidget *popup_open;
93 GtkWidget *popup_open_in_new_window;
94 GtkWidget *popup_open_in_new_tab;
95 GtkWidget *popup_create_folder;
96 GtkWidget *popup_cut;
97 GtkWidget *popup_copy;
98 GtkWidget *popup_paste;
99 GtkWidget *popup_rename;
100 GtkWidget *popup_pin;
101 GtkWidget *popup_unpin;
102 GtkWidget *popup_trash;
103 GtkWidget *popup_delete;
104 GtkWidget *popup_properties;
105 GtkWidget *popup_unmount_separator;
106 GtkWidget *popup_unmount;
107 GtkWidget *popup_eject;
108 GtkWidget *popup_action_separator;
109 NemoFile *popup_file;
110 guint popup_file_idle_handler;
111
112 guint selection_changed_timer;
113
114 NemoActionManager *action_manager;
115 guint action_manager_changed_id;
116 GList *action_items;
117 guint hidden_files_changed_id;
118 guint sort_directories_first : 1;
119 };
120
121 typedef struct {
122 GList *uris;
123 FMTreeView *view;
124 } PrependURIParameters;
125
126 typedef struct {
127 NemoAction *action;
128 FMTreeView *view;
129 GtkWidget *item;
130 } ActionPayload;
131
132 static GdkAtom copied_files_atom;
133
134 static void fm_tree_view_activate_file (FMTreeView *view,
135 NemoFile *file,
136 NemoWindowOpenFlags flags);
137
138 static void create_popup_menu (FMTreeView *view);
139
140 static void add_action_popup_items (FMTreeView *view);
141
G_DEFINE_TYPE(FMTreeView,fm_tree_view,GTK_TYPE_SCROLLED_WINDOW)142 G_DEFINE_TYPE (FMTreeView, fm_tree_view, GTK_TYPE_SCROLLED_WINDOW)
143 #define parent_class fm_tree_view_parent_class
144
145 static void
146 notify_clipboard_info (NemoClipboardMonitor *monitor,
147 NemoClipboardInfo *info,
148 FMTreeView *view)
149 {
150 if (info != NULL && info->cut) {
151 fm_tree_model_set_highlight_for_files (view->details->child_model, info->files);
152 } else {
153 fm_tree_model_set_highlight_for_files (view->details->child_model, NULL);
154 }
155 }
156
157
158 static gboolean
show_iter_for_file(FMTreeView * view,NemoFile * file,GtkTreeIter * iter)159 show_iter_for_file (FMTreeView *view, NemoFile *file, GtkTreeIter *iter)
160 {
161 GtkTreeModel *model;
162 NemoFile *parent_file;
163 GtkTreeIter parent_iter;
164 GtkTreePath *path, *sort_path;
165 GtkTreeIter cur_iter;
166
167 if (view->details->child_model == NULL) {
168 return FALSE;
169 }
170 model = GTK_TREE_MODEL (view->details->child_model);
171
172 /* check if file is visible in the same root as the currently selected folder is */
173 gtk_tree_view_get_cursor (view->details->tree_widget, &path, NULL);
174 if (path != NULL) {
175 if (gtk_tree_model_get_iter (model, &cur_iter, path) &&
176 fm_tree_model_file_get_iter (view->details->child_model, iter,
177 file, &cur_iter)) {
178 gtk_tree_path_free (path);
179 return TRUE;
180 }
181 gtk_tree_path_free (path);
182 }
183 /* check if file is visible at all */
184 if (fm_tree_model_file_get_iter (view->details->child_model,
185 iter, file, NULL)) {
186 return TRUE;
187 }
188
189 parent_file = nemo_file_get_parent (file);
190
191 if (parent_file == NULL) {
192 return FALSE;
193 }
194 if (!show_iter_for_file (view, parent_file, &parent_iter)) {
195 nemo_file_unref (parent_file);
196 return FALSE;
197 }
198 nemo_file_unref (parent_file);
199
200 if (parent_iter.user_data == NULL || parent_iter.stamp == 0) {
201 return FALSE;
202 }
203 path = gtk_tree_model_get_path (model, &parent_iter);
204 sort_path = gtk_tree_model_sort_convert_child_path_to_path
205 (view->details->sort_model, path);
206 gtk_tree_path_free (path);
207 gtk_tree_view_expand_row (view->details->tree_widget, sort_path, FALSE);
208 gtk_tree_path_free (sort_path);
209
210 return FALSE;
211 }
212
213 static void
refresh_highlight(FMTreeView * view)214 refresh_highlight (FMTreeView *view)
215 {
216 NemoClipboardMonitor *monitor;
217 NemoClipboardInfo *info;
218
219 monitor = nemo_clipboard_monitor_get ();
220 info = nemo_clipboard_monitor_get_clipboard_info (monitor);
221
222 notify_clipboard_info (monitor, info, view);
223 }
224
225 static gboolean
show_selection_idle_callback(gpointer callback_data)226 show_selection_idle_callback (gpointer callback_data)
227 {
228 FMTreeView *view;
229 NemoFile *file, *old_file;
230 GtkTreeIter iter;
231 GtkTreePath *path, *sort_path;
232
233 view = FM_TREE_VIEW (callback_data);
234
235 view->details->show_selection_idle_id = 0;
236
237 file = nemo_file_get_by_uri (view->details->selection_location);
238 if (file == NULL) {
239 return FALSE;
240 }
241
242 if (!nemo_file_is_directory (file)) {
243 old_file = file;
244 file = nemo_file_get_parent (file);
245 nemo_file_unref (old_file);
246 if (file == NULL) {
247 return FALSE;
248 }
249 }
250
251 view->details->selecting = TRUE;
252 if (!show_iter_for_file (view, file, &iter)) {
253 nemo_file_unref (file);
254 return FALSE;
255 }
256 view->details->selecting = FALSE;
257
258 path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->details->child_model), &iter);
259 sort_path = gtk_tree_model_sort_convert_child_path_to_path
260 (view->details->sort_model, path);
261 gtk_tree_path_free (path);
262 gtk_tree_view_set_cursor (view->details->tree_widget, sort_path, NULL, FALSE);
263 if (gtk_widget_get_realized (GTK_WIDGET (view->details->tree_widget))) {
264 gtk_tree_view_scroll_to_cell (view->details->tree_widget, sort_path, NULL, FALSE, 0, 0);
265 }
266 gtk_tree_path_free (sort_path);
267
268 nemo_file_unref (file);
269 refresh_highlight (view);
270
271 return FALSE;
272 }
273
274 static void
schedule_show_selection(FMTreeView * view)275 schedule_show_selection (FMTreeView *view)
276 {
277 if (view->details->show_selection_idle_id == 0) {
278 view->details->show_selection_idle_id = g_idle_add (show_selection_idle_callback, view);
279 }
280 }
281
282 static void
schedule_select_and_show_location(FMTreeView * view,char * location)283 schedule_select_and_show_location (FMTreeView *view, char *location)
284 {
285 if (view->details->selection_location != NULL) {
286 g_free (view->details->selection_location);
287 }
288 view->details->selection_location = g_strdup (location);
289 schedule_show_selection (view);
290 }
291
292 static void
row_loaded_callback(GtkTreeModel * tree_model,GtkTreeIter * iter,FMTreeView * view)293 row_loaded_callback (GtkTreeModel *tree_model,
294 GtkTreeIter *iter,
295 FMTreeView *view)
296 {
297 NemoFile *file, *tmp_file, *selection_file;
298
299 if (view->details->selection_location == NULL
300 || !view->details->selecting
301 || iter->user_data == NULL || iter->stamp == 0) {
302 return;
303 }
304
305 file = fm_tree_model_iter_get_file (view->details->child_model, iter);
306 if (file == NULL) {
307 return;
308 }
309 if (!nemo_file_is_directory (file)) {
310 nemo_file_unref(file);
311 return;
312 }
313
314 /* if iter is ancestor of wanted selection_location then update selection */
315 selection_file = nemo_file_get_by_uri (view->details->selection_location);
316 while (selection_file != NULL) {
317 if (file == selection_file) {
318 nemo_file_unref (file);
319 nemo_file_unref (selection_file);
320
321 schedule_show_selection (view);
322 return;
323 }
324 tmp_file = nemo_file_get_parent (selection_file);
325 nemo_file_unref (selection_file);
326 selection_file = tmp_file;
327 }
328 nemo_file_unref (file);
329 }
330
331 static NemoFile *
sort_model_iter_to_file(FMTreeView * view,GtkTreeIter * iter)332 sort_model_iter_to_file (FMTreeView *view, GtkTreeIter *iter)
333 {
334 GtkTreeIter child_iter;
335
336 gtk_tree_model_sort_convert_iter_to_child_iter (view->details->sort_model, &child_iter, iter);
337 return fm_tree_model_iter_get_file (view->details->child_model, &child_iter);
338 }
339
340 static NemoFile *
sort_model_path_to_file(FMTreeView * view,GtkTreePath * path)341 sort_model_path_to_file (FMTreeView *view, GtkTreePath *path)
342 {
343 GtkTreeIter iter;
344
345 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (view->details->sort_model), &iter, path)) {
346 return NULL;
347 }
348 return sort_model_iter_to_file (view, &iter);
349 }
350
351 static void
got_activation_uri_callback(NemoFile * file,gpointer callback_data)352 got_activation_uri_callback (NemoFile *file, gpointer callback_data)
353 {
354 char *uri, *file_uri;
355 FMTreeView *view;
356 GdkScreen *screen;
357 GFile *location;
358 NemoWindowSlot *slot;
359 gboolean open_in_same_slot;
360
361 view = FM_TREE_VIEW (callback_data);
362
363 screen = gtk_widget_get_screen (GTK_WIDGET (view->details->tree_widget));
364
365 g_assert (file == view->details->activation_file);
366
367 open_in_same_slot =
368 (view->details->activation_flags &
369 (NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW |
370 NEMO_WINDOW_OPEN_FLAG_NEW_TAB)) == 0;
371
372 slot = nemo_window_get_active_slot (view->details->window);
373
374 uri = nemo_file_get_activation_uri (file);
375 if (nemo_file_is_launcher (file)) {
376 file_uri = nemo_file_get_uri (file);
377 DEBUG ("Tree sidebar, launching %s", file_uri);
378 nemo_launch_desktop_file (screen, file_uri, NULL, NULL);
379 g_free (file_uri);
380 } else if (uri != NULL
381 && nemo_file_is_executable (file)
382 && nemo_file_can_execute (file)
383 && !nemo_file_is_directory (file)) {
384
385 file_uri = g_filename_from_uri (uri, NULL, NULL);
386
387 /* Non-local executables don't get launched. They act like non-executables. */
388 if (file_uri == NULL) {
389 DEBUG ("Tree sidebar, opening location %s", uri);
390
391 location = g_file_new_for_uri (uri);
392 nemo_window_slot_open_location
393 (slot, location,
394 view->details->activation_flags);
395 g_object_unref (location);
396 } else {
397 DEBUG ("Tree sidebar, launching application for %s", file_uri);
398 nemo_launch_application_from_command (screen, file_uri, FALSE, NULL);
399 g_free (file_uri);
400 }
401
402 } else if (uri != NULL) {
403 if (!open_in_same_slot ||
404 view->details->selection_location == NULL ||
405 strcmp (uri, view->details->selection_location) != 0) {
406 if (open_in_same_slot) {
407 if (view->details->selection_location != NULL) {
408 g_free (view->details->selection_location);
409 }
410 view->details->selection_location = g_strdup (uri);
411 }
412
413 DEBUG ("Tree sidebar, opening location %s", uri);
414
415 location = g_file_new_for_uri (uri);
416 nemo_window_slot_open_location
417 (slot, location,
418 view->details->activation_flags);
419 g_object_unref (location);
420 }
421 }
422
423 g_free (uri);
424 nemo_file_unref (view->details->activation_file);
425 view->details->activation_file = NULL;
426 }
427
428 static void
cancel_activation(FMTreeView * view)429 cancel_activation (FMTreeView *view)
430 {
431 if (view->details->activation_file == NULL) {
432 return;
433 }
434
435 nemo_file_cancel_call_when_ready
436 (view->details->activation_file,
437 got_activation_uri_callback, view);
438 nemo_file_unref (view->details->activation_file);
439 view->details->activation_file = NULL;
440 }
441
442 static void
row_activated_callback(GtkTreeView * treeview,GtkTreePath * path,GtkTreeViewColumn * column,FMTreeView * view)443 row_activated_callback (GtkTreeView *treeview, GtkTreePath *path,
444 GtkTreeViewColumn *column, FMTreeView *view)
445 {
446 if (gtk_tree_view_row_expanded (view->details->tree_widget, path)) {
447 gtk_tree_view_collapse_row (view->details->tree_widget, path);
448 } else {
449 gtk_tree_view_expand_row (view->details->tree_widget,
450 path, FALSE);
451 }
452 }
453
454 static gboolean
selection_changed_timer_callback(FMTreeView * view)455 selection_changed_timer_callback(FMTreeView *view)
456 {
457 NemoFileAttributes attributes;
458 GtkTreeIter iter;
459 GtkTreeSelection *selection;
460
461 /* no activation if popup menu is open */
462 if (view->details->popup_file != NULL) {
463 return FALSE;
464 }
465
466 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_widget));
467 cancel_activation (view);
468
469 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
470 return FALSE;
471 }
472
473 view->details->activation_file = sort_model_iter_to_file (view, &iter);
474 if (view->details->activation_file == NULL) {
475 return FALSE;
476 }
477 view->details->activation_flags = 0;
478
479 attributes = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO;
480 nemo_file_call_when_ready (view->details->activation_file, attributes,
481 got_activation_uri_callback, view);
482 return FALSE; /* remove timeout */
483 }
484
485 static void
selection_changed_callback(GtkTreeSelection * selection,FMTreeView * view)486 selection_changed_callback (GtkTreeSelection *selection,
487 FMTreeView *view)
488 {
489 GdkEvent *event;
490 gboolean is_keyboard;
491
492 if (view->details->selection_changed_timer) {
493 g_source_remove (view->details->selection_changed_timer);
494 view->details->selection_changed_timer = 0;
495 }
496
497 event = gtk_get_current_event ();
498 if (event) {
499 is_keyboard = (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE);
500 gdk_event_free (event);
501
502 if (is_keyboard) {
503 /* on keyboard event: delay the change */
504 /* TODO: make dependent on keyboard repeat rate as per Markus Bertheau ? */
505 view->details->selection_changed_timer = g_timeout_add (300, (GSourceFunc) selection_changed_timer_callback, view);
506 } else {
507 /* on mouse event: show the change immediately */
508 selection_changed_timer_callback (view);
509 }
510 }
511 }
512
513 static int
compare_rows(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer callback_data)514 compare_rows (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer callback_data)
515 {
516 NemoFile *file_a, *file_b;
517 int result;
518
519 /* Dummy rows are always first */
520 if (a->user_data == NULL) {
521 return -1;
522 }
523 else if (b->user_data == NULL) {
524 return 1;
525 }
526
527 /* don't sort root nodes */
528 if (fm_tree_model_iter_is_root (FM_TREE_MODEL (model), a) &&
529 fm_tree_model_iter_is_root (FM_TREE_MODEL (model), b)) {
530 return fm_tree_model_iter_compare_roots (FM_TREE_MODEL (model), a, b);
531 }
532
533 file_a = fm_tree_model_iter_get_file (FM_TREE_MODEL (model), a);
534 file_b = fm_tree_model_iter_get_file (FM_TREE_MODEL (model), b);
535
536 if (file_a == file_b) {
537 result = 0;
538 } else if (file_a == NULL) {
539 result = -1;
540 } else if (file_b == NULL) {
541 result = +1;
542 } else {
543 result = nemo_file_compare_for_sort (file_a, file_b,
544 NEMO_FILE_SORT_BY_DISPLAY_NAME,
545 FM_TREE_VIEW (callback_data)->details->sort_directories_first,
546 FALSE);
547 }
548
549 nemo_file_unref (file_a);
550 nemo_file_unref (file_b);
551
552 return result;
553 }
554
555
556 static char *
get_root_uri_callback(NemoTreeViewDragDest * dest,gpointer user_data)557 get_root_uri_callback (NemoTreeViewDragDest *dest,
558 gpointer user_data)
559 {
560 /* Don't allow drops on background */
561 return NULL;
562 }
563
564 static NemoFile *
get_file_for_path_callback(NemoTreeViewDragDest * dest,GtkTreePath * path,gpointer user_data)565 get_file_for_path_callback (NemoTreeViewDragDest *dest,
566 GtkTreePath *path,
567 gpointer user_data)
568 {
569 FMTreeView *view;
570
571 view = FM_TREE_VIEW (user_data);
572
573 return sort_model_path_to_file (view, path);
574 }
575
576 static void
move_copy_items_callback(NemoTreeViewDragDest * dest,const GList * item_uris,const char * target_uri,GdkDragAction action,int x,int y,gpointer user_data)577 move_copy_items_callback (NemoTreeViewDragDest *dest,
578 const GList *item_uris,
579 const char *target_uri,
580 GdkDragAction action,
581 int x,
582 int y,
583 gpointer user_data)
584 {
585 FMTreeView *view;
586
587 view = FM_TREE_VIEW (user_data);
588
589 nemo_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
590 item_uris,
591 copied_files_atom);
592 nemo_file_operations_copy_move
593 (item_uris,
594 NULL,
595 target_uri,
596 action,
597 GTK_WIDGET (view->details->tree_widget),
598 NULL, NULL);
599 }
600
601 static void
add_root_for_mount(FMTreeView * view,GMount * mount)602 add_root_for_mount (FMTreeView *view,
603 GMount *mount)
604 {
605 char *mount_uri, *name;
606 GFile *root;
607 GIcon *icon;
608
609 if (g_mount_is_shadowed (mount))
610 return;
611
612 icon = g_mount_get_icon (mount);
613 root = g_mount_get_root (mount);
614 mount_uri = g_file_get_uri (root);
615 g_object_unref (root);
616 name = g_mount_get_name (mount);
617
618 fm_tree_model_add_root_uri(view->details->child_model,
619 mount_uri, name, icon, mount);
620
621 g_object_unref (icon);
622 g_free (name);
623 g_free (mount_uri);
624
625 }
626
627 static void
mount_added_callback(GVolumeMonitor * volume_monitor,GMount * mount,FMTreeView * view)628 mount_added_callback (GVolumeMonitor *volume_monitor,
629 GMount *mount,
630 FMTreeView *view)
631 {
632 add_root_for_mount (view, mount);
633 }
634
635 static void
mount_removed_callback(GVolumeMonitor * volume_monitor,GMount * mount,FMTreeView * view)636 mount_removed_callback (GVolumeMonitor *volume_monitor,
637 GMount *mount,
638 FMTreeView *view)
639 {
640 GFile *root;
641 char *mount_uri;
642
643 root = g_mount_get_root (mount);
644 mount_uri = g_file_get_uri (root);
645 g_object_unref (root);
646 fm_tree_model_remove_root_uri (view->details->child_model,
647 mount_uri);
648 g_free (mount_uri);
649 }
650
651 static void
clipboard_contents_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer data)652 clipboard_contents_received_callback (GtkClipboard *clipboard,
653 GtkSelectionData *selection_data,
654 gpointer data)
655 {
656 FMTreeView *view;
657
658 view = FM_TREE_VIEW (data);
659
660 if (gtk_selection_data_get_data_type (selection_data) == copied_files_atom
661 && gtk_selection_data_get_length (selection_data) > 0 &&
662 view->details->popup != NULL) {
663 gtk_widget_set_sensitive (view->details->popup_paste, TRUE);
664 }
665
666 g_object_unref (view);
667 }
668
669 static gboolean
is_parent_writable(NemoFile * file)670 is_parent_writable (NemoFile *file)
671 {
672 NemoFile *parent;
673 gboolean result;
674
675 parent = nemo_file_get_parent (file);
676
677 /* No parent directory, return FALSE */
678 if (parent == NULL) {
679 return FALSE;
680 }
681
682 result = nemo_file_can_write (parent);
683 nemo_file_unref (parent);
684
685 return result;
686 }
687
688 static gboolean
button_pressed_callback(GtkTreeView * treeview,GdkEventButton * event,FMTreeView * view)689 button_pressed_callback (GtkTreeView *treeview, GdkEventButton *event,
690 FMTreeView *view)
691 {
692 GtkTreePath *path, *cursor_path;
693 gboolean parent_file_is_writable;
694 gboolean file_is_home_or_desktop;
695 gboolean file_is_special_link;
696 gboolean can_move_file_to_trash;
697 gboolean can_delete_file;
698 gboolean using_browser;
699
700 using_browser = g_settings_get_boolean (nemo_preferences,
701 NEMO_PREFERENCES_ALWAYS_USE_BROWSER);
702
703 if (event->button == 3) {
704 gboolean show_unmount = FALSE;
705 gboolean show_eject = FALSE;
706 GMount *mount = NULL;
707
708 if (view->details->popup_file != NULL) {
709 return FALSE; /* Already up, ignore */
710 }
711
712 if (!gtk_tree_view_get_path_at_pos (treeview, event->x, event->y,
713 &path, NULL, NULL, NULL)) {
714 return FALSE;
715 }
716
717 view->details->popup_file = sort_model_path_to_file (view, path);
718 if (view->details->popup_file == NULL) {
719 gtk_tree_path_free (path);
720 return FALSE;
721 }
722 gtk_tree_view_get_cursor (view->details->tree_widget, &cursor_path, NULL);
723
724 gtk_tree_path_free (path);
725
726 create_popup_menu (view);
727
728 if (using_browser) {
729 gtk_widget_set_sensitive (view->details->popup_open_in_new_window,
730 nemo_file_is_directory (view->details->popup_file));
731 gtk_widget_set_sensitive (view->details->popup_open_in_new_tab,
732 nemo_file_is_directory (view->details->popup_file));
733 }
734
735 gtk_widget_set_sensitive (view->details->popup_create_folder,
736 nemo_file_is_directory (view->details->popup_file) &&
737 nemo_file_can_write (view->details->popup_file));
738 gtk_widget_set_sensitive (view->details->popup_paste, FALSE);
739 if (nemo_file_is_directory (view->details->popup_file) &&
740 nemo_file_can_write (view->details->popup_file)) {
741 gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view->details->tree_widget)),
742 copied_files_atom,
743 clipboard_contents_received_callback, g_object_ref (view));
744 }
745 can_move_file_to_trash = nemo_file_can_trash (view->details->popup_file);
746 gtk_widget_set_sensitive (view->details->popup_trash, can_move_file_to_trash);
747
748 if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE)) {
749 parent_file_is_writable = is_parent_writable (view->details->popup_file);
750 file_is_home_or_desktop = nemo_file_is_home (view->details->popup_file)
751 || nemo_file_is_desktop_directory (view->details->popup_file);
752 file_is_special_link = NEMO_IS_DESKTOP_ICON_FILE (view->details->popup_file);
753
754 can_delete_file = parent_file_is_writable
755 && !file_is_home_or_desktop
756 && !file_is_special_link;
757
758 gtk_widget_show (view->details->popup_delete);
759 gtk_widget_set_sensitive (view->details->popup_delete, can_delete_file);
760 } else {
761 gtk_widget_hide (view->details->popup_delete);
762 }
763
764 mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, view->details->popup_file);
765 if (mount) {
766 show_unmount = g_mount_can_unmount (mount);
767 show_eject = g_mount_can_eject (mount);
768 }
769
770 if (show_unmount) {
771 gtk_widget_show (view->details->popup_unmount);
772 } else {
773 gtk_widget_hide (view->details->popup_unmount);
774 }
775
776 if (show_eject) {
777 gtk_widget_show (view->details->popup_eject);
778 } else {
779 gtk_widget_hide (view->details->popup_eject);
780 }
781
782 if (show_unmount || show_eject) {
783 gtk_widget_show (view->details->popup_unmount_separator);
784 } else {
785 gtk_widget_hide (view->details->popup_unmount_separator);
786 }
787
788 if (nemo_file_get_pinning (view->details->popup_file)) {
789 gtk_widget_hide (view->details->popup_pin);
790 gtk_widget_show (view->details->popup_unpin);
791 } else {
792 gtk_widget_show (view->details->popup_pin);
793 gtk_widget_hide (view->details->popup_unpin);
794 }
795
796 gboolean actions_visible = FALSE;
797
798 GList *l;
799 NemoFile *file = view->details->popup_file;
800 NemoFile *parent = nemo_file_get_parent (file);
801 GList *tmp = NULL;
802 tmp = g_list_append (tmp, file);
803 ActionPayload *p;
804
805 for (l = view->details->action_items; l != NULL; l = l->next) {
806 p = l->data;
807 if (nemo_action_get_visibility (p->action, tmp, parent, FALSE)) {
808 gchar *action_label;
809
810 action_label = nemo_action_get_label (p->action, tmp, parent);
811 gtk_menu_item_set_label (GTK_MENU_ITEM (p->item), action_label);
812 g_free (action_label);
813
814 gtk_widget_set_visible (p->item, TRUE);
815 actions_visible = TRUE;
816 } else {
817 gtk_widget_set_visible (p->item, FALSE);
818 }
819 }
820
821 gtk_widget_set_visible (view->details->popup_action_separator, actions_visible);
822
823 g_list_free (tmp); // Don't free the file, just the list, the file is owned by the model.
824
825 gtk_menu_popup (GTK_MENU (view->details->popup),
826 NULL, NULL, NULL, NULL,
827 event->button, event->time);
828
829 gtk_tree_view_set_cursor (view->details->tree_widget, cursor_path, NULL, FALSE);
830 gtk_tree_path_free (cursor_path);
831
832 return FALSE;
833 } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
834 NemoFile *file;
835 NemoWindowOpenFlags flags = 0;
836
837 if (!gtk_tree_view_get_path_at_pos (treeview, event->x, event->y,
838 &path, NULL, NULL, NULL)) {
839 return FALSE;
840 }
841
842 file = sort_model_path_to_file (view, path);
843
844 if (using_browser) {
845 flags = (event->state & GDK_CONTROL_MASK) ?
846 NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW :
847 NEMO_WINDOW_OPEN_FLAG_NEW_TAB;
848 } else {
849 flags = NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
850 }
851
852 if (file) {
853 fm_tree_view_activate_file (view, file, flags);
854 nemo_file_unref (file);
855 }
856
857 gtk_tree_path_free (path);
858
859 return TRUE;
860 }
861
862 return FALSE;
863 }
864
865 static void
fm_tree_view_activate_file(FMTreeView * view,NemoFile * file,NemoWindowOpenFlags flags)866 fm_tree_view_activate_file (FMTreeView *view,
867 NemoFile *file,
868 NemoWindowOpenFlags flags)
869 {
870 NemoFileAttributes attributes;
871
872 cancel_activation (view);
873
874 view->details->activation_file = nemo_file_ref (file);
875 view->details->activation_flags = flags;
876
877 attributes = NEMO_FILE_ATTRIBUTE_INFO | NEMO_FILE_ATTRIBUTE_LINK_INFO;
878 nemo_file_call_when_ready (view->details->activation_file, attributes,
879 got_activation_uri_callback, view);
880 }
881
882 static void
fm_tree_view_open_cb(GtkWidget * menu_item,FMTreeView * view)883 fm_tree_view_open_cb (GtkWidget *menu_item,
884 FMTreeView *view)
885 {
886 fm_tree_view_activate_file (view, view->details->popup_file, 0);
887 }
888
889 static void
fm_tree_view_open_in_new_tab_cb(GtkWidget * menu_item,FMTreeView * view)890 fm_tree_view_open_in_new_tab_cb (GtkWidget *menu_item,
891 FMTreeView *view)
892 {
893 fm_tree_view_activate_file (view, view->details->popup_file, NEMO_WINDOW_OPEN_FLAG_NEW_TAB);
894 }
895
896 static void
fm_tree_view_open_in_new_window_cb(GtkWidget * menu_item,FMTreeView * view)897 fm_tree_view_open_in_new_window_cb (GtkWidget *menu_item,
898 FMTreeView *view)
899 {
900 fm_tree_view_activate_file (view, view->details->popup_file, NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW);
901 }
902
903 static void
new_folder_done(GFile * new_folder,gboolean success,gpointer data)904 new_folder_done (GFile *new_folder,
905 gboolean success,
906 gpointer data)
907 {
908 GList *list;
909
910 /* show the properties window for the newly created
911 * folder so the user can change its name
912 */
913 list = g_list_prepend (NULL, nemo_file_get (new_folder));
914
915 nemo_properties_window_present (list, GTK_WIDGET (data), NULL);
916
917 nemo_file_list_free (list);
918 }
919
920 static void
fm_tree_view_create_folder_cb(GtkWidget * menu_item,FMTreeView * view)921 fm_tree_view_create_folder_cb (GtkWidget *menu_item,
922 FMTreeView *view)
923 {
924 char *parent_uri;
925
926 parent_uri = nemo_file_get_uri (view->details->popup_file);
927 nemo_file_operations_new_folder (GTK_WIDGET (view->details->tree_widget),
928 NULL,
929 parent_uri,
930 new_folder_done, view->details->tree_widget);
931
932 g_free (parent_uri);
933 }
934
935 static void
copy_or_cut_files(FMTreeView * view,gboolean cut)936 copy_or_cut_files (FMTreeView *view,
937 gboolean cut)
938 {
939 char *status_string, *name;
940 NemoClipboardInfo info;
941 GtkTargetList *target_list;
942 GtkTargetEntry *targets;
943 int n_targets;
944
945 info.cut = cut;
946 info.files = g_list_prepend (NULL, view->details->popup_file);
947
948 target_list = gtk_target_list_new (NULL, 0);
949 gtk_target_list_add (target_list, copied_files_atom, 0, 0);
950 gtk_target_list_add_uri_targets (target_list, 0);
951 gtk_target_list_add_text_targets (target_list, 0);
952
953 targets = gtk_target_table_new_from_list (target_list, &n_targets);
954 gtk_target_list_unref (target_list);
955
956 gtk_clipboard_set_with_data (nemo_clipboard_get (GTK_WIDGET (view->details->tree_widget)),
957 targets, n_targets,
958 nemo_get_clipboard_callback, nemo_clear_clipboard_callback,
959 NULL);
960 gtk_target_table_free (targets, n_targets);
961
962 nemo_clipboard_monitor_set_clipboard_info (nemo_clipboard_monitor_get (),
963 &info);
964 g_list_free (info.files);
965
966 name = nemo_file_get_display_name (view->details->popup_file);
967 if (cut) {
968 status_string = g_strdup_printf (_("\"%s\" will be moved "
969 "if you select the Paste command"),
970 name);
971 } else {
972 status_string = g_strdup_printf (_("\"%s\" will be copied "
973 "if you select the Paste command"),
974 name);
975 }
976 g_free (name);
977
978 nemo_window_push_status (view->details->window,
979 status_string);
980 g_free (status_string);
981 }
982
983 static void
fm_tree_view_cut_cb(GtkWidget * menu_item,FMTreeView * view)984 fm_tree_view_cut_cb (GtkWidget *menu_item,
985 FMTreeView *view)
986 {
987 copy_or_cut_files (view, TRUE);
988 }
989
990 static void
fm_tree_view_copy_cb(GtkWidget * menu_item,FMTreeView * view)991 fm_tree_view_copy_cb (GtkWidget *menu_item,
992 FMTreeView *view)
993 {
994 copy_or_cut_files (view, FALSE);
995 }
996
997 static void
paste_clipboard_data(FMTreeView * view,GtkSelectionData * selection_data,char * destination_uri)998 paste_clipboard_data (FMTreeView *view,
999 GtkSelectionData *selection_data,
1000 char *destination_uri)
1001 {
1002 gboolean cut;
1003 GList *item_uris;
1004
1005 cut = FALSE;
1006 item_uris = nemo_clipboard_get_uri_list_from_selection_data (selection_data, &cut,
1007 copied_files_atom);
1008
1009 if (item_uris == NULL|| destination_uri == NULL) {
1010 nemo_window_push_status (view->details->window,
1011 _("There is nothing on the clipboard to paste."));
1012 } else {
1013 nemo_file_operations_copy_move
1014 (item_uris, NULL, destination_uri,
1015 cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY,
1016 GTK_WIDGET (view->details->tree_widget),
1017 NULL, NULL);
1018
1019 /* If items are cut then remove from clipboard */
1020 if (cut) {
1021 gtk_clipboard_clear (nemo_clipboard_get (GTK_WIDGET (view)));
1022 }
1023
1024 g_list_free_full (item_uris, g_free);
1025 }
1026 }
1027
1028 static void
paste_into_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer data)1029 paste_into_clipboard_received_callback (GtkClipboard *clipboard,
1030 GtkSelectionData *selection_data,
1031 gpointer data)
1032 {
1033 FMTreeView *view;
1034 char *directory_uri;
1035
1036 view = FM_TREE_VIEW (data);
1037
1038 directory_uri = nemo_file_get_uri (view->details->popup_file);
1039
1040 paste_clipboard_data (view, selection_data, directory_uri);
1041
1042 g_free (directory_uri);
1043 }
1044
1045 static void
fm_tree_view_paste_cb(GtkWidget * menu_item,FMTreeView * view)1046 fm_tree_view_paste_cb (GtkWidget *menu_item,
1047 FMTreeView *view)
1048 {
1049 gtk_clipboard_request_contents (nemo_clipboard_get (GTK_WIDGET (view->details->tree_widget)),
1050 copied_files_atom,
1051 paste_into_clipboard_received_callback, view);
1052 }
1053
1054 static GtkWindow *
fm_tree_view_get_containing_window(FMTreeView * view)1055 fm_tree_view_get_containing_window (FMTreeView *view)
1056 {
1057 GtkWidget *window;
1058
1059 g_assert (FM_IS_TREE_VIEW (view));
1060
1061 window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
1062 if (window == NULL) {
1063 return NULL;
1064 }
1065
1066 return GTK_WINDOW (window);
1067 }
1068
1069 static void
fm_tree_view_pin_unpin_cb(GtkWidget * menu_item,FMTreeView * view)1070 fm_tree_view_pin_unpin_cb (GtkWidget *menu_item,
1071 FMTreeView *view)
1072 {
1073 nemo_file_set_pinning (view->details->popup_file,
1074 !nemo_file_get_pinning (view->details->popup_file));
1075 }
1076
1077 static void
fm_tree_view_trash_cb(GtkWidget * menu_item,FMTreeView * view)1078 fm_tree_view_trash_cb (GtkWidget *menu_item,
1079 FMTreeView *view)
1080 {
1081 GList *list;
1082
1083 if (!nemo_file_can_trash (view->details->popup_file)) {
1084 return;
1085 }
1086
1087 list = g_list_prepend (NULL,
1088 nemo_file_get_location (view->details->popup_file));
1089
1090 nemo_file_operations_trash_or_delete (list,
1091 fm_tree_view_get_containing_window (view),
1092 NULL, NULL);
1093 g_list_free_full (list, g_object_unref);
1094 }
1095
1096 static void
fm_tree_view_delete_cb(GtkWidget * menu_item,FMTreeView * view)1097 fm_tree_view_delete_cb (GtkWidget *menu_item,
1098 FMTreeView *view)
1099 {
1100 GList *location_list;
1101
1102 if (!g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ENABLE_DELETE)) {
1103 return;
1104 }
1105
1106 location_list = g_list_prepend (NULL,
1107 nemo_file_get_location (view->details->popup_file));
1108
1109 nemo_file_operations_delete (location_list, fm_tree_view_get_containing_window (view), NULL, NULL);
1110 g_list_free_full (location_list, g_object_unref);
1111 }
1112
1113 static void
fm_tree_view_properties_cb(GtkWidget * menu_item,FMTreeView * view)1114 fm_tree_view_properties_cb (GtkWidget *menu_item,
1115 FMTreeView *view)
1116 {
1117 GList *list;
1118
1119 list = g_list_prepend (NULL, nemo_file_ref (view->details->popup_file));
1120
1121 nemo_properties_window_present (list, GTK_WIDGET (view->details->tree_widget), NULL);
1122
1123 nemo_file_list_free (list);
1124 }
1125
1126 static void
fm_tree_view_unmount_cb(GtkWidget * menu_item,FMTreeView * view)1127 fm_tree_view_unmount_cb (GtkWidget *menu_item,
1128 FMTreeView *view)
1129 {
1130 NemoFile *file = view->details->popup_file;
1131 GMount *mount;
1132
1133 if (file == NULL) {
1134 return;
1135 }
1136
1137 mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, file);
1138
1139 if (mount != NULL) {
1140 nemo_file_operations_unmount_mount (fm_tree_view_get_containing_window (view),
1141 mount, FALSE, TRUE);
1142 }
1143 }
1144
1145 static void
fm_tree_view_eject_cb(GtkWidget * menu_item,FMTreeView * view)1146 fm_tree_view_eject_cb (GtkWidget *menu_item,
1147 FMTreeView *view)
1148 {
1149 NemoFile *file = view->details->popup_file;
1150 GMount *mount;
1151
1152 if (file == NULL) {
1153 return;
1154 }
1155
1156 mount = fm_tree_model_get_mount_for_root_node_file (view->details->child_model, file);
1157
1158 if (mount != NULL) {
1159 nemo_file_operations_unmount_mount (fm_tree_view_get_containing_window (view),
1160 mount, TRUE, TRUE);
1161 }
1162 }
1163
1164 static gboolean
free_popup_file_in_idle_cb(gpointer data)1165 free_popup_file_in_idle_cb (gpointer data)
1166 {
1167 FMTreeView *view;
1168
1169 view = FM_TREE_VIEW (data);
1170
1171 if (view->details->popup_file != NULL) {
1172 nemo_file_unref (view->details->popup_file);
1173 view->details->popup_file = NULL;
1174 }
1175 view->details->popup_file_idle_handler = 0;
1176 return FALSE;
1177 }
1178
1179 static void
popup_menu_deactivated(GtkMenuShell * menu_shell,gpointer data)1180 popup_menu_deactivated (GtkMenuShell *menu_shell, gpointer data)
1181 {
1182 FMTreeView *view;
1183
1184 view = FM_TREE_VIEW (data);
1185
1186 /* The popup menu is deactivated. (I.E. hidden)
1187 We want to free popup_file, but can't right away as it might immediately get
1188 used if we're deactivation due to activating a menu item. So, we free it in
1189 idle */
1190
1191 if (view->details->popup_file != NULL &&
1192 view->details->popup_file_idle_handler == 0) {
1193 view->details->popup_file_idle_handler = g_idle_add (free_popup_file_in_idle_cb, view);
1194 }
1195 }
1196
1197 static void
action_activated_callback(GtkMenuItem * item,ActionPayload * payload)1198 action_activated_callback (GtkMenuItem *item, ActionPayload *payload)
1199 {
1200 gchar *uri = NULL;
1201
1202 FMTreeView *view = payload->view;
1203
1204 NemoFile *file = view->details->popup_file;
1205 NemoFile *parent = nemo_file_get_parent (file);
1206 GList *tmp = NULL;
1207 tmp = g_list_append (tmp, file);
1208
1209 nemo_action_activate (NEMO_ACTION (payload->action), tmp, parent);
1210
1211 nemo_file_list_free (tmp);
1212
1213 g_free (uri);
1214 }
1215
1216 static void
add_action_popup_items(FMTreeView * view)1217 add_action_popup_items (FMTreeView *view)
1218 {
1219 if (view->details->action_items != NULL)
1220 g_list_free_full (view->details->action_items, g_free);
1221
1222 view->details->action_items = NULL;
1223
1224 GList *action_list = nemo_action_manager_list_actions (view->details->action_manager);
1225 GList *l;
1226 GtkWidget *menu_item;
1227 NemoAction *action;
1228 ActionPayload *payload;
1229
1230 gint index = 13;
1231
1232 for (l = action_list; l != NULL; l = l->next) {
1233 action = l->data;
1234 payload = g_new0 (ActionPayload, 1);
1235 payload->action = action;
1236 payload->view = view;
1237 menu_item = gtk_menu_item_new_with_mnemonic (nemo_action_get_orig_label (action));
1238 payload->item = menu_item;
1239 g_signal_connect (menu_item, "activate", G_CALLBACK (action_activated_callback), payload);
1240 gtk_widget_show (menu_item);
1241 gtk_menu_shell_insert (GTK_MENU_SHELL (view->details->popup), menu_item, index);
1242 view->details->action_items = g_list_append (view->details->action_items, payload);
1243 index ++;
1244 }
1245 }
1246
1247 /* Callback used when the file list's popup menu is detached */
1248 static void
popup_menu_detach_cb(GtkWidget * attach_widget,GtkMenu * menu)1249 popup_menu_detach_cb (GtkWidget *attach_widget,
1250 GtkMenu *menu)
1251 {
1252 FMTreeView *view;
1253
1254 view = FM_TREE_VIEW (attach_widget);
1255 g_assert (FM_IS_TREE_VIEW (view));
1256
1257 view->details->popup = NULL;
1258 view->details->popup_open = NULL;
1259 view->details->popup_open_in_new_window = NULL;
1260 view->details->popup_open_in_new_tab = NULL;
1261 view->details->popup_create_folder = NULL;
1262 view->details->popup_cut = NULL;
1263 view->details->popup_copy = NULL;
1264 view->details->popup_paste = NULL;
1265 view->details->popup_rename = NULL;
1266 view->details->popup_pin = NULL;
1267 view->details->popup_trash = NULL;
1268 view->details->popup_delete = NULL;
1269 view->details->popup_properties = NULL;
1270 view->details->popup_unmount_separator = NULL;
1271 view->details->popup_unmount = NULL;
1272 view->details->popup_eject = NULL;
1273 view->details->popup_action_separator = NULL;
1274 }
1275
1276 static void
actions_changed_callback(FMTreeView * view)1277 actions_changed_callback (FMTreeView *view)
1278 {
1279 if (view->details->popup) {
1280 gtk_menu_detach (GTK_MENU (view->details->popup));
1281 }
1282 }
1283
1284 static void
create_popup_menu(FMTreeView * view)1285 create_popup_menu (FMTreeView *view)
1286 {
1287 GtkWidget *popup, *menu_item, *menu_image;
1288
1289 if (view->details->popup != NULL) {
1290 /* already created */
1291 return;
1292 }
1293
1294 popup = gtk_menu_new ();
1295
1296 gtk_menu_attach_to_widget (GTK_MENU (popup),
1297 GTK_WIDGET (view),
1298 popup_menu_detach_cb);
1299
1300 g_signal_connect (popup, "deactivate",
1301 G_CALLBACK (popup_menu_deactivated),
1302 view);
1303
1304 /* add the "open" menu item */
1305 menu_image = gtk_image_new_from_icon_name ("folder-open-symbolic", GTK_ICON_SIZE_MENU);
1306 gtk_widget_show (menu_image);
1307 menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Open"));
1308 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1309 menu_image);
1310 g_signal_connect (menu_item, "activate",
1311 G_CALLBACK (fm_tree_view_open_cb),
1312 view);
1313 gtk_widget_show (menu_item);
1314 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1315 view->details->popup_open = menu_item;
1316
1317 /* add the "open in new tab" menu item */
1318 menu_item = gtk_menu_item_new_with_mnemonic (_("Open in New _Tab"));
1319 g_signal_connect (menu_item, "activate",
1320 G_CALLBACK (fm_tree_view_open_in_new_tab_cb),
1321 view);
1322 g_settings_bind (nemo_preferences,
1323 NEMO_PREFERENCES_ALWAYS_USE_BROWSER,
1324 menu_item,
1325 "visible",
1326 G_SETTINGS_BIND_GET);
1327
1328 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1329 view->details->popup_open_in_new_tab = menu_item;
1330
1331 /* add the "open in new window" menu item */
1332 menu_item = gtk_menu_item_new_with_mnemonic (_("Open in New _Window"));
1333 g_signal_connect (menu_item, "activate",
1334 G_CALLBACK (fm_tree_view_open_in_new_window_cb),
1335 view);
1336 g_settings_bind (nemo_preferences,
1337 NEMO_PREFERENCES_ALWAYS_USE_BROWSER,
1338 menu_item,
1339 "visible",
1340 G_SETTINGS_BIND_GET);
1341
1342 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1343 view->details->popup_open_in_new_window = menu_item;
1344
1345 eel_gtk_menu_append_separator (GTK_MENU (popup));
1346
1347 /* add the "create new folder" menu item */
1348 menu_item = gtk_image_menu_item_new_with_mnemonic (_("Create New _Folder"));
1349 g_signal_connect (menu_item, "activate",
1350 G_CALLBACK (fm_tree_view_create_folder_cb),
1351 view);
1352 gtk_widget_show (menu_item);
1353 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1354 view->details->popup_create_folder = menu_item;
1355
1356 eel_gtk_menu_append_separator (GTK_MENU (popup));
1357
1358 /* add the "cut folder" menu item */
1359 menu_image = gtk_image_new_from_icon_name ("edit-cut-symbolic", GTK_ICON_SIZE_MENU);
1360 gtk_widget_show (menu_image);
1361 menu_item = gtk_image_menu_item_new_with_mnemonic (_("Cu_t"));
1362 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image);
1363 g_signal_connect (menu_item, "activate",
1364 G_CALLBACK (fm_tree_view_cut_cb),
1365 view);
1366 gtk_widget_show (menu_item);
1367 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1368 view->details->popup_cut = menu_item;
1369
1370 /* add the "copy folder" menu item */
1371 menu_image = gtk_image_new_from_icon_name ("edit-copy-symbolic", GTK_ICON_SIZE_MENU);
1372 gtk_widget_show (menu_image);
1373 menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Copy"));
1374 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image);
1375 g_signal_connect (menu_item, "activate",
1376 G_CALLBACK (fm_tree_view_copy_cb),
1377 view);
1378 gtk_widget_show (menu_item);
1379 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1380 view->details->popup_copy = menu_item;
1381
1382 /* add the "paste files into folder" menu item */
1383 menu_image = gtk_image_new_from_icon_name ("edit-paste-symbolic", GTK_ICON_SIZE_MENU);
1384 gtk_widget_show (menu_image);
1385 menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Paste Into Folder"));
1386 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1387 menu_image);
1388 g_signal_connect (menu_item, "activate",
1389 G_CALLBACK (fm_tree_view_paste_cb),
1390 view);
1391 gtk_widget_show (menu_item);
1392 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1393 view->details->popup_paste = menu_item;
1394
1395 eel_gtk_menu_append_separator (GTK_MENU (popup));
1396
1397 menu_image = gtk_image_new_from_icon_name ("xapp-pin-symbolic", GTK_ICON_SIZE_MENU);
1398 gtk_widget_show (menu_image);
1399 menu_item = gtk_image_menu_item_new_with_mnemonic (_("P_in"));
1400 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1401 menu_image);
1402 g_signal_connect (menu_item, "activate",
1403 G_CALLBACK (fm_tree_view_pin_unpin_cb),
1404 view);
1405 gtk_widget_show (menu_item);
1406 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1407 view->details->popup_pin = menu_item;
1408
1409 menu_image = gtk_image_new_from_icon_name ("xapp-unpin-symbolic", GTK_ICON_SIZE_MENU);
1410 gtk_widget_show (menu_image);
1411 menu_item = gtk_image_menu_item_new_with_mnemonic (_("Unp_in"));
1412 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1413 menu_image);
1414 g_signal_connect (menu_item, "activate",
1415 G_CALLBACK (fm_tree_view_pin_unpin_cb),
1416 view);
1417 gtk_widget_show (menu_item);
1418 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1419 view->details->popup_unpin = menu_item;
1420
1421
1422 eel_gtk_menu_append_separator (GTK_MENU (popup));
1423
1424 /* add the "move to trash" menu item */
1425 menu_image = gtk_image_new_from_icon_name (NEMO_ICON_SYMBOLIC_TRASH_FULL,
1426 GTK_ICON_SIZE_MENU);
1427 gtk_widget_show (menu_image);
1428 menu_item = gtk_image_menu_item_new_with_mnemonic (_("Mo_ve to Trash"));
1429 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1430 menu_image);
1431 g_signal_connect (menu_item, "activate",
1432 G_CALLBACK (fm_tree_view_trash_cb),
1433 view);
1434 gtk_widget_show (menu_item);
1435 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1436 view->details->popup_trash = menu_item;
1437
1438 /* add the "delete" menu item */
1439 menu_image = gtk_image_new_from_icon_name (NEMO_ICON_DELETE,
1440 GTK_ICON_SIZE_MENU);
1441 gtk_widget_show (menu_image);
1442 menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Delete"));
1443 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
1444 menu_image);
1445 g_signal_connect (menu_item, "activate",
1446 G_CALLBACK (fm_tree_view_delete_cb),
1447 view);
1448 gtk_widget_show (menu_item);
1449 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1450 view->details->popup_delete = menu_item;
1451
1452 /* Nemo Actions */
1453
1454 view->details->popup_action_separator =
1455 GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (popup)));
1456
1457 eel_gtk_menu_append_separator (GTK_MENU (popup));
1458
1459 /* add the "Unmount" menu item */
1460 menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Unmount"));
1461 g_signal_connect (menu_item, "activate",
1462 G_CALLBACK (fm_tree_view_unmount_cb),
1463 view);
1464 gtk_widget_show (menu_item);
1465 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1466 view->details->popup_unmount = menu_item;
1467
1468 /* add the "Eject" menu item */
1469 menu_item = gtk_image_menu_item_new_with_mnemonic (_("_Eject"));
1470 g_signal_connect (menu_item, "activate",
1471 G_CALLBACK (fm_tree_view_eject_cb),
1472 view);
1473 gtk_widget_show (menu_item);
1474 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1475 view->details->popup_eject = menu_item;
1476
1477 /* add the unmount separator menu item */
1478 view->details->popup_unmount_separator =
1479 GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (popup)));
1480
1481 /* add the "properties" menu item */
1482 menu_image = gtk_image_new_from_icon_name ("document-properties-symbolic", GTK_ICON_SIZE_MENU);
1483 gtk_widget_show (menu_image);
1484 menu_item = gtk_image_menu_item_new_with_mnemonic (_("P_roperties"));
1485 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image);
1486 g_signal_connect (menu_item, "activate",
1487 G_CALLBACK (fm_tree_view_properties_cb),
1488 view);
1489 gtk_widget_show (menu_item);
1490 gtk_menu_shell_append (GTK_MENU_SHELL (popup), menu_item);
1491 view->details->popup_properties = menu_item;
1492
1493 view->details->popup = popup;
1494
1495 add_action_popup_items (view);
1496 }
1497
1498 static gint
get_icon_scale_callback(FMTreeModel * model,FMTreeView * view)1499 get_icon_scale_callback (FMTreeModel *model,
1500 FMTreeView *view)
1501 {
1502 return gtk_widget_get_scale_factor (GTK_WIDGET (view->details->tree_widget));
1503 }
1504
1505 static void
icon_data_func(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,gpointer data)1506 icon_data_func (GtkTreeViewColumn *tree_column,
1507 GtkCellRenderer *cell,
1508 GtkTreeModel *tree_model,
1509 GtkTreeIter *iter,
1510 gpointer data)
1511 {
1512 gboolean expanded;
1513 GIcon *icon;
1514
1515 g_object_get (cell,
1516 "is-expanded", &expanded,
1517 NULL);
1518
1519 gtk_tree_model_get (tree_model, iter,
1520 expanded ? FM_TREE_MODEL_OPEN_ICON_COLUMN : FM_TREE_MODEL_CLOSED_ICON_COLUMN,
1521 &icon,
1522 -1);
1523
1524 g_object_set (cell,
1525 "gicon", icon,
1526 NULL);
1527 }
1528
1529 static void
create_tree(FMTreeView * view)1530 create_tree (FMTreeView *view)
1531 {
1532 GtkCellRenderer *cell;
1533 GtkTreeViewColumn *column;
1534 GVolumeMonitor *volume_monitor;
1535 char *home_uri;
1536 GList *mounts, *l;
1537 char *location;
1538 GIcon *icon;
1539 NemoWindowSlot *slot;
1540
1541 view->details->child_model = fm_tree_model_new ();
1542 view->details->sort_model = GTK_TREE_MODEL_SORT
1543 (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (view->details->child_model)));
1544 view->details->tree_widget = GTK_TREE_VIEW
1545 (gtk_tree_view_new_with_model (GTK_TREE_MODEL (view->details->sort_model)));
1546 g_object_unref (view->details->sort_model);
1547
1548 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (view->details->tree_widget)),
1549 "NemoSidebar");
1550
1551 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (view->details->sort_model),
1552 compare_rows, view, NULL);
1553
1554 g_signal_connect_object (view->details->child_model, "row_loaded",
1555 G_CALLBACK (row_loaded_callback),
1556 view, G_CONNECT_AFTER);
1557 g_signal_connect_object (view->details->child_model, "get-icon-scale",
1558 G_CALLBACK (get_icon_scale_callback), view, 0);
1559
1560 #ifdef NOT_YET_USABLE /* Do we really want this? */
1561 icon = g_themed_icon_new (NEMO_ICON_COMPUTER);
1562 fm_tree_model_add_root_uri (view->details->child_model, "computer:///", _("Computer"), icon, NULL);
1563 g_object_unref (icon);
1564 #endif
1565 home_uri = nemo_get_home_directory_uri ();
1566 icon = g_themed_icon_new (NEMO_ICON_HOME);
1567 fm_tree_model_add_root_uri (view->details->child_model, home_uri, _("Home"), icon, NULL);
1568 g_object_unref (icon);
1569 g_free (home_uri);
1570
1571 icon = g_themed_icon_new ("favorites");
1572 fm_tree_model_add_root_uri (view->details->child_model, "favorites:///", _("Favorites"), icon, NULL);
1573 g_object_unref (icon);
1574
1575 icon = g_themed_icon_new (NEMO_ICON_FILESYSTEM);
1576 fm_tree_model_add_root_uri (view->details->child_model, "file:///", _("File System"), icon, NULL);
1577 g_object_unref (icon);
1578 #ifdef NOT_YET_USABLE /* Do we really want this? */
1579 icon = g_themed_icon_new (NEMO_ICON_NETWORK);
1580 fm_tree_model_add_root_uri (view->details->child_model, "network:///", _("Network"), icon, NULL);
1581 g_object_unref (icon);
1582 #endif
1583
1584 volume_monitor = g_volume_monitor_get ();
1585 view->details->volume_monitor = volume_monitor;
1586 mounts = g_volume_monitor_get_mounts (volume_monitor);
1587 for (l = mounts; l != NULL; l = l->next) {
1588 add_root_for_mount (view, l->data);
1589 g_object_unref (l->data);
1590 }
1591 g_list_free (mounts);
1592
1593 g_signal_connect_object (volume_monitor, "mount_added",
1594 G_CALLBACK (mount_added_callback), view, 0);
1595 g_signal_connect_object (volume_monitor, "mount_removed",
1596 G_CALLBACK (mount_removed_callback), view, 0);
1597
1598 g_object_unref (view->details->child_model);
1599
1600 gtk_tree_view_set_headers_visible (view->details->tree_widget, FALSE);
1601
1602 view->details->drag_dest =
1603 nemo_tree_view_drag_dest_new (view->details->tree_widget);
1604 g_signal_connect_object (view->details->drag_dest,
1605 "get_root_uri",
1606 G_CALLBACK (get_root_uri_callback),
1607 view, 0);
1608 g_signal_connect_object (view->details->drag_dest,
1609 "get_file_for_path",
1610 G_CALLBACK (get_file_for_path_callback),
1611 view, 0);
1612 g_signal_connect_object (view->details->drag_dest,
1613 "move_copy_items",
1614 G_CALLBACK (move_copy_items_callback),
1615 view, 0);
1616
1617 view->details->action_manager = nemo_action_manager_new ();
1618
1619 view->details->action_manager_changed_id = g_signal_connect_swapped (view->details->action_manager,
1620 "changed",
1621 G_CALLBACK (actions_changed_callback),
1622 view);
1623
1624 view->details->action_items = NULL;
1625
1626 /* Create column */
1627 column = gtk_tree_view_column_new ();
1628
1629 cell = gtk_cell_renderer_pixbuf_new ();
1630 gtk_tree_view_column_pack_start (column, cell, FALSE);
1631
1632 gtk_tree_view_column_set_cell_data_func (column, cell,
1633 (GtkTreeCellDataFunc) icon_data_func,
1634 NULL, NULL);
1635
1636 g_object_set (cell,
1637 "follow-state", TRUE,
1638 NULL);
1639
1640 cell = gtk_cell_renderer_text_new ();
1641 gtk_tree_view_column_pack_start (column, cell, TRUE);
1642 gtk_tree_view_column_set_attributes (column, cell,
1643 "text", FM_TREE_MODEL_DISPLAY_NAME_COLUMN,
1644 "style", FM_TREE_MODEL_FONT_STYLE_COLUMN,
1645 "weight", FM_TREE_MODEL_TEXT_WEIGHT_COLUMN,
1646 NULL);
1647
1648 gtk_tree_view_append_column (view->details->tree_widget, column);
1649
1650 gtk_widget_show (GTK_WIDGET (view->details->tree_widget));
1651
1652 gtk_container_add (GTK_CONTAINER (view),
1653 GTK_WIDGET (view->details->tree_widget));
1654
1655 g_signal_connect_object (gtk_tree_view_get_selection (GTK_TREE_VIEW (view->details->tree_widget)), "changed",
1656 G_CALLBACK (selection_changed_callback), view, 0);
1657
1658 g_signal_connect (G_OBJECT (view->details->tree_widget),
1659 "row-activated", G_CALLBACK (row_activated_callback),
1660 view);
1661
1662 g_signal_connect (G_OBJECT (view->details->tree_widget),
1663 "button_press_event", G_CALLBACK (button_pressed_callback),
1664 view);
1665
1666 slot = nemo_window_get_active_slot (view->details->window);
1667 location = nemo_window_slot_get_current_uri (slot);
1668 schedule_select_and_show_location (view, location);
1669 g_free (location);
1670 }
1671
1672 static void
update_filtering_from_preferences(FMTreeView * view)1673 update_filtering_from_preferences (FMTreeView *view)
1674 {
1675 NemoWindowShowHiddenFilesMode mode;
1676
1677 if (view->details->child_model == NULL) {
1678 return;
1679 }
1680
1681 mode = nemo_window_get_hidden_files_mode (view->details->window);
1682
1683 fm_tree_model_set_show_hidden_files (view->details->child_model,
1684 mode == NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE);
1685
1686 fm_tree_model_set_show_only_directories (view->details->child_model,
1687 g_settings_get_boolean (nemo_tree_sidebar_preferences,
1688 NEMO_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES));
1689 }
1690
1691 static void
parent_set_callback(GtkWidget * widget,GtkWidget * previous_parent,gpointer callback_data)1692 parent_set_callback (GtkWidget *widget,
1693 GtkWidget *previous_parent,
1694 gpointer callback_data)
1695 {
1696 FMTreeView *view;
1697
1698 view = FM_TREE_VIEW (callback_data);
1699
1700 if (gtk_widget_get_parent (widget) != NULL && view->details->tree_widget == NULL) {
1701 create_tree (view);
1702 update_filtering_from_preferences (view);
1703 }
1704 }
1705
1706 static void
filtering_changed_callback(gpointer callback_data)1707 filtering_changed_callback (gpointer callback_data)
1708 {
1709 update_filtering_from_preferences (FM_TREE_VIEW (callback_data));
1710 }
1711
1712 static void
loading_uri_callback(NemoWindow * window,char * location,gpointer callback_data)1713 loading_uri_callback (NemoWindow *window,
1714 char *location,
1715 gpointer callback_data)
1716 {
1717 FMTreeView *view;
1718
1719 view = FM_TREE_VIEW (callback_data);
1720 schedule_select_and_show_location (view, location);
1721 }
1722
1723 static void
sort_directories_first_changed_callback(gpointer callback_data)1724 sort_directories_first_changed_callback (gpointer callback_data)
1725 {
1726 FMTreeView *view;
1727 gboolean preference_value;
1728
1729 view = FM_TREE_VIEW (callback_data);
1730
1731 preference_value = g_settings_get_boolean (nemo_preferences,
1732 NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST);
1733
1734 if (preference_value != view->details->sort_directories_first) {
1735 view->details->sort_directories_first = preference_value;
1736 }
1737
1738 gtk_tree_model_sort_reset_default_sort_func (GTK_TREE_MODEL_SORT (view->details->sort_model));
1739
1740 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (view->details->sort_model),
1741 compare_rows, view, NULL);
1742 }
1743
1744 static void
fm_tree_view_init(FMTreeView * view)1745 fm_tree_view_init (FMTreeView *view)
1746 {
1747 view->details = g_new0 (FMTreeViewDetails, 1);
1748
1749 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
1750 GTK_POLICY_AUTOMATIC,
1751 GTK_POLICY_AUTOMATIC);
1752 gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (view), NULL);
1753 gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (view), NULL);
1754 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view), GTK_SHADOW_IN);
1755
1756 gtk_widget_show (GTK_WIDGET (view));
1757
1758 g_signal_connect_object (view, "parent_set",
1759 G_CALLBACK (parent_set_callback), view, 0);
1760
1761 view->details->selection_location = NULL;
1762
1763 view->details->selecting = FALSE;
1764
1765 g_signal_connect_swapped (nemo_tree_sidebar_preferences,
1766 "changed::" NEMO_PREFERENCES_TREE_SHOW_ONLY_DIRECTORIES,
1767 G_CALLBACK (filtering_changed_callback), view);
1768
1769 g_signal_connect_swapped (nemo_preferences,
1770 "changed::" NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST,
1771 G_CALLBACK (sort_directories_first_changed_callback), view);
1772
1773 view->details->sort_directories_first = g_settings_get_boolean (nemo_preferences,
1774 NEMO_PREFERENCES_SORT_DIRECTORIES_FIRST);
1775
1776 view->details->popup_file = NULL;
1777
1778 view->details->clipboard_handler_id =
1779 g_signal_connect (nemo_clipboard_monitor_get (),
1780 "clipboard_info",
1781 G_CALLBACK (notify_clipboard_info), view);
1782 }
1783
1784 static void
hidden_files_mode_changed_callback(NemoWindow * window,FMTreeView * view)1785 hidden_files_mode_changed_callback (NemoWindow *window,
1786 FMTreeView *view)
1787 {
1788 update_filtering_from_preferences (view);
1789 }
1790
1791 static void
fm_tree_view_dispose(GObject * object)1792 fm_tree_view_dispose (GObject *object)
1793 {
1794 FMTreeView *view;
1795
1796 view = FM_TREE_VIEW (object);
1797
1798 if (view->details->selection_changed_timer) {
1799 g_source_remove (view->details->selection_changed_timer);
1800 view->details->selection_changed_timer = 0;
1801 }
1802
1803 if (view->details->drag_dest) {
1804 g_object_unref (view->details->drag_dest);
1805 view->details->drag_dest = NULL;
1806 }
1807
1808 if (view->details->show_selection_idle_id) {
1809 g_source_remove (view->details->show_selection_idle_id);
1810 view->details->show_selection_idle_id = 0;
1811 }
1812
1813 if (view->details->clipboard_handler_id != 0) {
1814 g_signal_handler_disconnect (nemo_clipboard_monitor_get (),
1815 view->details->clipboard_handler_id);
1816 view->details->clipboard_handler_id = 0;
1817 }
1818
1819 cancel_activation (view);
1820
1821 if (view->details->popup != NULL) {
1822 gtk_widget_destroy (view->details->popup);
1823 view->details->popup = NULL;
1824 }
1825
1826 if (view->details->popup_file_idle_handler != 0) {
1827 g_source_remove (view->details->popup_file_idle_handler);
1828 view->details->popup_file_idle_handler = 0;
1829 }
1830
1831 if (view->details->popup_file != NULL) {
1832 nemo_file_unref (view->details->popup_file);
1833 view->details->popup_file = NULL;
1834 }
1835
1836 if (view->details->selection_location != NULL) {
1837 g_free (view->details->selection_location);
1838 view->details->selection_location = NULL;
1839 }
1840
1841 if (view->details->volume_monitor != NULL) {
1842 g_object_unref (view->details->volume_monitor);
1843 view->details->volume_monitor = NULL;
1844 }
1845
1846 if (view->details->hidden_files_changed_id != 0) {
1847 g_signal_handler_disconnect (view->details->window,
1848 view->details->hidden_files_changed_id);
1849 view->details->hidden_files_changed_id = 0;
1850 }
1851
1852 if (view->details->action_manager_changed_id != 0) {
1853 g_signal_handler_disconnect (view->details->action_manager,
1854 view->details->action_manager_changed_id);
1855 view->details->action_manager_changed_id = 0;
1856 }
1857
1858 g_clear_object (&view->details->action_manager);
1859
1860 g_signal_handlers_disconnect_by_func (nemo_tree_sidebar_preferences,
1861 G_CALLBACK(filtering_changed_callback),
1862 view);
1863
1864 g_signal_handlers_disconnect_by_func (nemo_tree_sidebar_preferences,
1865 G_CALLBACK(sort_directories_first_changed_callback),
1866 view);
1867
1868 view->details->window = NULL;
1869
1870 G_OBJECT_CLASS (parent_class)->dispose (object);
1871 }
1872
1873 static void
fm_tree_view_finalize(GObject * object)1874 fm_tree_view_finalize (GObject *object)
1875 {
1876 FMTreeView *view;
1877
1878 view = FM_TREE_VIEW (object);
1879
1880 g_free (view->details);
1881
1882 G_OBJECT_CLASS (parent_class)->finalize (object);
1883 }
1884
1885 static void
fm_tree_view_class_init(FMTreeViewClass * class)1886 fm_tree_view_class_init (FMTreeViewClass *class)
1887 {
1888 G_OBJECT_CLASS (class)->dispose = fm_tree_view_dispose;
1889 G_OBJECT_CLASS (class)->finalize = fm_tree_view_finalize;
1890
1891 copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE);
1892 }
1893
1894 static void
fm_tree_view_set_parent_window(FMTreeView * sidebar,NemoWindow * window)1895 fm_tree_view_set_parent_window (FMTreeView *sidebar,
1896 NemoWindow *window)
1897 {
1898 char *location;
1899 NemoWindowSlot *slot;
1900
1901 sidebar->details->window = window;
1902
1903 slot = nemo_window_get_active_slot (window);
1904
1905 g_signal_connect_object (window, "loading_uri",
1906 G_CALLBACK (loading_uri_callback), sidebar, 0);
1907 location = nemo_window_slot_get_current_uri (slot);
1908 loading_uri_callback (window, location, sidebar);
1909 g_free (location);
1910
1911 sidebar->details->hidden_files_changed_id =
1912 g_signal_connect_object (window, "hidden-files-mode-changed",
1913 G_CALLBACK (hidden_files_mode_changed_callback), sidebar, 0);
1914
1915 }
1916
1917 GtkWidget *
nemo_tree_sidebar_new(NemoWindow * window)1918 nemo_tree_sidebar_new (NemoWindow *window)
1919 {
1920 FMTreeView *sidebar;
1921
1922 sidebar = g_object_new (fm_tree_view_get_type (), NULL);
1923 fm_tree_view_set_parent_window (sidebar, window);
1924
1925 return GTK_WIDGET (sidebar);
1926 }
1927