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