1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  Nemo
5  *
6  *  Copyright (C) 1999, 2000, 2004 Red Hat, Inc.
7  *  Copyright (C) 1999, 2000, 2001 Eazel, Inc.
8  *
9  *  Nemo is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2 of the License, or (at your option) any later version.
13  *
14  *  Nemo is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public
20  *  License along with this program; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Suite 500, MA 02110-1335, USA.
22  *
23  *  Authors: Elliot Lee <sopwith@redhat.com>
24  *  	     John Sullivan <sullivan@eazel.com>
25  *           Alexander Larsson <alexl@redhat.com>
26  */
27 
28 /* nemo-window.c: Implementation of the main window object */
29 
30 #include <config.h>
31 
32 #include "nemo-window-private.h"
33 
34 #include "nemo-actions.h"
35 #include "nemo-application.h"
36 #include "nemo-bookmarks-window.h"
37 #include "nemo-location-bar.h"
38 #include "nemo-mime-actions.h"
39 #include "nemo-notebook.h"
40 #include "nemo-places-sidebar.h"
41 #include "nemo-tree-sidebar.h"
42 #include "nemo-view-factory.h"
43 #include "nemo-window-manage-views.h"
44 #include "nemo-window-bookmarks.h"
45 #include "nemo-window-slot.h"
46 #include "nemo-window-menus.h"
47 #include "nemo-icon-view.h"
48 #include "nemo-list-view.h"
49 #include "nemo-statusbar.h"
50 
51 #include <eel/eel-debug.h>
52 #include <eel/eel-gtk-extensions.h>
53 #include <eel/eel-string.h>
54 #include <eel/eel-vfs-extensions.h>
55 
56 #include <gdk-pixbuf/gdk-pixbuf.h>
57 #include <gdk/gdkx.h>
58 #include <gdk/gdkkeysyms.h>
59 #include <gtk/gtk.h>
60 #include <glib/gi18n.h>
61 #ifdef HAVE_X11_XF86KEYSYM_H
62 #include <X11/XF86keysym.h>
63 #endif
64 #include <libnemo-private/nemo-file-utilities.h>
65 #include <libnemo-private/nemo-file-attributes.h>
66 #include <libnemo-private/nemo-global-preferences.h>
67 #include <libnemo-private/nemo-metadata.h>
68 #include <libnemo-private/nemo-clipboard.h>
69 #include <libnemo-private/nemo-undo.h>
70 #include <libnemo-private/nemo-search-directory.h>
71 #include <libnemo-private/nemo-signaller.h>
72 
73 #define DEBUG_FLAG NEMO_DEBUG_WINDOW
74 #include <libnemo-private/nemo-debug.h>
75 
76 #include <math.h>
77 #include <sys/time.h>
78 
79 #define MAX_TITLE_LENGTH 180
80 
81 /* Forward and back buttons on the mouse */
82 static gboolean mouse_extra_buttons = TRUE;
83 static guint mouse_forward_button = 9;
84 static guint mouse_back_button = 8;
85 
86 static void mouse_back_button_changed		     (gpointer                  callback_data);
87 static void mouse_forward_button_changed	     (gpointer                  callback_data);
88 static void use_extra_mouse_buttons_changed          (gpointer              callback_data);
89 static void side_pane_id_changed                    (NemoWindow            *window);
90 static void toggle_menubar                          (NemoWindow            *window,
91                                                      gint                   action);
92 static void nemo_window_reload                      (NemoWindow            *window);
93 
94 /* Sanity check: highest mouse button value I could find was 14. 5 is our
95  * lower threshold (well-documented to be the one of the button events for the
96  * scrollwheel), so it's hardcoded in the functions below. However, if you have
97  * a button that registers higher and want to map it, file a bug and
98  * we'll move the bar. Makes you wonder why the X guys don't have
99  * defined values for these like the XKB stuff, huh?
100  */
101 #define UPPER_MOUSE_LIMIT 14
102 
103 enum {
104 	PROP_DISABLE_CHROME = 1,
105     PROP_SIDEBAR_VIEW_TYPE,
106     PROP_SHOW_SIDEBAR,
107 	NUM_PROPERTIES,
108 };
109 
110 enum {
111 	GO_UP,
112 	RELOAD,
113 	PROMPT_FOR_LOCATION,
114 	LOADING_URI,
115 	HIDDEN_FILES_MODE_CHANGED,
116 	SLOT_ADDED,
117 	SLOT_REMOVED,
118 	LAST_SIGNAL
119 };
120 
121 enum {
122     MENU_HIDE,
123     MENU_SHOW,
124     MENU_TOGGLE
125 };
126 
127 static guint signals[LAST_SIGNAL] = { 0 };
128 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
129 
130 G_DEFINE_TYPE (NemoWindow, nemo_window, GTK_TYPE_APPLICATION_WINDOW);
131 
132 static const struct {
133 	unsigned int keyval;
134 	const char *action;
135 } extra_window_keybindings [] = {
136 #ifdef HAVE_X11_XF86KEYSYM_H
137 	{ XF86XK_AddFavorite,	NEMO_ACTION_ADD_BOOKMARK },
138 	{ XF86XK_Favorites,	NEMO_ACTION_EDIT_BOOKMARKS },
139 	{ XF86XK_Go,		NEMO_ACTION_EDIT_LOCATION },
140 	{ XF86XK_HomePage,      NEMO_ACTION_GO_HOME },
141 	{ XF86XK_OpenURL,	NEMO_ACTION_EDIT_LOCATION },
142 	{ XF86XK_Refresh,	NEMO_ACTION_RELOAD },
143 	{ XF86XK_Reload,	NEMO_ACTION_RELOAD },
144 	{ XF86XK_Search,	NEMO_ACTION_SEARCH },
145 	{ XF86XK_Start,		NEMO_ACTION_GO_HOME },
146 	{ XF86XK_Stop,		NEMO_ACTION_STOP },
147 	{ XF86XK_ZoomIn,	NEMO_ACTION_ZOOM_IN },
148 	{ XF86XK_ZoomOut,	NEMO_ACTION_ZOOM_OUT },
149 	{ XF86XK_Back,		NEMO_ACTION_BACK },
150 	{ XF86XK_Forward,	NEMO_ACTION_FORWARD }
151 
152 #endif
153 };
154 
155 void
nemo_window_push_status(NemoWindow * window,const char * text)156 nemo_window_push_status (NemoWindow *window,
157 			     const char *text)
158 {
159 	g_return_if_fail (NEMO_IS_WINDOW (window));
160 
161 	/* clear any previous message, underflow is allowed */
162 	gtk_statusbar_pop (GTK_STATUSBAR (window->details->statusbar), 0);
163 
164 	if (text != NULL && text[0] != '\0') {
165 		gtk_statusbar_push (GTK_STATUSBAR (window->details->statusbar), 0, text);
166 	}
167 }
168 
169 void
nemo_window_go_to(NemoWindow * window,GFile * location)170 nemo_window_go_to (NemoWindow *window, GFile *location)
171 {
172 	g_return_if_fail (NEMO_IS_WINDOW (window));
173 
174 	nemo_window_slot_open_location (nemo_window_get_active_slot (window),
175 					    location, 0);
176 }
177 
178 void
nemo_window_go_to_tab(NemoWindow * window,GFile * location)179 nemo_window_go_to_tab (NemoWindow *window, GFile *location)
180 {
181 	g_return_if_fail (NEMO_IS_WINDOW (window));
182 
183 	nemo_window_slot_open_location (nemo_window_get_active_slot (window),
184 					    location, NEMO_WINDOW_OPEN_FLAG_NEW_TAB);
185 }
186 
187 void
nemo_window_go_to_full(NemoWindow * window,GFile * location,NemoWindowGoToCallback callback,gpointer user_data)188 nemo_window_go_to_full (NemoWindow *window,
189 			    GFile          *location,
190 			    NemoWindowGoToCallback callback,
191 			    gpointer        user_data)
192 {
193 	g_return_if_fail (NEMO_IS_WINDOW (window));
194 
195 	nemo_window_slot_open_location_full (nemo_window_get_active_slot (window),
196 						 location, 0, NULL, callback, user_data);
197 }
198 
199 static void
nemo_window_go_up_signal(NemoWindow * window)200 nemo_window_go_up_signal (NemoWindow *window)
201 {
202 	nemo_window_slot_go_up (nemo_window_get_active_slot (window), 0);
203 }
204 
205 void
nemo_window_slot_removed(NemoWindow * window,NemoWindowSlot * slot)206 nemo_window_slot_removed (NemoWindow *window,  NemoWindowSlot *slot)
207 {
208 	g_signal_emit (window, signals[SLOT_REMOVED], 0, slot);
209 }
210 
211 void
nemo_window_slot_added(NemoWindow * window,NemoWindowSlot * slot)212 nemo_window_slot_added (NemoWindow *window,  NemoWindowSlot *slot)
213 {
214     g_signal_emit (window, signals[SLOT_ADDED], 0, slot);
215 }
216 
217 void
nemo_window_new_tab(NemoWindow * window)218 nemo_window_new_tab (NemoWindow *window)
219 {
220 	NemoWindowSlot *current_slot;
221 	NemoWindowSlot *new_slot;
222 	NemoWindowOpenFlags flags;
223 	GFile *location;
224 	int new_slot_position;
225 	char *scheme;
226 
227 	current_slot = nemo_window_get_active_slot (window);
228 	location = nemo_window_slot_get_location (current_slot);
229 
230 	if (location != NULL) {
231 		flags = 0;
232 
233 		new_slot_position = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_NEW_TAB_POSITION);
234 		if (new_slot_position == NEMO_NEW_TAB_POSITION_END) {
235 			flags = NEMO_WINDOW_OPEN_SLOT_APPEND;
236 		}
237 
238 		scheme = g_file_get_uri_scheme (location);
239 		if (!strcmp (scheme, "x-nemo-search")) {
240 			g_object_unref (location);
241 			location = g_file_new_for_path (g_get_home_dir ());
242 		}
243 		g_free (scheme);
244 
245 		new_slot = nemo_window_pane_open_slot (current_slot->pane, flags);
246 		nemo_window_set_active_slot (window, new_slot);
247 		nemo_window_slot_open_location (new_slot, location, 0);
248 		g_object_unref (location);
249 	}
250 }
251 
252 static void
update_cursor(NemoWindow * window)253 update_cursor (NemoWindow *window)
254 {
255 	NemoWindowSlot *slot;
256 	GdkCursor *cursor;
257 
258 	slot = nemo_window_get_active_slot (window);
259 
260 	if (slot && slot->allow_stop) {
261 		cursor = gdk_cursor_new (GDK_WATCH);
262                 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
263 		g_object_unref (cursor);
264 	} else {
265                 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
266         }
267 }
268 
269 void
nemo_window_sync_allow_stop(NemoWindow * window,NemoWindowSlot * slot)270 nemo_window_sync_allow_stop (NemoWindow *window,
271 				 NemoWindowSlot *slot)
272 {
273 	GtkAction *stop_action;
274 	GtkAction *reload_action;
275 	gboolean allow_stop, slot_is_active;
276 	NemoNotebook *notebook;
277 
278 	stop_action = gtk_action_group_get_action (nemo_window_get_main_action_group (window),
279 						   NEMO_ACTION_STOP);
280 	reload_action = gtk_action_group_get_action (nemo_window_get_main_action_group (window),
281 						     NEMO_ACTION_RELOAD);
282 	allow_stop = gtk_action_get_sensitive (stop_action);
283 
284 	slot_is_active = (slot == nemo_window_get_active_slot (window));
285 
286 	if (!slot_is_active ||
287 	    allow_stop != slot->allow_stop) {
288 		if (slot_is_active) {
289 			gtk_action_set_visible (stop_action, slot->allow_stop);
290 			gtk_action_set_visible (reload_action, !slot->allow_stop);
291 		}
292 
293 		if (gtk_widget_get_realized (GTK_WIDGET (window))) {
294 			update_cursor (window);
295 		}
296 
297 
298 		notebook = NEMO_NOTEBOOK (slot->pane->notebook);
299 		nemo_notebook_sync_loading (notebook, slot);
300 	}
301 }
302 
303 static void
nemo_window_prompt_for_location(NemoWindow * window,const char * initial)304 nemo_window_prompt_for_location (NemoWindow *window,
305 				     const char     *initial)
306 {
307 	NemoWindowPane *pane;
308 
309 	g_return_if_fail (NEMO_IS_WINDOW (window));
310 
311 	if (initial) {
312 		nemo_window_show_location_entry(window);
313 		pane = window->details->active_pane;
314 		nemo_location_bar_set_location (NEMO_LOCATION_BAR (pane->location_bar),
315 						    initial);
316 	}
317 }
318 
319 /* Code should never force the window taller than this size.
320  * (The user can still stretch the window taller if desired).
321  */
322 static guint
get_max_forced_height(GdkScreen * screen)323 get_max_forced_height (GdkScreen *screen)
324 {
325 	return (gdk_screen_get_height (screen) * 90) / 100;
326 }
327 
328 /* Code should never force the window wider than this size.
329  * (The user can still stretch the window wider if desired).
330  */
331 static guint
get_max_forced_width(GdkScreen * screen)332 get_max_forced_width (GdkScreen *screen)
333 {
334 	return (gdk_screen_get_width (screen) * 90) / 100;
335 }
336 
337 /* This must be called when construction of NemoWindow is finished,
338  * since it depends on the type of the argument, which isn't decided at
339  * construction time.
340  */
341 static void
nemo_window_set_initial_window_geometry(NemoWindow * window)342 nemo_window_set_initial_window_geometry (NemoWindow *window)
343 {
344 	GdkScreen *screen;
345 	guint max_width_for_screen, max_height_for_screen;
346 	guint default_width, default_height;
347 
348 	screen = gtk_window_get_screen (GTK_WINDOW (window));
349 
350 	max_width_for_screen = get_max_forced_width (screen);
351 	max_height_for_screen = get_max_forced_height (screen);
352 
353 	default_width = NEMO_WINDOW_DEFAULT_WIDTH;
354 	default_height = NEMO_WINDOW_DEFAULT_HEIGHT;
355 
356 	gtk_window_set_default_size (GTK_WINDOW (window),
357 				     MIN (default_width,
358 				          max_width_for_screen),
359 				     MIN (default_height,
360 				          max_height_for_screen));
361 }
362 
363 static gboolean
save_sidebar_width_cb(gpointer user_data)364 save_sidebar_width_cb (gpointer user_data)
365 {
366 	NemoWindow *window = user_data;
367 
368 	window->details->sidebar_width_handler_id = 0;
369 
370 	DEBUG ("Saving sidebar width: %d", window->details->side_pane_width);
371 
372 	g_settings_set_int (nemo_window_state,
373 			    NEMO_WINDOW_STATE_SIDEBAR_WIDTH,
374 			    window->details->side_pane_width);
375 
376 	return FALSE;
377 }
378 
379 /* side pane helpers */
380 static void
side_pane_size_allocate_callback(GtkWidget * widget,GtkAllocation * allocation,gpointer user_data)381 side_pane_size_allocate_callback (GtkWidget *widget,
382 				  GtkAllocation *allocation,
383 				  gpointer user_data)
384 {
385 	NemoWindow *window;
386 
387 	window = user_data;
388 
389 	if (window->details->sidebar_width_handler_id != 0) {
390 		g_source_remove (window->details->sidebar_width_handler_id);
391 		window->details->sidebar_width_handler_id = 0;
392 	}
393 
394 	if (allocation->width != window->details->side_pane_width &&
395 	    allocation->width > 1) {
396 		window->details->side_pane_width = allocation->width;
397 
398 		window->details->sidebar_width_handler_id =
399 			g_timeout_add (100, save_sidebar_width_cb, window);
400 	}
401 }
402 
403 static void
setup_side_pane_width(NemoWindow * window)404 setup_side_pane_width (NemoWindow *window)
405 {
406 	g_return_if_fail (window->details->sidebar != NULL);
407 
408 	window->details->side_pane_width =
409 		g_settings_get_int (nemo_window_state,
410 				    NEMO_WINDOW_STATE_SIDEBAR_WIDTH);
411 
412 	gtk_paned_set_position (GTK_PANED (window->details->content_paned),
413 				window->details->side_pane_width);
414 }
415 
416 static void
nemo_window_set_up_sidebar(NemoWindow * window)417 nemo_window_set_up_sidebar (NemoWindow *window)
418 {
419 	GtkWidget *sidebar;
420 
421 	DEBUG ("Setting up sidebar id %s", window->details->sidebar_id);
422 
423 	window->details->sidebar = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
424 	gtk_style_context_add_class (gtk_widget_get_style_context (window->details->sidebar),
425 				     GTK_STYLE_CLASS_SIDEBAR);
426 
427 	gtk_paned_pack1 (GTK_PANED (window->details->content_paned),
428 			 GTK_WIDGET (window->details->sidebar),
429 			 FALSE, FALSE);
430 
431 	setup_side_pane_width (window);
432 	g_signal_connect (window->details->sidebar,
433 			  "size_allocate",
434 			  G_CALLBACK (side_pane_size_allocate_callback),
435 			  window);
436 
437     g_signal_connect_object (NEMO_WINDOW (window), "notify::sidebar-view-id",
438                              G_CALLBACK (side_pane_id_changed), window, 0);
439 
440     if (g_strcmp0 (window->details->sidebar_id, NEMO_WINDOW_SIDEBAR_PLACES) == 0) {
441         sidebar = nemo_places_sidebar_new (window);
442     } else if (g_strcmp0 (window->details->sidebar_id, NEMO_WINDOW_SIDEBAR_TREE) == 0) {
443         sidebar = nemo_tree_sidebar_new (window);
444     } else {
445         g_assert_not_reached ();
446     }
447 
448 	gtk_box_pack_start (GTK_BOX (window->details->sidebar), sidebar, TRUE, TRUE, 0);
449 	gtk_widget_show (sidebar);
450 	gtk_widget_show (GTK_WIDGET (window->details->sidebar));
451 }
452 
453 static void
nemo_window_tear_down_sidebar(NemoWindow * window)454 nemo_window_tear_down_sidebar (NemoWindow *window)
455 {
456 	DEBUG ("Destroying sidebar");
457 
458     g_signal_handlers_disconnect_by_func (NEMO_WINDOW (window), side_pane_id_changed, window);
459 
460 	if (window->details->sidebar != NULL) {
461 		gtk_widget_destroy (GTK_WIDGET (window->details->sidebar));
462 		window->details->sidebar = NULL;
463 	}
464 }
465 
466 void
nemo_window_hide_sidebar(NemoWindow * window)467 nemo_window_hide_sidebar (NemoWindow *window)
468 {
469 	DEBUG ("Called hide_sidebar()");
470 
471 	if (window->details->sidebar == NULL) {
472 		return;
473 	}
474 
475 	nemo_window_tear_down_sidebar (window);
476 	nemo_window_update_show_hide_menu_items (window);
477 
478     nemo_window_set_show_sidebar (window, FALSE);
479 }
480 
481 void
nemo_window_show_sidebar(NemoWindow * window)482 nemo_window_show_sidebar (NemoWindow *window)
483 {
484 	DEBUG ("Called show_sidebar()");
485 
486 	if (window->details->sidebar != NULL) {
487 		return;
488 	}
489 
490 	if (window->details->disable_chrome) {
491 		return;
492 	}
493 
494 	nemo_window_set_up_sidebar (window);
495 	nemo_window_update_show_hide_menu_items (window);
496 
497     nemo_window_set_show_sidebar (window, TRUE);
498 }
499 
500 static gboolean
sidebar_id_is_valid(const gchar * sidebar_id)501 sidebar_id_is_valid (const gchar *sidebar_id)
502 {
503     return (g_strcmp0 (sidebar_id, NEMO_WINDOW_SIDEBAR_PLACES) == 0 ||
504             g_strcmp0 (sidebar_id, NEMO_WINDOW_SIDEBAR_TREE) == 0);
505 }
506 
507 static void
side_pane_id_changed(NemoWindow * window)508 side_pane_id_changed (NemoWindow *window)
509 {
510 
511     if (!sidebar_id_is_valid (window->details->sidebar_id)) {
512         return;
513     }
514 
515     /* refresh the sidebar setting */
516     nemo_window_tear_down_sidebar (window);
517     nemo_window_set_up_sidebar (window);
518 }
519 
520 gboolean
nemo_window_disable_chrome_mapping(GValue * value,GVariant * variant,gpointer user_data)521 nemo_window_disable_chrome_mapping (GValue *value,
522 					GVariant *variant,
523 					gpointer user_data)
524 {
525 	NemoWindow *window = user_data;
526 
527 	g_value_set_boolean (value,
528 			     g_variant_get_boolean (variant) &&
529 			     !window->details->disable_chrome);
530 
531 	return TRUE;
532 }
533 
534 static gboolean
on_button_press_callback(GtkWidget * widget,GdkEventButton * event,gpointer user_data)535 on_button_press_callback (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
536 {
537     NemoWindow *window = NEMO_WINDOW (user_data);
538 
539     if (event->button == 3) {
540         toggle_menubar (window, MENU_TOGGLE);
541     }
542 
543     return GDK_EVENT_STOP;
544 }
545 
546 static void
clear_menu_hide_delay(NemoWindow * window)547 clear_menu_hide_delay (NemoWindow *window)
548 {
549     if (window->details->menu_hide_delay_id > 0) {
550         g_source_remove (window->details->menu_hide_delay_id);
551     }
552 
553     window->details->menu_hide_delay_id = 0;
554 }
555 
556 static gboolean
hide_menu_on_delay(NemoWindow * window)557 hide_menu_on_delay (NemoWindow *window)
558 {
559     toggle_menubar (window, MENU_HIDE);
560 
561     window->details->menu_hide_delay_id = 0;
562     return FALSE;
563 }
564 
565 static gboolean
on_menu_focus_out(GtkWidget * widget,GdkEvent * event,gpointer user_data)566 on_menu_focus_out (GtkWidget *widget,
567                    GdkEvent  *event,
568                    gpointer   user_data)
569 {
570     NemoWindow *window = NEMO_WINDOW (user_data);
571 
572     /* The menu, when visible on demand, gets the keyboard grab.
573      * If the user clicks on some element in the window,, we want the menu
574      * to disappear, but if it's done immediately, everything shifts up the
575      * height of the menu, and the user will more than likely end up clicking
576      * in the wrong spot.  Delay the hide momentarily, to allow the user to
577      * complete their click action. */
578     clear_menu_hide_delay (window);
579 
580     window->details->menu_hide_delay_id = g_timeout_add (200, (GSourceFunc) hide_menu_on_delay, window);
581 
582     return GDK_EVENT_PROPAGATE;
583 }
584 
585 static void
nemo_window_constructed(GObject * self)586 nemo_window_constructed (GObject *self)
587 {
588 	NemoWindow *window;
589 	GtkWidget *grid;
590 	GtkWidget *menu;
591 	GtkWidget *hpaned;
592 	GtkWidget *vbox;
593 	GtkWidget *toolbar_holder;
594     GtkWidget *nemo_statusbar;
595 	NemoWindowPane *pane;
596 	NemoWindowSlot *slot;
597 	NemoApplication *application;
598 
599 	window = NEMO_WINDOW (self);
600 	application = nemo_application_get_singleton ();
601 
602 	G_OBJECT_CLASS (nemo_window_parent_class)->constructed (self);
603 	gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (application));
604 
605 	/* disable automatic menubar handling, since we show our regular
606 	 * menubar together with the app menu.
607 	 */
608 	gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (self), FALSE);
609 
610 	grid = gtk_grid_new ();
611 	gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
612 	gtk_widget_show (grid);
613 	gtk_container_add (GTK_CONTAINER (window), grid);
614 
615 	/* Statusbar is packed in the subclasses */
616 
617 	nemo_window_initialize_menus (window);
618 	nemo_window_initialize_actions (window);
619 
620 	menu = gtk_ui_manager_get_widget (window->details->ui_manager, "/MenuBar");
621 	window->details->menubar = menu;
622 
623     gtk_widget_set_can_focus (menu, TRUE);
624 	gtk_widget_set_hexpand (menu, TRUE);
625 
626     g_signal_connect_object (menu,
627                              "focus-out-event",
628                              G_CALLBACK (on_menu_focus_out),
629                              window,
630                              0);
631 
632 	if (g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR)){
633 		gtk_widget_show (menu);
634 	} else {
635 		gtk_widget_hide (menu);
636 	}
637 
638     g_settings_bind_with_mapping (nemo_window_state,
639                       NEMO_WINDOW_STATE_START_WITH_MENU_BAR,
640                       window->details->menubar,
641                       "visible",
642                       G_SETTINGS_BIND_GET,
643                       nemo_window_disable_chrome_mapping, NULL,
644                       window, NULL);
645 
646 	gtk_container_add (GTK_CONTAINER (grid), menu);
647 
648 	/* Set up the toolbar place holder */
649 	toolbar_holder = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
650 	gtk_container_add (GTK_CONTAINER (grid), toolbar_holder);
651 	gtk_widget_show (toolbar_holder);
652 
653     g_signal_connect_object (toolbar_holder, "button-press-event",
654                              G_CALLBACK (on_button_press_callback), window, 0);
655 
656 	window->details->toolbar_holder = toolbar_holder;
657 
658 	/* Register to menu provider extension signal managing menu updates */
659 	g_signal_connect_object (nemo_signaller_get_current (), "popup_menu_changed",
660 			 G_CALLBACK (nemo_window_load_extension_menus), window, G_CONNECT_SWAPPED);
661 
662 	window->details->content_paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
663 	gtk_widget_set_hexpand (window->details->content_paned, TRUE);
664 	gtk_widget_set_vexpand (window->details->content_paned, TRUE);
665 
666 	gtk_container_add (GTK_CONTAINER (grid), window->details->content_paned);
667 	gtk_widget_show (window->details->content_paned);
668 
669 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
670 	gtk_paned_pack2 (GTK_PANED (window->details->content_paned), vbox,
671 			 TRUE, FALSE);
672 	gtk_widget_show (vbox);
673 
674 	hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
675 	gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
676 	gtk_widget_show (hpaned);
677 	window->details->split_view_hpane = hpaned;
678 
679 	pane = nemo_window_pane_new (window);
680 	window->details->panes = g_list_prepend (window->details->panes, pane);
681 
682 	gtk_paned_pack1 (GTK_PANED (hpaned), GTK_WIDGET (pane), TRUE, FALSE);
683 
684 
685     nemo_statusbar = nemo_status_bar_new (window);
686     window->details->nemo_status_bar = nemo_statusbar;
687 
688     GtkWidget *sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
689     gtk_container_add (GTK_CONTAINER (grid), sep);
690     gtk_widget_show (sep);
691 
692     GtkWidget *eb;
693 
694     eb = gtk_event_box_new ();
695     gtk_container_add (GTK_CONTAINER (eb), nemo_statusbar);
696     gtk_container_add (GTK_CONTAINER (grid), eb);
697     gtk_widget_show (eb);
698 
699     window->details->statusbar = nemo_status_bar_get_real_statusbar (NEMO_STATUS_BAR (nemo_statusbar));
700     window->details->help_message_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->details->statusbar),
701                                                                       "help_message");
702 
703     gtk_widget_add_events (GTK_WIDGET (eb), GDK_BUTTON_PRESS_MASK);
704 
705     g_signal_connect_object (GTK_WIDGET (eb), "button-press-event",
706                              G_CALLBACK (on_button_press_callback), window, 0);
707 
708     g_settings_bind_with_mapping (nemo_window_state,
709                       NEMO_WINDOW_STATE_START_WITH_STATUS_BAR,
710                       window->details->nemo_status_bar,
711                       "visible",
712                       G_SETTINGS_BIND_DEFAULT,
713                       nemo_window_disable_chrome_mapping, NULL,
714                       window, NULL);
715 
716     g_object_bind_property (window->details->nemo_status_bar, "visible",
717                             sep, "visible",
718                             G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
719 
720 	/* this has to be done after the location bar has been set up,
721 	 * but before menu stuff is being called */
722 	nemo_window_set_active_pane (window, pane);
723 
724 	side_pane_id_changed (window);
725 
726 	nemo_window_initialize_bookmarks_menu (window);
727 	nemo_window_set_initial_window_geometry (window);
728 
729 	slot = nemo_window_pane_open_slot (window->details->active_pane, 0);
730 	nemo_window_set_active_slot (window, slot);
731 
732     if (g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_START_WITH_DUAL_PANE) &&
733         !window->details->disable_chrome)
734         nemo_window_split_view_on (window);
735 
736     g_signal_connect_swapped (GTK_WINDOW (window),
737                               "notify::scale-factor",
738                               G_CALLBACK (nemo_window_reload),
739                               window);
740 }
741 
742 static void
nemo_window_set_property(GObject * object,guint arg_id,const GValue * value,GParamSpec * pspec)743 nemo_window_set_property (GObject *object,
744 			      guint arg_id,
745 			      const GValue *value,
746 			      GParamSpec *pspec)
747 {
748 	NemoWindow *window;
749 
750 	window = NEMO_WINDOW (object);
751 
752 	switch (arg_id) {
753 	case PROP_DISABLE_CHROME:
754 		window->details->disable_chrome = g_value_get_boolean (value);
755 		break;
756     case PROP_SIDEBAR_VIEW_TYPE:
757         window->details->sidebar_id = g_strdup (g_value_get_string (value));
758         break;
759     case PROP_SHOW_SIDEBAR:
760         nemo_window_set_show_sidebar (window, g_value_get_boolean (value));
761         break;
762 	default:
763 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec);
764 		break;
765 	}
766 }
767 
768 static void
nemo_window_get_property(GObject * object,guint arg_id,GValue * value,GParamSpec * pspec)769 nemo_window_get_property (GObject *object,
770 			      guint arg_id,
771 			      GValue *value,
772 			      GParamSpec *pspec)
773 {
774 	NemoWindow *window;
775 
776 	window = NEMO_WINDOW (object);
777 
778 	switch (arg_id) {
779         case PROP_DISABLE_CHROME:
780             g_value_set_boolean (value, window->details->disable_chrome);
781             break;
782         case PROP_SIDEBAR_VIEW_TYPE:
783             g_value_set_string (value, window->details->sidebar_id);
784             break;
785         case PROP_SHOW_SIDEBAR:
786             g_value_set_boolean (value, window->details->show_sidebar);
787             break;
788         default:
789         	g_assert_not_reached ();
790         	break;
791 	}
792 }
793 
794 static void
destroy_panes_foreach(gpointer data,gpointer user_data)795 destroy_panes_foreach (gpointer data,
796 		       gpointer user_data)
797 {
798 	NemoWindowPane *pane = data;
799 	NemoWindow *window = user_data;
800 
801 	nemo_window_close_pane (window, pane);
802 }
803 
804 static void
nemo_window_destroy(GtkWidget * object)805 nemo_window_destroy (GtkWidget *object)
806 {
807 	NemoWindow *window;
808 	GList *panes_copy;
809 
810 	window = NEMO_WINDOW (object);
811 
812 	DEBUG ("Destroying window");
813 
814 	/* close the sidebar first */
815 	nemo_window_tear_down_sidebar (window);
816 
817 	/* close all panes safely */
818 	panes_copy = g_list_copy (window->details->panes);
819 	g_list_foreach (panes_copy, (GFunc) destroy_panes_foreach, window);
820 	g_list_free (panes_copy);
821 
822 	/* the panes list should now be empty */
823 	g_assert (window->details->panes == NULL);
824 	g_assert (window->details->active_pane == NULL);
825 
826 	GTK_WIDGET_CLASS (nemo_window_parent_class)->destroy (object);
827 }
828 
829 static void
nemo_window_finalize(GObject * object)830 nemo_window_finalize (GObject *object)
831 {
832 	NemoWindow *window;
833 
834 	window = NEMO_WINDOW (object);
835 
836 	if (window->details->sidebar_width_handler_id != 0) {
837 		g_source_remove (window->details->sidebar_width_handler_id);
838 		window->details->sidebar_width_handler_id = 0;
839 	}
840 
841     g_signal_handlers_disconnect_by_func (nemo_preferences,
842                                           nemo_window_sync_thumbnail_action,
843                                           window);
844 
845     clear_menu_hide_delay (window);
846 
847 	nemo_window_finalize_menus (window);
848 
849 	g_clear_object (&window->details->nav_state);
850 
851 	g_clear_object (&window->details->ui_manager);
852 
853 	g_free (window->details->sidebar_id);
854 
855 	/* nemo_window_close() should have run */
856 	g_assert (window->details->panes == NULL);
857 
858 	G_OBJECT_CLASS (nemo_window_parent_class)->finalize (object);
859 }
860 
861 void
nemo_window_view_visible(NemoWindow * window,NemoView * view)862 nemo_window_view_visible (NemoWindow *window,
863 			      NemoView *view)
864 {
865 	NemoWindowSlot *slot;
866 	NemoWindowPane *pane;
867 	GList *l, *walk;
868 
869 	g_return_if_fail (NEMO_IS_WINDOW (window));
870 
871 	slot = nemo_window_get_slot_for_view (window, view);
872 
873 	if (slot->visible) {
874 		return;
875 	}
876 
877 	slot->visible = TRUE;
878 	pane = slot->pane;
879 
880 	if (gtk_widget_get_visible (GTK_WIDGET (pane))) {
881 		return;
882 	}
883 
884 	/* Look for other non-visible slots */
885 	for (l = pane->slots; l != NULL; l = l->next) {
886 		slot = l->data;
887 
888 		if (!slot->visible) {
889 			return;
890 		}
891 	}
892 
893 	/* None, this pane is visible */
894 	gtk_widget_show (GTK_WIDGET (pane));
895 
896 	/* Look for other non-visible panes */
897 	for (walk = window->details->panes; walk; walk = walk->next) {
898 		pane = walk->data;
899 
900 		if (!gtk_widget_get_visible (GTK_WIDGET (pane))) {
901 			return;
902 		}
903 
904 		for (l = pane->slots; l != NULL; l = l->next) {
905 			slot = l->data;
906 
907 			nemo_window_slot_update_title (slot);
908 			nemo_window_slot_update_icon (slot);
909 		}
910 	}
911 
912 	nemo_window_pane_grab_focus (window->details->active_pane);
913 
914 	/* All slots and panes visible, show window */
915 	gtk_widget_show (GTK_WIDGET (window));
916 }
917 
918 static gboolean
nemo_window_is_desktop(NemoWindow * window)919 nemo_window_is_desktop (NemoWindow *window)
920 {
921     return window->details->disable_chrome;
922 }
923 
924 static void
nemo_window_save_geometry(NemoWindow * window)925 nemo_window_save_geometry (NemoWindow *window)
926 {
927 	char *geometry_string;
928 	gboolean is_maximized;
929 
930 	g_assert (NEMO_IS_WINDOW (window));
931 
932 	if (gtk_widget_get_window (GTK_WIDGET (window)) && !nemo_window_is_desktop (window)) {
933 		geometry_string = eel_gtk_window_get_geometry_string (GTK_WINDOW (window));
934 		is_maximized = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)))
935 				& GDK_WINDOW_STATE_MAXIMIZED;
936 
937 		if (!is_maximized) {
938 			g_settings_set_string
939 				(nemo_window_state, NEMO_WINDOW_STATE_GEOMETRY,
940 				 geometry_string);
941 		}
942 		g_free (geometry_string);
943 
944 		g_settings_set_boolean
945 			(nemo_window_state, NEMO_WINDOW_STATE_MAXIMIZED,
946 			 is_maximized);
947 	}
948 }
949 
950 void
nemo_window_close(NemoWindow * window)951 nemo_window_close (NemoWindow *window)
952 {
953 	NEMO_WINDOW_CLASS (G_OBJECT_GET_CLASS (window))->close (window);
954 }
955 
956 void
nemo_window_close_pane(NemoWindow * window,NemoWindowPane * pane)957 nemo_window_close_pane (NemoWindow *window,
958 			    NemoWindowPane *pane)
959 {
960 	g_assert (NEMO_IS_WINDOW_PANE (pane));
961 
962 	while (pane->slots != NULL) {
963 		NemoWindowSlot *slot = pane->slots->data;
964 
965 		nemo_window_pane_remove_slot_unsafe (pane, slot);
966 	}
967 
968 	/* If the pane was active, set it to NULL. The caller is responsible
969 	 * for setting a new active pane with nemo_window_set_active_pane()
970 	 * if it wants to continue using the window. */
971 	if (window->details->active_pane == pane) {
972 		window->details->active_pane = NULL;
973 	}
974 
975 	/* Required really. Destroying the NemoWindowPane still leaves behind the toolbar.
976 	 * This kills it off. Do it before we call gtk_widget_destroy for safety. */
977 	gtk_container_remove (GTK_CONTAINER (window->details->toolbar_holder), GTK_WIDGET (pane->tool_bar));
978 
979 	window->details->panes = g_list_remove (window->details->panes, pane);
980 
981 	gtk_widget_destroy (GTK_WIDGET (pane));
982 }
983 
984 NemoWindowPane*
nemo_window_get_active_pane(NemoWindow * window)985 nemo_window_get_active_pane (NemoWindow *window)
986 {
987 	g_assert (NEMO_IS_WINDOW (window));
988 	return window->details->active_pane;
989 }
990 
991 static void
real_set_active_pane(NemoWindow * window,NemoWindowPane * new_pane)992 real_set_active_pane (NemoWindow *window, NemoWindowPane *new_pane)
993 {
994 	/* make old pane inactive, and new one active.
995 	 * Currently active pane may be NULL (after init). */
996 	if (window->details->active_pane &&
997 	    window->details->active_pane != new_pane) {
998 		nemo_window_pane_set_active (window->details->active_pane, FALSE);
999 	}
1000 	nemo_window_pane_set_active (new_pane, TRUE);
1001 
1002 	window->details->active_pane = new_pane;
1003 }
1004 
1005 /* Make the given pane the active pane of its associated window. This
1006  * always implies making the containing active slot the active slot of
1007  * the window. */
1008 void
nemo_window_set_active_pane(NemoWindow * window,NemoWindowPane * new_pane)1009 nemo_window_set_active_pane (NemoWindow *window,
1010 				 NemoWindowPane *new_pane)
1011 {
1012 	g_assert (NEMO_IS_WINDOW_PANE (new_pane));
1013 
1014 	DEBUG ("Setting new pane %p as active", new_pane);
1015 
1016 	if (new_pane->active_slot) {
1017 		nemo_window_set_active_slot (window, new_pane->active_slot);
1018 	} else if (new_pane != window->details->active_pane) {
1019 		real_set_active_pane (window, new_pane);
1020 	}
1021 }
1022 
1023 /* Make both, the given slot the active slot and its corresponding
1024  * pane the active pane of the associated window.
1025  * new_slot may be NULL. */
1026 void
nemo_window_set_active_slot(NemoWindow * window,NemoWindowSlot * new_slot)1027 nemo_window_set_active_slot (NemoWindow *window, NemoWindowSlot *new_slot)
1028 {
1029 	NemoWindowSlot *old_slot;
1030 	g_assert (NEMO_IS_WINDOW (window));
1031 
1032 	DEBUG ("Setting new slot %p as active", new_slot);
1033 
1034 	if (new_slot) {
1035 		g_assert ((window == nemo_window_slot_get_window (new_slot)));
1036 		g_assert (NEMO_IS_WINDOW_PANE (new_slot->pane));
1037 		g_assert (g_list_find (new_slot->pane->slots, new_slot) != NULL);
1038 	}
1039 
1040 	old_slot = nemo_window_get_active_slot (window);
1041 
1042 	if (old_slot == new_slot) {
1043 		return;
1044 	}
1045 
1046 	/* make old slot inactive if it exists (may be NULL after init, for example) */
1047 	if (old_slot != NULL) {
1048 		/* inform window */
1049 		if (old_slot->content_view != NULL) {
1050 			nemo_window_disconnect_content_view (window, old_slot->content_view);
1051 		}
1052 		gtk_widget_hide (GTK_WIDGET (old_slot->pane->tool_bar));
1053 		/* inform slot & view */
1054 		g_signal_emit_by_name (old_slot, "inactive");
1055 	}
1056 
1057 	/* deal with panes */
1058 	if (new_slot &&
1059 	    new_slot->pane != window->details->active_pane) {
1060 		real_set_active_pane (window, new_slot->pane);
1061 	}
1062 
1063 	window->details->active_pane->active_slot = new_slot;
1064 
1065 	/* make new slot active, if it exists */
1066 	if (new_slot) {
1067 		/* inform sidebar panels */
1068                 nemo_window_report_location_change (window);
1069 		/* TODO decide whether "selection-changed" should be emitted */
1070 
1071 		if (new_slot->content_view != NULL) {
1072                         /* inform window */
1073                         nemo_window_connect_content_view (window, new_slot->content_view);
1074                 }
1075 
1076 		// Show active toolbar
1077 		gboolean show_toolbar;
1078 		show_toolbar = g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_TOOLBAR);
1079 
1080 		if ( show_toolbar) {
1081 			gtk_widget_show (GTK_WIDGET (new_slot->pane->tool_bar));
1082 		}
1083 
1084 		/* inform slot & view */
1085                 g_signal_emit_by_name (new_slot, "active");
1086 	}
1087 }
1088 
1089 static void
nemo_window_realize(GtkWidget * widget)1090 nemo_window_realize (GtkWidget *widget)
1091 {
1092 	GTK_WIDGET_CLASS (nemo_window_parent_class)->realize (widget);
1093 	update_cursor (NEMO_WINDOW (widget));
1094 }
1095 
1096 static void
toggle_menubar(NemoWindow * window,gint action)1097 toggle_menubar (NemoWindow *window, gint action)
1098 {
1099     GtkWidget *menu;
1100     gboolean default_visible;
1101 
1102     default_visible = g_settings_get_boolean (nemo_window_state,
1103                                               NEMO_WINDOW_STATE_START_WITH_MENU_BAR);
1104 
1105     if (default_visible || window->details->disable_chrome) {
1106         return;
1107     }
1108 
1109     menu = window->details->menubar;
1110 
1111     if (action == MENU_TOGGLE) {
1112         action = gtk_widget_get_visible (menu) ? MENU_HIDE : MENU_SHOW;
1113     }
1114 
1115     if (action == MENU_HIDE) {
1116         gtk_widget_hide (menu);
1117     } else {
1118         gtk_widget_show (menu);
1119 
1120         /* When the menu is normally hidden, have an activation of it trigger a key grab.
1121          * For keyboard users, this is a natural progression, that they will type a mnemonic
1122          * next to open a menu.  Any loss of focus or click elsewhere will re-hide the menu
1123          * and cancel focus.
1124          */
1125         gtk_widget_grab_focus (menu);
1126         gtk_window_set_mnemonics_visible (GTK_WINDOW (window), TRUE);
1127     }
1128 
1129     return;
1130 }
1131 
1132 static gboolean
is_alt_key_event(GdkEventKey * event)1133 is_alt_key_event (GdkEventKey *event)
1134 {
1135     GdkModifierType nominal_state;
1136     gboolean state_ok;
1137 
1138     nominal_state = event->state & gtk_accelerator_get_default_mod_mask();
1139 
1140     /* A key press of alt will show just the alt keyval (GDK_KEY_Alt_L/R).  A key release
1141      * of a single modifier is always modified by itself.  So a valid press state is 0 and
1142      * a valid release state is GDK_MOD1_MASK (alt modifier).
1143      */
1144     state_ok = (event->type == GDK_KEY_PRESS && nominal_state == 0) ||
1145                (event->type == GDK_KEY_RELEASE && nominal_state == GDK_MOD1_MASK);
1146 
1147     if (state_ok && (event->keyval == GDK_KEY_Alt_L || event->keyval == GDK_KEY_Alt_R)) {
1148         return TRUE;
1149     }
1150 
1151     return FALSE;
1152 }
1153 
1154 static gboolean
nemo_window_key_press_event(GtkWidget * widget,GdkEventKey * event)1155 nemo_window_key_press_event (GtkWidget *widget,
1156 				 GdkEventKey *event)
1157 {
1158 	NemoWindow *window;
1159 	NemoWindowSlot *active_slot;
1160 	NemoView *view;
1161 	GtkWidget *focus_widget;
1162 	size_t i;
1163 
1164 	window = NEMO_WINDOW (widget);
1165 
1166 	active_slot = nemo_window_get_active_slot (window);
1167 	view = active_slot->content_view;
1168 
1169 	if (view != NULL && nemo_view_get_is_renaming (view)) {
1170 		/* if we're renaming, just forward the event to the
1171 		 * focused widget and return. We don't want to process the window
1172 		 * accelerator bindings, as they might conflict with the
1173 		 * editable widget bindings.
1174 		 */
1175 		if (gtk_window_propagate_key_event (GTK_WINDOW (window), event)) {
1176 			return TRUE;
1177 		}
1178 
1179                /* Do not allow for other accelerator bindings to fire off while
1180                 *  renaming is in progress
1181                 */
1182                return FALSE;
1183 	}
1184 
1185 	focus_widget = gtk_window_get_focus (GTK_WINDOW (window));
1186 	if (view != NULL && focus_widget != NULL &&
1187 	    GTK_IS_EDITABLE (focus_widget)) {
1188 		/* if we have input focus on a GtkEditable (e.g. a GtkEntry), forward
1189 		 * the event to it before activating accelerator bindings too.
1190 		 */
1191 		if (gtk_window_propagate_key_event (GTK_WINDOW (window), event)) {
1192 			return TRUE;
1193 		}
1194 	}
1195 
1196 	for (i = 0; i < G_N_ELEMENTS (extra_window_keybindings); i++) {
1197 		if (extra_window_keybindings[i].keyval == event->keyval) {
1198 			const GList *action_groups;
1199 			GtkAction *action;
1200 
1201 			action = NULL;
1202 
1203 			action_groups = gtk_ui_manager_get_action_groups (window->details->ui_manager);
1204 			while (action_groups != NULL && action == NULL) {
1205 				action = gtk_action_group_get_action (action_groups->data, extra_window_keybindings[i].action);
1206 				action_groups = action_groups->next;
1207 			}
1208 
1209 			g_assert (action != NULL);
1210 			if (gtk_action_is_sensitive (action)) {
1211 				gtk_action_activate (action);
1212 				return TRUE;
1213 			}
1214 
1215 			break;
1216 		}
1217 	}
1218 
1219     /* An alt key press by itself will always hide the menu if it's visible.  We set a flag
1220      * to skip the subsequent release, otherwise we'll show the menu again.
1221      *
1222      * When alt is pressed and the menu is NOT visible, we flag that on release we'll show the
1223      * menu.  If any other keys are pressed between alt being pressed and released, we clear that
1224      * flag, because it was more than likely part of some other shortcut, and otherwise, depending
1225      * on the order the keys are released, if the alt key is last to be released, we don't want to
1226      * show the menu, as that was not the original intent.
1227      */
1228 
1229     if (is_alt_key_event (event)) {
1230         if (gtk_widget_get_visible (window->details->menubar)) {
1231             toggle_menubar (window, MENU_HIDE);
1232             window->details->menu_skip_release = TRUE;
1233         } else {
1234             window->details->menu_show_queued = TRUE;
1235         }
1236     } else {
1237         window->details->menu_show_queued = FALSE;
1238     }
1239 
1240 	return GTK_WIDGET_CLASS (nemo_window_parent_class)->key_press_event (widget, event);
1241 }
1242 
1243 static gboolean
nemo_window_key_release_event(GtkWidget * widget,GdkEventKey * event)1244 nemo_window_key_release_event (GtkWidget *widget,
1245                              GdkEventKey *event)
1246 {
1247     NemoWindow *window = NEMO_WINDOW (widget);
1248 
1249     /* Conditions to show the menu via the alt key is that it must have been pressed and
1250      * released without any other key events in between, and we must not have hidden the
1251      * menu on the alt key press event.  Show we check both flags here, for opposing states.
1252      */
1253 
1254     if (is_alt_key_event (event)) {
1255         if (!window->details->menu_skip_release && window->details->menu_show_queued) {
1256             toggle_menubar (window, MENU_SHOW);
1257         }
1258     }
1259 
1260     window->details->menu_skip_release = FALSE;
1261     window->details->menu_show_queued = FALSE;
1262 
1263     return GTK_WIDGET_CLASS (nemo_window_parent_class)->key_release_event (widget, event);
1264 }
1265 
1266 /*
1267  * Main API
1268  */
1269 
1270 static void
sync_view_type_callback(NemoFile * file,gpointer callback_data)1271 sync_view_type_callback (NemoFile *file,
1272                          gpointer callback_data)
1273 {
1274     NemoWindow *window;
1275     NemoWindowSlot *slot;
1276 
1277     slot = callback_data;
1278     window = nemo_window_slot_get_window (slot);
1279 
1280     if (slot == nemo_window_get_active_slot (window)) {
1281         NemoWindowPane *pane;
1282         const gchar *view_id;
1283 
1284         if (slot->content_view == NULL) {
1285             return;
1286         }
1287 
1288         pane = nemo_window_get_active_pane(window);
1289         view_id = nemo_window_slot_get_content_view_id (slot);
1290 
1291         toolbar_set_view_button (action_for_view_id (view_id), pane);
1292         menu_set_view_selection (action_for_view_id (view_id), window);
1293     }
1294 }
1295 
1296 static void
cancel_sync_view_type_callback(NemoWindowSlot * slot)1297 cancel_sync_view_type_callback (NemoWindowSlot *slot)
1298 {
1299 	nemo_file_cancel_call_when_ready (slot->viewed_file,
1300 					      sync_view_type_callback,
1301 					      slot);
1302 }
1303 
1304 void
nemo_window_sync_view_type(NemoWindow * window)1305 nemo_window_sync_view_type (NemoWindow *window)
1306 {
1307     NemoWindowSlot *slot;
1308     NemoFileAttributes attributes;
1309 
1310     g_return_if_fail (NEMO_IS_WINDOW (window));
1311 
1312     attributes = nemo_mime_actions_get_required_file_attributes ();
1313 
1314     slot = nemo_window_get_active_slot (window);
1315 
1316     cancel_sync_view_type_callback (slot);
1317     nemo_file_call_when_ready (slot->viewed_file,
1318                                attributes,
1319                                sync_view_type_callback,
1320                                slot);
1321 }
1322 
1323 void
nemo_window_sync_menu_bar(NemoWindow * window)1324 nemo_window_sync_menu_bar (NemoWindow *window)
1325 {
1326     GtkWidget *menu = window->details->menubar;
1327 
1328     if (g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_MENU_BAR) &&
1329                                 !window->details->disable_chrome) {
1330         gtk_widget_show (menu);
1331     } else {
1332         gtk_widget_hide (menu);
1333     }
1334 }
1335 
1336 void
nemo_window_sync_up_button(NemoWindow * window)1337 nemo_window_sync_up_button (NemoWindow *window)
1338 {
1339 	GtkAction *action;
1340 	GtkActionGroup *action_group;
1341 	NemoWindowSlot *slot;
1342 	gboolean allowed;
1343 	GFile *parent;
1344 
1345 	slot = nemo_window_get_active_slot (window);
1346 
1347 	allowed = FALSE;
1348 	if (slot->location != NULL) {
1349 		parent = g_file_get_parent (slot->location);
1350 		allowed = parent != NULL;
1351 
1352 		g_clear_object (&parent);
1353 	}
1354 
1355 	action_group = nemo_window_get_main_action_group (window);
1356 
1357 	action = gtk_action_group_get_action (action_group,
1358 					      NEMO_ACTION_UP);
1359 	gtk_action_set_sensitive (action, allowed);
1360 	action = gtk_action_group_get_action (action_group,
1361 					      NEMO_ACTION_UP_ACCEL);
1362 	gtk_action_set_sensitive (action, allowed);
1363 }
1364 
1365 void
nemo_window_sync_title(NemoWindow * window,NemoWindowSlot * slot)1366 nemo_window_sync_title (NemoWindow *window,
1367 			    NemoWindowSlot *slot)
1368 {
1369 	NemoWindowPane *pane;
1370 	NemoNotebook *notebook;
1371 	char *full_title;
1372 	char *window_title;
1373 
1374 	if (NEMO_WINDOW_CLASS (G_OBJECT_GET_CLASS (window))->sync_title != NULL) {
1375 		NEMO_WINDOW_CLASS (G_OBJECT_GET_CLASS (window))->sync_title (window, slot);
1376 
1377 		return;
1378 	}
1379 
1380 	if (slot == nemo_window_get_active_slot (window)) {
1381 		/* if spatial mode is default, we keep "File Browser" in the window title
1382 		 * to recognize browser windows. Otherwise, we default to the directory name.
1383 		 */
1384 		if (!g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER)) {
1385 			full_title = g_strdup_printf (_("%s - File Browser"), slot->title);
1386 			window_title = eel_str_middle_truncate (full_title, MAX_TITLE_LENGTH);
1387 			g_free (full_title);
1388 		} else {
1389 			window_title = eel_str_middle_truncate (slot->title, MAX_TITLE_LENGTH);
1390 		}
1391 
1392 		gtk_window_set_title (GTK_WINDOW (window), window_title);
1393 		g_free (window_title);
1394 	}
1395 
1396 	pane = slot->pane;
1397 	notebook = NEMO_NOTEBOOK (pane->notebook);
1398 	nemo_notebook_sync_tab_label (notebook, slot);
1399 }
1400 
1401 void
nemo_window_sync_zoom_widgets(NemoWindow * window)1402 nemo_window_sync_zoom_widgets (NemoWindow *window)
1403 {
1404 	NemoWindowSlot *slot;
1405 	NemoView *view;
1406 	GtkActionGroup *action_group;
1407 	GtkAction *action;
1408 	gboolean supports_zooming;
1409 	gboolean can_zoom, can_zoom_in, can_zoom_out;
1410 	NemoZoomLevel zoom_level;
1411 
1412 	slot = nemo_window_get_active_slot (window);
1413 	view = slot->content_view;
1414 
1415 	if (view != NULL) {
1416 		supports_zooming = nemo_view_supports_zooming (view);
1417 		zoom_level = nemo_view_get_zoom_level (view);
1418 		can_zoom = supports_zooming &&
1419 			   zoom_level >= NEMO_ZOOM_LEVEL_SMALLEST &&
1420 			   zoom_level <= NEMO_ZOOM_LEVEL_LARGEST;
1421 		can_zoom_in = can_zoom && nemo_view_can_zoom_in (view);
1422 		can_zoom_out = can_zoom && nemo_view_can_zoom_out (view);
1423 	} else {
1424 		supports_zooming = FALSE;
1425 		can_zoom = FALSE;
1426 		can_zoom_in = FALSE;
1427 		can_zoom_out = FALSE;
1428 	}
1429 
1430 	action_group = nemo_window_get_main_action_group (window);
1431 
1432 	action = gtk_action_group_get_action (action_group,
1433 					      NEMO_ACTION_ZOOM_IN);
1434 	gtk_action_set_visible (action, supports_zooming);
1435 	gtk_action_set_sensitive (action, can_zoom_in);
1436 
1437 	action = gtk_action_group_get_action (action_group,
1438 					      NEMO_ACTION_ZOOM_OUT);
1439 	gtk_action_set_visible (action, supports_zooming);
1440 	gtk_action_set_sensitive (action, can_zoom_out);
1441 
1442 	action = gtk_action_group_get_action (action_group,
1443 					      NEMO_ACTION_ZOOM_NORMAL);
1444 	gtk_action_set_visible (action, supports_zooming);
1445 	gtk_action_set_sensitive (action, can_zoom);
1446 
1447     nemo_status_bar_sync_zoom_widgets (NEMO_STATUS_BAR (window->details->nemo_status_bar));
1448 }
1449 
1450 void
nemo_window_sync_bookmark_action(NemoWindow * window)1451 nemo_window_sync_bookmark_action (NemoWindow *window)
1452 {
1453     NemoWindowSlot *slot;
1454     GFile *location;
1455     GtkAction *action;
1456     gchar *uri;
1457     slot = nemo_window_get_active_slot (window);
1458     location = nemo_window_slot_get_location (slot);
1459 
1460     if (!location) {
1461         return;
1462     }
1463 
1464     uri = g_file_get_uri (location);
1465 
1466     action = gtk_action_group_get_action (nemo_window_get_main_action_group (window),
1467                                           NEMO_ACTION_ADD_BOOKMARK);
1468 
1469     gtk_action_set_sensitive (action, !eel_uri_is_search (uri));
1470 
1471     g_free (uri);
1472     g_object_unref (location);
1473 }
1474 
1475 void
sync_thumbnail_action_callback(NemoFile * file,gpointer callback_data)1476 sync_thumbnail_action_callback (NemoFile *file,
1477                        gpointer callback_data)
1478 {
1479     NemoWindow *window;
1480     NemoWindowSlot *slot;
1481 
1482     slot = callback_data;
1483     window = nemo_window_slot_get_window (slot);
1484 
1485     if (slot == nemo_window_get_active_slot (window)) {
1486         NemoWindowPane *pane;
1487         gboolean show_thumbnails;
1488 
1489         pane = nemo_window_get_active_pane(window);
1490         show_thumbnails = nemo_file_should_show_thumbnail (file);
1491 
1492         toolbar_set_show_thumbnails_button (show_thumbnails, pane);
1493         menu_set_show_thumbnails_action (show_thumbnails, window);
1494     }
1495 }
1496 
1497 static void
cancel_sync_show_thumbnail_callback(NemoWindowSlot * slot)1498 cancel_sync_show_thumbnail_callback (NemoWindowSlot *slot)
1499 {
1500 	nemo_file_cancel_call_when_ready (slot->viewed_file,
1501 					      sync_thumbnail_action_callback,
1502 					      slot);
1503 }
1504 
1505 void
nemo_window_sync_thumbnail_action(NemoWindow * window)1506 nemo_window_sync_thumbnail_action (NemoWindow *window)
1507 {
1508     NemoWindowSlot *slot;
1509     NemoFileAttributes attributes;
1510 
1511     g_return_if_fail (NEMO_IS_WINDOW (window));
1512 
1513     attributes = nemo_mime_actions_get_required_file_attributes ();
1514 
1515     slot = nemo_window_get_active_slot (window);
1516 
1517     cancel_sync_show_thumbnail_callback (slot);
1518     nemo_file_call_when_ready (slot->viewed_file,
1519                                attributes,
1520                                sync_thumbnail_action_callback,
1521                                slot);
1522 }
1523 
1524 static void
zoom_level_changed_callback(NemoView * view,NemoWindow * window)1525 zoom_level_changed_callback (NemoView *view,
1526                              NemoWindow *window)
1527 {
1528 	g_assert (NEMO_IS_WINDOW (window));
1529 
1530 	/* This is called each time the component in
1531 	 * the active slot successfully completed
1532 	 * a zooming operation.
1533 	 */
1534 	nemo_window_sync_zoom_widgets (window);
1535 }
1536 
1537 
1538 /* These are called
1539  *   A) when switching the view within the active slot
1540  *   B) when switching the active slot
1541  *   C) when closing the active slot (disconnect)
1542 */
1543 void
nemo_window_connect_content_view(NemoWindow * window,NemoView * view)1544 nemo_window_connect_content_view (NemoWindow *window,
1545 				      NemoView *view)
1546 {
1547 	NemoWindowSlot *slot;
1548 
1549 	g_assert (NEMO_IS_WINDOW (window));
1550 	g_assert (NEMO_IS_VIEW (view));
1551 
1552 	slot = nemo_window_get_slot_for_view (window, view);
1553 
1554 	if (slot != nemo_window_get_active_slot (window)) {
1555 		return;
1556 	}
1557 
1558 	g_signal_connect (view, "zoom-level-changed",
1559 			  G_CALLBACK (zoom_level_changed_callback),
1560 			  window);
1561 
1562     /* Update displayed the selected view type in the toolbar and menu. */
1563     if (slot->pending_location == NULL) {
1564         nemo_window_sync_view_type (window);
1565     }
1566 
1567 	nemo_view_grab_focus (view);
1568 }
1569 
1570 void
nemo_window_disconnect_content_view(NemoWindow * window,NemoView * view)1571 nemo_window_disconnect_content_view (NemoWindow *window,
1572 					 NemoView *view)
1573 {
1574 	NemoWindowSlot *slot;
1575 
1576 	g_assert (NEMO_IS_WINDOW (window));
1577 	g_assert (NEMO_IS_VIEW (view));
1578 
1579 	slot = nemo_window_get_slot_for_view (window, view);
1580 
1581 	if (slot != nemo_window_get_active_slot (window)) {
1582 		return;
1583 	}
1584 
1585 	g_signal_handlers_disconnect_by_func (view, G_CALLBACK (zoom_level_changed_callback), window);
1586 }
1587 
1588 /**
1589  * nemo_window_show:
1590  * @widget:	GtkWidget
1591  *
1592  * Call parent and then show/hide window items
1593  * base on user prefs.
1594  */
1595 static void
nemo_window_show(GtkWidget * widget)1596 nemo_window_show (GtkWidget *widget)
1597 {
1598 	NemoWindow *window;
1599 
1600 	window = NEMO_WINDOW (widget);
1601 
1602     window->details->sidebar_id = g_settings_get_string (nemo_window_state,
1603                                                          NEMO_WINDOW_STATE_SIDE_PANE_VIEW);
1604 
1605 	if (g_settings_get_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_SIDEBAR)) {
1606 		nemo_window_show_sidebar (window);
1607 	} else {
1608 		nemo_window_hide_sidebar (window);
1609 	}
1610 
1611 	GTK_WIDGET_CLASS (nemo_window_parent_class)->show (widget);
1612 
1613 	gtk_ui_manager_ensure_update (window->details->ui_manager);
1614 }
1615 
1616 GtkUIManager *
nemo_window_get_ui_manager(NemoWindow * window)1617 nemo_window_get_ui_manager (NemoWindow *window)
1618 {
1619 	g_return_val_if_fail (NEMO_IS_WINDOW (window), NULL);
1620 
1621 	return window->details->ui_manager;
1622 }
1623 
1624 GtkActionGroup *
nemo_window_get_main_action_group(NemoWindow * window)1625 nemo_window_get_main_action_group (NemoWindow *window)
1626 {
1627 	g_return_val_if_fail (NEMO_IS_WINDOW (window), NULL);
1628 
1629 	return window->details->main_action_group;
1630 }
1631 
1632 NemoNavigationState *
nemo_window_get_navigation_state(NemoWindow * window)1633 nemo_window_get_navigation_state (NemoWindow *window)
1634 {
1635 	g_return_val_if_fail (NEMO_IS_WINDOW (window), NULL);
1636 
1637 	return window->details->nav_state;
1638 }
1639 
1640 NemoWindowPane *
nemo_window_get_next_pane(NemoWindow * window)1641 nemo_window_get_next_pane (NemoWindow *window)
1642 {
1643        NemoWindowPane *next_pane;
1644        GList *node;
1645 
1646        /* return NULL if there is only one pane */
1647        if (!window->details->panes || !window->details->panes->next) {
1648 	       return NULL;
1649        }
1650 
1651        /* get next pane in the (wrapped around) list */
1652        node = g_list_find (window->details->panes, window->details->active_pane);
1653        g_return_val_if_fail (node, NULL);
1654        if (node->next) {
1655 	       next_pane = node->next->data;
1656        } else {
1657 	       next_pane =  window->details->panes->data;
1658        }
1659 
1660        return next_pane;
1661 }
1662 
1663 
1664 void
nemo_window_slot_set_viewed_file(NemoWindowSlot * slot,NemoFile * file)1665 nemo_window_slot_set_viewed_file (NemoWindowSlot *slot,
1666 				      NemoFile *file)
1667 {
1668 	NemoFileAttributes attributes;
1669 
1670 	if (slot->viewed_file == file) {
1671 		return;
1672 	}
1673 
1674 	nemo_file_ref (file);
1675 
1676 	cancel_sync_view_type_callback (slot);
1677 
1678 	if (slot->viewed_file != NULL) {
1679 		nemo_file_monitor_remove (slot->viewed_file,
1680 					      slot);
1681 	}
1682 
1683 	if (file != NULL) {
1684 		attributes =
1685 			NEMO_FILE_ATTRIBUTE_INFO |
1686 			NEMO_FILE_ATTRIBUTE_LINK_INFO;
1687 		nemo_file_monitor_add (file, slot, attributes);
1688 	}
1689 
1690 	nemo_file_unref (slot->viewed_file);
1691 	slot->viewed_file = file;
1692 }
1693 
1694 NemoWindowSlot *
nemo_window_get_slot_for_view(NemoWindow * window,NemoView * view)1695 nemo_window_get_slot_for_view (NemoWindow *window,
1696 				   NemoView *view)
1697 {
1698 	NemoWindowSlot *slot;
1699 	GList *l, *walk;
1700 
1701 	for (walk = window->details->panes; walk; walk = walk->next) {
1702 		NemoWindowPane *pane = walk->data;
1703 
1704 		for (l = pane->slots; l != NULL; l = l->next) {
1705 			slot = l->data;
1706 			if (slot->content_view == view ||
1707 			    slot->new_content_view == view) {
1708 				return slot;
1709 			}
1710 		}
1711 	}
1712 
1713 	return NULL;
1714 }
1715 
1716 NemoWindowShowHiddenFilesMode
nemo_window_get_hidden_files_mode(NemoWindow * window)1717 nemo_window_get_hidden_files_mode (NemoWindow *window)
1718 {
1719 	return window->details->show_hidden_files_mode;
1720 }
1721 
1722 void
nemo_window_set_hidden_files_mode(NemoWindow * window,NemoWindowShowHiddenFilesMode mode)1723 nemo_window_set_hidden_files_mode (NemoWindow *window,
1724 				       NemoWindowShowHiddenFilesMode  mode)
1725 {
1726 	window->details->show_hidden_files_mode = mode;
1727     g_settings_set_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES,
1728                             mode == NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE);
1729 	g_signal_emit_by_name (window, "hidden_files_mode_changed");
1730 }
1731 
1732 NemoWindowSlot *
nemo_window_get_active_slot(NemoWindow * window)1733 nemo_window_get_active_slot (NemoWindow *window)
1734 {
1735 	g_assert (NEMO_IS_WINDOW (window));
1736 
1737 	if (window->details->active_pane == NULL) {
1738 		return NULL;
1739 	}
1740 
1741 	return window->details->active_pane->active_slot;
1742 }
1743 
1744 NemoWindowSlot *
nemo_window_get_extra_slot(NemoWindow * window)1745 nemo_window_get_extra_slot (NemoWindow *window)
1746 {
1747 	NemoWindowPane *extra_pane;
1748 	GList *node;
1749 
1750 	g_assert (NEMO_IS_WINDOW (window));
1751 
1752 
1753 	/* return NULL if there is only one pane */
1754 	if (window->details->panes == NULL ||
1755 	    window->details->panes->next == NULL) {
1756 		return NULL;
1757 	}
1758 
1759 	/* get next pane in the (wrapped around) list */
1760 	node = g_list_find (window->details->panes,
1761 			    window->details->active_pane);
1762 	g_return_val_if_fail (node, FALSE);
1763 
1764 	if (node->next) {
1765 		extra_pane = node->next->data;
1766 	}
1767 	else {
1768 		extra_pane =  window->details->panes->data;
1769 	}
1770 
1771 	return extra_pane->active_slot;
1772 }
1773 
1774 GList *
nemo_window_get_panes(NemoWindow * window)1775 nemo_window_get_panes (NemoWindow *window)
1776 {
1777 	g_assert (NEMO_IS_WINDOW (window));
1778 
1779 	return window->details->panes;
1780 }
1781 
1782 static void
window_set_search_action_text(NemoWindow * window,gboolean setting)1783 window_set_search_action_text (NemoWindow *window,
1784 			       gboolean setting)
1785 {
1786 	GtkAction *action;
1787 	NemoWindowPane *pane;
1788 	GList *l;
1789 
1790 	for (l = window->details->panes; l != NULL; l = l->next) {
1791 		pane = l->data;
1792 		action = gtk_action_group_get_action (pane->action_group,
1793 						      NEMO_ACTION_SEARCH);
1794 
1795 		gtk_action_set_is_important (action, setting);
1796 	}
1797 }
1798 
1799 static void
center_pane_divider(GtkWidget * paned,GParamSpec * pspec,gpointer user_data)1800 center_pane_divider (GtkWidget  *paned,
1801                      GParamSpec *pspec,
1802                      gpointer    user_data)
1803 {
1804     /* Make the paned think it's been manually resized, otherwise
1805      * things like the trash bar will force unwanted resizes */
1806 
1807     g_object_set (G_OBJECT (paned),
1808                   "position", gtk_widget_get_allocated_width (paned) / 2,
1809                   NULL);
1810 
1811     g_signal_handlers_disconnect_by_func (G_OBJECT (paned), center_pane_divider, NULL);
1812 }
1813 
1814 static NemoWindowSlot *
create_extra_pane(NemoWindow * window)1815 create_extra_pane (NemoWindow *window)
1816 {
1817 	NemoWindowPane *pane;
1818 	NemoWindowSlot *slot;
1819 	GtkPaned *paned;
1820 
1821 	/* New pane */
1822 	pane = nemo_window_pane_new (window);
1823 	window->details->panes = g_list_append (window->details->panes, pane);
1824 
1825 	paned = GTK_PANED (window->details->split_view_hpane);
1826 
1827     g_signal_connect_after (paned,
1828                             "notify::position",
1829                             G_CALLBACK(center_pane_divider),
1830                             NULL);
1831 
1832 	if (gtk_paned_get_child1 (paned) == NULL) {
1833 		gtk_paned_pack1 (paned, GTK_WIDGET (pane), TRUE, FALSE);
1834 	} else {
1835 		gtk_paned_pack2 (paned, GTK_WIDGET (pane), TRUE, FALSE);
1836 	}
1837 
1838 	/* Ensure the toolbar doesn't pop itself into existence (double toolbars suck.) */
1839 	gtk_widget_hide (pane->tool_bar);
1840 
1841 	/* slot */
1842 	slot = nemo_window_pane_open_slot (NEMO_WINDOW_PANE (pane),
1843 					       NEMO_WINDOW_OPEN_SLOT_APPEND);
1844 	pane->active_slot = slot;
1845 
1846 	return slot;
1847 }
1848 
1849 static void
nemo_window_reload(NemoWindow * window)1850 nemo_window_reload (NemoWindow *window)
1851 {
1852 	NemoWindowSlot *active_slot;
1853 	active_slot = nemo_window_get_active_slot (window);
1854 	nemo_window_slot_queue_reload (active_slot, TRUE);
1855 }
1856 
1857 static gboolean
nemo_window_state_event(GtkWidget * widget,GdkEventWindowState * event)1858 nemo_window_state_event (GtkWidget *widget,
1859 			     GdkEventWindowState *event)
1860 {
1861 	if ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) && !nemo_window_is_desktop (NEMO_WINDOW (widget))) {
1862 		g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_MAXIMIZED,
1863 					event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED);
1864 	}
1865 
1866 	if (GTK_WIDGET_CLASS (nemo_window_parent_class)->window_state_event != NULL) {
1867 		return GTK_WIDGET_CLASS (nemo_window_parent_class)->window_state_event (widget, event);
1868 	}
1869 
1870 	return FALSE;
1871 }
1872 
1873 static gboolean
nemo_window_delete_event(GtkWidget * widget,GdkEventAny * event)1874 nemo_window_delete_event (GtkWidget *widget,
1875 			      GdkEventAny *event)
1876 {
1877 	nemo_window_close (NEMO_WINDOW (widget));
1878 	return FALSE;
1879 }
1880 
1881 static gboolean
nemo_window_button_press_event(GtkWidget * widget,GdkEventButton * event)1882 nemo_window_button_press_event (GtkWidget *widget,
1883 				    GdkEventButton *event)
1884 {
1885 	NemoWindow *window;
1886 	gboolean handled;
1887 
1888 	window = NEMO_WINDOW (widget);
1889 
1890 	if (mouse_extra_buttons && (event->button == mouse_back_button)) {
1891 		nemo_window_back_or_forward (window, TRUE, 0, 0);
1892 		handled = TRUE;
1893 	} else if (mouse_extra_buttons && (event->button == mouse_forward_button)) {
1894 		nemo_window_back_or_forward (window, FALSE, 0, 0);
1895 		handled = TRUE;
1896 	} else if (GTK_WIDGET_CLASS (nemo_window_parent_class)->button_press_event) {
1897 		handled = GTK_WIDGET_CLASS (nemo_window_parent_class)->button_press_event (widget, event);
1898 	} else {
1899 		handled = FALSE;
1900 	}
1901 	return handled;
1902 }
1903 
1904 static void
mouse_back_button_changed(gpointer callback_data)1905 mouse_back_button_changed (gpointer callback_data)
1906 {
1907 	int new_back_button;
1908 
1909 	new_back_button = g_settings_get_int (nemo_preferences, NEMO_PREFERENCES_MOUSE_BACK_BUTTON);
1910 
1911 	/* Bounds checking */
1912 	if (new_back_button < 6 || new_back_button > UPPER_MOUSE_LIMIT)
1913 		return;
1914 
1915 	mouse_back_button = new_back_button;
1916 }
1917 
1918 static void
mouse_forward_button_changed(gpointer callback_data)1919 mouse_forward_button_changed (gpointer callback_data)
1920 {
1921 	int new_forward_button;
1922 
1923 	new_forward_button = g_settings_get_int (nemo_preferences, NEMO_PREFERENCES_MOUSE_FORWARD_BUTTON);
1924 
1925 	/* Bounds checking */
1926 	if (new_forward_button < 6 || new_forward_button > UPPER_MOUSE_LIMIT)
1927 		return;
1928 
1929 	mouse_forward_button = new_forward_button;
1930 }
1931 
1932 static void
use_extra_mouse_buttons_changed(gpointer callback_data)1933 use_extra_mouse_buttons_changed (gpointer callback_data)
1934 {
1935 	mouse_extra_buttons = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS);
1936 }
1937 
1938 
1939 /*
1940  * Main API
1941  */
1942 
1943 static void
nemo_window_init(NemoWindow * window)1944 nemo_window_init (NemoWindow *window)
1945 {
1946     GtkWindowGroup *window_group;
1947 
1948 	window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NEMO_TYPE_WINDOW, NemoWindowDetails);
1949 
1950 	window->details->panes = NULL;
1951 	window->details->active_pane = NULL;
1952 
1953     gboolean show_hidden = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES);
1954 
1955     window->details->show_hidden_files_mode = show_hidden ? NEMO_WINDOW_SHOW_HIDDEN_FILES_ENABLE :
1956                                                             NEMO_WINDOW_SHOW_HIDDEN_FILES_DISABLE;
1957 
1958     window->details->show_sidebar = g_settings_get_boolean (nemo_window_state,
1959                                                             NEMO_WINDOW_STATE_START_WITH_SIDEBAR);
1960 
1961     window->details->menu_skip_release = FALSE;
1962     window->details->menu_show_queued = FALSE;
1963 
1964     window->details->ignore_meta_view_id = NULL;
1965     window->details->ignore_meta_zoom_level = -1;
1966     window->details->ignore_meta_visible_columns = NULL;
1967     window->details->ignore_meta_column_order = NULL;
1968     window->details->ignore_meta_sort_column = NULL;
1969     window->details->ignore_meta_sort_direction = SORT_NULL;
1970 
1971 	/* This makes it possible for GTK+ themes to apply styling that is specific to Nemo
1972 	 * without affecting other GTK+ applications.
1973 	 */
1974 	gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "nemo-window");
1975 
1976 	window_group = gtk_window_group_new ();
1977 	gtk_window_group_add_window (window_group, GTK_WINDOW (window));
1978 	g_object_unref (window_group);
1979 
1980 	/* Set initial window title */
1981 	gtk_window_set_title (GTK_WINDOW (window), _("Nemo"));
1982 
1983     g_signal_connect_swapped (nemo_preferences,
1984 				  "changed::" NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS,
1985 				  G_CALLBACK(nemo_window_sync_thumbnail_action),
1986 				  window);
1987     g_signal_connect_swapped (nemo_preferences,
1988 				  "changed::" NEMO_PREFERENCES_INHERIT_SHOW_THUMBNAILS,
1989 				  G_CALLBACK(nemo_window_sync_thumbnail_action),
1990 				  window);
1991 }
1992 
1993 static NemoIconInfo *
real_get_icon(NemoWindow * window,NemoWindowSlot * slot)1994 real_get_icon (NemoWindow *window,
1995                NemoWindowSlot *slot)
1996 {
1997         return nemo_file_get_icon (slot->viewed_file, 48, 0,
1998                        gtk_widget_get_scale_factor (GTK_WIDGET (window)),
1999 				       NEMO_FILE_ICON_FLAGS_IGNORE_VISITING |
2000 				       NEMO_FILE_ICON_FLAGS_USE_MOUNT_ICON);
2001 }
2002 
2003 static void
real_window_close(NemoWindow * window)2004 real_window_close (NemoWindow *window)
2005 {
2006 	g_return_if_fail (NEMO_IS_WINDOW (window));
2007 
2008 	nemo_window_save_geometry (window);
2009 
2010 	gtk_widget_destroy (GTK_WIDGET (window));
2011 }
2012 
2013 static void
nemo_window_class_init(NemoWindowClass * class)2014 nemo_window_class_init (NemoWindowClass *class)
2015 {
2016 	GtkBindingSet *binding_set;
2017 	GObjectClass *oclass = G_OBJECT_CLASS (class);
2018 	GtkWidgetClass *wclass = GTK_WIDGET_CLASS (class);
2019 
2020 	oclass->finalize = nemo_window_finalize;
2021 	oclass->constructed = nemo_window_constructed;
2022 	oclass->get_property = nemo_window_get_property;
2023 	oclass->set_property = nemo_window_set_property;
2024 
2025 	wclass->destroy = nemo_window_destroy;
2026 	wclass->show = nemo_window_show;
2027 	wclass->realize = nemo_window_realize;
2028 	wclass->key_press_event = nemo_window_key_press_event;
2029     wclass->key_release_event = nemo_window_key_release_event;
2030 	wclass->window_state_event = nemo_window_state_event;
2031 	wclass->button_press_event = nemo_window_button_press_event;
2032 	wclass->delete_event = nemo_window_delete_event;
2033 
2034 	class->get_icon = real_get_icon;
2035 	class->close = real_window_close;
2036 
2037 	properties[PROP_DISABLE_CHROME] =
2038 		g_param_spec_boolean ("disable-chrome",
2039 				      "Disable chrome",
2040 				      "Disable window chrome, for the desktop",
2041 				      FALSE,
2042 				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
2043 				      G_PARAM_STATIC_STRINGS);
2044 
2045     properties[PROP_SIDEBAR_VIEW_TYPE] =
2046         g_param_spec_string ("sidebar-view-id",
2047                       "Sidebar view type",
2048                       "Sidebar view type",
2049                       NULL,
2050                       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2051 
2052     properties[PROP_SHOW_SIDEBAR] =
2053         g_param_spec_boolean ("show-sidebar",
2054                               "Show the sidebar",
2055                               "Show the sidebar",
2056                               FALSE,
2057                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
2058 
2059 	signals[GO_UP] =
2060 		g_signal_new ("go-up",
2061 			      G_TYPE_FROM_CLASS (class),
2062 			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2063 			      G_STRUCT_OFFSET (NemoWindowClass, go_up),
2064 			      NULL, NULL,
2065 			      g_cclosure_marshal_generic,
2066 			      G_TYPE_NONE, 0);
2067 	signals[RELOAD] =
2068 		g_signal_new ("reload",
2069 			      G_TYPE_FROM_CLASS (class),
2070 			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2071 			      G_STRUCT_OFFSET (NemoWindowClass, reload),
2072 			      NULL, NULL,
2073 			      g_cclosure_marshal_VOID__VOID,
2074 			      G_TYPE_NONE, 0);
2075 	signals[PROMPT_FOR_LOCATION] =
2076 		g_signal_new ("prompt-for-location",
2077 			      G_TYPE_FROM_CLASS (class),
2078 			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2079 			      G_STRUCT_OFFSET (NemoWindowClass, prompt_for_location),
2080 			      NULL, NULL,
2081 			      g_cclosure_marshal_VOID__STRING,
2082 			      G_TYPE_NONE, 1, G_TYPE_STRING);
2083 	signals[HIDDEN_FILES_MODE_CHANGED] =
2084 		g_signal_new ("hidden_files_mode_changed",
2085 			      G_TYPE_FROM_CLASS (class),
2086 			      G_SIGNAL_RUN_LAST,
2087 			      0,
2088 			      NULL, NULL,
2089 			      g_cclosure_marshal_VOID__VOID,
2090 			      G_TYPE_NONE, 0);
2091 	signals[LOADING_URI] =
2092 		g_signal_new ("loading_uri",
2093 			      G_TYPE_FROM_CLASS (class),
2094 			      G_SIGNAL_RUN_LAST,
2095 			      0,
2096 			      NULL, NULL,
2097 			      g_cclosure_marshal_VOID__STRING,
2098 			      G_TYPE_NONE, 1,
2099 			      G_TYPE_STRING);
2100 	signals[SLOT_ADDED] =
2101 		g_signal_new ("slot-added",
2102 			      G_TYPE_FROM_CLASS (class),
2103 			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2104 			      0,
2105 			      NULL, NULL,
2106 			      g_cclosure_marshal_VOID__OBJECT,
2107 			      G_TYPE_NONE, 1, NEMO_TYPE_WINDOW_SLOT);
2108 	signals[SLOT_REMOVED] =
2109 		g_signal_new ("slot-removed",
2110 			      G_TYPE_FROM_CLASS (class),
2111 			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2112 			      0,
2113 			      NULL, NULL,
2114 			      g_cclosure_marshal_VOID__OBJECT,
2115 			      G_TYPE_NONE, 1, NEMO_TYPE_WINDOW_SLOT);
2116 
2117 	binding_set = gtk_binding_set_by_class (class);
2118 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0,
2119 				      "go-up", 0);
2120 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_F5, 0,
2121 				      "reload", 0);
2122 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
2123 				      "prompt-for-location", 1,
2124 				      G_TYPE_STRING, "/");
2125 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
2126 				      "prompt-for-location", 1,
2127 				      G_TYPE_STRING, "/");
2128 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_asciitilde, 0,
2129 				      "prompt-for-location", 1,
2130 				      G_TYPE_STRING, "~");
2131 
2132 	class->reload = nemo_window_reload;
2133 	class->go_up = nemo_window_go_up_signal;
2134 	class->prompt_for_location = nemo_window_prompt_for_location;
2135 
2136 	g_signal_connect_swapped (nemo_preferences,
2137 				  "changed::" NEMO_PREFERENCES_MOUSE_BACK_BUTTON,
2138 				  G_CALLBACK(mouse_back_button_changed),
2139 				  NULL);
2140 
2141 	g_signal_connect_swapped (nemo_preferences,
2142 				  "changed::" NEMO_PREFERENCES_MOUSE_FORWARD_BUTTON,
2143 				  G_CALLBACK(mouse_forward_button_changed),
2144 				  NULL);
2145 
2146 	g_signal_connect_swapped (nemo_preferences,
2147 				  "changed::" NEMO_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS,
2148 				  G_CALLBACK(use_extra_mouse_buttons_changed),
2149 				  NULL);
2150 
2151 	g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
2152 	g_type_class_add_private (oclass, sizeof (NemoWindowDetails));
2153 }
2154 
2155 NemoWindow *
nemo_window_new(GtkApplication * application,GdkScreen * screen)2156 nemo_window_new (GtkApplication *application,
2157                  GdkScreen *screen)
2158 {
2159 	return g_object_new (NEMO_TYPE_WINDOW,
2160 			     "application", application,
2161 			     "screen", screen,
2162 			     NULL);
2163 }
2164 
2165 void
nemo_window_split_view_on(NemoWindow * window)2166 nemo_window_split_view_on (NemoWindow *window)
2167 {
2168 	NemoWindowSlot *slot, *old_active_slot;
2169 	GFile *location;
2170 
2171 	old_active_slot = nemo_window_get_active_slot (window);
2172 	slot = create_extra_pane (window);
2173 
2174 	location = NULL;
2175 	if (old_active_slot != NULL) {
2176 		location = nemo_window_slot_get_location (old_active_slot);
2177 		if (location != NULL) {
2178 			if (g_file_has_uri_scheme (location, "x-nemo-search")) {
2179 				g_object_unref (location);
2180 				location = NULL;
2181 			}
2182 		}
2183 	}
2184 	if (location == NULL) {
2185 		location = g_file_new_for_path (g_get_home_dir ());
2186 	}
2187 
2188 	nemo_window_slot_open_location (slot, location, 0);
2189 	g_object_unref (location);
2190 
2191 	window_set_search_action_text (window, FALSE);
2192 }
2193 
2194 void
nemo_window_split_view_off(NemoWindow * window)2195 nemo_window_split_view_off (NemoWindow *window)
2196 {
2197 	NemoWindowPane *pane, *active_pane;
2198 	GList *l, *next;
2199 
2200 	active_pane = nemo_window_get_active_pane (window);
2201 
2202 	/* delete all panes except the first (main) pane */
2203 	for (l = window->details->panes; l != NULL; l = next) {
2204 		next = l->next;
2205 		pane = l->data;
2206 		if (pane != active_pane) {
2207 			nemo_window_close_pane (window, pane);
2208 		}
2209 	}
2210 
2211     /* Reset split view pane's position so the position can be
2212      * caught again later */
2213     g_object_set (G_OBJECT (window->details->split_view_hpane),
2214                   "position", 0,
2215                   "position-set", FALSE,
2216                   NULL);
2217 
2218 	nemo_window_set_active_pane (window, active_pane);
2219 	nemo_navigation_state_set_master (window->details->nav_state,
2220 					      active_pane->action_group);
2221 
2222 	nemo_window_update_show_hide_menu_items (window);
2223 }
2224 
2225 gboolean
nemo_window_split_view_showing(NemoWindow * window)2226 nemo_window_split_view_showing (NemoWindow *window)
2227 {
2228 	return g_list_length (NEMO_WINDOW (window)->details->panes) > 1;
2229 }
2230 
2231 void
nemo_window_set_sidebar_id(NemoWindow * window,const gchar * id)2232 nemo_window_set_sidebar_id (NemoWindow *window,
2233                             const gchar *id)
2234 {
2235     if (g_strcmp0 (id, window->details->sidebar_id) != 0) {
2236 
2237         g_settings_set_string (nemo_window_state,
2238                                NEMO_WINDOW_STATE_SIDE_PANE_VIEW,
2239                                id);
2240 
2241         g_free (window->details->sidebar_id);
2242 
2243         window->details->sidebar_id = g_strdup (id);
2244 
2245         g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_SIDEBAR_VIEW_TYPE]);
2246     }
2247 }
2248 
2249 const gchar *
nemo_window_get_sidebar_id(NemoWindow * window)2250 nemo_window_get_sidebar_id (NemoWindow *window)
2251 {
2252     return window->details->sidebar_id;
2253 }
2254 
2255 void
nemo_window_set_show_sidebar(NemoWindow * window,gboolean show)2256 nemo_window_set_show_sidebar (NemoWindow *window,
2257                               gboolean show)
2258 {
2259     window->details->show_sidebar = show;
2260 
2261     g_settings_set_boolean (nemo_window_state, NEMO_WINDOW_STATE_START_WITH_SIDEBAR, show);
2262 
2263     g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_SHOW_SIDEBAR]);
2264 }
2265 
2266 gboolean
nemo_window_get_show_sidebar(NemoWindow * window)2267 nemo_window_get_show_sidebar (NemoWindow *window)
2268 {
2269     return window->details->show_sidebar;
2270 }
2271 
2272 const gchar *
nemo_window_get_ignore_meta_view_id(NemoWindow * window)2273 nemo_window_get_ignore_meta_view_id (NemoWindow *window)
2274 {
2275     return window->details->ignore_meta_view_id;
2276 }
2277 
2278 void
nemo_window_set_ignore_meta_view_id(NemoWindow * window,const gchar * id)2279 nemo_window_set_ignore_meta_view_id (NemoWindow *window, const gchar *id)
2280 {
2281     if (id != NULL) {
2282         gchar *old_id = window->details->ignore_meta_view_id;
2283         if (g_strcmp0 (old_id, id) != 0) {
2284             nemo_window_set_ignore_meta_zoom_level (window, -1);
2285         }
2286         window->details->ignore_meta_view_id = g_strdup (id);
2287         g_free (old_id);
2288     }
2289 }
2290 
2291 gint
nemo_window_get_ignore_meta_zoom_level(NemoWindow * window)2292 nemo_window_get_ignore_meta_zoom_level (NemoWindow *window)
2293 {
2294     return window->details->ignore_meta_zoom_level;
2295 }
2296 
2297 void
nemo_window_set_ignore_meta_zoom_level(NemoWindow * window,gint level)2298 nemo_window_set_ignore_meta_zoom_level (NemoWindow *window, gint level)
2299 {
2300     window->details->ignore_meta_zoom_level = level;
2301 }
2302 
2303 /* FIXME:
2304  *
2305  * Remove this and just use g_list_copy_deep
2306  * when we no longer need to support GLib < 2.34
2307  *
2308  */
2309 
2310 static GList *
list_copy_deep(GList * list,GCopyFunc func,gpointer user_data)2311 list_copy_deep (GList *list, GCopyFunc func, gpointer user_data)
2312 {
2313   GList *new_list = NULL;
2314 
2315   if (list)
2316     {
2317       GList *last;
2318 
2319       new_list = g_slice_new (GList);
2320       if (func)
2321         new_list->data = func (list->data, user_data);
2322       else
2323         new_list->data = list->data;
2324       new_list->prev = NULL;
2325       last = new_list;
2326       list = list->next;
2327       while (list)
2328     {
2329       last->next = g_slice_new (GList);
2330       last->next->prev = last;
2331       last = last->next;
2332       if (func)
2333         last->data = func (list->data, user_data);
2334       else
2335         last->data = list->data;
2336       list = list->next;
2337     }
2338       last->next = NULL;
2339     }
2340 
2341   return new_list;
2342 }
2343 
2344 GList *
nemo_window_get_ignore_meta_visible_columns(NemoWindow * window)2345 nemo_window_get_ignore_meta_visible_columns (NemoWindow *window)
2346 {
2347     return list_copy_deep (window->details->ignore_meta_visible_columns, (GCopyFunc) g_strdup, NULL);
2348 }
2349 
2350 void
nemo_window_set_ignore_meta_visible_columns(NemoWindow * window,GList * list)2351 nemo_window_set_ignore_meta_visible_columns (NemoWindow *window, GList *list)
2352 {
2353     GList *old = window->details->ignore_meta_visible_columns;
2354     window->details->ignore_meta_visible_columns = list != NULL ? list_copy_deep (list, (GCopyFunc) g_strdup, NULL) :
2355                                                                   NULL;
2356     if (old != NULL)
2357         g_list_free_full (old, g_free);
2358 }
2359 
2360 GList *
nemo_window_get_ignore_meta_column_order(NemoWindow * window)2361 nemo_window_get_ignore_meta_column_order (NemoWindow *window)
2362 {
2363     return list_copy_deep (window->details->ignore_meta_column_order, (GCopyFunc) g_strdup, NULL);
2364 }
2365 
2366 void
nemo_window_set_ignore_meta_column_order(NemoWindow * window,GList * list)2367 nemo_window_set_ignore_meta_column_order (NemoWindow *window, GList *list)
2368 {
2369     GList *old = window->details->ignore_meta_column_order;
2370     window->details->ignore_meta_column_order = list != NULL ? list_copy_deep (list, (GCopyFunc) g_strdup, NULL) :
2371                                                                NULL;
2372     if (old != NULL)
2373         g_list_free_full (old, g_free);
2374 }
2375 
2376 const gchar *
nemo_window_get_ignore_meta_sort_column(NemoWindow * window)2377 nemo_window_get_ignore_meta_sort_column (NemoWindow *window)
2378 {
2379     return window->details->ignore_meta_sort_column;
2380 }
2381 
2382 void
nemo_window_set_ignore_meta_sort_column(NemoWindow * window,const gchar * column)2383 nemo_window_set_ignore_meta_sort_column (NemoWindow *window, const gchar *column)
2384 {
2385     if (column != NULL) {
2386         gchar *old_column = window->details->ignore_meta_sort_column;
2387         window->details->ignore_meta_sort_column = g_strdup (column);
2388         g_free (old_column);
2389     }
2390 }
2391 
2392 gint
nemo_window_get_ignore_meta_sort_direction(NemoWindow * window)2393 nemo_window_get_ignore_meta_sort_direction (NemoWindow *window)
2394 {
2395     return window->details->ignore_meta_sort_direction;
2396 }
2397 
2398 void
nemo_window_set_ignore_meta_sort_direction(NemoWindow * window,gint direction)2399 nemo_window_set_ignore_meta_sort_direction (NemoWindow *window, gint direction)
2400 {
2401     window->details->ignore_meta_sort_direction = direction;
2402 }
2403 
2404 NemoWindowOpenFlags
nemo_event_get_window_open_flags(void)2405 nemo_event_get_window_open_flags (void)
2406 {
2407 	NemoWindowOpenFlags flags = 0;
2408 	GdkEvent *event;
2409 
2410 	event = gtk_get_current_event ();
2411 
2412 	if (event == NULL) {
2413 		return flags;
2414 	}
2415 
2416 	if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
2417 	    (event->button.button == 2)) {
2418 		flags |= NEMO_WINDOW_OPEN_FLAG_NEW_TAB;
2419 	}
2420 
2421 	gdk_event_free (event);
2422 
2423 	return flags;
2424 }
2425