1 /*
2 * Nautilus
3 *
4 * Copyright (C) 1999, 2000, 2004 Red Hat, Inc.
5 * Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6 *
7 * Nautilus is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * Nautilus is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 * Authors: Elliot Lee <sopwith@redhat.com>
21 * John Sullivan <sullivan@eazel.com>
22 * Alexander Larsson <alexl@redhat.com>
23 */
24
25 /* nautilus-window.c: Implementation of the main window object */
26
27 #include "nautilus-window.h"
28
29 #include <eel/eel-debug.h>
30 #include <eel/eel-gtk-extensions.h>
31 #include <eel/eel-vfs-extensions.h>
32 #include <gdk-pixbuf/gdk-pixbuf.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <glib/gi18n.h>
35 #include <gtk/gtk.h>
36 #include <math.h>
37 #include <sys/time.h>
38
39 #ifdef GDK_WINDOWING_WAYLAND
40 #include <gdk/gdkwayland.h>
41 #endif
42
43 #ifdef GDK_WINDOWING_X11
44 #include <gdk/gdkx.h>
45 #endif
46
47 #define DEBUG_FLAG NAUTILUS_DEBUG_WINDOW
48 #include "nautilus-debug.h"
49
50 #include "nautilus-application.h"
51 #include "nautilus-bookmark-list.h"
52 #include "nautilus-clipboard.h"
53 #include "nautilus-dnd.h"
54 #include "nautilus-enums.h"
55 #include "nautilus-file-operations.h"
56 #include "nautilus-file-undo-manager.h"
57 #include "nautilus-file-utilities.h"
58 #include "nautilus-global-preferences.h"
59 #include "nautilus-list-view.h"
60 #include "nautilus-location-entry.h"
61 #include "nautilus-metadata.h"
62 #include "nautilus-mime-actions.h"
63 #include "nautilus-notebook.h"
64 #include "nautilus-pathbar.h"
65 #include "nautilus-profile.h"
66 #include "nautilus-properties-window.h"
67 #include "nautilus-signaller.h"
68 #include "nautilus-toolbar.h"
69 #include "nautilus-trash-monitor.h"
70 #include "nautilus-ui-utilities.h"
71 #include "nautilus-window-slot.h"
72
73 /* Forward and back buttons on the mouse */
74 static gboolean mouse_extra_buttons = TRUE;
75 static int mouse_forward_button = 9;
76 static int mouse_back_button = 8;
77
78 static void mouse_back_button_changed (gpointer callback_data);
79 static void mouse_forward_button_changed (gpointer callback_data);
80 static void use_extra_mouse_buttons_changed (gpointer callback_data);
81 static void nautilus_window_initialize_actions (NautilusWindow *window);
82 static GtkWidget *nautilus_window_ensure_location_entry (NautilusWindow *window);
83 static void nautilus_window_back_or_forward (NautilusWindow *window,
84 gboolean back,
85 guint distance);
86
87 /* Sanity check: highest mouse button value I could find was 14. 5 is our
88 * lower threshold (well-documented to be the one of the button events for the
89 * scrollwheel), so it's hardcoded in the functions below. However, if you have
90 * a button that registers higher and want to map it, file a bug and
91 * we'll move the bar. Makes you wonder why the X guys don't have
92 * defined values for these like the XKB stuff, huh?
93 */
94 #define UPPER_MOUSE_LIMIT 14
95
96 #define NOTIFICATION_TIMEOUT 6 /*s */
97
98 struct _NautilusWindow
99 {
100 HdyApplicationWindow parent_instance;
101
102 GtkWidget *notebook;
103
104 /* available slots, and active slot.
105 * Both of them may never be NULL.
106 */
107 GList *slots;
108 NautilusWindowSlot *active_slot; /* weak reference */
109
110 GtkWidget *content_paned;
111
112 /* Side Pane */
113 int side_pane_width;
114 GtkWidget *sidebar; /* container for the GtkPlacesSidebar */
115 GtkWidget *places_sidebar; /* the actual GtkPlacesSidebar */
116 GVolume *selected_volume; /* the selected volume in the sidebar popup callback */
117 GFile *selected_file; /* the selected file in the sidebar popup callback */
118
119 /* Main view */
120 GtkWidget *main_view;
121
122 /* Notifications */
123 GtkWidget *in_app_notification_undo;
124 GtkWidget *in_app_notification_undo_label;
125 GtkWidget *in_app_notification_undo_close_button;
126 GtkWidget *in_app_notification_undo_undo_button;
127 guint in_app_notification_undo_timeout_id;
128 GtkWidget *notification_operation;
129 GtkWidget *notification_operation_label;
130 GtkWidget *notification_operation_close;
131 GtkWidget *notification_operation_open;
132 guint notification_operation_timeout_id;
133 GFile *folder_to_open;
134
135 /* Toolbar */
136 GtkWidget *toolbar;
137 gboolean temporary_navigation_bar;
138
139 /* focus widget before the location bar has been shown temporarily */
140 GtkWidget *last_focus_widget;
141
142 /* Handle when exported */
143 gchar *export_handle;
144
145 guint sidebar_width_handler_id;
146 gulong bookmarks_id;
147
148 GQueue *tab_data_queue;
149
150 GtkPadController *pad_controller;
151
152 GtkGesture *multi_press_gesture;
153 GtkGesture *notebook_multi_press_gesture;
154 };
155
156 enum
157 {
158 SLOT_ADDED,
159 SLOT_REMOVED,
160 LAST_SIGNAL
161 };
162
163 static guint signals[LAST_SIGNAL] = { 0 };
164
165 G_DEFINE_TYPE (NautilusWindow, nautilus_window, HDY_TYPE_APPLICATION_WINDOW);
166
167 static const struct
168 {
169 unsigned int keyval;
170 const char *action;
171 } extra_window_keybindings [] =
172 {
173 /* Window actions */
174 { GDK_KEY_AddFavorite, "bookmark-current-location" },
175 { GDK_KEY_Favorites, "bookmarks" },
176 { GDK_KEY_Go, "enter-location" },
177 { GDK_KEY_HomePage, "go-home" },
178 { GDK_KEY_OpenURL, "enter-location" },
179 { GDK_KEY_Refresh, "reload" },
180 { GDK_KEY_Reload, "reload" },
181 { GDK_KEY_Search, "search" },
182 { GDK_KEY_Start, "go-home" },
183 { GDK_KEY_Stop, "stop" },
184 { GDK_KEY_Back, "back" },
185 { GDK_KEY_Forward, "forward" },
186 };
187
188 static const GtkPadActionEntry pad_actions[] =
189 {
190 { GTK_PAD_ACTION_BUTTON, 0, -1, N_("Parent folder"), "up" },
191 { GTK_PAD_ACTION_BUTTON, 1, -1, N_("Home"), "go-home" },
192 { GTK_PAD_ACTION_BUTTON, 2, -1, N_("New tab"), "new-tab" },
193 { GTK_PAD_ACTION_BUTTON, 3, -1, N_("Close current view"), "close-current-view" },
194 { GTK_PAD_ACTION_BUTTON, 4, -1, N_("Back"), "back" },
195 { GTK_PAD_ACTION_BUTTON, 5, -1, N_("Forward"), "forward" },
196 };
197
198 static void
action_close_current_view(GSimpleAction * action,GVariant * state,gpointer user_data)199 action_close_current_view (GSimpleAction *action,
200 GVariant *state,
201 gpointer user_data)
202 {
203 NautilusWindow *window;
204 NautilusWindowSlot *slot;
205
206 window = NAUTILUS_WINDOW (user_data);
207 slot = nautilus_window_get_active_slot (window);
208
209 nautilus_window_slot_close (window, slot);
210 }
211
212 static void
action_go_home(GSimpleAction * action,GVariant * state,gpointer user_data)213 action_go_home (GSimpleAction *action,
214 GVariant *state,
215 gpointer user_data)
216 {
217 NautilusWindow *window;
218 GFile *home;
219
220 window = NAUTILUS_WINDOW (user_data);
221 home = g_file_new_for_path (g_get_home_dir ());
222
223 nautilus_window_open_location_full (window, home, 0, NULL, NULL);
224
225 g_object_unref (home);
226 }
227
228 static void
action_reload(GSimpleAction * action,GVariant * state,gpointer user_data)229 action_reload (GSimpleAction *action,
230 GVariant *state,
231 gpointer user_data)
232 {
233 NautilusWindowSlot *slot;
234
235 slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (user_data));
236 nautilus_window_slot_queue_reload (slot);
237 }
238
239 static void
action_stop(GSimpleAction * action,GVariant * state,gpointer user_data)240 action_stop (GSimpleAction *action,
241 GVariant *state,
242 gpointer user_data)
243 {
244 NautilusWindow *window;
245 NautilusWindowSlot *slot;
246
247 window = NAUTILUS_WINDOW (user_data);
248 slot = nautilus_window_get_active_slot (window);
249
250 nautilus_window_slot_stop_loading (slot);
251 }
252
253 static void
action_up(GSimpleAction * action,GVariant * state,gpointer user_data)254 action_up (GSimpleAction *action,
255 GVariant *state,
256 gpointer user_data)
257 {
258 NautilusWindowSlot *slot;
259 GFile *parent, *location;
260
261 slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (user_data));
262 location = nautilus_window_slot_get_location (slot);
263
264 if (location != NULL)
265 {
266 parent = g_file_get_parent (location);
267 if (parent != NULL)
268 {
269 nautilus_window_open_location_full (NAUTILUS_WINDOW (user_data),
270 parent,
271 0,
272 NULL, NULL);
273 }
274
275 g_clear_object (&parent);
276 }
277 }
278
279 static void
action_back(GSimpleAction * action,GVariant * state,gpointer user_data)280 action_back (GSimpleAction *action,
281 GVariant *state,
282 gpointer user_data)
283 {
284 nautilus_window_back_or_forward (NAUTILUS_WINDOW (user_data), TRUE, 0);
285 }
286
287 static void
action_forward(GSimpleAction * action,GVariant * state,gpointer user_data)288 action_forward (GSimpleAction *action,
289 GVariant *state,
290 gpointer user_data)
291 {
292 nautilus_window_back_or_forward (NAUTILUS_WINDOW (user_data), FALSE, 0);
293 }
294
295 static void
action_bookmark_current_location(GSimpleAction * action,GVariant * state,gpointer user_data)296 action_bookmark_current_location (GSimpleAction *action,
297 GVariant *state,
298 gpointer user_data)
299 {
300 NautilusWindow *window = user_data;
301 NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ());
302 NautilusWindowSlot *slot;
303
304 slot = nautilus_window_get_active_slot (window);
305 nautilus_bookmark_list_append (nautilus_application_get_bookmarks (app),
306 nautilus_window_slot_get_bookmark (slot));
307 }
308
309 static void
action_new_tab(GSimpleAction * action,GVariant * state,gpointer user_data)310 action_new_tab (GSimpleAction *action,
311 GVariant *state,
312 gpointer user_data)
313 {
314 nautilus_window_new_tab (NAUTILUS_WINDOW (user_data));
315 }
316
317 static void
action_enter_location(GSimpleAction * action,GVariant * state,gpointer user_data)318 action_enter_location (GSimpleAction *action,
319 GVariant *state,
320 gpointer user_data)
321 {
322 NautilusWindow *window = user_data;
323
324 nautilus_window_ensure_location_entry (window);
325 }
326
327 static void
action_tab_previous(GSimpleAction * action,GVariant * state,gpointer user_data)328 action_tab_previous (GSimpleAction *action,
329 GVariant *state,
330 gpointer user_data)
331 {
332 NautilusWindow *window = user_data;
333
334 nautilus_notebook_prev_page (NAUTILUS_NOTEBOOK (window->notebook));
335 }
336
337 static void
action_tab_next(GSimpleAction * action,GVariant * state,gpointer user_data)338 action_tab_next (GSimpleAction *action,
339 GVariant *state,
340 gpointer user_data)
341 {
342 NautilusWindow *window = user_data;
343
344 nautilus_notebook_next_page (NAUTILUS_NOTEBOOK (window->notebook));
345 }
346
347 static void
action_tab_move_left(GSimpleAction * action,GVariant * state,gpointer user_data)348 action_tab_move_left (GSimpleAction *action,
349 GVariant *state,
350 gpointer user_data)
351 {
352 NautilusWindow *window = user_data;
353
354 nautilus_notebook_reorder_current_child_relative (NAUTILUS_NOTEBOOK (window->notebook), -1);
355 }
356
357 static void
action_tab_move_right(GSimpleAction * action,GVariant * state,gpointer user_data)358 action_tab_move_right (GSimpleAction *action,
359 GVariant *state,
360 gpointer user_data)
361 {
362 NautilusWindow *window = user_data;
363
364 nautilus_notebook_reorder_current_child_relative (NAUTILUS_NOTEBOOK (window->notebook), 1);
365 }
366
367 static void
action_go_to_tab(GSimpleAction * action,GVariant * value,gpointer user_data)368 action_go_to_tab (GSimpleAction *action,
369 GVariant *value,
370 gpointer user_data)
371 {
372 NautilusWindow *window = NAUTILUS_WINDOW (user_data);
373 GtkNotebook *notebook;
374 gint16 num;
375
376 notebook = GTK_NOTEBOOK (window->notebook);
377
378 num = g_variant_get_int32 (value);
379 if (num < gtk_notebook_get_n_pages (notebook))
380 {
381 gtk_notebook_set_current_page (notebook, num);
382 }
383 }
384
385 static void
action_prompt_for_location_root(GSimpleAction * action,GVariant * state,gpointer user_data)386 action_prompt_for_location_root (GSimpleAction *action,
387 GVariant *state,
388 gpointer user_data)
389 {
390 NautilusWindow *window = user_data;
391 GFile *location;
392 GtkWidget *entry;
393
394 location = g_file_new_for_path ("/");
395 entry = nautilus_window_ensure_location_entry (window);
396 nautilus_location_entry_set_location (NAUTILUS_LOCATION_ENTRY (entry), location);
397
398 g_object_unref (location);
399 }
400
401 static void
action_prompt_for_location_home(GSimpleAction * action,GVariant * state,gpointer user_data)402 action_prompt_for_location_home (GSimpleAction *action,
403 GVariant *state,
404 gpointer user_data)
405 {
406 GtkWidget *entry;
407
408 entry = nautilus_window_ensure_location_entry (NAUTILUS_WINDOW (user_data));
409 nautilus_location_entry_set_special_text (NAUTILUS_LOCATION_ENTRY (entry),
410 "~");
411 gtk_editable_set_position (GTK_EDITABLE (entry), -1);
412 }
413
414 static void
action_redo(GSimpleAction * action,GVariant * state,gpointer user_data)415 action_redo (GSimpleAction *action,
416 GVariant *state,
417 gpointer user_data)
418 {
419 NautilusWindow *window = user_data;
420
421 nautilus_file_undo_manager_redo (GTK_WINDOW (window), NULL);
422 }
423
424 static void
action_undo(GSimpleAction * action,GVariant * state,gpointer user_data)425 action_undo (GSimpleAction *action,
426 GVariant *state,
427 gpointer user_data)
428 {
429 NautilusWindow *window = user_data;
430
431 nautilus_file_undo_manager_undo (GTK_WINDOW (window), NULL);
432 }
433
434 static void
action_toggle_state_view_button(GSimpleAction * action,GVariant * state,gpointer user_data)435 action_toggle_state_view_button (GSimpleAction *action,
436 GVariant *state,
437 gpointer user_data)
438 {
439 GVariant *current_state;
440
441 current_state = g_action_get_state (G_ACTION (action));
442 g_action_change_state (G_ACTION (action),
443 g_variant_new_boolean (!g_variant_get_boolean (current_state)));
444 g_variant_unref (current_state);
445 }
446
447 static void
on_location_changed(NautilusWindow * window)448 on_location_changed (NautilusWindow *window)
449 {
450 gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (window->places_sidebar),
451 nautilus_window_slot_get_location (nautilus_window_get_active_slot (window)));
452 }
453
454 static void
on_slot_location_changed(NautilusWindowSlot * slot,GParamSpec * pspec,NautilusWindow * window)455 on_slot_location_changed (NautilusWindowSlot *slot,
456 GParamSpec *pspec,
457 NautilusWindow *window)
458 {
459 if (nautilus_window_get_active_slot (window) == slot)
460 {
461 on_location_changed (window);
462 }
463 }
464
465 static void
notebook_switch_page_cb(GtkNotebook * notebook,GtkWidget * page,unsigned int page_num,NautilusWindow * window)466 notebook_switch_page_cb (GtkNotebook *notebook,
467 GtkWidget *page,
468 unsigned int page_num,
469 NautilusWindow *window)
470 {
471 NautilusWindowSlot *slot;
472 GtkWidget *widget;
473
474 widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), page_num);
475 g_assert (widget != NULL);
476
477 /* find slot corresponding to the target page */
478 slot = NAUTILUS_WINDOW_SLOT (widget);
479 g_assert (slot != NULL);
480
481 nautilus_window_set_active_slot (nautilus_window_slot_get_window (slot),
482 slot);
483 }
484
485 static void
connect_slot(NautilusWindow * window,NautilusWindowSlot * slot)486 connect_slot (NautilusWindow *window,
487 NautilusWindowSlot *slot)
488 {
489 g_signal_connect (slot, "notify::location",
490 G_CALLBACK (on_slot_location_changed), window);
491 }
492
493 static void
disconnect_slot(NautilusWindow * window,NautilusWindowSlot * slot)494 disconnect_slot (NautilusWindow *window,
495 NautilusWindowSlot *slot)
496 {
497 g_signal_handlers_disconnect_by_data (slot, window);
498 }
499
500 static NautilusWindowSlot *
nautilus_window_create_and_init_slot(NautilusWindow * window,NautilusWindowOpenFlags flags)501 nautilus_window_create_and_init_slot (NautilusWindow *window,
502 NautilusWindowOpenFlags flags)
503 {
504 NautilusWindowSlot *slot;
505
506 slot = nautilus_window_slot_new (window);
507 nautilus_window_initialize_slot (window, slot, flags);
508
509 return slot;
510 }
511
512 void
nautilus_window_initialize_slot(NautilusWindow * window,NautilusWindowSlot * slot,NautilusWindowOpenFlags flags)513 nautilus_window_initialize_slot (NautilusWindow *window,
514 NautilusWindowSlot *slot,
515 NautilusWindowOpenFlags flags)
516 {
517 g_assert (NAUTILUS_IS_WINDOW (window));
518 g_assert (NAUTILUS_IS_WINDOW_SLOT (slot));
519
520 connect_slot (window, slot);
521
522 g_signal_handlers_block_by_func (window->notebook,
523 G_CALLBACK (notebook_switch_page_cb),
524 window);
525 nautilus_notebook_add_tab (NAUTILUS_NOTEBOOK (window->notebook),
526 slot,
527 (flags & NAUTILUS_WINDOW_OPEN_SLOT_APPEND) != 0 ?
528 -1 :
529 gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook)) + 1,
530 FALSE);
531 g_signal_handlers_unblock_by_func (window->notebook,
532 G_CALLBACK (notebook_switch_page_cb),
533 window);
534
535 window->slots = g_list_append (window->slots, slot);
536 g_signal_emit (window, signals[SLOT_ADDED], 0, slot);
537 }
538
539 void
nautilus_window_open_location_full(NautilusWindow * window,GFile * location,NautilusWindowOpenFlags flags,GList * selection,NautilusWindowSlot * target_slot)540 nautilus_window_open_location_full (NautilusWindow *window,
541 GFile *location,
542 NautilusWindowOpenFlags flags,
543 GList *selection,
544 NautilusWindowSlot *target_slot)
545 {
546 NautilusWindowSlot *active_slot;
547 gboolean new_tab_at_end;
548
549 /* Assert that we are not managing new windows */
550 g_assert (!(flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW));
551 /* if the flags say we want a new tab, open a slot in the current window */
552 if ((flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB) != 0)
553 {
554 new_tab_at_end = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_NEW_TAB_POSITION) == NAUTILUS_NEW_TAB_POSITION_END;
555 if (new_tab_at_end)
556 {
557 flags |= NAUTILUS_WINDOW_OPEN_SLOT_APPEND;
558 }
559 }
560
561 active_slot = nautilus_window_get_active_slot (window);
562 if (!target_slot)
563 {
564 target_slot = active_slot;
565 }
566
567 if (target_slot == NULL || (flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB) != 0)
568 {
569 target_slot = nautilus_window_create_and_init_slot (window, flags);
570 }
571
572 /* Make the opened location the one active if we weren't ask for the
573 * oposite, since it's the most usual use case */
574 if (!(flags & NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE))
575 {
576 gtk_window_present (GTK_WINDOW (window));
577 nautilus_window_set_active_slot (window, target_slot);
578 }
579
580 nautilus_window_slot_open_location_full (target_slot, location, flags, selection);
581 }
582
583 static void
unset_focus_widget(NautilusWindow * window)584 unset_focus_widget (NautilusWindow *window)
585 {
586 if (window->last_focus_widget != NULL)
587 {
588 g_object_remove_weak_pointer (G_OBJECT (window->last_focus_widget),
589 (gpointer *) &window->last_focus_widget);
590 window->last_focus_widget = NULL;
591 }
592 }
593
594 static void
remember_focus_widget(NautilusWindow * window)595 remember_focus_widget (NautilusWindow *window)
596 {
597 GtkWidget *focus_widget;
598
599 focus_widget = gtk_window_get_focus (GTK_WINDOW (window));
600 if (focus_widget != NULL)
601 {
602 unset_focus_widget (window);
603
604 window->last_focus_widget = focus_widget;
605 g_object_add_weak_pointer (G_OBJECT (focus_widget),
606 (gpointer *) &(window->last_focus_widget));
607 }
608 }
609
610 static void
nautilus_window_grab_focus(GtkWidget * widget)611 nautilus_window_grab_focus (GtkWidget *widget)
612 {
613 NautilusWindowSlot *slot;
614
615 slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (widget));
616
617 GTK_WIDGET_CLASS (nautilus_window_parent_class)->grab_focus (widget);
618
619 if (slot)
620 {
621 gtk_widget_grab_focus (GTK_WIDGET (slot));
622 }
623 }
624
625 static void
restore_focus_widget(NautilusWindow * window)626 restore_focus_widget (NautilusWindow *window)
627 {
628 if (window->last_focus_widget != NULL)
629 {
630 gtk_widget_grab_focus (window->last_focus_widget);
631 unset_focus_widget (window);
632 }
633 }
634
635 static void
location_entry_cancel_callback(GtkWidget * widget,NautilusWindow * window)636 location_entry_cancel_callback (GtkWidget *widget,
637 NautilusWindow *window)
638 {
639 nautilus_toolbar_set_show_location_entry (NAUTILUS_TOOLBAR (window->toolbar), FALSE);
640
641 restore_focus_widget (window);
642 }
643
644 static void
location_entry_location_changed_callback(GtkWidget * widget,GFile * location,NautilusWindow * window)645 location_entry_location_changed_callback (GtkWidget *widget,
646 GFile *location,
647 NautilusWindow *window)
648 {
649 nautilus_toolbar_set_show_location_entry (NAUTILUS_TOOLBAR (window->toolbar), FALSE);
650
651 restore_focus_widget (window);
652
653 nautilus_window_open_location_full (window, location, 0, NULL, NULL);
654 }
655
656 static void
close_slot(NautilusWindow * window,NautilusWindowSlot * slot,gboolean remove_from_notebook)657 close_slot (NautilusWindow *window,
658 NautilusWindowSlot *slot,
659 gboolean remove_from_notebook)
660 {
661 int page_num;
662 GtkNotebook *notebook;
663
664 g_assert (NAUTILUS_IS_WINDOW_SLOT (slot));
665
666
667 DEBUG ("Closing slot %p", slot);
668
669 disconnect_slot (window, slot);
670
671 window->slots = g_list_remove (window->slots, slot);
672
673 g_signal_emit (window, signals[SLOT_REMOVED], 0, slot);
674
675 notebook = GTK_NOTEBOOK (window->notebook);
676
677 if (remove_from_notebook)
678 {
679 page_num = gtk_notebook_page_num (notebook, GTK_WIDGET (slot));
680 g_assert (page_num >= 0);
681
682 /* this will call gtk_widget_destroy on the slot */
683 gtk_notebook_remove_page (notebook, page_num);
684 }
685 }
686
687 void
nautilus_window_new_tab(NautilusWindow * window)688 nautilus_window_new_tab (NautilusWindow *window)
689 {
690 NautilusWindowSlot *current_slot;
691 GFile *location;
692 g_autofree gchar *uri = NULL;
693
694 current_slot = nautilus_window_get_active_slot (window);
695 location = nautilus_window_slot_get_location (current_slot);
696
697 if (location != NULL)
698 {
699 uri = g_file_get_uri (location);
700 if (eel_uri_is_search (uri))
701 {
702 location = g_file_new_for_path (g_get_home_dir ());
703 }
704 else
705 {
706 g_object_ref (location);
707 }
708
709 nautilus_window_open_location_full (window, location,
710 NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB,
711 NULL, NULL);
712 g_object_unref (location);
713 }
714 }
715
716 static void
update_cursor(NautilusWindow * window)717 update_cursor (NautilusWindow *window)
718 {
719 NautilusWindowSlot *slot;
720
721 slot = nautilus_window_get_active_slot (window);
722
723 if (slot != NULL &&
724 nautilus_window_slot_get_allow_stop (slot))
725 {
726 GdkDisplay *display;
727 g_autoptr (GdkCursor) cursor = NULL;
728
729 display = gtk_widget_get_display (GTK_WIDGET (window));
730 cursor = gdk_cursor_new_from_name (display, "progress");
731 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
732 }
733 else
734 {
735 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
736 }
737 }
738
739 void
nautilus_window_reset_menus(NautilusWindow * window)740 nautilus_window_reset_menus (NautilusWindow *window)
741 {
742 nautilus_window_sync_allow_stop (window, nautilus_window_get_active_slot (window));
743 }
744
745 void
nautilus_window_sync_allow_stop(NautilusWindow * window,NautilusWindowSlot * slot)746 nautilus_window_sync_allow_stop (NautilusWindow *window,
747 NautilusWindowSlot *slot)
748 {
749 GAction *stop_action;
750 GAction *reload_action;
751 gboolean allow_stop, slot_is_active, slot_allow_stop;
752
753 stop_action = g_action_map_lookup_action (G_ACTION_MAP (window),
754 "stop");
755 reload_action = g_action_map_lookup_action (G_ACTION_MAP (window),
756 "reload");
757 allow_stop = g_action_get_enabled (stop_action);
758
759 slot_allow_stop = nautilus_window_slot_get_allow_stop (slot);
760 slot_is_active = (slot == nautilus_window_get_active_slot (window));
761
762
763 if (!slot_is_active ||
764 allow_stop != slot_allow_stop)
765 {
766 if (slot_is_active)
767 {
768 g_simple_action_set_enabled (G_SIMPLE_ACTION (stop_action), slot_allow_stop);
769 g_simple_action_set_enabled (G_SIMPLE_ACTION (reload_action), !slot_allow_stop);
770 }
771 if (gtk_widget_get_realized (GTK_WIDGET (window)))
772 {
773 update_cursor (window);
774 }
775
776 /* Avoid updating the notebook if we are calling on dispose or
777 * on removal of a notebook tab */
778 if (nautilus_notebook_contains_slot (NAUTILUS_NOTEBOOK (window->notebook), slot))
779 {
780 nautilus_notebook_sync_loading (NAUTILUS_NOTEBOOK (window->notebook), slot);
781 }
782 }
783 }
784
785 GtkWidget *
nautilus_window_get_notebook(NautilusWindow * window)786 nautilus_window_get_notebook (NautilusWindow *window)
787 {
788 g_return_val_if_fail (NAUTILUS_IS_WINDOW (window), NULL);
789
790 return window->notebook;
791 }
792
793 static gboolean
save_sidebar_width_cb(gpointer user_data)794 save_sidebar_width_cb (gpointer user_data)
795 {
796 NautilusWindow *window = user_data;
797
798
799 window->sidebar_width_handler_id = 0;
800
801 DEBUG ("Saving sidebar width: %d", window->side_pane_width);
802
803 g_settings_set_int (nautilus_window_state,
804 NAUTILUS_WINDOW_STATE_SIDEBAR_WIDTH,
805 window->side_pane_width);
806
807 return FALSE;
808 }
809
810 /* side pane helpers */
811 static void
side_pane_size_allocate_callback(GtkWidget * widget,GtkAllocation * allocation,gpointer user_data)812 side_pane_size_allocate_callback (GtkWidget *widget,
813 GtkAllocation *allocation,
814 gpointer user_data)
815 {
816 NautilusWindow *window = user_data;
817
818
819 if (window->sidebar_width_handler_id != 0)
820 {
821 g_source_remove (window->sidebar_width_handler_id);
822 window->sidebar_width_handler_id = 0;
823 }
824
825 if (allocation->width != window->side_pane_width &&
826 allocation->width > 1)
827 {
828 window->side_pane_width = allocation->width;
829
830 window->sidebar_width_handler_id =
831 g_idle_add (save_sidebar_width_cb, window);
832 }
833 }
834
835 static void
setup_side_pane_width(NautilusWindow * window)836 setup_side_pane_width (NautilusWindow *window)
837 {
838 g_return_if_fail (window->sidebar != NULL);
839
840 window->side_pane_width =
841 g_settings_get_int (nautilus_window_state,
842 NAUTILUS_WINDOW_STATE_SIDEBAR_WIDTH);
843
844 gtk_paned_set_position (GTK_PANED (window->content_paned),
845 window->side_pane_width);
846 }
847
848 /* Callback used when the places sidebar changes location; we need to change the displayed folder */
849 static void
open_location_cb(NautilusWindow * window,GFile * location,GtkPlacesOpenFlags open_flags)850 open_location_cb (NautilusWindow *window,
851 GFile *location,
852 GtkPlacesOpenFlags open_flags)
853 {
854 NautilusWindowOpenFlags flags;
855 NautilusApplication *application;
856
857 switch (open_flags)
858 {
859 case GTK_PLACES_OPEN_NEW_TAB:
860 {
861 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB |
862 NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE;
863 }
864 break;
865
866 case GTK_PLACES_OPEN_NEW_WINDOW:
867 {
868 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
869 }
870 break;
871
872 case GTK_PLACES_OPEN_NORMAL: /* fall-through */
873 default:
874 {
875 flags = 0;
876 }
877 break;
878 }
879
880 application = NAUTILUS_APPLICATION (g_application_get_default ());
881 /* FIXME: We shouldn't need to provide the window, but seems gtk_application_get_active_window
882 * is not working properly in GtkApplication, so we cannot rely on that...
883 */
884 nautilus_application_open_location_full (application, location, flags,
885 NULL, window, NULL);
886 }
887
888 static void
places_sidebar_unmount_operation_cb(NautilusWindow * window,GMountOperation * mount_operation)889 places_sidebar_unmount_operation_cb (NautilusWindow *window,
890 GMountOperation *mount_operation)
891 {
892 g_signal_connect (mount_operation, "show-unmount-progress",
893 G_CALLBACK (show_unmount_progress_cb), NULL);
894 g_signal_connect (mount_operation, "aborted",
895 G_CALLBACK (show_unmount_progress_aborted_cb), NULL);
896 }
897
898 /* Callback used when the places sidebar needs us to present an error message */
899 static void
places_sidebar_show_error_message_cb(GtkPlacesSidebar * sidebar,const char * primary,const char * secondary,gpointer user_data)900 places_sidebar_show_error_message_cb (GtkPlacesSidebar *sidebar,
901 const char *primary,
902 const char *secondary,
903 gpointer user_data)
904 {
905 NautilusWindow *window = NAUTILUS_WINDOW (user_data);
906
907 show_dialog (primary, secondary, GTK_WINDOW (window), GTK_MESSAGE_ERROR);
908 }
909
910 static void
places_sidebar_show_other_locations_with_flags(NautilusWindow * window,GtkPlacesOpenFlags open_flags)911 places_sidebar_show_other_locations_with_flags (NautilusWindow *window,
912 GtkPlacesOpenFlags open_flags)
913 {
914 GFile *location;
915
916 location = g_file_new_for_uri ("other-locations:///");
917
918 open_location_cb (window, location, open_flags);
919
920 g_object_unref (location);
921 }
922
923 static void
places_sidebar_show_starred_location(NautilusWindow * window,GtkPlacesOpenFlags open_flags)924 places_sidebar_show_starred_location (NautilusWindow *window,
925 GtkPlacesOpenFlags open_flags)
926 {
927 GFile *location;
928
929 location = g_file_new_for_uri ("starred:///");
930
931 open_location_cb (window, location, open_flags);
932
933 g_object_unref (location);
934 }
935
936 static GList *
build_selection_list_from_gfile_list(GList * gfile_list)937 build_selection_list_from_gfile_list (GList *gfile_list)
938 {
939 GList *result;
940 GList *l;
941
942 result = NULL;
943 for (l = gfile_list; l; l = l->next)
944 {
945 GFile *file;
946 NautilusDragSelectionItem *item;
947
948 file = l->data;
949
950 item = nautilus_drag_selection_item_new ();
951 item->uri = g_file_get_uri (file);
952 item->file = nautilus_file_get_existing (file);
953 item->got_icon_position = FALSE;
954 result = g_list_prepend (result, item);
955 }
956
957 return g_list_reverse (result);
958 }
959
960 void
nautilus_window_start_dnd(NautilusWindow * window,GdkDragContext * context)961 nautilus_window_start_dnd (NautilusWindow *window,
962 GdkDragContext *context)
963 {
964 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
965
966 gtk_places_sidebar_set_drop_targets_visible (GTK_PLACES_SIDEBAR (window->places_sidebar),
967 TRUE,
968 context);
969 }
970
971 void
nautilus_window_end_dnd(NautilusWindow * window,GdkDragContext * context)972 nautilus_window_end_dnd (NautilusWindow *window,
973 GdkDragContext *context)
974 {
975 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
976
977 gtk_places_sidebar_set_drop_targets_visible (GTK_PLACES_SIDEBAR (window->places_sidebar),
978 FALSE,
979 context);
980 }
981
982 /* Callback used when the places sidebar needs to know the drag action to suggest */
983 static GdkDragAction
places_sidebar_drag_action_requested_cb(GtkPlacesSidebar * sidebar,GdkDragContext * context,GFile * dest_file,GList * source_file_list,gpointer user_data)984 places_sidebar_drag_action_requested_cb (GtkPlacesSidebar *sidebar,
985 GdkDragContext *context,
986 GFile *dest_file,
987 GList *source_file_list,
988 gpointer user_data)
989 {
990 GList *items;
991 char *uri;
992 int action = 0;
993 NautilusDragInfo *info;
994 guint32 source_actions;
995
996 info = nautilus_drag_get_source_data (context);
997 if (info != NULL)
998 {
999 items = info->selection_cache;
1000 source_actions = info->source_actions;
1001 }
1002 else
1003 {
1004 items = build_selection_list_from_gfile_list (source_file_list);
1005 source_actions = 0;
1006 }
1007 uri = g_file_get_uri (dest_file);
1008
1009 if (items == NULL)
1010 {
1011 goto out;
1012 }
1013
1014 nautilus_drag_default_drop_action_for_icons (context, uri, items, source_actions, &action);
1015
1016 out:
1017 if (info == NULL)
1018 {
1019 nautilus_drag_destroy_selection_list (items);
1020 }
1021
1022 g_free (uri);
1023
1024 return action;
1025 }
1026
1027 /* Callback used when the places sidebar needs us to pop up a menu with possible drag actions */
1028 static GdkDragAction
places_sidebar_drag_action_ask_cb(GtkPlacesSidebar * sidebar,GdkDragAction actions,gpointer user_data)1029 places_sidebar_drag_action_ask_cb (GtkPlacesSidebar *sidebar,
1030 GdkDragAction actions,
1031 gpointer user_data)
1032 {
1033 return nautilus_drag_drop_action_ask (GTK_WIDGET (sidebar), actions);
1034 }
1035
1036 static GList *
build_uri_list_from_gfile_list(GList * file_list)1037 build_uri_list_from_gfile_list (GList *file_list)
1038 {
1039 GList *result;
1040 GList *l;
1041
1042 result = NULL;
1043
1044 for (l = file_list; l; l = l->next)
1045 {
1046 GFile *file = l->data;
1047 char *uri;
1048
1049 uri = g_file_get_uri (file);
1050 result = g_list_prepend (result, uri);
1051 }
1052
1053 return g_list_reverse (result);
1054 }
1055
1056 /* Callback used when the places sidebar has URIs dropped into it. We do a normal file operation for them. */
1057 static void
places_sidebar_drag_perform_drop_cb(GtkPlacesSidebar * sidebar,GFile * dest_file,GList * source_file_list,GdkDragAction action,gpointer user_data)1058 places_sidebar_drag_perform_drop_cb (GtkPlacesSidebar *sidebar,
1059 GFile *dest_file,
1060 GList *source_file_list,
1061 GdkDragAction action,
1062 gpointer user_data)
1063 {
1064 char *dest_uri;
1065 GList *source_uri_list;
1066
1067 dest_uri = g_file_get_uri (dest_file);
1068 source_uri_list = build_uri_list_from_gfile_list (source_file_list);
1069
1070 nautilus_file_operations_copy_move (source_uri_list, dest_uri, action, GTK_WIDGET (sidebar), NULL, NULL, NULL);
1071
1072 g_free (dest_uri);
1073 g_list_free_full (source_uri_list, g_free);
1074 }
1075
1076 /* Callback used in the "empty trash" menu item from the places sidebar */
1077 static void
action_empty_trash(GSimpleAction * action,GVariant * variant,gpointer user_data)1078 action_empty_trash (GSimpleAction *action,
1079 GVariant *variant,
1080 gpointer user_data)
1081 {
1082 NautilusWindow *window = NAUTILUS_WINDOW (user_data);
1083
1084 nautilus_file_operations_empty_trash (GTK_WIDGET (window), TRUE, NULL);
1085 }
1086
1087 /* Callback used for the "properties" menu item from the places sidebar */
1088 static void
action_properties(GSimpleAction * action,GVariant * variant,gpointer user_data)1089 action_properties (GSimpleAction *action,
1090 GVariant *variant,
1091 gpointer user_data)
1092 {
1093 NautilusWindow *window = NAUTILUS_WINDOW (user_data);
1094 GList *list;
1095 NautilusFile *file;
1096
1097 file = nautilus_file_get (window->selected_file);
1098
1099 list = g_list_append (NULL, file);
1100 nautilus_properties_window_present (list, GTK_WIDGET (window), NULL, NULL,
1101 NULL);
1102 nautilus_file_list_free (list);
1103
1104 g_clear_object (&window->selected_file);
1105 }
1106
1107 static gboolean
check_have_gnome_disks(void)1108 check_have_gnome_disks (void)
1109 {
1110 gchar *disks_path;
1111 gboolean res;
1112
1113 disks_path = g_find_program_in_path ("gnome-disks");
1114 res = (disks_path != NULL);
1115 g_free (disks_path);
1116
1117 return res;
1118 }
1119
1120 static gboolean
should_show_format_command(GVolume * volume)1121 should_show_format_command (GVolume *volume)
1122 {
1123 gchar *unix_device_id;
1124 gboolean show_format;
1125
1126 unix_device_id = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
1127 show_format = (unix_device_id != NULL) && check_have_gnome_disks ();
1128 g_free (unix_device_id);
1129
1130 return show_format;
1131 }
1132
1133 static void
action_restore_tab(GSimpleAction * action,GVariant * state,gpointer user_data)1134 action_restore_tab (GSimpleAction *action,
1135 GVariant *state,
1136 gpointer user_data)
1137 {
1138 NautilusWindow *window = NAUTILUS_WINDOW (user_data);
1139 NautilusWindowOpenFlags flags;
1140 g_autoptr (GFile) location = NULL;
1141 NautilusWindowSlot *slot;
1142 NautilusNavigationState *data;
1143
1144 if (g_queue_get_length (window->tab_data_queue) == 0)
1145 {
1146 return;
1147 }
1148
1149 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB | NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE;
1150
1151 data = g_queue_pop_head (window->tab_data_queue);
1152
1153 location = nautilus_file_get_location (data->file);
1154
1155 slot = nautilus_window_create_and_init_slot (window, flags);
1156
1157 nautilus_window_slot_open_location_full (slot, location, flags, NULL);
1158 nautilus_window_slot_restore_navigation_state (slot, data);
1159
1160 free_navigation_state (data);
1161 }
1162
1163 static guint
get_window_xid(NautilusWindow * window)1164 get_window_xid (NautilusWindow *window)
1165 {
1166 #ifdef GDK_WINDOWING_X11
1167 if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
1168 {
1169 GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
1170 return (guint) gdk_x11_window_get_xid (gdk_window);
1171 }
1172 #endif
1173 return 0;
1174 }
1175
1176 static void
action_format(GSimpleAction * action,GVariant * variant,gpointer user_data)1177 action_format (GSimpleAction *action,
1178 GVariant *variant,
1179 gpointer user_data)
1180 {
1181 NautilusWindow *window = NAUTILUS_WINDOW (user_data);
1182 GAppInfo *app_info;
1183 gchar *cmdline, *device_identifier, *xid_string;
1184
1185 device_identifier = g_volume_get_identifier (window->selected_volume,
1186 G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
1187 xid_string = g_strdup_printf ("%x", get_window_xid (window));
1188
1189 cmdline = g_strconcat ("gnome-disks ",
1190 "--block-device ", device_identifier, " ",
1191 "--format-device ",
1192 "--xid ", xid_string,
1193 NULL);
1194 app_info = g_app_info_create_from_commandline (cmdline, NULL, 0, NULL);
1195 g_app_info_launch (app_info, NULL, NULL, NULL);
1196
1197 g_free (cmdline);
1198 g_free (device_identifier);
1199 g_free (xid_string);
1200 g_clear_object (&app_info);
1201 g_clear_object (&window->selected_volume);
1202 }
1203
1204 static void
add_menu_separator(GtkWidget * menu)1205 add_menu_separator (GtkWidget *menu)
1206 {
1207 GtkWidget *separator;
1208
1209 separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
1210 gtk_container_add (GTK_CONTAINER (menu), separator);
1211 gtk_widget_show (separator);
1212 }
1213
1214 static void
places_sidebar_populate_popup_cb(GtkPlacesSidebar * sidebar,GtkWidget * menu,GFile * selected_file,GVolume * selected_volume,gpointer user_data)1215 places_sidebar_populate_popup_cb (GtkPlacesSidebar *sidebar,
1216 GtkWidget *menu,
1217 GFile *selected_file,
1218 GVolume *selected_volume,
1219 gpointer user_data)
1220 {
1221 NautilusWindow *window = NAUTILUS_WINDOW (user_data);
1222 GFile *trash;
1223 GtkWidget *menu_item;
1224 GAction *action;
1225
1226 g_clear_object (&window->selected_file);
1227 g_clear_object (&window->selected_volume);
1228
1229 if (selected_file)
1230 {
1231 trash = g_file_new_for_uri ("trash:///");
1232 if (g_file_equal (trash, selected_file))
1233 {
1234 add_menu_separator (menu);
1235
1236 menu_item = gtk_model_button_new ();
1237 gtk_actionable_set_action_name (GTK_ACTIONABLE (menu_item),
1238 "win.empty-trash");
1239 g_object_set (menu_item, "text", _("Empty _Trash…"), NULL);
1240 gtk_container_add (GTK_CONTAINER (menu), menu_item);
1241 gtk_widget_show (menu_item);
1242
1243 action = g_action_map_lookup_action (G_ACTION_MAP (window),
1244 "empty-trash");
1245 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
1246 !nautilus_trash_monitor_is_empty ());
1247 }
1248 g_object_unref (trash);
1249
1250 if (g_file_is_native (selected_file))
1251 {
1252 window->selected_file = g_object_ref (selected_file);
1253 add_menu_separator (menu);
1254
1255 menu_item = gtk_model_button_new ();
1256 gtk_actionable_set_action_name (GTK_ACTIONABLE (menu_item),
1257 "win.properties");
1258 g_object_set (menu_item, "text", _("_Properties"), NULL);
1259 gtk_container_add (GTK_CONTAINER (menu), menu_item);
1260 gtk_widget_show (menu_item);
1261 }
1262 }
1263 if (selected_volume)
1264 {
1265 if (should_show_format_command (selected_volume))
1266 {
1267 menu_item = gtk_model_button_new ();
1268 gtk_actionable_set_action_name (GTK_ACTIONABLE (menu_item),
1269 "win.format");
1270 g_object_set (menu_item, "text", _("_Format…"), NULL);
1271 if (selected_volume != NULL && G_IS_VOLUME (selected_volume))
1272 {
1273 window->selected_volume = g_object_ref (selected_volume);
1274 }
1275 gtk_container_add (GTK_CONTAINER (menu), menu_item);
1276 gtk_widget_show (menu_item);
1277
1278 action = g_action_map_lookup_action (G_ACTION_MAP (window),
1279 "format");
1280 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
1281 selected_volume != NULL &&
1282 G_IS_VOLUME (selected_volume));
1283 }
1284 }
1285 }
1286
1287 static void
nautilus_window_set_up_sidebar(NautilusWindow * window)1288 nautilus_window_set_up_sidebar (NautilusWindow *window)
1289 {
1290 setup_side_pane_width (window);
1291 g_signal_connect (window->sidebar,
1292 "size-allocate",
1293 G_CALLBACK (side_pane_size_allocate_callback),
1294 window);
1295
1296 gtk_places_sidebar_set_open_flags (GTK_PLACES_SIDEBAR (window->places_sidebar),
1297 (GTK_PLACES_OPEN_NORMAL
1298 | GTK_PLACES_OPEN_NEW_TAB
1299 | GTK_PLACES_OPEN_NEW_WINDOW));
1300
1301 g_signal_connect_swapped (window->places_sidebar, "open-location",
1302 G_CALLBACK (open_location_cb), window);
1303 g_signal_connect (window->places_sidebar, "show-error-message",
1304 G_CALLBACK (places_sidebar_show_error_message_cb), window);
1305 g_signal_connect (window->places_sidebar, "drag-action-requested",
1306 G_CALLBACK (places_sidebar_drag_action_requested_cb), window);
1307 g_signal_connect (window->places_sidebar, "drag-action-ask",
1308 G_CALLBACK (places_sidebar_drag_action_ask_cb), window);
1309 g_signal_connect (window->places_sidebar, "drag-perform-drop",
1310 G_CALLBACK (places_sidebar_drag_perform_drop_cb), window);
1311 g_signal_connect (window->places_sidebar, "populate-popup",
1312 G_CALLBACK (places_sidebar_populate_popup_cb), window);
1313 g_signal_connect (window->places_sidebar, "unmount",
1314 G_CALLBACK (places_sidebar_unmount_operation_cb), window);
1315 }
1316
1317 void
nautilus_window_hide_sidebar(NautilusWindow * window)1318 nautilus_window_hide_sidebar (NautilusWindow *window)
1319 {
1320 DEBUG ("Called hide_sidebar()");
1321
1322 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
1323
1324 gtk_widget_hide (window->sidebar);
1325 }
1326
1327 void
nautilus_window_show_sidebar(NautilusWindow * window)1328 nautilus_window_show_sidebar (NautilusWindow *window)
1329 {
1330 DEBUG ("Called show_sidebar()");
1331
1332 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
1333
1334 gtk_widget_show (window->sidebar);
1335 setup_side_pane_width (window);
1336 }
1337
1338 void
nautilus_window_slot_close(NautilusWindow * window,NautilusWindowSlot * slot)1339 nautilus_window_slot_close (NautilusWindow *window,
1340 NautilusWindowSlot *slot)
1341 {
1342 NautilusNavigationState *data;
1343
1344 DEBUG ("Requesting to remove slot %p from window %p", slot, window);
1345 if (window == NULL || slot == NULL)
1346 {
1347 return;
1348 }
1349
1350 data = nautilus_window_slot_get_navigation_state (slot);
1351 if (data != NULL)
1352 {
1353 g_queue_push_head (window->tab_data_queue, data);
1354 }
1355
1356 close_slot (window, slot, TRUE);
1357
1358 /* If that was the last slot in the window, close the window. */
1359 if (window->slots == NULL)
1360 {
1361 DEBUG ("Last slot removed, closing the window");
1362 nautilus_window_close (window);
1363 }
1364 }
1365
1366 static void
nautilus_window_sync_bookmarks(NautilusWindow * window)1367 nautilus_window_sync_bookmarks (NautilusWindow *window)
1368 {
1369 gboolean can_bookmark = FALSE;
1370 NautilusWindowSlot *slot;
1371 NautilusBookmarkList *bookmarks;
1372 GAction *action;
1373 GFile *location;
1374
1375 slot = window->active_slot;
1376 location = slot != NULL ? nautilus_window_slot_get_location (slot) : NULL;
1377
1378 if (location != NULL)
1379 {
1380 bookmarks = nautilus_application_get_bookmarks
1381 (NAUTILUS_APPLICATION (gtk_window_get_application (GTK_WINDOW (window))));
1382 can_bookmark = nautilus_bookmark_list_can_bookmark_location (bookmarks, location);
1383 }
1384
1385 action = g_action_map_lookup_action (G_ACTION_MAP (window), "bookmark-current-location");
1386 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_bookmark);
1387 }
1388
1389 void
nautilus_window_sync_location_widgets(NautilusWindow * window)1390 nautilus_window_sync_location_widgets (NautilusWindow *window)
1391 {
1392 NautilusWindowSlot *slot;
1393 GFile *location;
1394 GAction *action;
1395 gboolean enabled;
1396
1397 slot = window->active_slot;
1398 /* This function is called by the active slot. */
1399 g_assert (slot != NULL);
1400
1401 location = nautilus_window_slot_get_location (slot);
1402
1403 /* Change the location bar and path bar to match the current location. */
1404 if (location != NULL)
1405 {
1406 GtkWidget *location_entry;
1407 GtkWidget *path_bar;
1408
1409 location_entry = nautilus_toolbar_get_location_entry (NAUTILUS_TOOLBAR (window->toolbar));
1410 nautilus_location_entry_set_location (NAUTILUS_LOCATION_ENTRY (location_entry), location);
1411
1412 path_bar = nautilus_toolbar_get_path_bar (NAUTILUS_TOOLBAR (window->toolbar));
1413 nautilus_path_bar_set_path (NAUTILUS_PATH_BAR (path_bar), location);
1414 }
1415
1416 action = g_action_map_lookup_action (G_ACTION_MAP (window), "back");
1417 enabled = nautilus_window_slot_get_back_history (slot) != NULL;
1418 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
1419
1420 action = g_action_map_lookup_action (G_ACTION_MAP (window), "forward");
1421 enabled = nautilus_window_slot_get_forward_history (slot) != NULL;
1422 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
1423
1424 nautilus_window_sync_bookmarks (window);
1425 }
1426
1427 static GtkWidget *
nautilus_window_ensure_location_entry(NautilusWindow * window)1428 nautilus_window_ensure_location_entry (NautilusWindow *window)
1429 {
1430 GtkWidget *location_entry;
1431
1432 remember_focus_widget (window);
1433
1434 nautilus_toolbar_set_show_location_entry (NAUTILUS_TOOLBAR (window->toolbar), TRUE);
1435
1436 location_entry = nautilus_toolbar_get_location_entry (NAUTILUS_TOOLBAR (window->toolbar));
1437 gtk_widget_grab_focus (location_entry);
1438
1439 return location_entry;
1440 }
1441
1442 static void
remove_notifications(NautilusWindow * window)1443 remove_notifications (NautilusWindow *window)
1444 {
1445 GtkRevealerTransitionType transition_type;
1446
1447 /* Hide it inmediatily so we can animate the new notification. */
1448 transition_type = gtk_revealer_get_transition_type (GTK_REVEALER (window->in_app_notification_undo));
1449 gtk_revealer_set_transition_type (GTK_REVEALER (window->in_app_notification_undo),
1450 GTK_REVEALER_TRANSITION_TYPE_NONE);
1451 gtk_revealer_set_reveal_child (GTK_REVEALER (window->in_app_notification_undo),
1452 FALSE);
1453 gtk_revealer_set_transition_type (GTK_REVEALER (window->in_app_notification_undo),
1454 transition_type);
1455 if (window->in_app_notification_undo_timeout_id != 0)
1456 {
1457 g_source_remove (window->in_app_notification_undo_timeout_id);
1458 window->in_app_notification_undo_timeout_id = 0;
1459 }
1460
1461 transition_type = gtk_revealer_get_transition_type (GTK_REVEALER (window->notification_operation));
1462 gtk_revealer_set_transition_type (GTK_REVEALER (window->notification_operation),
1463 GTK_REVEALER_TRANSITION_TYPE_NONE);
1464 gtk_revealer_set_reveal_child (GTK_REVEALER (window->notification_operation),
1465 FALSE);
1466 gtk_revealer_set_transition_type (GTK_REVEALER (window->notification_operation),
1467 transition_type);
1468 if (window->notification_operation_timeout_id != 0)
1469 {
1470 g_source_remove (window->notification_operation_timeout_id);
1471 window->notification_operation_timeout_id = 0;
1472 }
1473 }
1474
1475 static void
hide_in_app_notification_undo(NautilusWindow * window)1476 hide_in_app_notification_undo (NautilusWindow *window)
1477 {
1478 if (window->in_app_notification_undo_timeout_id != 0)
1479 {
1480 g_source_remove (window->in_app_notification_undo_timeout_id);
1481 window->in_app_notification_undo_timeout_id = 0;
1482 }
1483
1484 gtk_revealer_set_reveal_child (GTK_REVEALER (window->in_app_notification_undo), FALSE);
1485 }
1486
1487 static void
on_in_app_notification_undo_undo_button_clicked(GtkWidget * notification,NautilusWindow * window)1488 on_in_app_notification_undo_undo_button_clicked (GtkWidget *notification,
1489 NautilusWindow *window)
1490 {
1491 hide_in_app_notification_undo (window);
1492
1493 nautilus_file_undo_manager_undo (GTK_WINDOW (window), NULL);
1494 }
1495
1496 static void
on_in_app_notification_undo_close_button_clicked(GtkWidget * notification,NautilusWindow * window)1497 on_in_app_notification_undo_close_button_clicked (GtkWidget *notification,
1498 NautilusWindow *window)
1499 {
1500 hide_in_app_notification_undo (window);
1501 }
1502
1503 static gboolean
on_in_app_notification_undo_timeout(NautilusWindow * window)1504 on_in_app_notification_undo_timeout (NautilusWindow *window)
1505 {
1506 hide_in_app_notification_undo (window);
1507
1508 return G_SOURCE_REMOVE;
1509 }
1510
1511 static gchar *
in_app_notification_undo_deleted_get_label(NautilusFileUndoInfo * undo_info)1512 in_app_notification_undo_deleted_get_label (NautilusFileUndoInfo *undo_info)
1513 {
1514 GList *files;
1515 gchar *file_label;
1516 gchar *label;
1517 gint length;
1518
1519 files = nautilus_file_undo_info_trash_get_files (NAUTILUS_FILE_UNDO_INFO_TRASH (undo_info));
1520 length = g_list_length (files);
1521 if (length == 1)
1522 {
1523 file_label = g_file_get_basename (files->data);
1524 /* Translators: only one item has been deleted and %s is its name. */
1525 label = g_markup_printf_escaped (_("“%s” deleted"), file_label);
1526 g_free (file_label);
1527 }
1528 else
1529 {
1530 /* Translators: one or more items might have been deleted, and %d
1531 * is the count. */
1532 label = g_markup_printf_escaped (ngettext ("%d file deleted", "%d files deleted", length), length);
1533 }
1534
1535 return label;
1536 }
1537
1538 static gchar *
in_app_notification_undo_unstar_get_label(NautilusFileUndoInfo * undo_info)1539 in_app_notification_undo_unstar_get_label (NautilusFileUndoInfo *undo_info)
1540 {
1541 GList *files;
1542 gchar *label;
1543 gint length;
1544
1545 files = nautilus_file_undo_info_starred_get_files (NAUTILUS_FILE_UNDO_INFO_STARRED (undo_info));
1546 length = g_list_length (files);
1547 if (length == 1)
1548 {
1549 g_autofree gchar *file_label = NULL;
1550
1551 file_label = nautilus_file_get_display_name (files->data);
1552 /* Translators: one item has been unstarred and %s is its name. */
1553 label = g_markup_printf_escaped (_("“%s” unstarred"), file_label);
1554 }
1555 else
1556 {
1557 /* Translators: one or more items have been unstarred, and %d
1558 * is the count. */
1559 label = g_markup_printf_escaped (ngettext ("%d file unstarred", "%d files unstarred", length), length);
1560 }
1561
1562 return label;
1563 }
1564
1565 static void
nautilus_window_on_undo_changed(NautilusFileUndoManager * manager,NautilusWindow * window)1566 nautilus_window_on_undo_changed (NautilusFileUndoManager *manager,
1567 NautilusWindow *window)
1568 {
1569 NautilusFileUndoInfo *undo_info;
1570 NautilusFileUndoManagerState state;
1571
1572 undo_info = nautilus_file_undo_manager_get_action ();
1573 state = nautilus_file_undo_manager_get_state ();
1574
1575 if (undo_info != NULL &&
1576 state == NAUTILUS_FILE_UNDO_MANAGER_STATE_UNDO)
1577 {
1578 gboolean popup_notification = FALSE;
1579 g_autofree gchar *label = NULL;
1580
1581 if (nautilus_file_undo_info_get_op_type (undo_info) == NAUTILUS_FILE_UNDO_OP_MOVE_TO_TRASH)
1582 {
1583 g_autoptr (GList) files = NULL;
1584
1585 files = nautilus_file_undo_info_trash_get_files (NAUTILUS_FILE_UNDO_INFO_TRASH (undo_info));
1586
1587 /* Don't pop up a notification if user canceled the operation or the focus
1588 * is not in the this window. This is an easy way to know from which window
1589 * was the delete operation made */
1590 if (files != NULL && gtk_window_has_toplevel_focus (GTK_WINDOW (window)))
1591 {
1592 popup_notification = TRUE;
1593 label = in_app_notification_undo_deleted_get_label (undo_info);
1594 }
1595 }
1596 else if (nautilus_file_undo_info_get_op_type (undo_info) == NAUTILUS_FILE_UNDO_OP_STARRED)
1597 {
1598 NautilusWindowSlot *active_slot;
1599 GFile *location;
1600
1601 active_slot = nautilus_window_get_active_slot (window);
1602 location = nautilus_window_slot_get_location (active_slot);
1603 /* Don't pop up a notification if the focus is not in the this
1604 * window. This is an easy way to know from which window was the
1605 * unstart operation made */
1606 if (eel_uri_is_starred (g_file_get_uri (location)) &&
1607 gtk_window_has_toplevel_focus (GTK_WINDOW (window)) &&
1608 !nautilus_file_undo_info_starred_is_starred (NAUTILUS_FILE_UNDO_INFO_STARRED (undo_info)))
1609 {
1610 popup_notification = TRUE;
1611 label = in_app_notification_undo_unstar_get_label (undo_info);
1612 }
1613 }
1614
1615 if (popup_notification)
1616 {
1617 remove_notifications (window);
1618 gtk_label_set_markup (GTK_LABEL (window->in_app_notification_undo_label),
1619 label);
1620 gtk_revealer_set_reveal_child (GTK_REVEALER (window->in_app_notification_undo),
1621 TRUE);
1622 window->in_app_notification_undo_timeout_id = g_timeout_add_seconds (NOTIFICATION_TIMEOUT,
1623 (GSourceFunc) on_in_app_notification_undo_timeout,
1624 window);
1625 }
1626 }
1627 else
1628 {
1629 hide_in_app_notification_undo (window);
1630 }
1631 }
1632
1633 static void
hide_notification_operation(NautilusWindow * window)1634 hide_notification_operation (NautilusWindow *window)
1635 {
1636 if (window->notification_operation_timeout_id != 0)
1637 {
1638 g_source_remove (window->notification_operation_timeout_id);
1639 window->notification_operation_timeout_id = 0;
1640 }
1641
1642 gtk_revealer_set_reveal_child (GTK_REVEALER (window->notification_operation), FALSE);
1643 g_clear_object (&window->folder_to_open);
1644 }
1645
1646 static void
on_notification_operation_open_clicked(GtkWidget * notification,NautilusWindow * window)1647 on_notification_operation_open_clicked (GtkWidget *notification,
1648 NautilusWindow *window)
1649 {
1650 nautilus_window_open_location_full (window, window->folder_to_open,
1651 0, NULL, NULL);
1652 hide_notification_operation (window);
1653 }
1654
1655 static void
on_notification_operation_close_clicked(GtkWidget * notification,NautilusWindow * window)1656 on_notification_operation_close_clicked (GtkWidget *notification,
1657 NautilusWindow *window)
1658 {
1659 hide_notification_operation (window);
1660 }
1661
1662 static gboolean
on_notification_operation_timeout(NautilusWindow * window)1663 on_notification_operation_timeout (NautilusWindow *window)
1664 {
1665 hide_notification_operation (window);
1666
1667 return FALSE;
1668 }
1669
1670 void
nautilus_window_show_operation_notification(NautilusWindow * window,gchar * main_label,GFile * folder_to_open)1671 nautilus_window_show_operation_notification (NautilusWindow *window,
1672 gchar *main_label,
1673 GFile *folder_to_open)
1674 {
1675 gchar *button_label;
1676 gchar *folder_name;
1677 NautilusFile *folder;
1678 GFile *current_location;
1679
1680 if (window->active_slot == NULL)
1681 {
1682 return;
1683 }
1684
1685 current_location = nautilus_window_slot_get_location (window->active_slot);
1686 if (gtk_window_has_toplevel_focus (GTK_WINDOW (window)))
1687 {
1688 remove_notifications (window);
1689 gtk_label_set_text (GTK_LABEL (window->notification_operation_label),
1690 main_label);
1691
1692 if (g_file_equal (folder_to_open, current_location))
1693 {
1694 gtk_widget_hide (window->notification_operation_open);
1695 }
1696 else
1697 {
1698 gtk_widget_show (window->notification_operation_open);
1699 window->folder_to_open = g_object_ref (folder_to_open);
1700 folder = nautilus_file_get (folder_to_open);
1701 folder_name = nautilus_file_get_display_name (folder);
1702 button_label = g_strdup_printf (_("Open %s"), folder_name);
1703 gtk_button_set_label (GTK_BUTTON (window->notification_operation_open),
1704 button_label);
1705 nautilus_file_unref (folder);
1706 g_free (folder_name);
1707 g_free (button_label);
1708 }
1709
1710 gtk_revealer_set_reveal_child (GTK_REVEALER (window->notification_operation), TRUE);
1711 window->notification_operation_timeout_id = g_timeout_add_seconds (NOTIFICATION_TIMEOUT,
1712 (GSourceFunc) on_notification_operation_timeout,
1713 window);
1714 }
1715 }
1716
1717 static void
path_bar_location_changed_callback(GtkWidget * widget,GFile * location,NautilusWindow * window)1718 path_bar_location_changed_callback (GtkWidget *widget,
1719 GFile *location,
1720 NautilusWindow *window)
1721 {
1722 nautilus_window_open_location_full (window, location, 0, NULL, NULL);
1723 }
1724
1725 static void
notebook_popup_menu_new_tab_cb(GtkMenuItem * menuitem,gpointer user_data)1726 notebook_popup_menu_new_tab_cb (GtkMenuItem *menuitem,
1727 gpointer user_data)
1728 {
1729 NautilusWindow *window = user_data;
1730
1731 nautilus_window_new_tab (window);
1732 }
1733
1734 static void
notebook_popup_menu_move_left_cb(GtkMenuItem * menuitem,gpointer user_data)1735 notebook_popup_menu_move_left_cb (GtkMenuItem *menuitem,
1736 gpointer user_data)
1737 {
1738 NautilusWindow *window = user_data;
1739
1740 nautilus_notebook_reorder_current_child_relative (NAUTILUS_NOTEBOOK (window->notebook), -1);
1741 }
1742
1743 static void
notebook_popup_menu_move_right_cb(GtkMenuItem * menuitem,gpointer user_data)1744 notebook_popup_menu_move_right_cb (GtkMenuItem *menuitem,
1745 gpointer user_data)
1746 {
1747 NautilusWindow *window = user_data;
1748
1749
1750 nautilus_notebook_reorder_current_child_relative (NAUTILUS_NOTEBOOK (window->notebook), 1);
1751 }
1752
1753 static void
notebook_popup_menu_close_cb(GtkMenuItem * menuitem,gpointer user_data)1754 notebook_popup_menu_close_cb (GtkMenuItem *menuitem,
1755 gpointer user_data)
1756 {
1757 NautilusWindow *window = user_data;
1758 NautilusWindowSlot *slot;
1759
1760 slot = window->active_slot;
1761 nautilus_window_slot_close (window, slot);
1762 }
1763
1764 static void
notebook_popup_menu_show(NautilusWindow * window,const GdkEvent * event)1765 notebook_popup_menu_show (NautilusWindow *window,
1766 const GdkEvent *event)
1767 {
1768 GtkWidget *popup;
1769 GtkWidget *item;
1770 gboolean can_move_left, can_move_right;
1771 NautilusNotebook *notebook;
1772
1773 notebook = NAUTILUS_NOTEBOOK (window->notebook);
1774
1775 can_move_left = nautilus_notebook_can_reorder_current_child_relative (notebook, -1);
1776 can_move_right = nautilus_notebook_can_reorder_current_child_relative (notebook, 1);
1777
1778 popup = gtk_menu_new ();
1779
1780 item = gtk_menu_item_new_with_mnemonic (_("_New Tab"));
1781 g_signal_connect (item, "activate",
1782 G_CALLBACK (notebook_popup_menu_new_tab_cb),
1783 window);
1784 gtk_menu_shell_append (GTK_MENU_SHELL (popup),
1785 item);
1786
1787 gtk_menu_shell_append (GTK_MENU_SHELL (popup),
1788 gtk_separator_menu_item_new ());
1789
1790 item = gtk_menu_item_new_with_mnemonic (_("Move Tab _Left"));
1791 g_signal_connect (item, "activate",
1792 G_CALLBACK (notebook_popup_menu_move_left_cb),
1793 window);
1794 gtk_menu_shell_append (GTK_MENU_SHELL (popup),
1795 item);
1796 gtk_widget_set_sensitive (item, can_move_left);
1797
1798 item = gtk_menu_item_new_with_mnemonic (_("Move Tab _Right"));
1799 g_signal_connect (item, "activate",
1800 G_CALLBACK (notebook_popup_menu_move_right_cb),
1801 window);
1802 gtk_menu_shell_append (GTK_MENU_SHELL (popup),
1803 item);
1804 gtk_widget_set_sensitive (item, can_move_right);
1805
1806 gtk_menu_shell_append (GTK_MENU_SHELL (popup),
1807 gtk_separator_menu_item_new ());
1808
1809 item = gtk_menu_item_new_with_mnemonic (_("_Close Tab"));
1810 g_signal_connect (item, "activate",
1811 G_CALLBACK (notebook_popup_menu_close_cb), window);
1812 gtk_menu_shell_append (GTK_MENU_SHELL (popup),
1813 item);
1814
1815 gtk_widget_show_all (popup);
1816
1817 gtk_menu_popup_at_pointer (GTK_MENU (popup), event);
1818 }
1819
1820 /* emitted when the user clicks the "close" button of tabs */
1821 static void
notebook_tab_close_requested(NautilusNotebook * notebook,NautilusWindowSlot * slot,NautilusWindow * window)1822 notebook_tab_close_requested (NautilusNotebook *notebook,
1823 NautilusWindowSlot *slot,
1824 NautilusWindow *window)
1825 {
1826 nautilus_window_slot_close (window, slot);
1827 }
1828
1829 static void
notebook_button_press_cb(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,gpointer user_data)1830 notebook_button_press_cb (GtkGestureMultiPress *gesture,
1831 gint n_press,
1832 gdouble x,
1833 gdouble y,
1834 gpointer user_data)
1835 {
1836 NautilusWindow *window;
1837 GdkEventSequence *sequence;
1838 const GdkEvent *event;
1839
1840 window = NAUTILUS_WINDOW (user_data);
1841
1842 if (nautilus_notebook_content_area_hit (NAUTILUS_NOTEBOOK (window->notebook), x, y))
1843 {
1844 return;
1845 }
1846
1847 sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
1848 event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
1849
1850 notebook_popup_menu_show (window, event);
1851 }
1852
1853 static gboolean
notebook_popup_menu_cb(GtkWidget * widget,gpointer user_data)1854 notebook_popup_menu_cb (GtkWidget *widget,
1855 gpointer user_data)
1856 {
1857 NautilusWindow *window = user_data;
1858 notebook_popup_menu_show (window, NULL);
1859 return TRUE;
1860 }
1861
1862 GtkWidget *
nautilus_window_get_toolbar(NautilusWindow * window)1863 nautilus_window_get_toolbar (NautilusWindow *window)
1864 {
1865 g_return_val_if_fail (NAUTILUS_IS_WINDOW (window), NULL);
1866
1867 return window->toolbar;
1868 }
1869
1870 static void
setup_toolbar(NautilusWindow * window)1871 setup_toolbar (NautilusWindow *window)
1872 {
1873 GtkWidget *path_bar;
1874 GtkWidget *location_entry;
1875
1876
1877 g_object_set (window->toolbar, "window", window, NULL);
1878
1879 /* connect to the pathbar signals */
1880 path_bar = nautilus_toolbar_get_path_bar (NAUTILUS_TOOLBAR (window->toolbar));
1881
1882 g_signal_connect_object (path_bar, "path-clicked",
1883 G_CALLBACK (path_bar_location_changed_callback), window, 0);
1884 g_signal_connect_swapped (path_bar, "open-location",
1885 G_CALLBACK (open_location_cb), window);
1886
1887 /* connect to the location entry signals */
1888 location_entry = nautilus_toolbar_get_location_entry (NAUTILUS_TOOLBAR (window->toolbar));
1889
1890 g_signal_connect_object (location_entry, "location-changed",
1891 G_CALLBACK (location_entry_location_changed_callback), window, 0);
1892 g_signal_connect_object (location_entry, "cancel",
1893 G_CALLBACK (location_entry_cancel_callback), window, 0);
1894 }
1895
1896 static void
notebook_page_removed_cb(GtkNotebook * notebook,GtkWidget * page,guint page_num,gpointer user_data)1897 notebook_page_removed_cb (GtkNotebook *notebook,
1898 GtkWidget *page,
1899 guint page_num,
1900 gpointer user_data)
1901 {
1902 NautilusWindow *window = user_data;
1903 NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (page);
1904 gboolean dnd_slot;
1905
1906 dnd_slot = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (slot), "dnd-window-slot"));
1907 if (!dnd_slot)
1908 {
1909 return;
1910 }
1911
1912 close_slot (window, slot, FALSE);
1913 }
1914
1915 static void
notebook_page_added_cb(GtkNotebook * notebook,GtkWidget * page,guint page_num,gpointer user_data)1916 notebook_page_added_cb (GtkNotebook *notebook,
1917 GtkWidget *page,
1918 guint page_num,
1919 gpointer user_data)
1920 {
1921 NautilusWindow *window = user_data;
1922 NautilusWindowSlot *slot = NAUTILUS_WINDOW_SLOT (page);
1923 NautilusWindowSlot *dummy_slot;
1924 gboolean dnd_slot;
1925
1926 dnd_slot = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (slot), "dnd-window-slot"));
1927 if (!dnd_slot)
1928 {
1929 return;
1930 }
1931
1932 g_object_set_data (G_OBJECT (page), "dnd-window-slot",
1933 GINT_TO_POINTER (FALSE));
1934
1935 nautilus_window_slot_set_window (slot, window);
1936 window->slots = g_list_append (window->slots, slot);
1937 g_signal_emit (window, signals[SLOT_ADDED], 0, slot);
1938
1939 nautilus_window_set_active_slot (window, slot);
1940
1941 dummy_slot = g_list_nth_data (window->slots, 0);
1942 if (dummy_slot != NULL)
1943 {
1944 close_slot (window, dummy_slot, TRUE);
1945 }
1946
1947 gtk_widget_show (GTK_WIDGET (window));
1948 }
1949
1950 static GtkNotebook *
notebook_create_window_cb(GtkNotebook * notebook,GtkWidget * page,gint x,gint y,gpointer user_data)1951 notebook_create_window_cb (GtkNotebook *notebook,
1952 GtkWidget *page,
1953 gint x,
1954 gint y,
1955 gpointer user_data)
1956 {
1957 NautilusApplication *app;
1958 NautilusWindow *new_window;
1959 NautilusWindowSlot *slot;
1960
1961 if (!NAUTILUS_IS_WINDOW_SLOT (page))
1962 {
1963 return NULL;
1964 }
1965
1966 app = NAUTILUS_APPLICATION (g_application_get_default ());
1967 new_window = nautilus_application_create_window
1968 (app, gtk_widget_get_screen (GTK_WIDGET (notebook)));
1969
1970 slot = NAUTILUS_WINDOW_SLOT (page);
1971 g_object_set_data (G_OBJECT (slot), "dnd-window-slot",
1972 GINT_TO_POINTER (TRUE));
1973
1974 gtk_window_set_position (GTK_WINDOW (new_window), GTK_WIN_POS_MOUSE);
1975
1976 return GTK_NOTEBOOK (new_window->notebook);
1977 }
1978
1979 static void
setup_notebook(NautilusWindow * window)1980 setup_notebook (NautilusWindow *window)
1981 {
1982 g_signal_connect (window->notebook, "tab-close-request",
1983 G_CALLBACK (notebook_tab_close_requested),
1984 window);
1985 g_signal_connect (window->notebook, "popup-menu",
1986 G_CALLBACK (notebook_popup_menu_cb),
1987 window);
1988 g_signal_connect (window->notebook, "switch-page",
1989 G_CALLBACK (notebook_switch_page_cb),
1990 window);
1991 g_signal_connect (window->notebook, "create-window",
1992 G_CALLBACK (notebook_create_window_cb),
1993 window);
1994 g_signal_connect (window->notebook, "page-added",
1995 G_CALLBACK (notebook_page_added_cb),
1996 window);
1997 g_signal_connect (window->notebook, "page-removed",
1998 G_CALLBACK (notebook_page_removed_cb),
1999 window);
2000
2001 g_signal_connect (window->notebook_multi_press_gesture, "pressed",
2002 G_CALLBACK (notebook_button_press_cb),
2003 window);
2004 }
2005
2006 const GActionEntry win_entries[] =
2007 {
2008 { "back", action_back },
2009 { "forward", action_forward },
2010 { "up", action_up },
2011 { "view-menu", action_toggle_state_view_button, NULL, "false", NULL },
2012 { "reload", action_reload },
2013 { "stop", action_stop },
2014 { "new-tab", action_new_tab },
2015 { "enter-location", action_enter_location },
2016 { "bookmark-current-location", action_bookmark_current_location },
2017 { "undo", action_undo },
2018 { "redo", action_redo },
2019 /* Only accesible by shorcuts */
2020 { "close-current-view", action_close_current_view },
2021 { "go-home", action_go_home },
2022 { "tab-previous", action_tab_previous },
2023 { "tab-next", action_tab_next },
2024 { "tab-move-left", action_tab_move_left },
2025 { "tab-move-right", action_tab_move_right },
2026 { "prompt-root-location", action_prompt_for_location_root },
2027 { "prompt-home-location", action_prompt_for_location_home },
2028 { "go-to-tab", NULL, "i", "0", action_go_to_tab },
2029 { "empty-trash", action_empty_trash },
2030 { "properties", action_properties },
2031 { "format", action_format },
2032 { "restore-tab", action_restore_tab },
2033 };
2034
2035 static void
nautilus_window_initialize_actions(NautilusWindow * window)2036 nautilus_window_initialize_actions (NautilusWindow *window)
2037 {
2038 GApplication *app;
2039 GAction *action;
2040 GVariant *state;
2041 gchar detailed_action[80];
2042 gchar accel[80];
2043 gint i;
2044 const gchar *reload_accels[] =
2045 {
2046 "F5",
2047 "<ctrl>r",
2048 NULL
2049 };
2050 const gchar *prompt_root_location_accels[] =
2051 {
2052 "slash",
2053 "KP_Divide",
2054 NULL
2055 };
2056 const gchar *prompt_home_location_accels[] =
2057 {
2058 "asciitilde",
2059 "dead_tilde",
2060 NULL
2061 };
2062
2063 g_action_map_add_action_entries (G_ACTION_MAP (window),
2064 win_entries, G_N_ELEMENTS (win_entries),
2065 window);
2066
2067 app = g_application_get_default ();
2068 nautilus_application_set_accelerator (app, "win.back", "<alt>Left");
2069 nautilus_application_set_accelerator (app, "win.forward", "<alt>Right");
2070 nautilus_application_set_accelerator (app, "win.enter-location", "<control>l");
2071 nautilus_application_set_accelerator (app, "win.new-tab", "<control>t");
2072 nautilus_application_set_accelerator (app, "win.close-current-view", "<control>w");
2073
2074 /* Special case reload, since users are used to use two shortcuts instead of one */
2075 nautilus_application_set_accelerators (app, "win.reload", reload_accels);
2076
2077 nautilus_application_set_accelerator (app, "win.undo", "<control>z");
2078 nautilus_application_set_accelerator (app, "win.redo", "<shift><control>z");
2079 /* Only accesible by shorcuts */
2080 nautilus_application_set_accelerator (app, "win.bookmark-current-location", "<control>d");
2081 nautilus_application_set_accelerator (app, "win.up", "<alt>Up");
2082 nautilus_application_set_accelerator (app, "win.go-home", "<alt>Home");
2083 nautilus_application_set_accelerator (app, "win.tab-previous", "<control>Page_Up");
2084 nautilus_application_set_accelerator (app, "win.tab-next", "<control>Page_Down");
2085 nautilus_application_set_accelerator (app, "win.tab-move-left", "<shift><control>Page_Up");
2086 nautilus_application_set_accelerator (app, "win.tab-move-right", "<shift><control>Page_Down");
2087 nautilus_application_set_accelerators (app, "win.prompt-root-location", prompt_root_location_accels);
2088 /* Support keyboard layouts which have a dead tilde key but not a tilde key. */
2089 nautilus_application_set_accelerators (app, "win.prompt-home-location", prompt_home_location_accels);
2090 nautilus_application_set_accelerator (app, "win.view-menu", "F10");
2091 nautilus_application_set_accelerator (app, "win.restore-tab", "<shift><control>t");
2092
2093 /* Alt+N for the first 9 tabs */
2094 for (i = 0; i < 9; ++i)
2095 {
2096 g_snprintf (detailed_action, sizeof (detailed_action), "win.go-to-tab(%i)", i);
2097 g_snprintf (accel, sizeof (accel), "<alt>%i", i + 1);
2098 nautilus_application_set_accelerator (app, detailed_action, accel);
2099 }
2100
2101 action = g_action_map_lookup_action (G_ACTION_MAP (app), "show-hide-sidebar");
2102 state = g_action_get_state (action);
2103 if (g_variant_get_boolean (state))
2104 {
2105 nautilus_window_show_sidebar (window);
2106 }
2107
2108 g_variant_unref (state);
2109 }
2110
2111
2112 static void
nautilus_window_constructed(GObject * self)2113 nautilus_window_constructed (GObject *self)
2114 {
2115 NautilusWindow *window;
2116 NautilusWindowSlot *slot;
2117 NautilusApplication *application;
2118
2119 window = NAUTILUS_WINDOW (self);
2120
2121 nautilus_profile_start (NULL);
2122
2123 G_OBJECT_CLASS (nautilus_window_parent_class)->constructed (self);
2124
2125 application = NAUTILUS_APPLICATION (g_application_get_default ());
2126 gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (application));
2127
2128 setup_toolbar (window);
2129
2130 gtk_window_set_default_size (GTK_WINDOW (window),
2131 NAUTILUS_WINDOW_DEFAULT_WIDTH,
2132 NAUTILUS_WINDOW_DEFAULT_HEIGHT);
2133
2134 setup_notebook (window);
2135 nautilus_window_set_up_sidebar (window);
2136
2137
2138 g_signal_connect_object (nautilus_file_undo_manager_get (), "undo-changed",
2139 G_CALLBACK (nautilus_window_on_undo_changed), self,
2140 G_CONNECT_AFTER);
2141
2142 /* Is required that the UI is constructed before initializating the actions, since
2143 * some actions trigger UI widgets to show/hide. */
2144 nautilus_window_initialize_actions (window);
2145
2146 slot = nautilus_window_create_and_init_slot (window, 0);
2147 nautilus_window_set_active_slot (window, slot);
2148
2149 window->bookmarks_id =
2150 g_signal_connect_swapped (nautilus_application_get_bookmarks (application), "changed",
2151 G_CALLBACK (nautilus_window_sync_bookmarks), window);
2152
2153 nautilus_toolbar_on_window_constructed (NAUTILUS_TOOLBAR (window->toolbar));
2154
2155 nautilus_profile_end (NULL);
2156 }
2157
2158 static gint
sort_slots_active_last(NautilusWindowSlot * a,NautilusWindowSlot * b,NautilusWindow * window)2159 sort_slots_active_last (NautilusWindowSlot *a,
2160 NautilusWindowSlot *b,
2161 NautilusWindow *window)
2162 {
2163 if (window->active_slot == a)
2164 {
2165 return 1;
2166 }
2167 if (window->active_slot == b)
2168 {
2169 return -1;
2170 }
2171 return 0;
2172 }
2173
2174 static void
destroy_slots_foreach(gpointer data,gpointer user_data)2175 destroy_slots_foreach (gpointer data,
2176 gpointer user_data)
2177 {
2178 NautilusWindowSlot *slot = data;
2179 NautilusWindow *window = user_data;
2180
2181 close_slot (window, slot, TRUE);
2182 }
2183
2184 static void
nautilus_window_destroy(GtkWidget * object)2185 nautilus_window_destroy (GtkWidget *object)
2186 {
2187 NautilusWindow *window;
2188 NautilusApplication *application;
2189 GList *slots_copy;
2190
2191 window = NAUTILUS_WINDOW (object);
2192 application = NAUTILUS_APPLICATION (gtk_window_get_application (GTK_WINDOW (window)));
2193
2194 DEBUG ("Destroying window");
2195
2196 /* close all slots safely */
2197 slots_copy = g_list_copy (window->slots);
2198 if (window->active_slot != NULL)
2199 {
2200 /* Make sure active slot is last one to be closed, to avoid default activation
2201 * of others slots when closing the active one, see bug #741952 */
2202 slots_copy = g_list_sort_with_data (slots_copy, (GCompareDataFunc) sort_slots_active_last, window);
2203 }
2204 g_list_foreach (slots_copy, (GFunc) destroy_slots_foreach, window);
2205 g_list_free (slots_copy);
2206
2207 /* the slots list should now be empty */
2208 g_assert (window->slots == NULL);
2209
2210 g_clear_weak_pointer (&window->active_slot);
2211
2212 g_clear_signal_handler (&window->bookmarks_id, nautilus_application_get_bookmarks (application));
2213
2214 g_clear_handle_id (&window->in_app_notification_undo_timeout_id, g_source_remove);
2215
2216 nautilus_window_unexport_handle (window);
2217
2218 GTK_WIDGET_CLASS (nautilus_window_parent_class)->destroy (object);
2219 }
2220
2221 static void
nautilus_window_dispose(GObject * object)2222 nautilus_window_dispose (GObject *object)
2223 {
2224 NautilusWindow *window;
2225
2226 window = NAUTILUS_WINDOW (object);
2227
2228 g_clear_object (&window->notebook_multi_press_gesture);
2229
2230 G_OBJECT_CLASS (nautilus_window_parent_class)->dispose (object);
2231 }
2232
2233 static void
nautilus_window_finalize(GObject * object)2234 nautilus_window_finalize (GObject *object)
2235 {
2236 NautilusWindow *window;
2237
2238 window = NAUTILUS_WINDOW (object);
2239
2240 if (window->sidebar_width_handler_id != 0)
2241 {
2242 g_source_remove (window->sidebar_width_handler_id);
2243 window->sidebar_width_handler_id = 0;
2244 }
2245
2246 if (window->in_app_notification_undo_timeout_id != 0)
2247 {
2248 g_source_remove (window->in_app_notification_undo_timeout_id);
2249 window->in_app_notification_undo_timeout_id = 0;
2250 }
2251
2252 if (window->notification_operation_timeout_id != 0)
2253 {
2254 g_source_remove (window->notification_operation_timeout_id);
2255 window->notification_operation_timeout_id = 0;
2256 }
2257
2258 g_clear_object (&window->selected_file);
2259 g_clear_object (&window->selected_volume);
2260
2261 g_signal_handlers_disconnect_by_func (nautilus_file_undo_manager_get (),
2262 G_CALLBACK (nautilus_window_on_undo_changed),
2263 window);
2264
2265 g_queue_free_full (window->tab_data_queue, free_navigation_state);
2266
2267 g_object_unref (window->pad_controller);
2268
2269 /* nautilus_window_close() should have run */
2270 g_assert (window->slots == NULL);
2271
2272 G_OBJECT_CLASS (nautilus_window_parent_class)->finalize (object);
2273 }
2274
2275 static void
nautilus_window_save_geometry(NautilusWindow * window)2276 nautilus_window_save_geometry (NautilusWindow *window)
2277 {
2278 GdkWindow *gdk_window;
2279 GdkWindowState window_state;
2280 gboolean is_maximized;
2281
2282 g_assert (NAUTILUS_IS_WINDOW (window));
2283
2284 gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
2285
2286 if (!gdk_window)
2287 {
2288 return;
2289 }
2290
2291 window_state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
2292
2293 /* Don't save the window state for tiled windows. This is a special case,
2294 * where the geometry only makes sense in combination with other tiled
2295 * windows, that we can't possibly restore. */
2296 if (window_state & GDK_WINDOW_STATE_TILED)
2297 {
2298 return;
2299 }
2300
2301 is_maximized = window_state & GDK_WINDOW_STATE_MAXIMIZED;
2302
2303 /* Only save the initial size when the window is not maximized. If the
2304 * window is maximized, a previously stored initial size will be more
2305 * appropriate when unmaximizing the window in the future. */
2306 if (!is_maximized)
2307 {
2308 gint width;
2309 gint height;
2310 GVariant *initial_size;
2311
2312 gtk_window_get_size (GTK_WINDOW (window), &width, &height);
2313 initial_size = g_variant_new_parsed ("(%i, %i)", width, height);
2314
2315 g_settings_set_value (nautilus_window_state,
2316 NAUTILUS_WINDOW_STATE_INITIAL_SIZE,
2317 initial_size);
2318 }
2319
2320 g_settings_set_boolean (nautilus_window_state,
2321 NAUTILUS_WINDOW_STATE_MAXIMIZED,
2322 is_maximized);
2323 }
2324
2325 void
nautilus_window_close(NautilusWindow * window)2326 nautilus_window_close (NautilusWindow *window)
2327 {
2328 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
2329
2330 nautilus_window_save_geometry (window);
2331 nautilus_window_set_active_slot (window, NULL);
2332
2333 gtk_widget_destroy (GTK_WIDGET (window));
2334 }
2335
2336 void
nautilus_window_set_active_slot(NautilusWindow * window,NautilusWindowSlot * new_slot)2337 nautilus_window_set_active_slot (NautilusWindow *window,
2338 NautilusWindowSlot *new_slot)
2339 {
2340 NautilusWindowSlot *old_slot;
2341
2342 g_assert (NAUTILUS_IS_WINDOW (window));
2343
2344 if (new_slot)
2345 {
2346 g_assert ((window == nautilus_window_slot_get_window (new_slot)));
2347 }
2348
2349 old_slot = nautilus_window_get_active_slot (window);
2350
2351 if (old_slot == new_slot)
2352 {
2353 return;
2354 }
2355
2356 DEBUG ("Setting new slot %p as active, old slot inactive %p", new_slot, old_slot);
2357
2358 /* make old slot inactive if it exists (may be NULL after init, for example) */
2359 if (old_slot != NULL)
2360 {
2361 /* inform slot & view */
2362 nautilus_window_slot_set_active (old_slot, FALSE);
2363 nautilus_toolbar_set_window_slot (NAUTILUS_TOOLBAR (window->toolbar), NULL);
2364 }
2365
2366 g_set_weak_pointer (&window->active_slot, new_slot);
2367
2368 /* make new slot active, if it exists */
2369 if (new_slot)
2370 {
2371 /* inform slot & view */
2372 nautilus_window_slot_set_active (new_slot, TRUE);
2373 nautilus_toolbar_set_window_slot (NAUTILUS_TOOLBAR (window->toolbar), new_slot);
2374
2375 on_location_changed (window);
2376 }
2377 }
2378
2379 static void
nautilus_window_realize(GtkWidget * widget)2380 nautilus_window_realize (GtkWidget *widget)
2381 {
2382 GTK_WIDGET_CLASS (nautilus_window_parent_class)->realize (widget);
2383 update_cursor (NAUTILUS_WINDOW (widget));
2384 }
2385
2386 static gboolean
nautilus_window_key_press_event(GtkWidget * widget,GdkEventKey * event)2387 nautilus_window_key_press_event (GtkWidget *widget,
2388 GdkEventKey *event)
2389 {
2390 NautilusWindow *window;
2391 guint keyval;
2392 GtkWidget *focus_widget;
2393
2394 window = NAUTILUS_WINDOW (widget);
2395
2396 if (G_UNLIKELY (!gdk_event_get_keyval ((GdkEvent *) event, &keyval)))
2397 {
2398 g_return_val_if_reached (GDK_EVENT_PROPAGATE);
2399 }
2400
2401 focus_widget = gtk_window_get_focus (GTK_WINDOW (window));
2402 if (focus_widget != NULL && GTK_IS_EDITABLE (focus_widget))
2403 {
2404 /* if we have input focus on a GtkEditable (e.g. a GtkEntry), forward
2405 * the event to it before activating accelerator bindings too.
2406 */
2407 if (gtk_window_propagate_key_event (GTK_WINDOW (window),
2408 (GdkEventKey *) event))
2409 {
2410 return GDK_EVENT_STOP;
2411 }
2412 }
2413
2414 for (int i = 0; i < G_N_ELEMENTS (extra_window_keybindings); i++)
2415 {
2416 if (extra_window_keybindings[i].keyval == keyval)
2417 {
2418 GAction *action;
2419
2420 action = g_action_map_lookup_action (G_ACTION_MAP (window), extra_window_keybindings[i].action);
2421
2422 g_assert (action != NULL);
2423 if (g_action_get_enabled (action))
2424 {
2425 g_action_activate (action, NULL);
2426 return GDK_EVENT_STOP;
2427 }
2428
2429 break;
2430 }
2431 }
2432
2433 if (GTK_WIDGET_CLASS (nautilus_window_parent_class)->key_press_event (widget, event))
2434 {
2435 return GDK_EVENT_STOP;
2436 }
2437
2438 if (window->active_slot != NULL &&
2439 nautilus_window_slot_handle_event (window->active_slot, (GdkEvent *) event))
2440 {
2441 return GDK_EVENT_STOP;
2442 }
2443
2444 return GDK_EVENT_PROPAGATE;
2445 }
2446
2447 void
nautilus_window_sync_title(NautilusWindow * window,NautilusWindowSlot * slot)2448 nautilus_window_sync_title (NautilusWindow *window,
2449 NautilusWindowSlot *slot)
2450 {
2451 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
2452 g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (slot));
2453
2454 if (slot == nautilus_window_get_active_slot (window))
2455 {
2456 gtk_window_set_title (GTK_WINDOW (window), nautilus_window_slot_get_title (slot));
2457 }
2458
2459 nautilus_notebook_sync_tab_label (NAUTILUS_NOTEBOOK (window->notebook), slot);
2460 }
2461
2462 #ifdef GDK_WINDOWING_WAYLAND
2463 typedef struct
2464 {
2465 NautilusWindow *window;
2466 NautilusWindowHandleExported callback;
2467 gpointer user_data;
2468 } WaylandWindowHandleExportedData;
2469
2470 static void
wayland_window_handle_exported(GdkWindow * window,const char * wayland_handle_str,gpointer user_data)2471 wayland_window_handle_exported (GdkWindow *window,
2472 const char *wayland_handle_str,
2473 gpointer user_data)
2474 {
2475 WaylandWindowHandleExportedData *data = user_data;
2476
2477 data->window->export_handle = g_strdup_printf ("wayland:%s", wayland_handle_str);
2478 data->callback (data->window, data->window->export_handle, 0, data->user_data);
2479 }
2480 #endif
2481
2482 gboolean
nautilus_window_export_handle(NautilusWindow * window,NautilusWindowHandleExported callback,gpointer user_data)2483 nautilus_window_export_handle (NautilusWindow *window,
2484 NautilusWindowHandleExported callback,
2485 gpointer user_data)
2486 {
2487 guint xid = get_window_xid (window);
2488
2489 if (window->export_handle != NULL)
2490 {
2491 callback (window, window->export_handle, xid, user_data);
2492 return TRUE;
2493 }
2494
2495 #ifdef GDK_WINDOWING_X11
2496 if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
2497 {
2498 window->export_handle = g_strdup_printf ("x11:%x", xid);
2499 callback (window, window->export_handle, xid, user_data);
2500
2501 return TRUE;
2502 }
2503 #endif
2504 #ifdef GDK_WINDOWING_WAYLAND
2505 if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
2506 {
2507 GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
2508 WaylandWindowHandleExportedData *data;
2509
2510 data = g_new0 (WaylandWindowHandleExportedData, 1);
2511 data->window = window;
2512 data->callback = callback;
2513 data->user_data = user_data;
2514
2515 if (!gdk_wayland_window_export_handle (gdk_window,
2516 wayland_window_handle_exported,
2517 data,
2518 g_free))
2519 {
2520 g_free (data);
2521 return FALSE;
2522 }
2523 else
2524 {
2525 return TRUE;
2526 }
2527 }
2528 #endif
2529
2530 g_warning ("Couldn't export handle, unsupported windowing system");
2531
2532 return FALSE;
2533 }
2534
2535 void
nautilus_window_unexport_handle(NautilusWindow * window)2536 nautilus_window_unexport_handle (NautilusWindow *window)
2537 {
2538 if (window->export_handle == NULL)
2539 {
2540 return;
2541 }
2542
2543 #ifdef GDK_WINDOWING_WAYLAND
2544 if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
2545 {
2546 GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
2547 if (gdk_window != NULL)
2548 {
2549 gdk_wayland_window_unexport_handle (gdk_window);
2550 }
2551 }
2552 #endif
2553
2554 g_clear_pointer (&window->export_handle, g_free);
2555 }
2556
2557 /**
2558 * nautilus_window_show:
2559 * @widget: GtkWidget
2560 *
2561 * Call parent and then show/hide window items
2562 * base on user prefs.
2563 */
2564 static void
nautilus_window_show(GtkWidget * widget)2565 nautilus_window_show (GtkWidget *widget)
2566 {
2567 GTK_WIDGET_CLASS (nautilus_window_parent_class)->show (widget);
2568 }
2569
2570 NautilusWindowSlot *
nautilus_window_get_active_slot(NautilusWindow * window)2571 nautilus_window_get_active_slot (NautilusWindow *window)
2572 {
2573 g_assert (NAUTILUS_IS_WINDOW (window));
2574
2575 return window->active_slot;
2576 }
2577
2578 GList *
nautilus_window_get_slots(NautilusWindow * window)2579 nautilus_window_get_slots (NautilusWindow *window)
2580 {
2581 g_assert (NAUTILUS_IS_WINDOW (window));
2582
2583 return window->slots;
2584 }
2585
2586 static void
on_is_maximized_changed(GObject * object,GParamSpec * pspec,gpointer user_data)2587 on_is_maximized_changed (GObject *object,
2588 GParamSpec *pspec,
2589 gpointer user_data)
2590 {
2591 gboolean is_maximized;
2592
2593 is_maximized = gtk_window_is_maximized (GTK_WINDOW (object));
2594
2595 g_settings_set_boolean (nautilus_window_state,
2596 NAUTILUS_WINDOW_STATE_MAXIMIZED, is_maximized);
2597 }
2598
2599 static gboolean
nautilus_window_delete_event(GtkWidget * widget,GdkEventAny * event)2600 nautilus_window_delete_event (GtkWidget *widget,
2601 GdkEventAny *event)
2602 {
2603 nautilus_window_close (NAUTILUS_WINDOW (widget));
2604 return FALSE;
2605 }
2606
2607 static void
nautilus_window_back_or_forward(NautilusWindow * window,gboolean back,guint distance)2608 nautilus_window_back_or_forward (NautilusWindow *window,
2609 gboolean back,
2610 guint distance)
2611 {
2612 NautilusWindowSlot *slot;
2613
2614 slot = nautilus_window_get_active_slot (window);
2615
2616 if (slot != NULL)
2617 {
2618 nautilus_window_slot_back_or_forward (slot, back, distance);
2619 }
2620 }
2621
2622 static void
on_multi_press_gesture_pressed(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,gpointer user_data)2623 on_multi_press_gesture_pressed (GtkGestureMultiPress *gesture,
2624 gint n_press,
2625 gdouble x,
2626 gdouble y,
2627 gpointer user_data)
2628 {
2629 GtkWidget *widget;
2630 NautilusWindow *window;
2631 guint button;
2632
2633 widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
2634 window = NAUTILUS_WINDOW (widget);
2635 button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
2636
2637 if (mouse_extra_buttons && (button == mouse_back_button))
2638 {
2639 nautilus_window_back_or_forward (window, TRUE, 0);
2640 }
2641 else if (mouse_extra_buttons && (button == mouse_forward_button))
2642 {
2643 nautilus_window_back_or_forward (window, FALSE, 0);
2644 }
2645 }
2646
2647 static void
mouse_back_button_changed(gpointer callback_data)2648 mouse_back_button_changed (gpointer callback_data)
2649 {
2650 int new_back_button;
2651
2652 new_back_button = g_settings_get_int (nautilus_preferences, NAUTILUS_PREFERENCES_MOUSE_BACK_BUTTON);
2653
2654 /* Bounds checking */
2655 if (new_back_button < 6 || new_back_button > UPPER_MOUSE_LIMIT)
2656 {
2657 return;
2658 }
2659
2660 mouse_back_button = new_back_button;
2661 }
2662
2663 static void
mouse_forward_button_changed(gpointer callback_data)2664 mouse_forward_button_changed (gpointer callback_data)
2665 {
2666 int new_forward_button;
2667
2668 new_forward_button = g_settings_get_int (nautilus_preferences, NAUTILUS_PREFERENCES_MOUSE_FORWARD_BUTTON);
2669
2670 /* Bounds checking */
2671 if (new_forward_button < 6 || new_forward_button > UPPER_MOUSE_LIMIT)
2672 {
2673 return;
2674 }
2675
2676 mouse_forward_button = new_forward_button;
2677 }
2678
2679 static void
use_extra_mouse_buttons_changed(gpointer callback_data)2680 use_extra_mouse_buttons_changed (gpointer callback_data)
2681 {
2682 mouse_extra_buttons = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS);
2683 }
2684
2685 static void
nautilus_window_init(NautilusWindow * window)2686 nautilus_window_init (NautilusWindow *window)
2687 {
2688 GtkWindowGroup *window_group;
2689
2690 g_type_ensure (NAUTILUS_TYPE_TOOLBAR);
2691 g_type_ensure (NAUTILUS_TYPE_NOTEBOOK);
2692 gtk_widget_init_template (GTK_WIDGET (window));
2693
2694 g_signal_connect (window, "notify::is-maximized",
2695 G_CALLBACK (on_is_maximized_changed), NULL);
2696
2697 g_signal_connect_object (window->in_app_notification_undo_close_button, "clicked",
2698 G_CALLBACK (on_in_app_notification_undo_close_button_clicked), window, 0);
2699 g_signal_connect_object (window->in_app_notification_undo_undo_button, "clicked",
2700 G_CALLBACK (on_in_app_notification_undo_undo_button_clicked), window, 0);
2701
2702 window->slots = NULL;
2703 window->active_slot = NULL;
2704
2705 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)),
2706 "nautilus-window");
2707
2708 window_group = gtk_window_group_new ();
2709 gtk_window_group_add_window (window_group, GTK_WINDOW (window));
2710 g_object_unref (window_group);
2711
2712 window->tab_data_queue = g_queue_new ();
2713
2714 window->pad_controller = gtk_pad_controller_new (GTK_WINDOW (window),
2715 G_ACTION_GROUP (window),
2716 NULL);
2717 gtk_pad_controller_set_action_entries (window->pad_controller,
2718 pad_actions, G_N_ELEMENTS (pad_actions));
2719
2720 window->multi_press_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (window));
2721
2722 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (window->multi_press_gesture),
2723 GTK_PHASE_CAPTURE);
2724 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (window->multi_press_gesture), 0);
2725
2726 g_signal_connect (window->multi_press_gesture, "pressed",
2727 G_CALLBACK (on_multi_press_gesture_pressed), NULL);
2728
2729 window->notebook_multi_press_gesture = gtk_gesture_multi_press_new (window->notebook);
2730
2731 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (window->notebook_multi_press_gesture),
2732 GTK_PHASE_CAPTURE);
2733 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (window->notebook_multi_press_gesture),
2734 GDK_BUTTON_SECONDARY);
2735 }
2736
2737 static void
nautilus_window_class_init(NautilusWindowClass * class)2738 nautilus_window_class_init (NautilusWindowClass *class)
2739 {
2740 GObjectClass *oclass = G_OBJECT_CLASS (class);
2741 GtkWidgetClass *wclass = GTK_WIDGET_CLASS (class);
2742
2743 oclass->dispose = nautilus_window_dispose;
2744 oclass->finalize = nautilus_window_finalize;
2745 oclass->constructed = nautilus_window_constructed;
2746
2747 wclass->destroy = nautilus_window_destroy;
2748 wclass->show = nautilus_window_show;
2749 wclass->realize = nautilus_window_realize;
2750 wclass->key_press_event = nautilus_window_key_press_event;
2751 wclass->delete_event = nautilus_window_delete_event;
2752 wclass->grab_focus = nautilus_window_grab_focus;
2753
2754 gtk_widget_class_set_template_from_resource (wclass,
2755 "/org/gnome/nautilus/ui/nautilus-window.ui");
2756 gtk_widget_class_bind_template_child (wclass, NautilusWindow, toolbar);
2757 gtk_widget_class_bind_template_child (wclass, NautilusWindow, content_paned);
2758 gtk_widget_class_bind_template_child (wclass, NautilusWindow, sidebar);
2759 gtk_widget_class_bind_template_child (wclass, NautilusWindow, places_sidebar);
2760 gtk_widget_class_bind_template_child (wclass, NautilusWindow, main_view);
2761 gtk_widget_class_bind_template_child (wclass, NautilusWindow, notebook);
2762 gtk_widget_class_bind_template_child (wclass, NautilusWindow, in_app_notification_undo);
2763 gtk_widget_class_bind_template_child (wclass, NautilusWindow, in_app_notification_undo_label);
2764 gtk_widget_class_bind_template_child (wclass, NautilusWindow, in_app_notification_undo_undo_button);
2765 gtk_widget_class_bind_template_child (wclass, NautilusWindow, in_app_notification_undo_close_button);
2766 gtk_widget_class_bind_template_child (wclass, NautilusWindow, notification_operation);
2767 gtk_widget_class_bind_template_child (wclass, NautilusWindow, notification_operation_label);
2768 gtk_widget_class_bind_template_child (wclass, NautilusWindow, notification_operation_open);
2769 gtk_widget_class_bind_template_child (wclass, NautilusWindow, notification_operation_close);
2770
2771 gtk_widget_class_bind_template_callback (wclass, places_sidebar_show_other_locations_with_flags);
2772 gtk_widget_class_bind_template_callback (wclass, places_sidebar_show_starred_location);
2773
2774 signals[SLOT_ADDED] =
2775 g_signal_new ("slot-added",
2776 G_TYPE_FROM_CLASS (class),
2777 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2778 0,
2779 NULL, NULL,
2780 g_cclosure_marshal_VOID__OBJECT,
2781 G_TYPE_NONE, 1, NAUTILUS_TYPE_WINDOW_SLOT);
2782 signals[SLOT_REMOVED] =
2783 g_signal_new ("slot-removed",
2784 G_TYPE_FROM_CLASS (class),
2785 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2786 0,
2787 NULL, NULL,
2788 g_cclosure_marshal_VOID__OBJECT,
2789 G_TYPE_NONE, 1, NAUTILUS_TYPE_WINDOW_SLOT);
2790
2791 g_signal_connect_swapped (nautilus_preferences,
2792 "changed::" NAUTILUS_PREFERENCES_MOUSE_BACK_BUTTON,
2793 G_CALLBACK (mouse_back_button_changed),
2794 NULL);
2795
2796 g_signal_connect_swapped (nautilus_preferences,
2797 "changed::" NAUTILUS_PREFERENCES_MOUSE_FORWARD_BUTTON,
2798 G_CALLBACK (mouse_forward_button_changed),
2799 NULL);
2800
2801 g_signal_connect_swapped (nautilus_preferences,
2802 "changed::" NAUTILUS_PREFERENCES_MOUSE_USE_EXTRA_BUTTONS,
2803 G_CALLBACK (use_extra_mouse_buttons_changed),
2804 NULL);
2805
2806 gtk_widget_class_bind_template_callback (wclass, on_notification_operation_open_clicked);
2807 gtk_widget_class_bind_template_callback (wclass, on_notification_operation_close_clicked);
2808 }
2809
2810 NautilusWindow *
nautilus_window_new(GdkScreen * screen)2811 nautilus_window_new (GdkScreen *screen)
2812 {
2813 return g_object_new (NAUTILUS_TYPE_WINDOW,
2814 "icon-name", APPLICATION_ID,
2815 "screen", screen,
2816 NULL);
2817 }
2818
2819 void
nautilus_window_show_about_dialog(NautilusWindow * window)2820 nautilus_window_show_about_dialog (NautilusWindow *window)
2821 {
2822 const gchar *artists[] =
2823 {
2824 "The GNOME Project",
2825 NULL
2826 };
2827 const gchar *authors[] =
2828 {
2829 "The contributors to the Nautilus project",
2830 NULL
2831 };
2832 const gchar *documenters[] =
2833 {
2834 "GNOME Documentation Team",
2835 "Sun Microsystems",
2836 NULL
2837 };
2838 g_autofree gchar *program_name = NULL;
2839
2840 /* “Files” is the generic application name and the suffix is
2841 * an arbitrary and deliberately unlocalized string only shown
2842 * in development builds.
2843 */
2844 program_name = g_strconcat (_("Files"), NAME_SUFFIX, NULL);
2845
2846 gtk_show_about_dialog (window ? GTK_WINDOW (window) : NULL,
2847 "program-name", program_name,
2848 "version", VERSION,
2849 "comments", _("Access and organize your files"),
2850 "website", "https://wiki.gnome.org/action/show/Apps/Files",
2851 "copyright", "© 1999 The Files Authors",
2852 "license-type", GTK_LICENSE_GPL_3_0,
2853 "artists", artists,
2854 "authors", authors,
2855 "documenters", documenters,
2856 /* Translators should localize the following string
2857 * which will be displayed at the bottom of the about
2858 * box to give credit to the translator(s).
2859 */
2860 "translator-credits", _("translator-credits"),
2861 "logo-icon-name", APPLICATION_ID,
2862 NULL);
2863 }
2864
2865 void
nautilus_window_search(NautilusWindow * window,NautilusQuery * query)2866 nautilus_window_search (NautilusWindow *window,
2867 NautilusQuery *query)
2868 {
2869 NautilusWindowSlot *active_slot;
2870
2871 active_slot = nautilus_window_get_active_slot (window);
2872 if (active_slot)
2873 {
2874 nautilus_window_slot_search (active_slot, query);
2875 }
2876 else
2877 {
2878 g_warning ("Trying search on a slot but no active slot present");
2879 }
2880 }
2881