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