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