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