1 /*
2  *  Caja
3  *
4  *  Copyright (C) 1999, 2000, 2004 Red Hat, Inc.
5  *  Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6  *
7  *  Caja 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  *  Caja 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
18  *  License along with this program; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  *  Authors: Elliot Lee <sopwith@redhat.com>
22  *  	     John Sullivan <sullivan@eazel.com>
23  *           Alexander Larsson <alexl@redhat.com>
24  */
25 
26 /* caja-window.c: Implementation of the main window object */
27 
28 #include <config.h>
29 
30 #include <gdk-pixbuf/gdk-pixbuf.h>
31 #include <gdk/gdkx.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <gtk/gtk.h>
34 #include <glib/gi18n.h>
35 #ifdef HAVE_X11_XF86KEYSYM_H
36 #include <X11/XF86keysym.h>
37 #endif
38 
39 #include <eel/eel-debug.h>
40 #include <eel/eel-gtk-macros.h>
41 #include <eel/eel-string.h>
42 
43 #include <libcaja-private/caja-file-utilities.h>
44 #include <libcaja-private/caja-file-attributes.h>
45 #include <libcaja-private/caja-global-preferences.h>
46 #include <libcaja-private/caja-metadata.h>
47 #include <libcaja-private/caja-mime-actions.h>
48 #include <libcaja-private/caja-program-choosing.h>
49 #include <libcaja-private/caja-view-factory.h>
50 #include <libcaja-private/caja-clipboard.h>
51 #include <libcaja-private/caja-search-directory.h>
52 #include <libcaja-private/caja-signaller.h>
53 
54 #include "caja-window-private.h"
55 #include "caja-actions.h"
56 #include "caja-application.h"
57 #include "caja-bookmarks-window.h"
58 #include "caja-information-panel.h"
59 #include "caja-window-manage-views.h"
60 #include "caja-window-bookmarks.h"
61 #include "caja-window-slot.h"
62 #include "caja-navigation-window-slot.h"
63 #include "caja-search-bar.h"
64 #include "caja-navigation-window-pane.h"
65 #include "caja-src-marshal.h"
66 
67 #define MAX_HISTORY_ITEMS 50
68 
69 #define EXTRA_VIEW_WIDGETS_BACKGROUND "#a7c6e1"
70 
71 /* dock items */
72 
73 #define CAJA_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER	"/MenuBar/View/View Choices/Extra Viewer"
74 #define CAJA_MENU_PATH_SHORT_LIST_PLACEHOLDER  	"/MenuBar/View/View Choices/Short List"
75 
76 enum {
77 	ARG_0,
78 	ARG_APP
79 };
80 
81 enum {
82 	GO_UP,
83 	RELOAD,
84 	PROMPT_FOR_LOCATION,
85 	ZOOM_CHANGED,
86 	VIEW_AS_CHANGED,
87 	LAST_SIGNAL
88 };
89 
90 static guint signals[LAST_SIGNAL] = { 0 };
91 
92 typedef struct
93 {
94     CajaWindow *window;
95     char *id;
96 } ActivateViewData;
97 
98 static void cancel_view_as_callback         (CajaWindowSlot      *slot);
99 static void caja_window_info_iface_init (CajaWindowInfoIface *iface);
100 static void action_view_as_callback         (GtkAction               *action,
101         ActivateViewData        *data);
102 
103 static GList *history_list;
104 
105 G_DEFINE_TYPE_WITH_CODE (CajaWindow, caja_window, GTK_TYPE_WINDOW,
106                          G_ADD_PRIVATE (CajaWindow)
107                          G_IMPLEMENT_INTERFACE (CAJA_TYPE_WINDOW_INFO,
108                                  caja_window_info_iface_init));
109 
110 static const struct
111 {
112     unsigned int keyval;
113     const char *action;
114 } extra_window_keybindings [] =
115 {
116 #ifdef HAVE_X11_XF86KEYSYM_H
117     { XF86XK_AddFavorite,	CAJA_ACTION_ADD_BOOKMARK },
118     { XF86XK_Favorites,	CAJA_ACTION_EDIT_BOOKMARKS },
119     { XF86XK_Go,		CAJA_ACTION_GO_TO_LOCATION },
120     /* TODO?{ XF86XK_History,	CAJA_ACTION_HISTORY }, */
121     { XF86XK_HomePage,      CAJA_ACTION_GO_HOME },
122     { XF86XK_OpenURL,	CAJA_ACTION_GO_TO_LOCATION },
123     { XF86XK_Refresh,	CAJA_ACTION_RELOAD },
124     { XF86XK_Reload,	CAJA_ACTION_RELOAD },
125     { XF86XK_Search,	CAJA_ACTION_SEARCH },
126     { XF86XK_Start,		CAJA_ACTION_GO_HOME },
127     { XF86XK_Stop,		CAJA_ACTION_STOP },
128     { XF86XK_ZoomIn,	CAJA_ACTION_ZOOM_IN },
129     { XF86XK_ZoomOut,	CAJA_ACTION_ZOOM_OUT }
130 #endif
131 };
132 
133 static void
caja_window_init(CajaWindow * window)134 caja_window_init (CajaWindow *window)
135 {
136     GtkWidget *grid;
137     GtkWidget *menu;
138     GtkWidget *statusbar;
139 
140     static const gchar css_custom[] =
141       "#caja-extra-view-widget {"
142       "  background-color: " EXTRA_VIEW_WIDGETS_BACKGROUND ";"
143       "}";
144 
145     GError *error = NULL;
146     GtkCssProvider *provider = gtk_css_provider_new ();
147     gtk_css_provider_load_from_data (provider, css_custom, -1, &error);
148 
149     if (error != NULL) {
150             g_warning ("Can't parse CajaWindow's CSS custom description: %s\n", error->message);
151             g_error_free (error);
152     } else {
153             gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (window)),
154                                             GTK_STYLE_PROVIDER (provider),
155                                             GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
156     }
157 
158     g_object_unref (provider);
159     window->details = caja_window_get_instance_private (window);
160 
161     window->details->panes = NULL;
162     window->details->active_pane = NULL;
163 
164     window->details->show_hidden_files_mode = CAJA_WINDOW_SHOW_HIDDEN_FILES_DEFAULT;
165 
166     /* Set initial window title */
167     gtk_window_set_title (GTK_WINDOW (window), _("Caja"));
168 
169     grid = gtk_grid_new ();
170     gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
171     window->details->grid = grid;
172     gtk_widget_show (grid);
173     gtk_container_add (GTK_CONTAINER (window), grid);
174 
175     statusbar = gtk_statusbar_new ();
176     gtk_widget_set_name (statusbar, "statusbar-noborder");
177 
178 /* set margin to zero to reduce size of statusbar */
179 	gtk_widget_set_margin_top (GTK_WIDGET (statusbar), 0);
180 	gtk_widget_set_margin_bottom (GTK_WIDGET (statusbar), 0);
181 
182     window->details->statusbar = statusbar;
183     window->details->help_message_cid = gtk_statusbar_get_context_id
184                                         (GTK_STATUSBAR (statusbar), "help_message");
185     /* Statusbar is packed in the subclasses */
186 
187     caja_window_initialize_menus (window);
188 
189     menu = gtk_ui_manager_get_widget (window->details->ui_manager, "/MenuBar");
190     window->details->menubar = menu;
191     gtk_widget_set_hexpand (menu, TRUE);
192     gtk_widget_show (menu);
193     gtk_grid_attach (GTK_GRID (grid), menu, 0, 0, 1, 1);
194 
195     /* Register to menu provider extension signal managing menu updates */
196     g_signal_connect_object (caja_signaller_get_current (), "popup_menu_changed",
197                              G_CALLBACK (caja_window_load_extension_menus), window, G_CONNECT_SWAPPED);
198 }
199 
200 /* Unconditionally synchronize the GtkUIManager of WINDOW. */
201 static void
caja_window_ui_update(CajaWindow * window)202 caja_window_ui_update (CajaWindow *window)
203 {
204     g_assert (CAJA_IS_WINDOW (window));
205 
206     gtk_ui_manager_ensure_update (window->details->ui_manager);
207 }
208 
209 static void
caja_window_push_status(CajaWindow * window,const char * text)210 caja_window_push_status (CajaWindow *window,
211                          const char *text)
212 {
213     g_return_if_fail (CAJA_IS_WINDOW (window));
214 
215     /* clear any previous message, underflow is allowed */
216     gtk_statusbar_pop (GTK_STATUSBAR (window->details->statusbar), 0);
217 
218     if (text != NULL && text[0] != '\0')
219     {
220         gtk_statusbar_push (GTK_STATUSBAR (window->details->statusbar), 0, text);
221     }
222 }
223 
224 void
caja_window_sync_status(CajaWindow * window)225 caja_window_sync_status (CajaWindow *window)
226 {
227     CajaWindowSlot *slot;
228 
229     slot = window->details->active_pane->active_slot;
230     caja_window_push_status (window, slot->status_text);
231 }
232 
233 void
caja_window_go_to(CajaWindow * window,GFile * location)234 caja_window_go_to (CajaWindow *window, GFile *location)
235 {
236     g_return_if_fail (CAJA_IS_WINDOW (window));
237 
238     caja_window_slot_go_to (window->details->active_pane->active_slot, location, FALSE);
239 }
240 
241 void
caja_window_go_to_tab(CajaWindow * window,GFile * location)242 caja_window_go_to_tab (CajaWindow *window, GFile *location)
243 {
244     g_return_if_fail (CAJA_IS_WINDOW (window));
245 
246     caja_window_slot_go_to (window->details->active_pane->active_slot, location, TRUE);
247 }
248 
249 void
caja_window_go_to_full(CajaWindow * window,GFile * location,CajaWindowGoToCallback callback,gpointer user_data)250 caja_window_go_to_full (CajaWindow *window,
251                         GFile                 *location,
252                         CajaWindowGoToCallback callback,
253                         gpointer               user_data)
254 {
255     g_return_if_fail (CAJA_IS_WINDOW (window));
256 
257     caja_window_slot_go_to_full (window->details->active_pane->active_slot, location, FALSE, callback, user_data);
258 }
259 
260 void
caja_window_go_to_with_selection(CajaWindow * window,GFile * location,GList * new_selection)261 caja_window_go_to_with_selection (CajaWindow *window, GFile *location, GList *new_selection)
262 {
263     g_return_if_fail (CAJA_IS_WINDOW (window));
264 
265     caja_window_slot_go_to_with_selection (window->details->active_pane->active_slot, location, new_selection);
266 }
267 
268 static gboolean
caja_window_go_up_signal(CajaWindow * window,gboolean close_behind)269 caja_window_go_up_signal (CajaWindow *window, gboolean close_behind)
270 {
271     caja_window_go_up (window, close_behind, FALSE);
272     return TRUE;
273 }
274 
275 static void
caja_window_reload_signal(CajaWindow * window)276 caja_window_reload_signal (CajaWindow *window)
277 {
278     caja_window_reload (window, FALSE);
279 }
280 
281 void
caja_window_new_tab(CajaWindow * window)282 caja_window_new_tab (CajaWindow *window)
283 {
284     CajaWindowSlot *current_slot;
285     CajaWindowOpenFlags flags;
286     GFile *location = NULL;
287 
288     current_slot = window->details->active_pane->active_slot;
289     location = caja_window_slot_get_location (current_slot);
290 
291     if (location != NULL) {
292         CajaWindowSlot *new_slot;
293         int new_slot_position;
294         char *scheme;
295 
296     	flags = 0;
297 
298     	new_slot_position = g_settings_get_enum (caja_preferences, CAJA_PREFERENCES_NEW_TAB_POSITION);
299     	if (new_slot_position == CAJA_NEW_TAB_POSITION_END) {
300     		flags = CAJA_WINDOW_OPEN_SLOT_APPEND;
301     	}
302 
303     	scheme = g_file_get_uri_scheme (location);
304     	if (!strcmp (scheme, "x-caja-search")) {
305     		g_object_unref (location);
306     		location = g_file_new_for_path (g_get_home_dir ());
307     	}
308     	g_free (scheme);
309 
310     	new_slot = caja_window_open_slot (current_slot->pane, flags);
311     	caja_window_set_active_slot (window, new_slot);
312     	caja_window_slot_go_to (new_slot, location, FALSE);
313     	g_object_unref (location);
314     }
315 }
316 
317 /*Opens a new window when called from an existing window and goes to the same location that's in the existing window.*/
318 void
caja_window_new_window(CajaWindow * window)319 caja_window_new_window (CajaWindow *window)
320 {
321     CajaWindowSlot *current_slot;
322     GFile *location = NULL;
323     g_return_if_fail (CAJA_IS_WINDOW (window));
324 
325     /*Get and set the directory location of current window (slot).*/
326     current_slot = window->details->active_pane->active_slot;
327     location = caja_window_slot_get_location (current_slot);
328 
329     if (location != NULL)
330     {
331         CajaWindow *new_window;
332         CajaWindowSlot *new_slot;
333         CajaWindowOpenFlags flags;
334         flags = FALSE;
335 
336         /*Create a new window*/
337         new_window = caja_application_create_navigation_window (
338                      window->application,
339         gtk_window_get_screen (GTK_WINDOW (window)));
340 
341         /*Create a slot in the new window.*/
342         new_slot = new_window->details->active_pane->active_slot;
343         g_return_if_fail (CAJA_IS_WINDOW_SLOT (new_slot));
344 
345         /*Open a directory at the set location in the new window (slot).*/
346         caja_window_slot_open_location_full (new_slot, location,
347                                              CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
348                                              flags, NULL, NULL, NULL);
349         g_object_unref (location);
350     }
351 }
352 
353 void
caja_window_go_up(CajaWindow * window,gboolean close_behind,gboolean new_tab)354 caja_window_go_up (CajaWindow *window, gboolean close_behind, gboolean new_tab)
355 {
356     CajaWindowSlot *slot;
357     GFile *parent;
358     GList *selection;
359     CajaWindowOpenFlags flags;
360 
361     g_assert (CAJA_IS_WINDOW (window));
362 
363     slot = window->details->active_pane->active_slot;
364 
365     if (slot->location == NULL)
366     {
367         return;
368     }
369 
370     parent = g_file_get_parent (slot->location);
371 
372     if (parent == NULL)
373     {
374         return;
375     }
376 
377     selection = g_list_prepend (NULL, g_object_ref (slot->location));
378 
379     flags = 0;
380     if (close_behind)
381     {
382         flags |= CAJA_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
383     }
384     if (new_tab)
385     {
386         flags |= CAJA_WINDOW_OPEN_FLAG_NEW_TAB;
387     }
388 
389     caja_window_slot_open_location_full (slot, parent,
390                                          CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
391                                          flags,
392                                          selection,
393                                          NULL, NULL);
394 
395     g_object_unref (parent);
396 
397     g_list_free_full (selection, g_object_unref);
398 }
399 
400 static void
real_set_allow_up(CajaWindow * window,gboolean allow)401 real_set_allow_up (CajaWindow *window,
402                    gboolean        allow)
403 {
404     GtkAction *action;
405 
406     g_assert (CAJA_IS_WINDOW (window));
407 
408     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
409     action = gtk_action_group_get_action (window->details->main_action_group,
410                                           CAJA_ACTION_UP);
411     gtk_action_set_sensitive (action, allow);
412     action = gtk_action_group_get_action (window->details->main_action_group,
413                                           CAJA_ACTION_UP_ACCEL);
414     gtk_action_set_sensitive (action, allow);
415     G_GNUC_END_IGNORE_DEPRECATIONS;
416 }
417 
418 void
caja_window_allow_up(CajaWindow * window,gboolean allow)419 caja_window_allow_up (CajaWindow *window, gboolean allow)
420 {
421     g_return_if_fail (CAJA_IS_WINDOW (window));
422 
423     EEL_CALL_METHOD (CAJA_WINDOW_CLASS, window,
424                      set_allow_up, (window, allow));
425 }
426 
427 static void
update_cursor(CajaWindow * window)428 update_cursor (CajaWindow *window)
429 {
430     CajaWindowSlot *slot;
431 
432     slot = window->details->active_pane->active_slot;
433 
434     if (slot->allow_stop)
435     {
436         GdkDisplay *display;
437         GdkCursor * cursor;
438 
439         display = gtk_widget_get_display (GTK_WIDGET (window));
440         cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
441         gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
442         g_object_unref (cursor);
443     }
444     else
445     {
446         gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
447     }
448 }
449 
450 void
caja_window_sync_allow_stop(CajaWindow * window,CajaWindowSlot * slot)451 caja_window_sync_allow_stop (CajaWindow *window,
452                              CajaWindowSlot *slot)
453 {
454     GtkAction *action;
455     gboolean allow_stop;
456 
457     g_assert (CAJA_IS_WINDOW (window));
458 
459     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
460     action = gtk_action_group_get_action (window->details->main_action_group,
461                                           CAJA_ACTION_STOP);
462     allow_stop = gtk_action_get_sensitive (action);
463     G_GNUC_END_IGNORE_DEPRECATIONS;
464 
465     if (slot != window->details->active_pane->active_slot ||
466             allow_stop != slot->allow_stop)
467     {
468         if (slot == window->details->active_pane->active_slot)
469         {
470             G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
471             gtk_action_set_sensitive (action, slot->allow_stop);
472             G_GNUC_END_IGNORE_DEPRECATIONS;
473         }
474 
475         if (gtk_widget_get_realized (GTK_WIDGET (window)))
476         {
477             update_cursor (window);
478         }
479 
480         EEL_CALL_METHOD (CAJA_WINDOW_CLASS, window,
481                          sync_allow_stop, (window, slot));
482     }
483 }
484 
485 void
caja_window_reload(CajaWindow * window,gboolean new_tab)486 caja_window_reload (CajaWindow *window, gboolean new_tab)
487 {
488     CajaWindowSlot *slot;
489 
490     g_assert (CAJA_IS_WINDOW (window));
491 
492     slot = window->details->active_pane->active_slot;
493 
494     if (new_tab && slot->location != NULL)
495     {
496         caja_window_slot_open_location_full (slot, slot->location,
497                                              CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
498                                              CAJA_WINDOW_OPEN_FLAG_NEW_TAB,
499                                              NULL, NULL, NULL);
500     }
501     else
502     {
503         caja_window_slot_reload (slot);
504     }
505 }
506 
507 void
caja_window_allow_reload(CajaWindow * window,gboolean allow)508 caja_window_allow_reload (CajaWindow *window, gboolean allow)
509 {
510     GtkAction *action;
511 
512     g_return_if_fail (CAJA_IS_WINDOW (window));
513 
514     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
515     action = gtk_action_group_get_action (window->details->main_action_group,
516                                           CAJA_ACTION_RELOAD);
517     gtk_action_set_sensitive (action, allow);
518     G_GNUC_END_IGNORE_DEPRECATIONS;
519 }
520 
521 void
caja_window_go_home(CajaWindow * window)522 caja_window_go_home (CajaWindow *window)
523 {
524     g_return_if_fail (CAJA_IS_WINDOW (window));
525 
526     caja_window_slot_go_home (window->details->active_pane->active_slot, FALSE);
527 }
528 
529 void
caja_window_prompt_for_location(CajaWindow * window,const char * initial)530 caja_window_prompt_for_location (CajaWindow *window,
531                                  const char     *initial)
532 {
533     g_return_if_fail (CAJA_IS_WINDOW (window));
534 
535     EEL_CALL_METHOD (CAJA_WINDOW_CLASS, window,
536                      prompt_for_location, (window, initial));
537 }
538 
539 static char *
caja_window_get_location_uri(CajaWindow * window)540 caja_window_get_location_uri (CajaWindow *window)
541 {
542     CajaWindowSlot *slot;
543 
544     g_assert (CAJA_IS_WINDOW (window));
545 
546     slot = window->details->active_pane->active_slot;
547 
548     if (slot->location)
549     {
550         return g_file_get_uri (slot->location);
551     }
552     return NULL;
553 }
554 
555 void
caja_window_zoom_in(CajaWindow * window)556 caja_window_zoom_in (CajaWindow *window)
557 {
558     g_assert (window != NULL);
559 
560     caja_window_pane_zoom_in (window->details->active_pane);
561 }
562 
563 void
caja_window_zoom_to_level(CajaWindow * window,CajaZoomLevel level)564 caja_window_zoom_to_level (CajaWindow *window,
565                            CajaZoomLevel level)
566 {
567     g_assert (window != NULL);
568 
569     caja_window_pane_zoom_to_level (window->details->active_pane, level);
570 }
571 
572 void
caja_window_zoom_out(CajaWindow * window)573 caja_window_zoom_out (CajaWindow *window)
574 {
575     g_assert (window != NULL);
576 
577     caja_window_pane_zoom_out (window->details->active_pane);
578 }
579 
580 void
caja_window_zoom_to_default(CajaWindow * window)581 caja_window_zoom_to_default (CajaWindow *window)
582 {
583     g_assert (window != NULL);
584 
585     caja_window_pane_zoom_to_default (window->details->active_pane);
586 }
587 
588 /* Code should never force the window taller than this size.
589  * (The user can still stretch the window taller if desired).
590  */
591 static guint
get_max_forced_height(GdkScreen * screen)592 get_max_forced_height (GdkScreen *screen)
593 {
594     gint scale = gdk_window_get_scale_factor (gdk_screen_get_root_window (screen));
595     return (HeightOfScreen (gdk_x11_screen_get_xscreen (screen)) / scale * 90) / 100;
596 }
597 
598 /* Code should never force the window wider than this size.
599  * (The user can still stretch the window wider if desired).
600  */
601 static guint
get_max_forced_width(GdkScreen * screen)602 get_max_forced_width (GdkScreen *screen)
603 {
604     gint scale = gdk_window_get_scale_factor (gdk_screen_get_root_window (screen));
605     return (WidthOfScreen (gdk_x11_screen_get_xscreen (screen)) / scale * 90) / 100;
606 }
607 
608 /* This must be called when construction of CajaWindow is finished,
609  * since it depends on the type of the argument, which isn't decided at
610  * construction time.
611  */
612 static void
caja_window_set_initial_window_geometry(CajaWindow * window)613 caja_window_set_initial_window_geometry (CajaWindow *window)
614 {
615     GdkScreen *screen;
616     guint max_width_for_screen, max_height_for_screen;
617 
618     guint default_width = 0;
619     guint default_height = 0;
620 
621     screen = gtk_window_get_screen (GTK_WINDOW (window));
622 
623     max_width_for_screen = get_max_forced_width (screen);
624     max_height_for_screen = get_max_forced_height (screen);
625 
626     EEL_CALL_METHOD (CAJA_WINDOW_CLASS, window,
627                      get_default_size, (window, &default_width, &default_height));
628 
629     gtk_window_set_default_size (GTK_WINDOW (window),
630                                  MIN (default_width,
631                                       max_width_for_screen),
632                                  MIN (default_height,
633                                       max_height_for_screen));
634 }
635 
636 static void
caja_window_constructed(GObject * self)637 caja_window_constructed (GObject *self)
638 {
639     CajaWindow *window;
640 
641     window = CAJA_WINDOW (self);
642 
643     caja_window_initialize_bookmarks_menu (window);
644     caja_window_set_initial_window_geometry (window);
645 }
646 
647 static void
caja_window_set_property(GObject * object,guint arg_id,const GValue * value,GParamSpec * pspec)648 caja_window_set_property (GObject *object,
649                           guint arg_id,
650                           const GValue *value,
651                           GParamSpec *pspec)
652 {
653     CajaWindow *window;
654 
655     window = CAJA_WINDOW (object);
656 
657     switch (arg_id)
658     {
659     case ARG_APP:
660         window->application = CAJA_APPLICATION (g_value_get_object (value));
661         break;
662     }
663 }
664 
665 static void
caja_window_get_property(GObject * object,guint arg_id,GValue * value,GParamSpec * pspec)666 caja_window_get_property (GObject *object,
667                           guint arg_id,
668                           GValue *value,
669                           GParamSpec *pspec)
670 {
671     switch (arg_id)
672     {
673     case ARG_APP:
674         g_value_set_object (value, CAJA_WINDOW (object)->application);
675         break;
676     }
677 }
678 
679 static void
free_stored_viewers(CajaWindow * window)680 free_stored_viewers (CajaWindow *window)
681 {
682     g_list_free_full (window->details->short_list_viewers, g_free);
683     window->details->short_list_viewers = NULL;
684     g_free (window->details->extra_viewer);
685     window->details->extra_viewer = NULL;
686 }
687 
688 static void
caja_window_destroy(GtkWidget * object)689 caja_window_destroy (GtkWidget *object)
690 {
691     CajaWindow *window;
692     GList *panes_copy;
693 
694     window = CAJA_WINDOW (object);
695 
696     /* close all panes safely */
697     panes_copy = g_list_copy (window->details->panes);
698     g_list_free_full (panes_copy, (GDestroyNotify) caja_window_close_pane);
699 
700     /* the panes list should now be empty */
701     g_assert (window->details->panes == NULL);
702     g_assert (window->details->active_pane == NULL);
703 
704     GTK_WIDGET_CLASS (caja_window_parent_class)->destroy (object);
705 }
706 
707 static void
caja_window_finalize(GObject * object)708 caja_window_finalize (GObject *object)
709 {
710     CajaWindow *window;
711 
712     window = CAJA_WINDOW (object);
713 
714     caja_window_finalize_menus (window);
715     free_stored_viewers (window);
716 
717     if (window->details->bookmark_list != NULL)
718     {
719         g_object_unref (window->details->bookmark_list);
720     }
721 
722     /* caja_window_close() should have run */
723     g_assert (window->details->panes == NULL);
724 
725     g_object_unref (window->details->ui_manager);
726 
727     G_OBJECT_CLASS (caja_window_parent_class)->finalize (object);
728 }
729 
730 static GObject *
caja_window_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_params)731 caja_window_constructor (GType type,
732                          guint n_construct_properties,
733                          GObjectConstructParam *construct_params)
734 {
735     GObject *object;
736     CajaWindow *window;
737     CajaWindowSlot *slot;
738 
739     object = (* G_OBJECT_CLASS (caja_window_parent_class)->constructor) (type,
740              n_construct_properties,
741              construct_params);
742 
743     window = CAJA_WINDOW (object);
744 
745     slot = caja_window_open_slot (window->details->active_pane, 0);
746     caja_window_set_active_slot (window, slot);
747 
748     return object;
749 }
750 
751 void
caja_window_show_window(CajaWindow * window)752 caja_window_show_window (CajaWindow    *window)
753 {
754     CajaWindowSlot *slot;
755     CajaWindowPane *pane;
756     GList *l, *walk;
757 
758     for (walk = window->details->panes; walk; walk = walk->next)
759     {
760         pane = walk->data;
761         for (l = pane->slots; l != NULL; l = l->next)
762         {
763             slot = l->data;
764 
765             caja_window_slot_update_title (slot);
766             caja_window_slot_update_icon (slot);
767         }
768     }
769 
770     gtk_widget_show (GTK_WIDGET (window));
771 
772     slot = window->details->active_pane->active_slot;
773 
774     if (slot->viewed_file)
775     {
776         if (CAJA_IS_SPATIAL_WINDOW (window))
777         {
778             caja_file_set_has_open_window (slot->viewed_file, TRUE);
779         }
780     }
781 }
782 
783 static void
caja_window_view_visible(CajaWindow * window,CajaView * view)784 caja_window_view_visible (CajaWindow *window,
785                           CajaView *view)
786 {
787     CajaWindowSlot *slot;
788     CajaWindowPane *pane;
789     GList *l, *walk;
790 
791     g_return_if_fail (CAJA_IS_WINDOW (window));
792 
793     slot = caja_window_get_slot_for_view (window, view);
794 
795     /* Ensure we got the right active state for newly added panes */
796     caja_window_slot_is_in_active_pane (slot, slot->pane->is_active);
797 
798     if (slot->visible)
799     {
800         return;
801     }
802 
803     slot->visible = TRUE;
804 
805     pane = slot->pane;
806 
807     if (pane->visible)
808     {
809         return;
810     }
811 
812     /* Look for other non-visible slots */
813     for (l = pane->slots; l != NULL; l = l->next)
814     {
815         slot = l->data;
816 
817         if (!slot->visible)
818         {
819             return;
820         }
821     }
822 
823     /* None, this pane is visible */
824     caja_window_pane_show (pane);
825 
826     /* Look for other non-visible panes */
827     for (walk = window->details->panes; walk; walk = walk->next)
828     {
829         pane = walk->data;
830 
831         if (!pane->visible)
832         {
833             return;
834         }
835     }
836 
837     caja_window_pane_grab_focus (window->details->active_pane);
838 
839     /* All slots and panes visible, show window */
840     caja_window_show_window (window);
841 }
842 
843 void
caja_window_close(CajaWindow * window)844 caja_window_close (CajaWindow *window)
845 {
846     g_return_if_fail (CAJA_IS_WINDOW (window));
847 
848     EEL_CALL_METHOD (CAJA_WINDOW_CLASS, window,
849                      close, (window));
850 
851     gtk_widget_destroy (GTK_WIDGET (window));
852 }
853 
854 CajaWindowSlot *
caja_window_open_slot(CajaWindowPane * pane,CajaWindowOpenSlotFlags flags)855 caja_window_open_slot (CajaWindowPane *pane,
856                        CajaWindowOpenSlotFlags flags)
857 {
858     CajaWindowSlot *slot;
859 
860     g_assert (CAJA_IS_WINDOW_PANE (pane));
861     g_assert (CAJA_IS_WINDOW (pane->window));
862 
863     slot = EEL_CALL_METHOD_WITH_RETURN_VALUE (CAJA_WINDOW_CLASS, pane->window,
864             open_slot, (pane, flags));
865 
866     g_assert (CAJA_IS_WINDOW_SLOT (slot));
867     g_assert (pane->window == slot->pane->window);
868 
869     pane->slots = g_list_append (pane->slots, slot);
870 
871     return slot;
872 }
873 
874 void
caja_window_close_pane(CajaWindowPane * pane)875 caja_window_close_pane (CajaWindowPane *pane)
876 {
877     CajaWindow *window;
878 
879     g_assert (CAJA_IS_WINDOW_PANE (pane));
880     g_assert (CAJA_IS_WINDOW (pane->window));
881     g_assert (g_list_find (pane->window->details->panes, pane) != NULL);
882 
883     while (pane->slots != NULL)
884     {
885         CajaWindowSlot *slot = pane->slots->data;
886 
887         caja_window_close_slot (slot);
888     }
889 
890     window = pane->window;
891 
892     /* If the pane was active, set it to NULL. The caller is responsible
893      * for setting a new active pane with caja_window_pane_switch_to()
894      * if it wants to continue using the window. */
895     if (window->details->active_pane == pane)
896     {
897         window->details->active_pane = NULL;
898     }
899 
900     window->details->panes = g_list_remove (window->details->panes, pane);
901 
902     g_object_unref (pane);
903 }
904 
905 static void
real_close_slot(CajaWindowPane * pane,CajaWindowSlot * slot)906 real_close_slot (CajaWindowPane *pane,
907                  CajaWindowSlot *slot)
908 {
909     caja_window_manage_views_close_slot (pane, slot);
910     cancel_view_as_callback (slot);
911 }
912 
913 void
caja_window_close_slot(CajaWindowSlot * slot)914 caja_window_close_slot (CajaWindowSlot *slot)
915 {
916     CajaWindowPane *pane;
917 
918     g_assert (CAJA_IS_WINDOW_SLOT (slot));
919     g_assert (CAJA_IS_WINDOW_PANE(slot->pane));
920     g_assert (g_list_find (slot->pane->slots, slot) != NULL);
921 
922     /* save pane because slot is not valid anymore after this call */
923     pane = slot->pane;
924 
925     EEL_CALL_METHOD (CAJA_WINDOW_CLASS, slot->pane->window,
926                      close_slot, (slot->pane, slot));
927 
928     g_object_run_dispose (G_OBJECT (slot));
929     slot->pane = NULL;
930     g_object_unref (slot);
931     pane->slots = g_list_remove (pane->slots, slot);
932     pane->active_slots = g_list_remove (pane->active_slots, slot);
933 
934 }
935 
936 CajaWindowPane*
caja_window_get_active_pane(CajaWindow * window)937 caja_window_get_active_pane (CajaWindow *window)
938 {
939     g_assert (CAJA_IS_WINDOW (window));
940     return window->details->active_pane;
941 }
942 
943 static void
real_set_active_pane(CajaWindow * window,CajaWindowPane * new_pane)944 real_set_active_pane (CajaWindow *window, CajaWindowPane *new_pane)
945 {
946     /* make old pane inactive, and new one active.
947      * Currently active pane may be NULL (after init). */
948     if (window->details->active_pane &&
949             window->details->active_pane != new_pane)
950     {
951         caja_window_pane_set_active (new_pane->window->details->active_pane, FALSE);
952     }
953     caja_window_pane_set_active (new_pane, TRUE);
954 
955     window->details->active_pane = new_pane;
956 }
957 
958 /* Make the given pane the active pane of its associated window. This
959  * always implies making the containing active slot the active slot of
960  * the window. */
961 void
caja_window_set_active_pane(CajaWindow * window,CajaWindowPane * new_pane)962 caja_window_set_active_pane (CajaWindow *window,
963                              CajaWindowPane *new_pane)
964 {
965     g_assert (CAJA_IS_WINDOW_PANE (new_pane));
966     if (new_pane->active_slot)
967     {
968         caja_window_set_active_slot (window, new_pane->active_slot);
969     }
970     else if (new_pane != window->details->active_pane)
971     {
972         real_set_active_pane (window, new_pane);
973     }
974 }
975 
976 /* Make both, the given slot the active slot and its corresponding
977  * pane the active pane of the associated window.
978  * new_slot may be NULL. */
979 void
caja_window_set_active_slot(CajaWindow * window,CajaWindowSlot * new_slot)980 caja_window_set_active_slot (CajaWindow *window, CajaWindowSlot *new_slot)
981 {
982     CajaWindowSlot *old_slot;
983 
984     g_assert (CAJA_IS_WINDOW (window));
985 
986     if (new_slot)
987     {
988         g_assert (CAJA_IS_WINDOW_SLOT (new_slot));
989         g_assert (CAJA_IS_WINDOW_PANE (new_slot->pane));
990         g_assert (window == new_slot->pane->window);
991         g_assert (g_list_find (new_slot->pane->slots, new_slot) != NULL);
992     }
993 
994     if (window->details->active_pane != NULL)
995     {
996         old_slot = window->details->active_pane->active_slot;
997     }
998     else
999     {
1000         old_slot = NULL;
1001     }
1002 
1003     if (old_slot == new_slot)
1004     {
1005         return;
1006     }
1007 
1008     /* make old slot inactive if it exists (may be NULL after init, for example) */
1009     if (old_slot != NULL)
1010     {
1011         /* inform window */
1012         if (old_slot->content_view != NULL)
1013         {
1014             caja_window_slot_disconnect_content_view (old_slot, old_slot->content_view);
1015         }
1016 
1017         /* inform slot & view */
1018         g_signal_emit_by_name (old_slot, "inactive");
1019     }
1020 
1021     /* deal with panes */
1022     if (new_slot &&
1023             new_slot->pane != window->details->active_pane)
1024     {
1025         real_set_active_pane (window, new_slot->pane);
1026     }
1027 
1028     window->details->active_pane->active_slot = new_slot;
1029 
1030     /* make new slot active, if it exists */
1031     if (new_slot)
1032     {
1033         window->details->active_pane->active_slots =
1034             g_list_remove (window->details->active_pane->active_slots, new_slot);
1035         window->details->active_pane->active_slots =
1036             g_list_prepend (window->details->active_pane->active_slots, new_slot);
1037 
1038         /* inform sidebar panels */
1039         caja_window_report_location_change (window);
1040         /* TODO decide whether "selection-changed" should be emitted */
1041 
1042         if (new_slot->content_view != NULL)
1043         {
1044             /* inform window */
1045             caja_window_slot_connect_content_view (new_slot, new_slot->content_view);
1046         }
1047 
1048         /* inform slot & view */
1049         g_signal_emit_by_name (new_slot, "active");
1050     }
1051 }
1052 
1053 void
caja_window_slot_close(CajaWindowSlot * slot)1054 caja_window_slot_close (CajaWindowSlot *slot)
1055 {
1056     caja_window_pane_slot_close (slot->pane, slot);
1057 }
1058 
1059 static void
caja_window_realize(GtkWidget * widget)1060 caja_window_realize (GtkWidget *widget)
1061 {
1062     GTK_WIDGET_CLASS (caja_window_parent_class)->realize (widget);
1063     update_cursor (CAJA_WINDOW (widget));
1064 }
1065 
1066 static gboolean
caja_window_key_press_event(GtkWidget * widget,GdkEventKey * event)1067 caja_window_key_press_event (GtkWidget *widget,
1068                              GdkEventKey *event)
1069 {
1070     /* Fix for https://github.com/mate-desktop/caja/issues/1024 */
1071     if ((event->state & GDK_CONTROL_MASK) &&
1072         ((event->keyval == '.') || (event->keyval == ';')))
1073         return TRUE;
1074 
1075     CajaWindow *window;
1076     int i;
1077 
1078     window = CAJA_WINDOW (widget);
1079 
1080     for (i = 0; i < G_N_ELEMENTS (extra_window_keybindings); i++)
1081     {
1082         if (extra_window_keybindings[i].keyval == event->keyval)
1083         {
1084             const GList *action_groups;
1085             GtkAction *action;
1086 
1087             action = NULL;
1088 
1089             action_groups = gtk_ui_manager_get_action_groups (window->details->ui_manager);
1090             G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1091             while (action_groups != NULL && action == NULL)
1092             {
1093                 action = gtk_action_group_get_action (action_groups->data, extra_window_keybindings[i].action);
1094                 action_groups = action_groups->next;
1095             }
1096 
1097             g_assert (action != NULL);
1098             if (gtk_action_is_sensitive (action))
1099             {
1100                 gtk_action_activate (action);
1101                 return TRUE;
1102             }
1103             G_GNUC_END_IGNORE_DEPRECATIONS;
1104 
1105             break;
1106         }
1107     }
1108 
1109     return GTK_WIDGET_CLASS (caja_window_parent_class)->key_press_event (widget, event);
1110 }
1111 
1112 /*
1113  * Main API
1114  */
1115 
1116 static void
free_activate_view_data(gpointer data,GClosure * closure)1117 free_activate_view_data (gpointer  data,
1118                          GClosure *closure)
1119 {
1120     ActivateViewData *activate_data;
1121     (void) closure;
1122 
1123     activate_data = data;
1124     g_free (activate_data->id);
1125     g_slice_free (ActivateViewData, activate_data);
1126 }
1127 
1128 static void
action_view_as_callback(GtkAction * action,ActivateViewData * data)1129 action_view_as_callback (GtkAction *action,
1130                          ActivateViewData *data)
1131 {
1132     CajaWindow *window;
1133 
1134     window = data->window;
1135 
1136     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1137     if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
1138     {
1139         CajaWindowSlot *slot;
1140 
1141         slot = window->details->active_pane->active_slot;
1142         caja_window_slot_set_content_view (slot,
1143                                            data->id);
1144     }
1145     G_GNUC_END_IGNORE_DEPRECATIONS;
1146 }
1147 
1148 static GtkRadioAction *
add_view_as_menu_item(CajaWindow * window,const char * placeholder_path,const char * identifier,int index,guint merge_id)1149 add_view_as_menu_item (CajaWindow *window,
1150                        const char *placeholder_path,
1151                        const char *identifier,
1152                        int index, /* extra_viewer is always index 0 */
1153                        guint merge_id)
1154 {
1155     const CajaViewInfo *info;
1156     GtkRadioAction *action;
1157     char action_name[32];
1158     ActivateViewData *data;
1159 
1160     info = caja_view_factory_lookup (identifier);
1161 
1162     g_snprintf (action_name, sizeof (action_name), "view_as_%d", index);
1163     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1164     action = gtk_radio_action_new (action_name,
1165                                    _(info->view_menu_label_with_mnemonic),
1166                                    _(info->display_location_label),
1167                                    NULL,
1168                                    0);
1169     G_GNUC_END_IGNORE_DEPRECATIONS;
1170 
1171     if (index >= 1 && index <= 9)
1172     {
1173         char accel[32];
1174         char accel_path[48];
1175         unsigned int accel_keyval;
1176 
1177         g_snprintf (accel, sizeof (accel), "%d", index);
1178         g_snprintf (accel_path, sizeof (accel_path), "<Caja-Window>/%s", action_name);
1179 
1180         accel_keyval = gdk_keyval_from_name (accel);
1181 		g_assert (accel_keyval != GDK_KEY_VoidSymbol);
1182 
1183         gtk_accel_map_add_entry (accel_path, accel_keyval, GDK_CONTROL_MASK);
1184         G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1185         gtk_action_set_accel_path (GTK_ACTION (action), accel_path);
1186         G_GNUC_END_IGNORE_DEPRECATIONS;
1187     }
1188 
1189     if (window->details->view_as_radio_action != NULL)
1190     {
1191         G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1192         gtk_radio_action_set_group (action,
1193                                     gtk_radio_action_get_group (window->details->view_as_radio_action));
1194         G_GNUC_END_IGNORE_DEPRECATIONS;
1195     }
1196     else if (index != 0)
1197     {
1198         /* Index 0 is the extra view, and we don't want to use that here,
1199            as it can get deleted/changed later */
1200         window->details->view_as_radio_action = action;
1201     }
1202 
1203     data = g_slice_new (ActivateViewData);
1204     data->window = window;
1205     data->id = g_strdup (identifier);
1206     g_signal_connect_data (action, "activate",
1207                            G_CALLBACK (action_view_as_callback),
1208                            data, free_activate_view_data, 0);
1209 
1210     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1211     gtk_action_group_add_action (window->details->view_as_action_group,
1212                                  GTK_ACTION (action));
1213     g_object_unref (action);
1214     G_GNUC_END_IGNORE_DEPRECATIONS;
1215 
1216     gtk_ui_manager_add_ui (window->details->ui_manager,
1217                            merge_id,
1218                            placeholder_path,
1219                            action_name,
1220                            action_name,
1221                            GTK_UI_MANAGER_MENUITEM,
1222                            FALSE);
1223 
1224     return action; /* return value owned by group */
1225 }
1226 
1227 /* Make a special first item in the "View as" option menu that represents
1228  * the current content view. This should only be called if the current
1229  * content view isn't already in the "View as" option menu.
1230  */
1231 static void
update_extra_viewer_in_view_as_menus(CajaWindow * window,const char * id)1232 update_extra_viewer_in_view_as_menus (CajaWindow *window,
1233                                       const char *id)
1234 {
1235     gboolean had_extra_viewer;
1236 
1237     had_extra_viewer = window->details->extra_viewer != NULL;
1238 
1239     if (id == NULL)
1240     {
1241         if (!had_extra_viewer)
1242         {
1243             return;
1244         }
1245     }
1246     else
1247     {
1248         if (had_extra_viewer
1249                 && strcmp (window->details->extra_viewer, id) == 0)
1250         {
1251             return;
1252         }
1253     }
1254     g_free (window->details->extra_viewer);
1255     window->details->extra_viewer = g_strdup (id);
1256 
1257     if (window->details->extra_viewer_merge_id != 0)
1258     {
1259         gtk_ui_manager_remove_ui (window->details->ui_manager,
1260                                   window->details->extra_viewer_merge_id);
1261         window->details->extra_viewer_merge_id = 0;
1262     }
1263 
1264     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1265     if (window->details->extra_viewer_radio_action != NULL)
1266     {
1267         gtk_action_group_remove_action (window->details->view_as_action_group,
1268                                         GTK_ACTION (window->details->extra_viewer_radio_action));
1269         window->details->extra_viewer_radio_action = NULL;
1270     }
1271     G_GNUC_END_IGNORE_DEPRECATIONS;
1272 
1273     if (id != NULL)
1274     {
1275         window->details->extra_viewer_merge_id = gtk_ui_manager_new_merge_id (window->details->ui_manager);
1276         window->details->extra_viewer_radio_action =
1277             add_view_as_menu_item (window,
1278                                    CAJA_MENU_PATH_EXTRA_VIEWER_PLACEHOLDER,
1279                                    window->details->extra_viewer,
1280                                    0,
1281                                    window->details->extra_viewer_merge_id);
1282     }
1283 }
1284 
1285 static void
remove_extra_viewer_in_view_as_menus(CajaWindow * window)1286 remove_extra_viewer_in_view_as_menus (CajaWindow *window)
1287 {
1288     update_extra_viewer_in_view_as_menus (window, NULL);
1289 }
1290 
1291 static void
replace_extra_viewer_in_view_as_menus(CajaWindow * window)1292 replace_extra_viewer_in_view_as_menus (CajaWindow *window)
1293 {
1294     CajaWindowSlot *slot;
1295     const char *id;
1296 
1297     slot = window->details->active_pane->active_slot;
1298 
1299     id = caja_window_slot_get_content_view_id (slot);
1300     update_extra_viewer_in_view_as_menus (window, id);
1301 }
1302 
1303 /**
1304  * caja_window_synch_view_as_menus:
1305  *
1306  * Set the visible item of the "View as" option menu and
1307  * the marked "View as" item in the View menu to
1308  * match the current content view.
1309  *
1310  * @window: The CajaWindow whose "View as" option menu should be synched.
1311  */
1312 static void
caja_window_synch_view_as_menus(CajaWindow * window)1313 caja_window_synch_view_as_menus (CajaWindow *window)
1314 {
1315     CajaWindowSlot *slot;
1316     int index;
1317     char action_name[32];
1318     GList *node;
1319     GtkAction *action;
1320 
1321     g_assert (CAJA_IS_WINDOW (window));
1322 
1323     slot = window->details->active_pane->active_slot;
1324 
1325     if (slot->content_view == NULL)
1326     {
1327         return;
1328     }
1329     for (node = window->details->short_list_viewers, index = 1;
1330             node != NULL;
1331             node = node->next, ++index)
1332     {
1333         if (caja_window_slot_content_view_matches_iid (slot, (char *)node->data))
1334         {
1335             break;
1336         }
1337     }
1338     if (node == NULL)
1339     {
1340         replace_extra_viewer_in_view_as_menus (window);
1341         index = 0;
1342     }
1343     else
1344     {
1345         remove_extra_viewer_in_view_as_menus (window);
1346     }
1347 
1348     g_snprintf (action_name, sizeof (action_name), "view_as_%d", index);
1349     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1350     action = gtk_action_group_get_action (window->details->view_as_action_group,
1351                                           action_name);
1352     G_GNUC_END_IGNORE_DEPRECATIONS;
1353 
1354     /* Don't trigger the action callback when we're synchronizing */
1355     g_signal_handlers_block_matched (action,
1356                                      G_SIGNAL_MATCH_FUNC,
1357                                      0, 0,
1358                                      NULL,
1359                                      action_view_as_callback,
1360                                      NULL);
1361     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1362     gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1363     G_GNUC_END_IGNORE_DEPRECATIONS;
1364     g_signal_handlers_unblock_matched (action,
1365                                        G_SIGNAL_MATCH_FUNC,
1366                                        0, 0,
1367                                        NULL,
1368                                        action_view_as_callback,
1369                                        NULL);
1370 }
1371 
1372 static void
refresh_stored_viewers(CajaWindow * window)1373 refresh_stored_viewers (CajaWindow *window)
1374 {
1375     CajaWindowSlot *slot;
1376     GList *viewers;
1377     char *uri, *mimetype;
1378 
1379     slot = window->details->active_pane->active_slot;
1380 
1381     uri = caja_file_get_uri (slot->viewed_file);
1382     mimetype = caja_file_get_mime_type (slot->viewed_file);
1383     viewers = caja_view_factory_get_views_for_uri (uri,
1384               caja_file_get_file_type (slot->viewed_file),
1385               mimetype);
1386     g_free (uri);
1387     g_free (mimetype);
1388 
1389     free_stored_viewers (window);
1390     window->details->short_list_viewers = viewers;
1391 }
1392 
1393 static void
load_view_as_menu(CajaWindow * window)1394 load_view_as_menu (CajaWindow *window)
1395 {
1396     GList *node;
1397     guint merge_id;
1398 
1399     if (window->details->short_list_merge_id != 0)
1400     {
1401         gtk_ui_manager_remove_ui (window->details->ui_manager,
1402                                   window->details->short_list_merge_id);
1403         window->details->short_list_merge_id = 0;
1404     }
1405     if (window->details->extra_viewer_merge_id != 0)
1406     {
1407         gtk_ui_manager_remove_ui (window->details->ui_manager,
1408                                   window->details->extra_viewer_merge_id);
1409         window->details->extra_viewer_merge_id = 0;
1410         window->details->extra_viewer_radio_action = NULL;
1411     }
1412     if (window->details->view_as_action_group != NULL)
1413     {
1414         gtk_ui_manager_remove_action_group (window->details->ui_manager,
1415                                             window->details->view_as_action_group);
1416         window->details->view_as_action_group = NULL;
1417     }
1418 
1419 
1420     refresh_stored_viewers (window);
1421 
1422     merge_id = gtk_ui_manager_new_merge_id (window->details->ui_manager);
1423     window->details->short_list_merge_id = merge_id;
1424     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1425     window->details->view_as_action_group = gtk_action_group_new ("ViewAsGroup");
1426 #ifdef ENABLE_NLS
1427     gtk_action_group_set_translation_domain (window->details->view_as_action_group, GETTEXT_PACKAGE);
1428 #endif /* ENABLE_NLS */
1429     G_GNUC_END_IGNORE_DEPRECATIONS;
1430     window->details->view_as_radio_action = NULL;
1431 
1432     if (g_list_length (window->details->short_list_viewers) > 1) {
1433         int index;
1434         /* Add a menu item for each view in the preferred list for this location. */
1435         /* Start on 1, because extra_viewer gets index 0 */
1436         for (node = window->details->short_list_viewers, index = 1;
1437                 node != NULL;
1438                 node = node->next, ++index)
1439         {
1440             /* Menu item in View menu. */
1441             add_view_as_menu_item (window,
1442                     CAJA_MENU_PATH_SHORT_LIST_PLACEHOLDER,
1443                     node->data,
1444                     index,
1445                     merge_id);
1446         }
1447     }
1448     gtk_ui_manager_insert_action_group (window->details->ui_manager,
1449                                         window->details->view_as_action_group,
1450                                         -1);
1451     g_object_unref (window->details->view_as_action_group); /* owned by ui_manager */
1452 
1453     caja_window_synch_view_as_menus (window);
1454 
1455     g_signal_emit (window, signals[VIEW_AS_CHANGED], 0);
1456 
1457 }
1458 
1459 static void
load_view_as_menus_callback(CajaFile * file,gpointer callback_data)1460 load_view_as_menus_callback (CajaFile *file,
1461                              gpointer callback_data)
1462 {
1463     CajaWindow *window;
1464     CajaWindowSlot *slot;
1465 
1466     slot = callback_data;
1467     window = CAJA_WINDOW (slot->pane->window);
1468 
1469     if (slot == window->details->active_pane->active_slot)
1470     {
1471         load_view_as_menu (window);
1472     }
1473 }
1474 
1475 static void
cancel_view_as_callback(CajaWindowSlot * slot)1476 cancel_view_as_callback (CajaWindowSlot *slot)
1477 {
1478     caja_file_cancel_call_when_ready (slot->viewed_file,
1479                                       load_view_as_menus_callback,
1480                                       slot);
1481 }
1482 
1483 void
caja_window_load_view_as_menus(CajaWindow * window)1484 caja_window_load_view_as_menus (CajaWindow *window)
1485 {
1486     CajaWindowSlot *slot;
1487     CajaFileAttributes attributes;
1488 
1489     g_return_if_fail (CAJA_IS_WINDOW (window));
1490 
1491     attributes = caja_mime_actions_get_required_file_attributes ();
1492 
1493     slot = window->details->active_pane->active_slot;
1494 
1495     cancel_view_as_callback (slot);
1496     caja_file_call_when_ready (slot->viewed_file,
1497                                attributes,
1498                                load_view_as_menus_callback,
1499                                slot);
1500 }
1501 
1502 void
caja_window_display_error(CajaWindow * window,const char * error_msg)1503 caja_window_display_error (CajaWindow *window, const char *error_msg)
1504 {
1505     GtkWidget *dialog;
1506 
1507     g_return_if_fail (CAJA_IS_WINDOW (window));
1508 
1509     dialog = gtk_message_dialog_new (GTK_WINDOW (window), 0, GTK_MESSAGE_ERROR,
1510                                      GTK_BUTTONS_OK, error_msg, NULL);
1511     gtk_widget_show (dialog);
1512 }
1513 
1514 static char *
real_get_title(CajaWindow * window)1515 real_get_title (CajaWindow *window)
1516 {
1517     g_assert (CAJA_IS_WINDOW (window));
1518 
1519     return caja_window_slot_get_title (window->details->active_pane->active_slot);
1520 }
1521 
1522 static void
real_sync_title(CajaWindow * window,CajaWindowSlot * slot)1523 real_sync_title (CajaWindow *window,
1524                  CajaWindowSlot *slot)
1525 {
1526     if (slot == window->details->active_pane->active_slot)
1527     {
1528         g_signal_emit_by_name (window, "title_changed",
1529                                slot->title);
1530     }
1531 }
1532 
1533 void
caja_window_sync_title(CajaWindow * window,CajaWindowSlot * slot)1534 caja_window_sync_title (CajaWindow *window,
1535                         CajaWindowSlot *slot)
1536 {
1537     EEL_CALL_METHOD (CAJA_WINDOW_CLASS, window,
1538                      sync_title, (window, slot));
1539 }
1540 
1541 void
caja_window_sync_zoom_widgets(CajaWindow * window)1542 caja_window_sync_zoom_widgets (CajaWindow *window)
1543 {
1544     CajaWindowSlot *slot;
1545     CajaView *view;
1546     GtkAction *action;
1547     gboolean supports_zooming;
1548     gboolean can_zoom, can_zoom_in, can_zoom_out;
1549     CajaZoomLevel zoom_level;
1550 
1551     slot = window->details->active_pane->active_slot;
1552     view = slot->content_view;
1553 
1554     if (view != NULL)
1555     {
1556         supports_zooming = caja_view_supports_zooming (view);
1557         zoom_level = caja_view_get_zoom_level (view);
1558         can_zoom = supports_zooming &&
1559                    zoom_level >= CAJA_ZOOM_LEVEL_SMALLEST &&
1560                    zoom_level <= CAJA_ZOOM_LEVEL_LARGEST;
1561         can_zoom_in = can_zoom && caja_view_can_zoom_in (view);
1562         can_zoom_out = can_zoom && caja_view_can_zoom_out (view);
1563     }
1564     else
1565     {
1566         zoom_level = CAJA_ZOOM_LEVEL_STANDARD;
1567         supports_zooming = FALSE;
1568         can_zoom = FALSE;
1569         can_zoom_in = FALSE;
1570         can_zoom_out = FALSE;
1571     }
1572 
1573     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1574     action = gtk_action_group_get_action (window->details->main_action_group,
1575                                           CAJA_ACTION_ZOOM_IN);
1576     gtk_action_set_visible (action, supports_zooming);
1577     gtk_action_set_sensitive (action, can_zoom_in);
1578 
1579     action = gtk_action_group_get_action (window->details->main_action_group,
1580                                           CAJA_ACTION_ZOOM_OUT);
1581     gtk_action_set_visible (action, supports_zooming);
1582     gtk_action_set_sensitive (action, can_zoom_out);
1583 
1584     action = gtk_action_group_get_action (window->details->main_action_group,
1585                                           CAJA_ACTION_ZOOM_NORMAL);
1586     gtk_action_set_visible (action, supports_zooming);
1587     gtk_action_set_sensitive (action, can_zoom);
1588     G_GNUC_END_IGNORE_DEPRECATIONS;
1589 
1590     g_signal_emit (window, signals[ZOOM_CHANGED], 0,
1591                    zoom_level, supports_zooming, can_zoom,
1592                    can_zoom_in, can_zoom_out);
1593 }
1594 
1595 static void
zoom_level_changed_callback(CajaView * view,CajaWindow * window)1596 zoom_level_changed_callback (CajaView *view,
1597                              CajaWindow *window)
1598 {
1599     g_assert (CAJA_IS_WINDOW (window));
1600 
1601     /* This is called each time the component in
1602      * the active slot successfully completed
1603      * a zooming operation.
1604      */
1605     caja_window_sync_zoom_widgets (window);
1606 }
1607 
1608 
1609 /* These are called
1610  *   A) when switching the view within the active slot
1611  *   B) when switching the active slot
1612  *   C) when closing the active slot (disconnect)
1613 */
1614 void
caja_window_connect_content_view(CajaWindow * window,CajaView * view)1615 caja_window_connect_content_view (CajaWindow *window,
1616                                   CajaView *view)
1617 {
1618     CajaWindowSlot *slot;
1619 
1620     g_assert (CAJA_IS_WINDOW (window));
1621     g_assert (CAJA_IS_VIEW (view));
1622 
1623     slot = caja_window_get_slot_for_view (window, view);
1624     g_assert (slot == caja_window_get_active_slot (window));
1625 
1626     g_signal_connect (view, "zoom-level-changed",
1627                       G_CALLBACK (zoom_level_changed_callback),
1628                       window);
1629 
1630     /* Update displayed view in menu. Only do this if we're not switching
1631      * locations though, because if we are switching locations we'll
1632      * install a whole new set of views in the menu later (the current
1633      * views in the menu are for the old location).
1634      */
1635     if (slot->pending_location == NULL)
1636     {
1637         caja_window_load_view_as_menus (window);
1638     }
1639 
1640     caja_view_grab_focus (view);
1641 }
1642 
1643 void
caja_window_disconnect_content_view(CajaWindow * window,CajaView * view)1644 caja_window_disconnect_content_view (CajaWindow *window,
1645                                      CajaView *view)
1646 {
1647     CajaWindowSlot *slot;
1648 
1649     g_assert (CAJA_IS_WINDOW (window));
1650     g_assert (CAJA_IS_VIEW (view));
1651 
1652     slot = caja_window_get_slot_for_view (window, view);
1653     g_assert (slot == caja_window_get_active_slot (window));
1654 
1655     g_signal_handlers_disconnect_by_func (view, G_CALLBACK (zoom_level_changed_callback), window);
1656 }
1657 
1658 /**
1659  * caja_window_show:
1660  * @widget:	GtkWidget
1661  *
1662  * Call parent and then show/hide window items
1663  * base on user prefs.
1664  */
1665 static void
caja_window_show(GtkWidget * widget)1666 caja_window_show (GtkWidget *widget)
1667 {
1668     CajaWindow *window;
1669 
1670     window = CAJA_WINDOW (widget);
1671 
1672     GTK_WIDGET_CLASS (caja_window_parent_class)->show (widget);
1673 
1674     caja_window_ui_update (window);
1675 }
1676 
1677 GtkUIManager *
caja_window_get_ui_manager(CajaWindow * window)1678 caja_window_get_ui_manager (CajaWindow *window)
1679 {
1680     g_return_val_if_fail (CAJA_IS_WINDOW (window), NULL);
1681 
1682     return window->details->ui_manager;
1683 }
1684 
1685 CajaWindowPane *
caja_window_get_next_pane(CajaWindow * window)1686 caja_window_get_next_pane (CajaWindow *window)
1687 {
1688     CajaWindowPane *next_pane;
1689     GList *node;
1690 
1691     /* return NULL if there is only one pane */
1692     if (!window->details->panes || !window->details->panes->next)
1693     {
1694         return NULL;
1695     }
1696 
1697     /* get next pane in the (wrapped around) list */
1698     node = g_list_find (window->details->panes, window->details->active_pane);
1699     g_return_val_if_fail (node, NULL);
1700     if (node->next)
1701     {
1702         next_pane = node->next->data;
1703     }
1704     else
1705     {
1706         next_pane =  window->details->panes->data;
1707     }
1708 
1709     return next_pane;
1710 }
1711 
1712 
1713 void
caja_window_slot_set_viewed_file(CajaWindowSlot * slot,CajaFile * file)1714 caja_window_slot_set_viewed_file (CajaWindowSlot *slot,
1715                                   CajaFile *file)
1716 {
1717     CajaFileAttributes attributes;
1718 
1719     if (slot->viewed_file == file)
1720     {
1721         return;
1722     }
1723 
1724     caja_file_ref (file);
1725 
1726     cancel_view_as_callback (slot);
1727 
1728     if (slot->viewed_file != NULL)
1729     {
1730         CajaWindow *window;
1731 
1732         window = slot->pane->window;
1733 
1734         if (CAJA_IS_SPATIAL_WINDOW (window))
1735         {
1736             caja_file_set_has_open_window (slot->viewed_file,
1737                                            FALSE);
1738         }
1739         caja_file_monitor_remove (slot->viewed_file,
1740                                   slot);
1741     }
1742 
1743     if (file != NULL)
1744     {
1745         attributes =
1746             CAJA_FILE_ATTRIBUTE_INFO |
1747             CAJA_FILE_ATTRIBUTE_LINK_INFO;
1748         caja_file_monitor_add (file, slot, attributes);
1749     }
1750 
1751     caja_file_unref (slot->viewed_file);
1752     slot->viewed_file = file;
1753 }
1754 
1755 void
caja_send_history_list_changed(void)1756 caja_send_history_list_changed (void)
1757 {
1758     g_signal_emit_by_name (caja_signaller_get_current (),
1759                            "history_list_changed");
1760 }
1761 
1762 static void
free_history_list(void)1763 free_history_list (void)
1764 {
1765     g_list_free_full (history_list, g_object_unref);
1766     history_list = NULL;
1767 }
1768 
1769 /* Remove the this URI from the history list.
1770  * Do not sent out a change notice.
1771  * We pass in a bookmark for convenience.
1772  */
1773 static void
remove_from_history_list(CajaBookmark * bookmark)1774 remove_from_history_list (CajaBookmark *bookmark)
1775 {
1776     GList *node;
1777 
1778     /* Compare only the uris here. Comparing the names also is not
1779      * necessary and can cause problems due to the asynchronous
1780      * nature of when the title of the window is set.
1781      */
1782     node = g_list_find_custom (history_list,
1783                                bookmark,
1784                                caja_bookmark_compare_uris);
1785 
1786     /* Remove any older entry for this same item. There can be at most 1. */
1787     if (node != NULL)
1788     {
1789         history_list = g_list_remove_link (history_list, node);
1790         g_object_unref (node->data);
1791         g_list_free_1 (node);
1792     }
1793 }
1794 
1795 gboolean
caja_add_bookmark_to_history_list(CajaBookmark * bookmark)1796 caja_add_bookmark_to_history_list (CajaBookmark *bookmark)
1797 {
1798     /* Note that the history is shared amongst all windows so
1799      * this is not a CajaNavigationWindow function. Perhaps it belongs
1800      * in its own file.
1801      */
1802     GList *l, *next;
1803     static gboolean free_history_list_is_set_up;
1804 
1805     g_assert (CAJA_IS_BOOKMARK (bookmark));
1806 
1807     if (!free_history_list_is_set_up)
1808     {
1809         eel_debug_call_at_shutdown (free_history_list);
1810         free_history_list_is_set_up = TRUE;
1811     }
1812 
1813     /*	g_warning ("Add to history list '%s' '%s'",
1814     		   caja_bookmark_get_name (bookmark),
1815     		   caja_bookmark_get_uri (bookmark)); */
1816 
1817     if (!history_list ||
1818             caja_bookmark_compare_uris (history_list->data, bookmark))
1819     {
1820         int i;
1821 
1822         g_object_ref (bookmark);
1823         remove_from_history_list (bookmark);
1824         history_list = g_list_prepend (history_list, bookmark);
1825 
1826         for (i = 0, l = history_list; l; l = next)
1827         {
1828             next = l->next;
1829 
1830             if (i++ >= MAX_HISTORY_ITEMS)
1831             {
1832                 g_object_unref (l->data);
1833                 history_list = g_list_delete_link (history_list, l);
1834             }
1835         }
1836 
1837         return TRUE;
1838     }
1839 
1840     return FALSE;
1841 }
1842 
1843 void
caja_remove_from_history_list_no_notify(GFile * location)1844 caja_remove_from_history_list_no_notify (GFile *location)
1845 {
1846     CajaBookmark *bookmark;
1847 
1848     bookmark = caja_bookmark_new (location, "", FALSE, NULL);
1849     remove_from_history_list (bookmark);
1850     g_object_unref (bookmark);
1851 }
1852 
1853 gboolean
caja_add_to_history_list_no_notify(GFile * location,const char * name,gboolean has_custom_name,GIcon * icon)1854 caja_add_to_history_list_no_notify (GFile *location,
1855                                     const char *name,
1856                                     gboolean has_custom_name,
1857                                     GIcon *icon)
1858 {
1859     CajaBookmark *bookmark;
1860     gboolean ret;
1861 
1862     bookmark = caja_bookmark_new (location, name, has_custom_name, icon);
1863     ret = caja_add_bookmark_to_history_list (bookmark);
1864     g_object_unref (bookmark);
1865 
1866     return ret;
1867 }
1868 
1869 CajaWindowSlot *
caja_window_get_slot_for_view(CajaWindow * window,CajaView * view)1870 caja_window_get_slot_for_view (CajaWindow *window,
1871                                CajaView *view)
1872 {
1873     CajaWindowSlot *slot;
1874     GList *l, *walk;
1875 
1876     for (walk = window->details->panes; walk; walk = walk->next)
1877     {
1878         CajaWindowPane *pane = walk->data;
1879 
1880         for (l = pane->slots; l != NULL; l = l->next)
1881         {
1882             slot = l->data;
1883             if (slot->content_view == view ||
1884                     slot->new_content_view == view)
1885             {
1886                 return slot;
1887             }
1888         }
1889     }
1890 
1891     return NULL;
1892 }
1893 
1894 void
caja_forget_history(void)1895 caja_forget_history (void)
1896 {
1897     CajaWindowSlot *slot;
1898     CajaNavigationWindowSlot *navigation_slot;
1899     GList *window_node, *l, *walk;
1900     CajaApplication *app;
1901 
1902     app = CAJA_APPLICATION (g_application_get_default ());
1903     /* Clear out each window's back & forward lists. Also, remove
1904      * each window's current location bookmark from history list
1905      * so it doesn't get clobbered.
1906      */
1907     for (window_node = gtk_application_get_windows (GTK_APPLICATION (app));
1908             window_node != NULL;
1909             window_node = window_node->next)
1910     {
1911 
1912         if (CAJA_IS_NAVIGATION_WINDOW (window_node->data))
1913         {
1914             CajaNavigationWindow *window;
1915 
1916             window = CAJA_NAVIGATION_WINDOW (window_node->data);
1917 
1918             for (walk = CAJA_WINDOW (window_node->data)->details->panes; walk; walk = walk->next)
1919             {
1920                 CajaWindowPane *pane = walk->data;
1921                 for (l = pane->slots; l != NULL; l = l->next)
1922                 {
1923                     navigation_slot = l->data;
1924 
1925                     caja_navigation_window_slot_clear_back_list (navigation_slot);
1926                     caja_navigation_window_slot_clear_forward_list (navigation_slot);
1927                 }
1928             }
1929 
1930             caja_navigation_window_allow_back (window, FALSE);
1931             caja_navigation_window_allow_forward (window, FALSE);
1932         }
1933 
1934         for (walk = CAJA_WINDOW (window_node->data)->details->panes; walk; walk = walk->next)
1935         {
1936             CajaWindowPane *pane = walk->data;
1937             for (l = pane->slots; l != NULL; l = l->next)
1938             {
1939                 slot = l->data;
1940                 history_list = g_list_remove (history_list,
1941                                               slot->current_location_bookmark);
1942             }
1943         }
1944     }
1945 
1946     /* Clobber history list. */
1947     free_history_list ();
1948 
1949     /* Re-add each window's current location to history list. */
1950     for (window_node = gtk_application_get_windows (GTK_APPLICATION (app));
1951             window_node != NULL;
1952             window_node = window_node->next)
1953     {
1954         CajaWindow *window;
1955         CajaWindowSlot *slot;
1956         GList *l;
1957 
1958         window = CAJA_WINDOW (window_node->data);
1959         for (walk = window->details->panes; walk; walk = walk->next)
1960         {
1961             CajaWindowPane *pane = walk->data;
1962             for (l = pane->slots; l != NULL; l = l->next)
1963             {
1964                 slot = CAJA_WINDOW_SLOT (l->data);
1965                 caja_window_slot_add_current_location_to_history_list (slot);
1966             }
1967         }
1968     }
1969 }
1970 
1971 GList *
caja_get_history_list(void)1972 caja_get_history_list (void)
1973 {
1974     return history_list;
1975 }
1976 
1977 static gpointer
caja_window_copy_history_item(gconstpointer src,gpointer data)1978 caja_window_copy_history_item (gconstpointer src,
1979                                gpointer      data)
1980 {
1981     (void) data;
1982     return g_object_ref (G_OBJECT (src));
1983 }
1984 
1985 static GList *
caja_window_get_history(CajaWindow * window)1986 caja_window_get_history (CajaWindow *window)
1987 {
1988     return g_list_copy_deep (history_list, caja_window_copy_history_item, NULL);
1989 }
1990 
1991 
1992 static CajaWindowType
caja_window_get_window_type(CajaWindow * window)1993 caja_window_get_window_type (CajaWindow *window)
1994 {
1995     g_assert (CAJA_IS_WINDOW (window));
1996 
1997     return CAJA_WINDOW_GET_CLASS (window)->window_type;
1998 }
1999 
2000 static int
caja_window_get_selection_count(CajaWindow * window)2001 caja_window_get_selection_count (CajaWindow *window)
2002 {
2003     CajaWindowSlot *slot;
2004 
2005     g_assert (CAJA_IS_WINDOW (window));
2006 
2007     slot = window->details->active_pane->active_slot;
2008 
2009     if (slot->content_view != NULL)
2010     {
2011         return caja_view_get_selection_count (slot->content_view);
2012     }
2013 
2014     return 0;
2015 }
2016 
2017 static GList *
caja_window_get_selection(CajaWindow * window)2018 caja_window_get_selection (CajaWindow *window)
2019 {
2020     CajaWindowSlot *slot;
2021 
2022     g_assert (CAJA_IS_WINDOW (window));
2023 
2024     slot = window->details->active_pane->active_slot;
2025 
2026     if (slot->content_view != NULL)
2027     {
2028         return caja_view_get_selection (slot->content_view);
2029     }
2030     return NULL;
2031 }
2032 
2033 static CajaWindowShowHiddenFilesMode
caja_window_get_hidden_files_mode(CajaWindowInfo * window)2034 caja_window_get_hidden_files_mode (CajaWindowInfo *window)
2035 {
2036     return window->details->show_hidden_files_mode;
2037 }
2038 
2039 static void
caja_window_set_hidden_files_mode(CajaWindowInfo * window,CajaWindowShowHiddenFilesMode mode)2040 caja_window_set_hidden_files_mode (CajaWindowInfo *window,
2041                                    CajaWindowShowHiddenFilesMode  mode)
2042 {
2043     window->details->show_hidden_files_mode = mode;
2044 
2045     g_signal_emit_by_name (window, "hidden_files_mode_changed");
2046 }
2047 
2048 static CajaWindowShowBackupFilesMode
caja_window_get_backup_files_mode(CajaWindowInfo * window)2049 caja_window_get_backup_files_mode (CajaWindowInfo *window)
2050 {
2051     return window->details->show_backup_files_mode;
2052 }
2053 
2054 static void
caja_window_set_backup_files_mode(CajaWindowInfo * window,CajaWindowShowBackupFilesMode mode)2055 caja_window_set_backup_files_mode (CajaWindowInfo *window,
2056                                    CajaWindowShowBackupFilesMode  mode)
2057 {
2058     window->details->show_backup_files_mode = mode;
2059 
2060     g_signal_emit_by_name (window, "backup_files_mode_changed");
2061 }
2062 
2063 static gboolean
caja_window_get_initiated_unmount(CajaWindowInfo * window)2064 caja_window_get_initiated_unmount (CajaWindowInfo *window)
2065 {
2066     return window->details->initiated_unmount;
2067 }
2068 
2069 static void
caja_window_set_initiated_unmount(CajaWindowInfo * window,gboolean initiated_unmount)2070 caja_window_set_initiated_unmount (CajaWindowInfo *window,
2071                                    gboolean initiated_unmount)
2072 {
2073     window->details->initiated_unmount = initiated_unmount;
2074 }
2075 
2076 static char *
caja_window_get_cached_title(CajaWindow * window)2077 caja_window_get_cached_title (CajaWindow *window)
2078 {
2079     CajaWindowSlot *slot;
2080 
2081     g_assert (CAJA_IS_WINDOW (window));
2082 
2083     slot = window->details->active_pane->active_slot;
2084 
2085     return g_strdup (slot->title);
2086 }
2087 
2088 CajaWindowSlot *
caja_window_get_active_slot(CajaWindow * window)2089 caja_window_get_active_slot (CajaWindow *window)
2090 {
2091     g_assert (CAJA_IS_WINDOW (window));
2092 
2093     return window->details->active_pane->active_slot;
2094 }
2095 
2096 CajaWindowSlot *
caja_window_get_extra_slot(CajaWindow * window)2097 caja_window_get_extra_slot (CajaWindow *window)
2098 {
2099     CajaWindowPane *extra_pane;
2100     GList *node;
2101 
2102     g_assert (CAJA_IS_WINDOW (window));
2103 
2104 
2105     /* return NULL if there is only one pane */
2106     if (window->details->panes == NULL ||
2107             window->details->panes->next == NULL)
2108     {
2109         return NULL;
2110     }
2111 
2112     /* get next pane in the (wrapped around) list */
2113     node = g_list_find (window->details->panes,
2114                         window->details->active_pane);
2115     g_return_val_if_fail (node, FALSE);
2116 
2117     if (node->next)
2118     {
2119         extra_pane = node->next->data;
2120     }
2121     else
2122     {
2123         extra_pane =  window->details->panes->data;
2124     }
2125 
2126     return extra_pane->active_slot;
2127 }
2128 
2129 GList *
caja_window_get_slots(CajaWindow * window)2130 caja_window_get_slots (CajaWindow *window)
2131 {
2132     GList *walk,*list;
2133 
2134     g_assert (CAJA_IS_WINDOW (window));
2135 
2136     list = NULL;
2137     for (walk = window->details->panes; walk; walk = walk->next)
2138     {
2139         CajaWindowPane *pane = walk->data;
2140         list  = g_list_concat (list, g_list_copy(pane->slots));
2141     }
2142     return list;
2143 }
2144 
2145 static void
caja_window_info_iface_init(CajaWindowInfoIface * iface)2146 caja_window_info_iface_init (CajaWindowInfoIface *iface)
2147 {
2148     iface->report_load_underway = caja_window_report_load_underway;
2149     iface->report_load_complete = caja_window_report_load_complete;
2150     iface->report_selection_changed = caja_window_report_selection_changed;
2151     iface->report_view_failed = caja_window_report_view_failed;
2152     iface->view_visible = caja_window_view_visible;
2153     iface->close_window = caja_window_close;
2154     iface->push_status = caja_window_push_status;
2155     iface->get_window_type = caja_window_get_window_type;
2156     iface->get_title = caja_window_get_cached_title;
2157     iface->get_history = caja_window_get_history;
2158     iface->get_current_location = caja_window_get_location_uri;
2159     iface->get_ui_manager = caja_window_get_ui_manager;
2160     iface->get_selection_count = caja_window_get_selection_count;
2161     iface->get_selection = caja_window_get_selection;
2162     iface->get_hidden_files_mode = caja_window_get_hidden_files_mode;
2163     iface->set_hidden_files_mode = caja_window_set_hidden_files_mode;
2164 
2165     iface->get_backup_files_mode = caja_window_get_backup_files_mode;
2166     iface->set_backup_files_mode = caja_window_set_backup_files_mode;
2167 
2168     iface->get_active_slot = caja_window_get_active_slot;
2169     iface->get_extra_slot = caja_window_get_extra_slot;
2170     iface->get_initiated_unmount = caja_window_get_initiated_unmount;
2171     iface->set_initiated_unmount = caja_window_set_initiated_unmount;
2172 }
2173 
2174 static void
caja_window_class_init(CajaWindowClass * class)2175 caja_window_class_init (CajaWindowClass *class)
2176 {
2177     GtkBindingSet *binding_set;
2178 
2179     G_OBJECT_CLASS (class)->constructor = caja_window_constructor;
2180     G_OBJECT_CLASS (class)->constructed = caja_window_constructed;
2181     G_OBJECT_CLASS (class)->get_property = caja_window_get_property;
2182     G_OBJECT_CLASS (class)->set_property = caja_window_set_property;
2183     G_OBJECT_CLASS (class)->finalize = caja_window_finalize;
2184 
2185     GTK_WIDGET_CLASS (class)->destroy = caja_window_destroy;
2186 
2187     GTK_WIDGET_CLASS (class)->show = caja_window_show;
2188 
2189     GTK_WIDGET_CLASS (class)->realize = caja_window_realize;
2190     GTK_WIDGET_CLASS (class)->key_press_event = caja_window_key_press_event;
2191     class->get_title = real_get_title;
2192     class->sync_title = real_sync_title;
2193     class->set_allow_up = real_set_allow_up;
2194     class->close_slot = real_close_slot;
2195 
2196     g_object_class_install_property (G_OBJECT_CLASS (class),
2197                                      ARG_APP,
2198                                      g_param_spec_object ("app",
2199                                              "Application",
2200                                              "The CajaApplication associated with this window.",
2201                                              CAJA_TYPE_APPLICATION,
2202                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
2203 
2204     signals[GO_UP] =
2205         g_signal_new ("go_up",
2206                       G_TYPE_FROM_CLASS (class),
2207                       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2208                       G_STRUCT_OFFSET (CajaWindowClass, go_up),
2209                       g_signal_accumulator_true_handled, NULL,
2210                       caja_src_marshal_BOOLEAN__BOOLEAN,
2211                       G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN);
2212     signals[RELOAD] =
2213         g_signal_new ("reload",
2214                       G_TYPE_FROM_CLASS (class),
2215                       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2216                       G_STRUCT_OFFSET (CajaWindowClass, reload),
2217                       NULL, NULL,
2218                       g_cclosure_marshal_VOID__VOID,
2219                       G_TYPE_NONE, 0);
2220     signals[PROMPT_FOR_LOCATION] =
2221         g_signal_new ("prompt-for-location",
2222                       G_TYPE_FROM_CLASS (class),
2223                       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
2224                       G_STRUCT_OFFSET (CajaWindowClass, prompt_for_location),
2225                       NULL, NULL,
2226                       g_cclosure_marshal_VOID__STRING,
2227                       G_TYPE_NONE, 1, G_TYPE_STRING);
2228     signals[ZOOM_CHANGED] =
2229         g_signal_new ("zoom-changed",
2230                       G_TYPE_FROM_CLASS (class),
2231                       G_SIGNAL_RUN_LAST,
2232                       0,
2233                       NULL, NULL,
2234                       caja_src_marshal_VOID__INT_BOOLEAN_BOOLEAN_BOOLEAN_BOOLEAN,
2235                       G_TYPE_NONE, 5,
2236                       G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
2237                       G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
2238     signals[VIEW_AS_CHANGED] =
2239         g_signal_new ("view-as-changed",
2240                       G_TYPE_FROM_CLASS (class),
2241                       G_SIGNAL_RUN_LAST,
2242                       0,
2243                       NULL, NULL,
2244                       g_cclosure_marshal_VOID__VOID,
2245                       G_TYPE_NONE, 0);
2246 
2247     binding_set = gtk_binding_set_by_class (class);
2248 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0,
2249                                   "go_up", 1,
2250                                   G_TYPE_BOOLEAN, FALSE);
2251 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_F5, 0,
2252                                   "reload", 0);
2253 	gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
2254                                   "prompt-for-location", 1,
2255                                   G_TYPE_STRING, "/");
2256 
2257     class->reload = caja_window_reload_signal;
2258     class->go_up = caja_window_go_up_signal;
2259 }
2260