1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2
3 /*
4 * Caja
5 *
6 * Copyright (C) 1999, 2000 Red Hat, Inc.
7 * Copyright (C) 2000, 2001 Eazel, Inc.
8 *
9 * Caja is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * Caja is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22 *
23 * Authors: Elliot Lee <sopwith@redhat.com>,
24 * Darin Adler <darin@bentspoon.com>,
25 * Cosimo Cecchi <cosimoc@gnome.org>
26 *
27 */
28
29 #include <config.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34
35 #include <libxml/xmlsave.h>
36 #include <glib/gstdio.h>
37 #include <glib/gi18n.h>
38 #include <gio/gio.h>
39 #include <gdk/gdkx.h>
40 #include <gtk/gtk.h>
41 #include <libnotify/notify.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #define MATE_DESKTOP_USE_UNSTABLE_API
45 #include <libmate-desktop/mate-bg.h>
46
47 #include <eel/eel-gtk-extensions.h>
48 #include <eel/eel-gtk-macros.h>
49 #include <eel/eel-stock-dialogs.h>
50
51 #include <libcaja-private/caja-debug-log.h>
52 #include <libcaja-private/caja-file-utilities.h>
53 #include <libcaja-private/caja-global-preferences.h>
54 #include <libcaja-private/caja-lib-self-check-functions.h>
55 #include <libcaja-private/caja-extensions.h>
56 #include <libcaja-private/caja-module.h>
57 #include <libcaja-private/caja-desktop-link-monitor.h>
58 #include <libcaja-private/caja-directory-private.h>
59 #include <libcaja-private/caja-signaller.h>
60 #include <libcaja-extension/caja-menu-provider.h>
61 #include <libcaja-private/caja-autorun.h>
62
63 #if ENABLE_EMPTY_VIEW
64 #include "file-manager/fm-empty-view.h"
65 #endif /* ENABLE_EMPTY_VIEW */
66 #include "file-manager/fm-desktop-icon-view.h"
67 #include "file-manager/fm-icon-view.h"
68 #include "file-manager/fm-list-view.h"
69 #include "file-manager/fm-tree-view.h"
70 #include "file-manager/fm-widget-view.h"
71
72 #include "caja-application.h"
73 #include "caja-information-panel.h"
74 #include "caja-history-sidebar.h"
75 #include "caja-places-sidebar.h"
76 #include "caja-self-check-functions.h"
77 #include "caja-notes-viewer.h"
78 #include "caja-emblem-sidebar.h"
79 #include "caja-bookmarks-sidebar.h"
80 #include "caja-image-properties-page.h"
81 #include "caja-desktop-window.h"
82 #include "caja-spatial-window.h"
83 #include "caja-navigation-window.h"
84 #include "caja-window-slot.h"
85 #include "caja-navigation-window-slot.h"
86 #include "caja-window-bookmarks.h"
87 #include "libcaja-private/caja-file-operations.h"
88 #include "caja-window-private.h"
89 #include "caja-window-manage-views.h"
90 #include "caja-freedesktop-dbus.h"
91
92 /* Keep window from shrinking down ridiculously small; numbers are somewhat arbitrary */
93 #define APPLICATION_WINDOW_MIN_WIDTH 300
94 #define APPLICATION_WINDOW_MIN_HEIGHT 100
95
96 #define CAJA_ACCEL_MAP_SAVE_DELAY 30
97
98 /* Keeps track of all the desktop windows. */
99 static GList *caja_application_desktop_windows;
100
101 /* Keeps track of all the object windows */
102 static GList *caja_application_spatial_window_list;
103
104 /* The saving of the accelerator map was requested */
105 static gboolean save_of_accel_map_requested = FALSE;
106
107 /* File Manager DBus Interface */
108 static CajaFreedesktopDBus *fdb_manager = NULL;
109
110 static char * caja_application_get_session_data (CajaApplication *self);
111 void caja_application_quit (CajaApplication *self);
112
113 struct _CajaApplicationPrivate {
114 GVolumeMonitor *volume_monitor;
115 gboolean no_desktop;
116 gboolean force_desktop;
117 gboolean autostart;
118 gchar *geometry;
119 };
120
121 G_DEFINE_TYPE_WITH_PRIVATE (CajaApplication, caja_application, GTK_TYPE_APPLICATION);
122
123 static GList *
caja_application_get_spatial_window_list(void)124 caja_application_get_spatial_window_list (void)
125 {
126 return caja_application_spatial_window_list;
127 }
128
129 static void
startup_volume_mount_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)130 startup_volume_mount_cb (GObject *source_object,
131 GAsyncResult *res,
132 gpointer user_data)
133 {
134 g_volume_mount_finish (G_VOLUME (source_object), res, NULL);
135 }
136
137 static void
automount_all_volumes(CajaApplication * application)138 automount_all_volumes (CajaApplication *application)
139 {
140 GList *volumes, *l;
141
142 if (g_settings_get_boolean (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTOMOUNT))
143 {
144 /* automount all mountable volumes at start-up */
145
146 GVolume *volume = NULL;
147 GMount *mount = NULL;
148
149 volumes = g_volume_monitor_get_volumes (application->priv->volume_monitor);
150
151 for (l = volumes; l != NULL; l = l->next)
152 {
153 volume = l->data;
154
155 if (!g_volume_should_automount (volume) ||
156 !g_volume_can_mount (volume))
157 {
158 continue;
159 }
160
161 mount = g_volume_get_mount (volume);
162 if (mount != NULL)
163 {
164 g_object_unref (mount);
165 continue;
166 }
167
168 /* pass NULL as GMountOperation to avoid user interaction */
169 g_volume_mount (volume, 0, NULL, NULL, startup_volume_mount_cb, NULL);
170 }
171 g_list_free_full (volumes, g_object_unref);
172 }
173
174 }
175
176 static void
smclient_save_state_cb(EggSMClient * client,GKeyFile * state_file,CajaApplication * application)177 smclient_save_state_cb (EggSMClient *client,
178 GKeyFile *state_file,
179 CajaApplication *application)
180 {
181 char *data;
182 data = caja_application_get_session_data (application);
183
184 if (data != NULL)
185 {
186 g_key_file_set_string (state_file,
187 "Caja",
188 "documents",
189 data);
190 }
191 g_free (data);
192 }
193
194 static void
smclient_quit_cb(EggSMClient * client,CajaApplication * application)195 smclient_quit_cb (EggSMClient *client,
196 CajaApplication *application)
197 {
198 caja_application_quit (application);
199 }
200
201 static void
caja_application_smclient_initialize(CajaApplication * self)202 caja_application_smclient_initialize (CajaApplication *self)
203 {
204 g_signal_connect (self->smclient, "save_state",
205 G_CALLBACK (smclient_save_state_cb),
206 self);
207 g_signal_connect (self->smclient, "quit",
208 G_CALLBACK (smclient_quit_cb),
209 self);
210
211 /* TODO: Should connect to quit_requested and block logout on active transfer? */
212 }
213
214 static void
caja_application_smclient_startup(CajaApplication * self)215 caja_application_smclient_startup (CajaApplication *self)
216 {
217 g_assert (self->smclient == NULL);
218 self->smclient = egg_sm_client_get ();
219 }
220
221 static void
caja_empty_callback_to_ensure_read(CajaApplication * self)222 caja_empty_callback_to_ensure_read (CajaApplication *self) {
223 /*do nothing, just exist to suppress runtime error*/
224 (void) self;
225 }
226
227 static void
open_window(CajaApplication * application,GFile * location,GdkScreen * screen,const char * geometry,gboolean browser_window)228 open_window (CajaApplication *application,
229 GFile *location,
230 GdkScreen *screen,
231 const char *geometry,
232 gboolean browser_window)
233 {
234 CajaApplication *self = CAJA_APPLICATION (application);
235 CajaWindow *window;
236 gchar *uri;
237
238 uri = g_file_get_uri (location);
239 g_debug ("Opening new window at uri %s", uri);
240
241 /*monitor the preference to use browser or spatial windows */
242 /*connect before trying to read or this preference won't be read by root or after change*/
243 g_signal_connect_swapped(caja_preferences, "changed::"CAJA_PREFERENCES_ALWAYS_USE_BROWSER,
244 G_CALLBACK (caja_empty_callback_to_ensure_read),
245 self);
246
247 if (browser_window ||g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
248 window = caja_application_create_navigation_window (application,
249 screen);
250 } else {
251 window = caja_application_get_spatial_window (application,
252 NULL,
253 NULL,
254 location,
255 screen,
256 NULL);
257 }
258
259 caja_window_go_to (window, location);
260
261 if (geometry != NULL && !gtk_widget_get_visible (GTK_WIDGET (window))) {
262 /* never maximize windows opened from shell if a
263 * custom geometry has been requested. */
264 gtk_window_unmaximize (GTK_WINDOW (window));
265 eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window),
266 geometry,
267 APPLICATION_WINDOW_MIN_WIDTH,
268 APPLICATION_WINDOW_MIN_HEIGHT,
269 FALSE);
270 }
271
272 g_free (uri);
273 }
274
275 static void
open_tabs(CajaApplication * application,GFile ** locations,guint n_files,GdkScreen * screen,const char * geometry,gboolean browser_window)276 open_tabs (CajaApplication *application,
277 GFile **locations,
278 guint n_files,
279 GdkScreen *screen,
280 const char *geometry,
281 gboolean browser_window)
282 {
283 CajaApplication *self = CAJA_APPLICATION (application);
284 CajaWindow *window;
285 gchar *uri = NULL;
286
287 /* monitor the preference to use browser or spatial windows */
288 /* connect before trying to read or this preference won't be read by root or after change */
289 g_signal_connect_swapped (caja_preferences,
290 "changed::"CAJA_PREFERENCES_ALWAYS_USE_BROWSER,
291 G_CALLBACK (caja_empty_callback_to_ensure_read),
292 self);
293
294 if (browser_window ||g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
295 window = caja_application_create_navigation_window (application, screen);
296 } else {
297 window = caja_application_get_spatial_window (application,
298 NULL,
299 NULL,
300 locations[0],
301 screen,
302 NULL);
303 }
304
305 /* open all locations */
306 uri = g_file_get_uri (locations[0]);
307 g_debug ("Opening new tab at uri %s\n", uri);
308 caja_window_go_to (window, locations[0]);
309 g_free (uri);
310 for (int i = 1; i< n_files;i++) {
311 /* open tabs in reverse order because each
312 * tab is opened before the previous one */
313 guint tab = n_files-i;
314 uri = g_file_get_uri (locations[tab]);
315 g_debug ("Opening new tab at uri %s\n", uri);
316 caja_window_go_to_tab (window, locations[tab]);
317 g_free (uri);
318 }
319
320 if (geometry != NULL && !gtk_widget_get_visible (GTK_WIDGET (window))) {
321 /* never maximize windows opened from shell if a
322 * custom geometry has been requested. */
323 gtk_window_unmaximize (GTK_WINDOW (window));
324 eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window),
325 geometry,
326 APPLICATION_WINDOW_MIN_WIDTH,
327 APPLICATION_WINDOW_MIN_HEIGHT,
328 FALSE);
329 }
330 }
331
332 static void
open_windows(CajaApplication * application,GFile ** files,GdkScreen * screen,const char * geometry,guint n_files,gboolean browser_window,gboolean open_in_tabs)333 open_windows (CajaApplication *application,
334 GFile **files,
335 GdkScreen *screen,
336 const char *geometry,
337 guint n_files,
338 gboolean browser_window,
339 gboolean open_in_tabs)
340 {
341 guint i;
342
343 if (files == NULL || files[0] == NULL) {
344 /* Open a window pointing at the default location. */
345 open_window (application, NULL, screen, geometry, browser_window);
346 } else {
347 if (open_in_tabs) {
348 /* Open one window with one tab at each requested location */
349 open_tabs (application, files, n_files, screen, geometry, browser_window);
350 } else {
351 /* Open windows at each requested location. */
352 i = 0;
353 while (i < n_files) {
354 open_window (application, files[i], screen, geometry, browser_window);
355 i++ ;
356 }
357 }
358 }
359 }
360
361 static void
caja_application_open(GApplication * app,GFile ** files,gint n_files,const gchar * options)362 caja_application_open (GApplication *app,
363 GFile **files,
364 gint n_files,
365 const gchar *options)
366 {
367 CajaApplication *self = CAJA_APPLICATION (app);
368 gboolean browser_window = FALSE;
369 gboolean open_in_tabs = FALSE;
370 const gchar *geometry = NULL;
371 const char splitter = '=';
372
373 g_debug ("Open called on the GApplication instance; %d files", n_files);
374
375 /* Check if local command line passed --browser, --geometry or --tabs */
376 if (strlen (options) > 0) {
377 gchar** splitedOptions = g_strsplit (options, &splitter, 3);
378 sscanf (splitedOptions[0], "%d", &browser_window);
379 if (strcmp (splitedOptions[1], "NULL") != 0) {
380 geometry = splitedOptions[1];
381 }
382 sscanf (splitedOptions[2], "%d", &open_in_tabs);
383
384 open_windows (self, files,
385 gdk_screen_get_default (),
386 geometry,
387 n_files,
388 browser_window,
389 open_in_tabs);
390
391 /* Reset this or 3ed and later invocations will use same
392 * geometry even if the user has resized open window */
393 self->priv->geometry = NULL;
394 g_strfreev (splitedOptions);
395 }
396 else
397 open_windows (self, files,
398 gdk_screen_get_default (),
399 geometry,
400 n_files,
401 browser_window,
402 open_in_tabs);
403 }
404
405 void
caja_application_open_location(CajaApplication * application,GFile * location,GFile * selection,const char * startup_id,const gboolean open_in_tabs)406 caja_application_open_location (CajaApplication *application,
407 GFile *location,
408 GFile *selection,
409 const char *startup_id,
410 const gboolean open_in_tabs)
411 {
412 CajaWindow *window;
413 GList *sel_list = NULL;
414
415 window = caja_application_create_navigation_window (application, gdk_screen_get_default ());
416
417 if (selection != NULL) {
418 sel_list = g_list_prepend (NULL, g_object_ref (selection));
419 }
420
421 caja_window_slot_open_location_full (caja_window_get_active_slot (window), location,
422 open_in_tabs, CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW,
423 sel_list, NULL, NULL);
424
425 if (sel_list != NULL) {
426 caja_file_list_free (sel_list);
427 }
428 }
429
430 void
caja_application_quit(CajaApplication * self)431 caja_application_quit (CajaApplication *self)
432 {
433 GApplication *app = G_APPLICATION (self);
434 GList *windows;
435
436 windows = gtk_application_get_windows (GTK_APPLICATION (app));
437 g_list_foreach (windows, (GFunc) gtk_widget_destroy, NULL);
438 /* we have been asked to force quit */
439 g_application_quit (G_APPLICATION (self));
440 }
441
442 static void
caja_application_init(CajaApplication * application)443 caja_application_init (CajaApplication *application)
444 {
445 GSimpleAction *action;
446 application->priv = caja_application_get_instance_private (application);
447 action = g_simple_action_new ("quit", NULL);
448
449 g_action_map_add_action (G_ACTION_MAP (application), G_ACTION (action));
450
451 g_signal_connect_swapped (action, "activate",
452 G_CALLBACK (caja_application_quit), application);
453
454 g_object_unref (action);
455 }
456
457 static void
caja_application_finalize(GObject * object)458 caja_application_finalize (GObject *object)
459 {
460 CajaApplication *application;
461
462 application = CAJA_APPLICATION (object);
463
464 caja_bookmarks_exiting ();
465
466 if (application->volume_monitor)
467 {
468 g_object_unref (application->priv->volume_monitor);
469 application->priv->volume_monitor = NULL;
470 }
471
472 g_free (application->priv->geometry);
473
474 if (application->ss_watch_id > 0)
475 {
476 g_bus_unwatch_name (application->ss_watch_id);
477 }
478
479 if (application->volume_queue != NULL)
480 {
481 g_list_free_full (application->volume_queue, g_object_unref);
482 application->volume_queue = NULL;
483 }
484
485 if (application->automount_idle_id != 0)
486 {
487 g_source_remove (application->automount_idle_id);
488 application->automount_idle_id = 0;
489 }
490
491 if (fdb_manager != NULL)
492 {
493 g_object_unref (fdb_manager);
494 fdb_manager = NULL;
495 }
496
497 if (application->ss_proxy != NULL)
498 {
499 g_object_unref (application->ss_proxy);
500 application->ss_proxy = NULL;
501 }
502
503 notify_uninit ();
504
505 G_OBJECT_CLASS (caja_application_parent_class)->finalize (object);
506 }
507
508 static gboolean
check_required_directories(CajaApplication * application)509 check_required_directories (CajaApplication *application)
510 {
511 char *user_directory;
512 char *desktop_directory;
513 GSList *directories;
514 gboolean ret;
515
516 g_assert (CAJA_IS_APPLICATION (application));
517
518 ret = TRUE;
519
520 user_directory = caja_get_user_directory ();
521 desktop_directory = caja_get_desktop_directory ();
522
523 directories = NULL;
524
525 if (!g_file_test (user_directory, G_FILE_TEST_IS_DIR))
526 {
527 directories = g_slist_prepend (directories, user_directory);
528 }
529
530 if (!g_file_test (desktop_directory, G_FILE_TEST_IS_DIR))
531 {
532 directories = g_slist_prepend (directories, desktop_directory);
533 }
534
535 if (directories != NULL)
536 {
537 int failed_count;
538 GString *directories_as_string;
539 GSList *l;
540 char *error_string;
541 const char *detail_string;
542 GtkDialog *dialog;
543
544 ret = FALSE;
545
546 failed_count = g_slist_length (directories);
547
548 directories_as_string = g_string_new ((const char *)directories->data);
549 for (l = directories->next; l != NULL; l = l->next)
550 {
551 g_string_append_printf (directories_as_string, ", %s", (const char *)l->data);
552 }
553
554 if (failed_count == 1)
555 {
556 error_string = g_strdup_printf (_("Caja could not create the required folder \"%s\"."),
557 directories_as_string->str);
558 detail_string = _("Before running Caja, please create the following folder, or "
559 "set permissions such that Caja can create it.");
560 }
561 else
562 {
563 error_string = g_strdup_printf (_("Caja could not create the following required folders: "
564 "%s."), directories_as_string->str);
565 detail_string = _("Before running Caja, please create these folders, or "
566 "set permissions such that Caja can create them.");
567 }
568
569 dialog = eel_show_error_dialog (error_string, detail_string, NULL);
570 /* We need the main event loop so the user has a chance to see the dialog. */
571
572 gtk_application_add_window (GTK_APPLICATION (application),
573 GTK_WINDOW (dialog));
574
575 g_string_free (directories_as_string, TRUE);
576 g_free (error_string);
577 }
578
579 g_slist_free (directories);
580 g_free (user_directory);
581 g_free (desktop_directory);
582
583 return ret;
584 }
585
586 static void
menu_provider_items_updated_handler(CajaMenuProvider * provider,GtkWidget * parent_window,gpointer data)587 menu_provider_items_updated_handler (CajaMenuProvider *provider, GtkWidget* parent_window, gpointer data)
588 {
589
590 g_signal_emit_by_name (caja_signaller_get_current (),
591 "popup_menu_changed");
592 }
593
594 static void
menu_provider_init_callback(void)595 menu_provider_init_callback (void)
596 {
597 GList *providers;
598 GList *l;
599
600 providers = caja_extensions_get_for_type (CAJA_TYPE_MENU_PROVIDER);
601
602 for (l = providers; l != NULL; l = l->next)
603 {
604 CajaMenuProvider *provider = CAJA_MENU_PROVIDER (l->data);
605
606 g_signal_connect_after (G_OBJECT (provider), "items_updated",
607 (GCallback)menu_provider_items_updated_handler,
608 NULL);
609 }
610
611 caja_module_extension_list_free (providers);
612 }
613
614 static gboolean
automount_all_volumes_idle_cb(gpointer data)615 automount_all_volumes_idle_cb (gpointer data)
616 {
617 CajaApplication *application = CAJA_APPLICATION (data);
618
619 automount_all_volumes (application);
620
621 application->automount_idle_id = 0;
622 return FALSE;
623 }
624
625 static void
selection_get_cb(GtkWidget * widget,GtkSelectionData * selection_data,guint info,guint time)626 selection_get_cb (GtkWidget *widget,
627 GtkSelectionData *selection_data,
628 guint info,
629 guint time)
630 {
631 /* No extra targets atm */
632 }
633
634 static GtkWidget *
get_desktop_manager_selection(GdkDisplay * display)635 get_desktop_manager_selection (GdkDisplay *display)
636 {
637 char selection_name[32];
638 GdkAtom selection_atom;
639 Window selection_owner;
640 GtkWidget *selection_widget;
641
642 g_snprintf (selection_name, sizeof (selection_name), "_NET_DESKTOP_MANAGER_S0");
643 selection_atom = gdk_atom_intern (selection_name, FALSE);
644
645 selection_owner = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
646 gdk_x11_atom_to_xatom_for_display (display,
647 selection_atom));
648 if (selection_owner != None)
649 {
650 return NULL;
651 }
652
653 selection_widget = gtk_invisible_new_for_screen (gdk_display_get_default_screen (display));
654 /* We need this for gdk_x11_get_server_time() */
655 gtk_widget_add_events (selection_widget, GDK_PROPERTY_CHANGE_MASK);
656
657 if (gtk_selection_owner_set_for_display (display,
658 selection_widget,
659 selection_atom,
660 gdk_x11_get_server_time (gtk_widget_get_window (selection_widget))))
661 {
662
663 g_signal_connect (selection_widget, "selection_get",
664 G_CALLBACK (selection_get_cb), NULL);
665 return selection_widget;
666 }
667
668 gtk_widget_destroy (selection_widget);
669
670 return NULL;
671 }
672
673 static void
desktop_unrealize_cb(GtkWidget * widget,GtkWidget * selection_widget)674 desktop_unrealize_cb (GtkWidget *widget,
675 GtkWidget *selection_widget)
676 {
677 gtk_widget_destroy (selection_widget);
678 }
679
680 static gboolean
selection_clear_event_cb(GtkWidget * widget,GdkEventSelection * event,CajaDesktopWindow * window)681 selection_clear_event_cb (GtkWidget *widget,
682 GdkEventSelection *event,
683 CajaDesktopWindow *window)
684 {
685 gtk_widget_destroy (GTK_WIDGET (window));
686
687 caja_application_desktop_windows =
688 g_list_remove (caja_application_desktop_windows, window);
689
690 return TRUE;
691 }
692
693 static void
caja_application_create_desktop_windows(CajaApplication * application)694 caja_application_create_desktop_windows (CajaApplication *application)
695 {
696 GdkDisplay *display;
697 GtkWidget *selection_widget;
698
699 g_return_if_fail (caja_application_desktop_windows == NULL);
700 g_return_if_fail (CAJA_IS_APPLICATION (application));
701 display = gdk_display_get_default ();
702
703 selection_widget = get_desktop_manager_selection (display);
704
705 if (selection_widget != NULL)
706 {
707 CajaDesktopWindow *window;
708
709 window = caja_desktop_window_new (application, gdk_display_get_default_screen (display));
710
711 g_signal_connect (selection_widget, "selection_clear_event",
712 G_CALLBACK (selection_clear_event_cb), window);
713
714 g_signal_connect (window, "unrealize",
715 G_CALLBACK (desktop_unrealize_cb), selection_widget);
716
717 /* We realize it immediately so that the CAJA_DESKTOP_WINDOW_ID
718 property is set so mate-settings-daemon doesn't try to set the
719 background. And we do a gdk_display_flush() to be sure X gets it. */
720 gtk_widget_realize (GTK_WIDGET (window));
721 gdk_display_flush (display);
722
723 caja_application_desktop_windows =
724 g_list_prepend (caja_application_desktop_windows, window);
725 gtk_application_add_window (GTK_APPLICATION (application),
726 GTK_WINDOW (window));
727 }
728 }
729
730 static void
caja_application_open_desktop(CajaApplication * application)731 caja_application_open_desktop (CajaApplication *application)
732 {
733 if (caja_application_desktop_windows == NULL)
734 {
735 caja_application_create_desktop_windows (application);
736 }
737 }
738 static void
caja_application_close_desktop(void)739 caja_application_close_desktop (void)
740 {
741 if (caja_application_desktop_windows != NULL)
742 {
743 g_list_free_full (caja_application_desktop_windows, (GDestroyNotify) gtk_widget_destroy);
744 caja_application_desktop_windows = NULL;
745 }
746 }
747
748 void
caja_application_close_all_navigation_windows(CajaApplication * self)749 caja_application_close_all_navigation_windows (CajaApplication *self)
750 {
751 GList *list_copy;
752 GList *l;
753 list_copy = g_list_copy (gtk_application_get_windows (GTK_APPLICATION (self)));
754 /* First hide all window to get the feeling of quick response */
755 for (l = list_copy; l != NULL; l = l->next)
756 {
757 CajaWindow *window;
758
759 window = CAJA_WINDOW (l->data);
760
761 if (CAJA_IS_NAVIGATION_WINDOW (window))
762 {
763 gtk_widget_hide (GTK_WIDGET (window));
764 }
765 }
766
767 for (l = list_copy; l != NULL; l = l->next)
768 {
769 CajaWindow *window;
770
771 window = CAJA_WINDOW (l->data);
772
773 if (CAJA_IS_NAVIGATION_WINDOW (window))
774 {
775 caja_window_close (window);
776 }
777 }
778 g_list_free (list_copy);
779 }
780
781 static CajaSpatialWindow *
caja_application_get_existing_spatial_window(GFile * location)782 caja_application_get_existing_spatial_window (GFile *location)
783 {
784 GList *l;
785 CajaWindowSlot *slot;
786 GFile *window_location = NULL;
787
788 for (l = caja_application_get_spatial_window_list ();
789 l != NULL; l = l->next) {
790 slot = CAJA_WINDOW (l->data)->details->active_pane->active_slot;
791
792 window_location = slot->pending_location;
793
794 if (window_location == NULL) {
795 window_location = slot->location;
796 }
797
798 if (window_location != NULL) {
799 if (g_file_equal (location, window_location)) {
800 return CAJA_SPATIAL_WINDOW (l->data);
801 }
802 }
803 }
804
805 return NULL;
806 }
807
808 static CajaSpatialWindow *
find_parent_spatial_window(CajaSpatialWindow * window)809 find_parent_spatial_window (CajaSpatialWindow *window)
810 {
811 CajaFile *file;
812 CajaFile *parent_file;
813 CajaWindowSlot *slot;
814 GFile *location;
815
816 slot = CAJA_WINDOW (window)->details->active_pane->active_slot;
817
818 location = slot->location;
819 if (location == NULL)
820 {
821 return NULL;
822 }
823 file = caja_file_get (location);
824
825 if (!file)
826 {
827 return NULL;
828 }
829
830 parent_file = caja_file_get_parent (file);
831 caja_file_unref (file);
832 while (parent_file)
833 {
834 CajaSpatialWindow *parent_window;
835
836 location = caja_file_get_location (parent_file);
837 parent_window = caja_application_get_existing_spatial_window (location);
838 g_object_unref (location);
839
840 /* Stop at the desktop directory if it's not explicitely opened
841 * in a spatial window of its own.
842 */
843 if (caja_file_is_desktop_directory (parent_file) && !parent_window)
844 {
845 caja_file_unref (parent_file);
846 return NULL;
847 }
848
849 if (parent_window)
850 {
851 caja_file_unref (parent_file);
852 return parent_window;
853 }
854 file = parent_file;
855 parent_file = caja_file_get_parent (file);
856 caja_file_unref (file);
857 }
858
859 return NULL;
860 }
861
862 void
caja_application_close_parent_windows(CajaSpatialWindow * window)863 caja_application_close_parent_windows (CajaSpatialWindow *window)
864 {
865 CajaSpatialWindow *parent_window;
866 CajaSpatialWindow *new_parent_window;
867
868 g_return_if_fail (CAJA_IS_SPATIAL_WINDOW (window));
869
870 parent_window = find_parent_spatial_window (window);
871
872 while (parent_window)
873 {
874
875 new_parent_window = find_parent_spatial_window (parent_window);
876 caja_window_close (CAJA_WINDOW (parent_window));
877 parent_window = new_parent_window;
878 }
879 }
880
881 void
caja_application_close_all_spatial_windows(void)882 caja_application_close_all_spatial_windows (void)
883 {
884 GList *list_copy;
885 GList *l;
886
887 list_copy = g_list_copy (caja_application_spatial_window_list);
888 /* First hide all window to get the feeling of quick response */
889 for (l = list_copy; l != NULL; l = l->next)
890 {
891 CajaWindow *window;
892
893 window = CAJA_WINDOW (l->data);
894
895 if (CAJA_IS_SPATIAL_WINDOW (window))
896 {
897 gtk_widget_hide (GTK_WIDGET (window));
898 }
899 }
900
901 for (l = list_copy; l != NULL; l = l->next)
902 {
903 CajaWindow *window;
904
905 window = CAJA_WINDOW (l->data);
906
907 if (CAJA_IS_SPATIAL_WINDOW (window))
908 {
909 caja_window_close (window);
910 }
911 }
912 g_list_free (list_copy);
913 }
914
915 static gboolean
caja_window_delete_event_callback(GtkWidget * widget,GdkEvent * event,gpointer user_data)916 caja_window_delete_event_callback (GtkWidget *widget,
917 GdkEvent *event,
918 gpointer user_data)
919 {
920 CajaWindow *window;
921
922 window = CAJA_WINDOW (widget);
923 caja_window_close (window);
924
925 return TRUE;
926 }
927
928
929 static CajaWindow *
create_window(CajaApplication * application,GType window_type,GdkScreen * screen)930 create_window (CajaApplication *application,
931 GType window_type,
932 GdkScreen *screen)
933 {
934 CajaWindow *window;
935
936 g_return_val_if_fail (CAJA_IS_APPLICATION (application), NULL);
937
938 window = CAJA_WINDOW (gtk_widget_new (window_type,
939 "app", application,
940 "screen", screen,
941 NULL));
942 g_signal_connect_data (window, "delete_event",
943 G_CALLBACK (caja_window_delete_event_callback), NULL, NULL,
944 G_CONNECT_AFTER);
945
946 gtk_application_add_window (GTK_APPLICATION (application),
947 GTK_WINDOW (window));
948
949 /* Do not yet show the window. It will be shown later on if it can
950 * successfully display its initial URI. Otherwise it will be destroyed
951 * without ever having seen the light of day.
952 */
953
954 return window;
955 }
956
957 static void
spatial_window_destroyed_callback(void * user_data,GObject * window)958 spatial_window_destroyed_callback (void *user_data, GObject *window)
959 {
960 caja_application_spatial_window_list = g_list_remove (caja_application_spatial_window_list, window);
961
962 }
963
964 CajaWindow *
caja_application_get_spatial_window(CajaApplication * application,CajaWindow * requesting_window,const char * startup_id,GFile * location,GdkScreen * screen,gboolean * existing)965 caja_application_get_spatial_window (CajaApplication *application,
966 CajaWindow *requesting_window,
967 const char *startup_id,
968 GFile *location,
969 GdkScreen *screen,
970 gboolean *existing)
971 {
972 CajaWindow *window;
973 gchar *uri;
974
975 g_return_val_if_fail (CAJA_IS_APPLICATION (application), NULL);
976 window = CAJA_WINDOW
977 (caja_application_get_existing_spatial_window (location));
978
979 if (window != NULL) {
980 if (existing != NULL) {
981 *existing = TRUE;
982 }
983
984 return window;
985 }
986
987 if (existing != NULL) {
988 *existing = FALSE;
989 }
990 window = create_window (application, CAJA_TYPE_SPATIAL_WINDOW, screen);
991
992 if (requesting_window)
993 {
994 /* Center the window over the requesting window by default */
995 int orig_x, orig_y, orig_width, orig_height;
996 int new_x, new_y, new_width, new_height;
997
998 gtk_window_get_position (GTK_WINDOW (requesting_window),
999 &orig_x, &orig_y);
1000 gtk_window_get_size (GTK_WINDOW (requesting_window),
1001 &orig_width, &orig_height);
1002 gtk_window_get_default_size (GTK_WINDOW (window),
1003 &new_width, &new_height);
1004
1005 new_x = orig_x + (orig_width - new_width) / 2;
1006 new_y = orig_y + (orig_height - new_height) / 2;
1007
1008 if (orig_width - new_width < 10)
1009 {
1010 new_x += 10;
1011 new_y += 10;
1012 }
1013
1014 gtk_window_move (GTK_WINDOW (window), new_x, new_y);
1015 }
1016
1017 caja_application_spatial_window_list = g_list_prepend (caja_application_spatial_window_list, window);
1018 g_object_weak_ref (G_OBJECT (window),
1019 spatial_window_destroyed_callback, NULL);
1020
1021 uri = g_file_get_uri (location);
1022 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
1023 "present NEW spatial window=%p: %s",
1024 window, uri);
1025 g_free (uri);
1026
1027 return window;
1028 }
1029
1030 CajaWindow *
caja_application_create_navigation_window(CajaApplication * application,GdkScreen * screen)1031 caja_application_create_navigation_window (CajaApplication *application,
1032 GdkScreen *screen)
1033 {
1034 CajaWindow *window;
1035 char *geometry_string;
1036 gboolean maximized;
1037
1038 g_return_val_if_fail (CAJA_IS_APPLICATION (application), NULL);
1039 window = create_window (application, CAJA_TYPE_NAVIGATION_WINDOW, screen);
1040
1041 maximized = g_settings_get_boolean (caja_window_state,
1042 CAJA_WINDOW_STATE_MAXIMIZED);
1043 if (maximized)
1044 {
1045 gtk_window_maximize (GTK_WINDOW (window));
1046 }
1047 else
1048 {
1049 gtk_window_unmaximize (GTK_WINDOW (window));
1050 }
1051
1052 geometry_string = g_settings_get_string (caja_window_state,
1053 CAJA_WINDOW_STATE_GEOMETRY);
1054 if (geometry_string != NULL &&
1055 geometry_string[0] != 0)
1056 {
1057 eel_gtk_window_set_initial_geometry_from_string
1058 (GTK_WINDOW (window),
1059 geometry_string,
1060 CAJA_NAVIGATION_WINDOW_MIN_WIDTH,
1061 CAJA_NAVIGATION_WINDOW_MIN_HEIGHT,
1062 TRUE);
1063 }
1064 g_free (geometry_string);
1065
1066 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
1067 "create new navigation window=%p",
1068 window);
1069
1070 return window;
1071 }
1072
1073 /* callback for showing or hiding the desktop based on the user's preference */
1074 static void
desktop_changed_callback(gpointer user_data)1075 desktop_changed_callback (gpointer user_data)
1076 {
1077 CajaApplication *application;
1078
1079 application = CAJA_APPLICATION (user_data);
1080 if (g_settings_get_boolean (mate_background_preferences, MATE_BG_KEY_SHOW_DESKTOP))
1081 {
1082 caja_application_open_desktop (application);
1083 }
1084 else
1085 {
1086 caja_application_close_desktop ();
1087 }
1088 }
1089
1090 static gboolean
window_can_be_closed(CajaWindow * window)1091 window_can_be_closed (CajaWindow *window)
1092 {
1093 if (!CAJA_IS_DESKTOP_WINDOW (window))
1094 {
1095 return TRUE;
1096 }
1097
1098 return FALSE;
1099 }
1100
1101 static void
check_screen_lock_and_mount(CajaApplication * application,GVolume * volume)1102 check_screen_lock_and_mount (CajaApplication *application,
1103 GVolume *volume)
1104 {
1105 if (application->screensaver_active)
1106 {
1107 /* queue the volume, to mount it after the screensaver state changed */
1108 g_debug ("Queuing volume %p", volume);
1109 application->volume_queue = g_list_prepend (application->volume_queue,
1110 g_object_ref (volume));
1111 } else {
1112 /* mount it immediately */
1113 caja_file_operations_mount_volume (NULL, volume, TRUE);
1114 }
1115 }
1116
1117 static void
volume_removed_callback(GVolumeMonitor * monitor,GVolume * volume,CajaApplication * application)1118 volume_removed_callback (GVolumeMonitor *monitor,
1119 GVolume *volume,
1120 CajaApplication *application)
1121 {
1122 g_debug ("Volume %p removed, removing from the queue", volume);
1123
1124 /* clear it from the queue, if present */
1125 application->volume_queue =
1126 g_list_remove (application->volume_queue, volume);
1127 }
1128
1129 static void
volume_added_callback(GVolumeMonitor * monitor,GVolume * volume,CajaApplication * application)1130 volume_added_callback (GVolumeMonitor *monitor,
1131 GVolume *volume,
1132 CajaApplication *application)
1133 {
1134 if (g_settings_get_boolean (caja_media_preferences, CAJA_PREFERENCES_MEDIA_AUTOMOUNT) &&
1135 g_volume_should_automount (volume) &&
1136 g_volume_can_mount (volume))
1137 {
1138 check_screen_lock_and_mount (application, volume);
1139 }
1140 else
1141 {
1142 /* Allow caja_autorun() to run. When the mount is later
1143 * added programmatically (i.e. for a blank CD),
1144 * caja_autorun() will be called by mount_added_callback(). */
1145 caja_allow_autorun_for_volume (volume);
1146 caja_allow_autorun_for_volume_finish (volume);
1147 }
1148 }
1149
1150 static void
drive_eject_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1151 drive_eject_cb (GObject *source_object,
1152 GAsyncResult *res,
1153 gpointer user_data)
1154 {
1155 GError *error;
1156 error = NULL;
1157
1158 if (!g_drive_eject_with_operation_finish (G_DRIVE (source_object), res, &error))
1159 {
1160 if (error->code != G_IO_ERROR_FAILED_HANDLED)
1161 {
1162 char *primary;
1163 char *name;
1164
1165 name = g_drive_get_name (G_DRIVE (source_object));
1166 primary = g_strdup_printf (_("Unable to eject %s"), name);
1167 g_free (name);
1168 eel_show_error_dialog (primary,
1169 error->message,
1170 NULL);
1171 g_free (primary);
1172 }
1173 g_error_free (error);
1174 }
1175 }
1176
1177 static void
drive_eject_button_pressed(GDrive * drive,CajaApplication * application)1178 drive_eject_button_pressed (GDrive *drive,
1179 CajaApplication *application)
1180 {
1181 GMountOperation *mount_op;
1182
1183 mount_op = gtk_mount_operation_new (NULL);
1184 g_drive_eject_with_operation (drive, 0, mount_op, NULL, drive_eject_cb, NULL);
1185 g_object_unref (mount_op);
1186 }
1187
1188 static void
drive_listen_for_eject_button(GDrive * drive,CajaApplication * application)1189 drive_listen_for_eject_button (GDrive *drive, CajaApplication *application)
1190 {
1191 g_signal_connect (drive,
1192 "eject-button",
1193 G_CALLBACK (drive_eject_button_pressed),
1194 application);
1195 }
1196
1197 static void
drive_connected_callback(GVolumeMonitor * monitor,GDrive * drive,CajaApplication * application)1198 drive_connected_callback (GVolumeMonitor *monitor,
1199 GDrive *drive,
1200 CajaApplication *application)
1201 {
1202 drive_listen_for_eject_button (drive, application);
1203 }
1204
1205 static void
autorun_show_window(GMount * mount,gpointer user_data)1206 autorun_show_window (GMount *mount, gpointer user_data)
1207 {
1208 GFile *location;
1209 CajaApplication *application = user_data;
1210 CajaWindow *window;
1211
1212 location = g_mount_get_root (mount);
1213
1214 /* There should probably be an easier way to do this */
1215 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
1216 window = caja_application_create_navigation_window (application,
1217 gdk_screen_get_default ());
1218 }
1219 else
1220 {
1221 window = caja_application_get_spatial_window (application,
1222 NULL,
1223 NULL,
1224 location,
1225 gdk_screen_get_default (),
1226 NULL);
1227 }
1228
1229 caja_window_go_to (window, location);
1230
1231 g_object_unref (location);
1232 }
1233
1234 static void
mount_added_callback(GVolumeMonitor * monitor,GMount * mount,CajaApplication * application)1235 mount_added_callback (GVolumeMonitor *monitor,
1236 GMount *mount,
1237 CajaApplication *application)
1238 {
1239 CajaDirectory *directory;
1240 GFile *root;
1241 gchar *uri;
1242
1243 root = g_mount_get_root (mount);
1244 uri = g_file_get_uri (root);
1245
1246 g_debug ("Added mount at uri %s", uri);
1247 g_free (uri);
1248
1249 directory = caja_directory_get_existing (root);
1250 g_object_unref (root);
1251 if (directory != NULL) {
1252 caja_directory_force_reload (directory);
1253 caja_directory_unref (directory);
1254 }
1255 caja_autorun (mount, autorun_show_window, application);
1256 }
1257
1258 static CajaWindowSlot *
get_first_navigation_slot(GList * slot_list)1259 get_first_navigation_slot (GList *slot_list)
1260 {
1261 GList *l;
1262
1263 for (l = slot_list; l != NULL; l = l->next)
1264 {
1265 if (CAJA_IS_NAVIGATION_WINDOW_SLOT (l->data))
1266 {
1267 return l->data;
1268 }
1269 }
1270
1271 return NULL;
1272 }
1273
1274 /* We redirect some slots and close others */
1275 static gboolean
should_close_slot_with_mount(CajaWindow * window,CajaWindowSlot * slot,GMount * mount)1276 should_close_slot_with_mount (CajaWindow *window,
1277 CajaWindowSlot *slot,
1278 GMount *mount)
1279 {
1280 if (CAJA_IS_SPATIAL_WINDOW (window))
1281 {
1282 return TRUE;
1283 }
1284 return caja_navigation_window_slot_should_close_with_mount (CAJA_NAVIGATION_WINDOW_SLOT (slot),
1285 mount);
1286 }
1287
1288 /* Called whenever a mount is unmounted. Check and see if there are
1289 * any windows open displaying contents on the mount. If there are,
1290 * close them. It would also be cool to save open window and position
1291 * info.
1292 *
1293 * This is also called on pre_unmount.
1294 */
1295 static void
mount_removed_callback(GVolumeMonitor * monitor,GMount * mount,CajaApplication * application)1296 mount_removed_callback (GVolumeMonitor *monitor,
1297 GMount *mount,
1298 CajaApplication *application)
1299 {
1300 GList *window_list, *node, *close_list;
1301 CajaWindow *window;
1302 CajaWindowSlot *slot;
1303 CajaWindowSlot *force_no_close_slot;
1304 GFile *root, *computer;
1305 gboolean unclosed_slot;
1306
1307 close_list = NULL;
1308 force_no_close_slot = NULL;
1309 unclosed_slot = FALSE;
1310
1311 /* Check and see if any of the open windows are displaying contents from the unmounted mount */
1312 window_list = gtk_application_get_windows (GTK_APPLICATION (application));
1313 root = g_mount_get_root (mount);
1314 /* Construct a list of windows to be closed. Do not add the non-closable windows to the list. */
1315 for (node = window_list; node != NULL; node = node->next)
1316 {
1317 window = CAJA_WINDOW (node->data);
1318 if (window != NULL && window_can_be_closed (window))
1319 {
1320 GList *l;
1321 GList *lp;
1322 GFile *location;
1323
1324 for (lp = window->details->panes; lp != NULL; lp = lp->next)
1325 {
1326 CajaWindowPane *pane;
1327 pane = (CajaWindowPane*) lp->data;
1328 for (l = pane->slots; l != NULL; l = l->next)
1329 {
1330 slot = l->data;
1331 location = slot->location;
1332 if (g_file_has_prefix (location, root) ||
1333 g_file_equal (location, root))
1334 {
1335 close_list = g_list_prepend (close_list, slot);
1336
1337 if (!should_close_slot_with_mount (window, slot, mount))
1338 {
1339 /* We'll be redirecting this, not closing */
1340 unclosed_slot = TRUE;
1341 }
1342 }
1343 else
1344 {
1345 unclosed_slot = TRUE;
1346 }
1347 } /* for all slots */
1348 } /* for all panes */
1349 }
1350 }
1351
1352 if (caja_application_desktop_windows == NULL &&
1353 !unclosed_slot)
1354 {
1355 /* We are trying to close all open slots. Keep one navigation slot open. */
1356 force_no_close_slot = get_first_navigation_slot (close_list);
1357 }
1358
1359 /* Handle the windows in the close list. */
1360 for (node = close_list; node != NULL; node = node->next)
1361 {
1362 slot = node->data;
1363 window = slot->pane->window;
1364
1365 if (should_close_slot_with_mount (window, slot, mount) &&
1366 slot != force_no_close_slot)
1367 {
1368 caja_window_slot_close (slot);
1369 }
1370 else
1371 {
1372 computer = g_file_new_for_uri ("computer:///");
1373 caja_window_slot_go_to (slot, computer, FALSE);
1374 g_object_unref(computer);
1375 }
1376 }
1377
1378 g_list_free (close_list);
1379 }
1380
1381 static char *
caja_application_get_session_data(CajaApplication * self)1382 caja_application_get_session_data (CajaApplication *self)
1383 {
1384 xmlDocPtr doc;
1385 xmlNodePtr root_node, history_node;
1386 GList *l, *window_list;
1387
1388 char *data;
1389 unsigned n_processed;
1390 xmlSaveCtxtPtr ctx;
1391 xmlBufferPtr buffer;
1392
1393 doc = xmlNewDoc ((const xmlChar *) "1.0");
1394
1395 root_node = xmlNewNode (NULL, (const xmlChar *) "session");
1396 xmlDocSetRootElement (doc, root_node);
1397
1398 history_node = xmlNewChild (root_node, NULL, (const xmlChar *) "history", NULL);
1399
1400 n_processed = 0;
1401 for (l = caja_get_history_list (); l != NULL; l = l->next) {
1402 CajaBookmark *bookmark;
1403 xmlNodePtr bookmark_node;
1404 GIcon *icon;
1405 char *tmp;
1406
1407 bookmark = l->data;
1408
1409 bookmark_node = xmlNewChild (history_node, NULL, (const xmlChar *) "bookmark", NULL);
1410
1411 tmp = caja_bookmark_get_name (bookmark);
1412 xmlNewProp (bookmark_node, (const xmlChar *) "name", (const xmlChar *) tmp);
1413 g_free (tmp);
1414
1415 icon = caja_bookmark_get_icon (bookmark);
1416
1417 tmp = g_icon_to_string (icon);
1418 g_object_unref (icon);
1419 if (tmp) {
1420 xmlNewProp (bookmark_node, (const xmlChar *) "icon", (const xmlChar *) tmp);
1421 g_free (tmp);
1422 }
1423
1424 tmp = caja_bookmark_get_uri (bookmark);
1425 xmlNewProp (bookmark_node, (const xmlChar *) "uri", (const xmlChar *) tmp);
1426 g_free (tmp);
1427
1428 if (caja_bookmark_get_has_custom_name (bookmark)) {
1429 xmlNewProp (bookmark_node, (const xmlChar *) "has_custom_name", (const xmlChar *) "TRUE");
1430 }
1431
1432 if (++n_processed > 50) { /* prevent history list from growing arbitrarily large. */
1433 break;
1434 }
1435 }
1436 window_list = gtk_application_get_windows (GTK_APPLICATION (self));
1437 for (l = window_list; l != NULL; l = l->next) {
1438 xmlNodePtr win_node, slot_node;
1439 CajaWindow *window;
1440 GList *slots, *m;
1441 char *tmp;
1442 CajaWindowSlot *active_slot;
1443 CajaWindowSlot *slot = NULL;
1444
1445 window = l->data;
1446
1447 slots = caja_window_get_slots (window);
1448 active_slot = caja_window_get_active_slot (window);
1449
1450 /* store one slot as window location. Otherwise
1451 * older Caja versions will bail when reading the file. */
1452 tmp = caja_window_slot_get_location_uri (active_slot);
1453
1454 if (eel_uri_is_desktop (tmp)) {
1455 g_list_free (slots);
1456 g_free (tmp);
1457 continue;
1458 }
1459
1460 win_node = xmlNewChild (root_node, NULL, (const xmlChar *) "window", NULL);
1461
1462 xmlNewProp (win_node, (const xmlChar *) "location", (const xmlChar *) tmp);
1463 g_free (tmp);
1464
1465 xmlNewProp (win_node, (const xmlChar *) "type", CAJA_IS_NAVIGATION_WINDOW (window) ? (const xmlChar *) "navigation" : (const xmlChar *) "spatial");
1466
1467 if (CAJA_IS_NAVIGATION_WINDOW (window)) { /* spatial windows store their state as file metadata */
1468 GdkWindow *gdk_window;
1469
1470 tmp = eel_gtk_window_get_geometry_string (GTK_WINDOW (window));
1471 xmlNewProp (win_node, (const xmlChar *) "geometry", (const xmlChar *) tmp);
1472 g_free (tmp);
1473
1474 gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
1475
1476 if (gdk_window &&
1477 gdk_window_get_state (gdk_window) & GDK_WINDOW_STATE_MAXIMIZED) {
1478 xmlNewProp (win_node, (const xmlChar *) "maximized", (const xmlChar *) "TRUE");
1479 }
1480
1481 if (gdk_window &&
1482 gdk_window_get_state (gdk_window) & GDK_WINDOW_STATE_STICKY) {
1483 xmlNewProp (win_node, (const xmlChar *) "sticky", (const xmlChar *) "TRUE");
1484 }
1485
1486 if (gdk_window &&
1487 gdk_window_get_state (gdk_window) & GDK_WINDOW_STATE_ABOVE) {
1488 xmlNewProp (win_node, (const xmlChar *) "keep-above", (const xmlChar *) "TRUE");
1489 }
1490 }
1491
1492 for (m = slots; m != NULL; m = m->next) {
1493 slot = CAJA_WINDOW_SLOT (m->data);
1494
1495 slot_node = xmlNewChild (win_node, NULL, (const xmlChar *) "slot", NULL);
1496
1497 tmp = caja_window_slot_get_location_uri (slot);
1498 xmlNewProp (slot_node, (const xmlChar *) "location", (const xmlChar *) tmp);
1499 g_free (tmp);
1500
1501 if (slot == active_slot) {
1502 xmlNewProp (slot_node, (const xmlChar *) "active", (const xmlChar *) "TRUE");
1503 }
1504 }
1505
1506 g_list_free (slots);
1507 }
1508
1509 buffer = xmlBufferCreate ();
1510 xmlIndentTreeOutput = 1;
1511 ctx = xmlSaveToBuffer (buffer, "UTF-8", XML_SAVE_FORMAT);
1512 if (xmlSaveDoc (ctx, doc) < 0 ||
1513 xmlSaveFlush (ctx) < 0) {
1514 g_message ("failed to save session");
1515 }
1516
1517 xmlSaveClose(ctx);
1518 data = g_strndup ((const char *) buffer->content, buffer->use);
1519 xmlBufferFree (buffer);
1520
1521 xmlFreeDoc (doc);
1522
1523 return data;
1524 }
1525
1526 static void
caja_application_load_session(CajaApplication * application)1527 caja_application_load_session (CajaApplication *application)
1528
1529 {
1530 xmlDocPtr doc;
1531 gboolean bail;
1532 xmlNodePtr root_node;
1533 GKeyFile *state_file;
1534 char *data;
1535 caja_application_smclient_initialize (application);
1536 if (!egg_sm_client_is_resumed (application->smclient))
1537 {
1538 return;
1539 }
1540
1541 state_file = egg_sm_client_get_state_file (application->smclient);
1542 if (!state_file)
1543 {
1544 return;
1545 }
1546
1547 data = g_key_file_get_string (state_file,
1548 "Caja",
1549 "documents",
1550 NULL);
1551 if (data == NULL)
1552 {
1553 return;
1554 }
1555
1556 bail = TRUE;
1557
1558 doc = xmlReadMemory (data, strlen (data), NULL, "UTF-8", 0);
1559 if (doc != NULL && (root_node = xmlDocGetRootElement (doc)) != NULL)
1560 {
1561 xmlNodePtr node;
1562
1563 bail = FALSE;
1564
1565 for (node = root_node->children; node != NULL; node = node->next)
1566 {
1567 if (node->name == NULL || *node->name == '\0' ||
1568 xmlStrcmp (node->name, (const xmlChar *) "text") == 0)
1569 {
1570 continue;
1571 }
1572
1573 if (xmlStrcmp (node->name, (const xmlChar *) "history") == 0)
1574 {
1575 xmlNodePtr bookmark_node;
1576 gboolean emit_change;
1577
1578 emit_change = FALSE;
1579
1580 for (bookmark_node = node->children; bookmark_node != NULL; bookmark_node = bookmark_node->next)
1581 {
1582 if (bookmark_node->name == NULL || *bookmark_node->name == '\0' ||
1583 xmlStrcmp (bookmark_node->name, (const xmlChar *) "text") == 0)
1584 {
1585 continue;
1586 }
1587
1588 if (xmlStrcmp (bookmark_node->name, (const xmlChar *) "bookmark") == 0)
1589 {
1590 xmlChar *name, *icon_str, *uri;
1591 gboolean has_custom_name;
1592 GIcon *icon;
1593 GFile *location;
1594
1595 uri = xmlGetProp (bookmark_node, (const xmlChar *) "uri");
1596 name = xmlGetProp (bookmark_node, (const xmlChar *) "name");
1597 has_custom_name = xmlHasProp (bookmark_node, (const xmlChar *) "has_custom_name") ? TRUE : FALSE;
1598 icon_str = xmlGetProp (bookmark_node, (const xmlChar *) "icon");
1599 icon = NULL;
1600 if (icon_str)
1601 {
1602 icon = g_icon_new_for_string ((const char *) icon_str, NULL);
1603 }
1604 location = g_file_new_for_uri ((const char *) uri);
1605
1606 emit_change |= caja_add_to_history_list_no_notify (location, (const char *) name, has_custom_name, icon);
1607
1608 g_object_unref (location);
1609
1610 if (icon)
1611 {
1612 g_object_unref (icon);
1613 }
1614 xmlFree (name);
1615 xmlFree (uri);
1616 xmlFree (icon_str);
1617 }
1618 else
1619 {
1620 g_message ("unexpected bookmark node %s while parsing session data", bookmark_node->name);
1621 bail = TRUE;
1622 continue;
1623 }
1624 }
1625
1626 if (emit_change)
1627 {
1628 caja_send_history_list_changed ();
1629 }
1630 }
1631
1632 else if (xmlStrcmp (node->name, (const xmlChar *) "window") == 0)
1633
1634 {
1635 CajaWindow *window;
1636 xmlChar *type, *location_uri;
1637 xmlNodePtr slot_node;
1638 GFile *location;
1639
1640 type = xmlGetProp (node, (const xmlChar *) "type");
1641 if (type == NULL)
1642 {
1643 g_message ("empty type node while parsing session data");
1644 bail = TRUE;
1645 continue;
1646 }
1647
1648 location_uri = xmlGetProp (node, (const xmlChar *) "location");
1649 if (location_uri == NULL)
1650 {
1651 g_message ("empty location node while parsing session data");
1652 bail = TRUE;
1653 xmlFree (type);
1654 continue;
1655 }
1656
1657 if (xmlStrcmp (type, (const xmlChar *) "navigation") == 0)
1658 {
1659 xmlChar *geometry;
1660 int i;
1661
1662 window = caja_application_create_navigation_window (application, gdk_screen_get_default ());
1663 geometry = xmlGetProp (node, (const xmlChar *) "geometry");
1664 if (geometry != NULL && *geometry != '\0')
1665 {
1666 eel_gtk_window_set_initial_geometry_from_string (GTK_WINDOW (window),
1667 (const char *) geometry,
1668 CAJA_NAVIGATION_WINDOW_MIN_WIDTH,
1669 CAJA_NAVIGATION_WINDOW_MIN_HEIGHT,
1670 FALSE);
1671 }
1672 xmlFree (geometry);
1673
1674 if (xmlHasProp (node, (const xmlChar *) "maximized"))
1675 {
1676 gtk_window_maximize (GTK_WINDOW (window));
1677 }
1678 else
1679 {
1680 gtk_window_unmaximize (GTK_WINDOW (window));
1681 }
1682
1683 if (xmlHasProp (node, (const xmlChar *) "sticky"))
1684 {
1685 gtk_window_stick (GTK_WINDOW (window));
1686 }
1687 else
1688 {
1689 gtk_window_unstick (GTK_WINDOW (window));
1690 }
1691
1692 if (xmlHasProp (node, (const xmlChar *) "keep-above"))
1693 {
1694 gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
1695 }
1696 else
1697 {
1698 gtk_window_set_keep_above (GTK_WINDOW (window), FALSE);
1699 }
1700
1701 for (i = 0, slot_node = node->children; slot_node != NULL; slot_node = slot_node->next)
1702 {
1703 if (slot_node->name && xmlStrcmp (slot_node->name, (const xmlChar *) "slot") == 0)
1704 {
1705 xmlChar *slot_uri;
1706
1707 slot_uri = xmlGetProp (slot_node, (const xmlChar *) "location");
1708 if (slot_uri != NULL)
1709 {
1710 CajaWindowSlot *slot;
1711
1712 if (i == 0)
1713 {
1714 slot = window->details->active_pane->active_slot;
1715 }
1716 else
1717 {
1718 slot = caja_window_open_slot (window->details->active_pane, CAJA_WINDOW_OPEN_SLOT_APPEND);
1719 }
1720
1721 location = g_file_new_for_uri ((const char *) slot_uri);
1722 caja_window_slot_open_location (slot, location, FALSE);
1723
1724 if (xmlHasProp (slot_node, (const xmlChar *) "active"))
1725 {
1726 caja_window_set_active_slot (slot->pane->window, slot);
1727 }
1728
1729 i++;
1730 }
1731 xmlFree (slot_uri);
1732 }
1733 }
1734
1735 if (i == 0)
1736 {
1737 /* This may be an old session file */
1738 location = g_file_new_for_uri ((const char *) location_uri);
1739 caja_window_slot_open_location (window->details->active_pane->active_slot, location, FALSE);
1740 g_object_unref (location);
1741 }
1742 }
1743 else if (xmlStrcmp (type, (const xmlChar *) "spatial") == 0)
1744 {
1745 location = g_file_new_for_uri ((const char *) location_uri);
1746 window = caja_application_get_spatial_window (application, NULL, NULL,
1747 location, gdk_screen_get_default (),
1748 NULL);
1749 caja_window_go_to (window, location);
1750 g_object_unref (location);
1751 }
1752 else
1753 {
1754 g_message ("unknown window type \"%s\" while parsing session data", type);
1755 bail = TRUE;
1756 }
1757
1758 xmlFree (type);
1759 xmlFree (location_uri);
1760 }
1761 else
1762 {
1763 g_message ("unexpected node %s while parsing session data", node->name);
1764 bail = TRUE;
1765 continue;
1766 }
1767 }
1768 }
1769
1770 if (doc != NULL)
1771 {
1772 xmlFreeDoc (doc);
1773 }
1774
1775 g_free (data);
1776
1777 if (bail)
1778 {
1779 g_message ("failed to load session");
1780 }
1781 }
1782
1783 static gboolean
do_cmdline_sanity_checks(CajaApplication * self,gboolean perform_self_check,gboolean version,gboolean kill_shell,gboolean select_uris,gchar ** remaining)1784 do_cmdline_sanity_checks (CajaApplication *self,
1785 gboolean perform_self_check,
1786 gboolean version,
1787 gboolean kill_shell,
1788 gboolean select_uris,
1789 gchar **remaining)
1790 {
1791 gboolean retval = FALSE;
1792
1793 if (perform_self_check && (remaining != NULL || kill_shell)) {
1794 g_printerr ("%s\n",
1795 _("--check cannot be used with other options."));
1796 goto out;
1797 }
1798
1799 if (kill_shell && remaining != NULL) {
1800 g_printerr ("%s\n",
1801 _("--quit cannot be used with URIs."));
1802 goto out;
1803 }
1804
1805 if (self->priv->geometry != NULL &&
1806 remaining != NULL && remaining[0] != NULL && remaining[1] != NULL) {
1807 g_printerr ("%s\n",
1808 _("--geometry cannot be used with more than one URI."));
1809 goto out;
1810 }
1811
1812 if (select_uris && remaining == NULL) {
1813 g_printerr ("%s\n",
1814 _("--select must be used with at least an URI."));
1815 goto out;
1816 }
1817
1818 retval = TRUE;
1819
1820 out:
1821 return retval;
1822 }
1823
1824 static void
do_perform_self_checks(gint * exit_status)1825 do_perform_self_checks (gint *exit_status)
1826 {
1827 #ifndef CAJA_OMIT_SELF_CHECK
1828 /* Run the checks (each twice) for caja and libcaja-private. */
1829
1830 caja_run_self_checks ();
1831 caja_run_lib_self_checks ();
1832 eel_exit_if_self_checks_failed ();
1833
1834 caja_run_self_checks ();
1835 caja_run_lib_self_checks ();
1836 eel_exit_if_self_checks_failed ();
1837 #endif
1838
1839 *exit_status = EXIT_SUCCESS;
1840 }
1841
1842 static void
select_items_ready_cb(GObject * source,GAsyncResult * res,gpointer user_data)1843 select_items_ready_cb (GObject *source,
1844 GAsyncResult *res,
1845 gpointer user_data)
1846 {
1847 GDBusConnection *connection = G_DBUS_CONNECTION (source);
1848 CajaApplication *self = user_data;
1849 GError *error = NULL;
1850
1851 g_dbus_connection_call_finish (connection, res, &error);
1852
1853 if (error != NULL) {
1854 g_warning ("Unable to select specified URIs %s\n", error->message);
1855 g_error_free (error);
1856
1857 /* open default location instead */
1858 g_application_open (G_APPLICATION (self), NULL, 0, "");
1859 }
1860 }
1861
1862 static void
caja_application_select(CajaApplication * self,GFile ** files,gint len)1863 caja_application_select (CajaApplication *self,
1864 GFile **files,
1865 gint len)
1866 {
1867 GDBusConnection *connection = g_application_get_dbus_connection (G_APPLICATION (self));
1868 GVariantBuilder builder;
1869 gint idx;
1870 gchar *uri;
1871
1872 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
1873 for (idx = 0; idx < len; idx++) {
1874 uri = g_file_get_uri (files[idx]);
1875 g_variant_builder_add (&builder, "s", uri);
1876 g_free (uri);
1877 }
1878
1879 g_dbus_connection_call (connection,
1880 CAJA_FDO_DBUS_NAME,
1881 CAJA_FDO_DBUS_PATH,
1882 CAJA_FDO_DBUS_IFACE,
1883 "ShowItems",
1884 g_variant_new ("(ass)", &builder, ""), NULL,
1885 G_DBUS_CALL_FLAGS_NONE, G_MAXINT, NULL,
1886 select_items_ready_cb, self);
1887
1888 g_variant_builder_clear (&builder);
1889 }
1890
1891 static gboolean
running_in_mate(void)1892 running_in_mate (void)
1893 {
1894 return (g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "MATE") == 0)
1895 || (g_strcmp0 (g_getenv ("XDG_SESSION_DESKTOP"), "mate") == 0)
1896 || (g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "mate") == 0);
1897 }
1898
1899 static gboolean
running_as_root(void)1900 running_as_root (void)
1901 {
1902 return geteuid () == 0;
1903 }
1904
1905 static gboolean
caja_application_local_command_line(GApplication * application,gchar *** arguments,gint * exit_status)1906 caja_application_local_command_line (GApplication *application,
1907 gchar ***arguments,
1908 gint *exit_status)
1909 {
1910 gboolean perform_self_check = FALSE;
1911 gboolean version = FALSE;
1912 gboolean browser_window = FALSE;
1913 gboolean open_in_tabs = FALSE;
1914 gboolean kill_shell = FALSE;
1915 const gchar *autostart_id;
1916 gboolean no_default_window = FALSE;
1917 gboolean select_uris = FALSE;
1918 gchar **remaining = NULL;
1919 CajaApplication *self = CAJA_APPLICATION (application);
1920
1921 /*First set these FALSE */
1922 self->priv->force_desktop = FALSE;
1923 self->priv->no_desktop = FALSE;
1924
1925 const GOptionEntry options[] = {
1926 #ifndef CAJA_OMIT_SELF_CHECK
1927 { "check", 'c', 0, G_OPTION_ARG_NONE, &perform_self_check,
1928 N_("Perform a quick set of self-check tests."), NULL },
1929 #endif
1930 { "version", '\0', 0, G_OPTION_ARG_NONE, &version,
1931 N_("Show the version of the program."), NULL },
1932 { "geometry", 'g', 0, G_OPTION_ARG_STRING, &self->priv->geometry,
1933 N_("Create the initial window with the given geometry."), N_("GEOMETRY") },
1934 { "no-default-window", 'n', 0, G_OPTION_ARG_NONE, &no_default_window,
1935 N_("Only create windows for explicitly specified URIs."), NULL },
1936 { "no-desktop", '\0', 0, G_OPTION_ARG_NONE, &self->priv->no_desktop,
1937 N_("Do not manage the desktop (ignore the preference set in the preferences dialog)."), NULL },
1938 { "force-desktop", '\0', 0, G_OPTION_ARG_NONE, &self->priv->force_desktop,
1939 N_("Manage the desktop regardless of set preferences or environment (on new startup only)"), NULL },
1940 { "tabs", 't', 0, G_OPTION_ARG_NONE, &open_in_tabs,
1941 N_("Open URIs in tabs."), NULL },
1942 { "browser", '\0', 0, G_OPTION_ARG_NONE, &browser_window,
1943 N_("Open a browser window."), NULL },
1944 { "quit", 'q', 0, G_OPTION_ARG_NONE, &kill_shell,
1945 N_("Quit Caja."), NULL },
1946 { "select", 's', 0, G_OPTION_ARG_NONE, &select_uris,
1947 N_("Select specified URI in parent folder."), NULL },
1948 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, N_("[URI...]") },
1949
1950 { NULL }
1951 };
1952 GOptionContext *context;
1953 GError *error = NULL;
1954 gint argc = 0;
1955 gchar **argv = NULL;
1956
1957 *exit_status = EXIT_SUCCESS;
1958
1959 context = g_option_context_new (_("\n\nBrowse the file system with the file manager"));
1960 g_option_context_add_main_entries (context, options, NULL);
1961 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1962
1963 g_option_context_add_group (context, egg_sm_client_get_option_group ());
1964
1965
1966 /* we need to do this here, as parsing the EggSMClient option context,
1967 * unsets this variable.
1968 */
1969 autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
1970 if (autostart_id != NULL && *autostart_id != '\0') {
1971 no_default_window = TRUE;
1972 self->priv->autostart = TRUE;
1973 }
1974
1975
1976 argv = *arguments;
1977 argc = g_strv_length (argv);
1978
1979 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1980 g_printerr ("Could not parse arguments: %s\n", error->message);
1981 g_error_free (error);
1982
1983 *exit_status = EXIT_FAILURE;
1984 goto out;
1985 }
1986
1987 if (version) {
1988 g_print ("MATE caja " PACKAGE_VERSION "\n");
1989 goto out;
1990 }
1991
1992 if (!do_cmdline_sanity_checks (self, perform_self_check,
1993 version, kill_shell, select_uris, remaining)) {
1994 *exit_status = EXIT_FAILURE;
1995 goto out;
1996 }
1997
1998 if (perform_self_check) {
1999 do_perform_self_checks (exit_status);
2000 goto out;
2001 }
2002
2003 g_debug ("Parsing local command line, no_default_window %d, quit %d, "
2004 "self checks %d, no_desktop %d",
2005 no_default_window, kill_shell, perform_self_check, self->priv->no_desktop);
2006
2007 g_application_register (application, NULL, &error);
2008
2009 if (error != NULL) {
2010 g_printerr ("Could not register the application: %s\n", error->message);
2011 g_error_free (error);
2012
2013 *exit_status = EXIT_FAILURE;
2014 goto out;
2015 }
2016
2017 if (kill_shell) {
2018 g_debug ("Killing application, as requested");
2019 g_action_group_activate_action (G_ACTION_GROUP (application),
2020 "quit", NULL);
2021 goto out;
2022 }
2023
2024 /* Initialize and load session info if available */
2025 /* Load session if and only if autostarted */
2026 /* This avoids errors on command line invocation */
2027 if (autostart_id != NULL && self->smclient != NULL ) {
2028 caja_application_load_session (self);
2029 }
2030
2031 GFile **files;
2032 gint idx, len;
2033
2034 len = 0;
2035 files = NULL;
2036
2037 /* Convert args to GFiles */
2038 if (remaining != NULL) {
2039 GPtrArray *file_array;
2040 GFile *file = NULL;
2041
2042 file_array = g_ptr_array_new ();
2043
2044 for (idx = 0; remaining[idx] != NULL; idx++) {
2045 file = g_file_new_for_commandline_arg (remaining[idx]);
2046 if (file != NULL) {
2047 g_ptr_array_add (file_array, file);
2048 }
2049 }
2050
2051 len = file_array->len;
2052 files = (GFile **) g_ptr_array_free (file_array, FALSE);
2053 g_strfreev (remaining);
2054 }
2055
2056 if (files == NULL && !no_default_window && !select_uris) {
2057 files = g_malloc0 (2 * sizeof (GFile *));
2058 len = 1;
2059
2060 files[0] = g_file_new_for_path (g_get_home_dir ());
2061 files[1] = NULL;
2062 }
2063
2064 if (len == 0) {
2065 goto out;
2066 }
2067
2068 if (select_uris) {
2069 caja_application_select (self, files, len);
2070 } else {
2071 /*Set up --geometry, --browser and --tabs options */
2072 /*Invoke "Open" to create new windows */
2073 gchar* concatOptions = g_malloc0(64);
2074 if (self->priv->geometry == NULL) {
2075 g_snprintf (concatOptions, 64, "%d=NULL=%d", browser_window, open_in_tabs);
2076 } else {
2077 g_snprintf (concatOptions, 64, "%d=%s=%d", browser_window, self->priv->geometry, open_in_tabs);
2078 }
2079 g_application_open (application, files, len, concatOptions);
2080 g_free (concatOptions);
2081 }
2082
2083 if (files)
2084 for (idx = 0; idx < len; idx++) {
2085 g_object_unref (files[idx]);
2086 }
2087 g_free (files);
2088
2089 out:
2090 g_option_context_free (context);
2091
2092 return TRUE;
2093 }
2094
2095 static void
load_custom_css(GtkCssProvider * provider,const gchar * filename,guint priority)2096 load_custom_css (GtkCssProvider *provider,
2097 const gchar *filename,
2098 guint priority)
2099 {
2100 GError *error = NULL;
2101 gchar *path = g_build_filename (CAJA_DATADIR, filename, NULL);
2102
2103 if (provider)
2104 g_object_ref (provider);
2105 else
2106 provider = gtk_css_provider_new ();
2107
2108 gtk_css_provider_load_from_path (provider, path, &error);
2109
2110 if (error != NULL) {
2111 g_warning ("Can't parse Caja' CSS custom description '%s': %s\n",
2112 filename, error->message);
2113 g_error_free (error);
2114 } else {
2115 gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
2116 GTK_STYLE_PROVIDER (provider),
2117 priority);
2118 }
2119
2120 g_object_unref (provider);
2121 g_free (path);
2122 }
2123
2124 static void
reload_theme_css(GtkSettings * settings,GParamSpec * unused G_GNUC_UNUSED,GtkCssProvider * provider)2125 reload_theme_css (GtkSettings *settings,
2126 GParamSpec *unused G_GNUC_UNUSED,
2127 GtkCssProvider *provider)
2128 {
2129 gchar *theme_name;
2130 gchar *css_theme_name;
2131 gchar *path;
2132
2133 g_object_get (settings, "gtk-theme-name", &theme_name, NULL);
2134 css_theme_name = g_strconcat ("caja-desktop-", theme_name, ".css", NULL);
2135 path = g_build_filename (CAJA_DATADIR, css_theme_name, NULL);
2136
2137 if (g_file_test (path, G_FILE_TEST_EXISTS))
2138 load_custom_css (provider, css_theme_name, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
2139 else /* just empty the provider */
2140 gtk_css_provider_load_from_data (provider, "", 0, NULL);
2141
2142 g_free (path);
2143 g_free (css_theme_name);
2144 g_free (theme_name);
2145 }
2146
2147 static void
init_icons_and_styles(void)2148 init_icons_and_styles (void)
2149 {
2150 GtkSettings *settings = gtk_settings_get_default ();
2151 GtkCssProvider *provider;
2152
2153 /* add our custom CSS provider */
2154 load_custom_css (NULL, "caja.css", GTK_STYLE_PROVIDER_PRIORITY_THEME);
2155 /* add our desktop CSS provider, ensures the desktop background does not get covered */
2156 load_custom_css (NULL, "caja-desktop.css", GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
2157 /* add theme-specific desktop CSS */
2158 provider = gtk_css_provider_new ();
2159 reload_theme_css (settings, NULL, provider);
2160 g_signal_connect_data (settings, "notify::gtk-theme-name", G_CALLBACK (reload_theme_css),
2161 provider, (GClosureNotify) g_object_unref, 0);
2162
2163 /* initialize search path for custom icons */
2164 gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
2165 CAJA_DATADIR G_DIR_SEPARATOR_S "icons");
2166 }
2167
2168 static void
init_desktop(CajaApplication * self)2169 init_desktop (CajaApplication *self)
2170 {
2171 /* Initialize the desktop link monitor singleton */
2172 caja_desktop_link_monitor_get ();
2173
2174 if (!self->priv->no_desktop &&
2175 !g_settings_get_boolean (mate_background_preferences,
2176 MATE_BG_KEY_SHOW_DESKTOP)) {
2177 self->priv->no_desktop = TRUE;
2178 }
2179
2180 if (running_as_root () || !running_in_mate ())
2181 {
2182 /* do not manage desktop when running as root or on other desktops unless forced */
2183 self->priv->no_desktop = TRUE;
2184 }
2185
2186 if (!self->priv->no_desktop || self->priv->force_desktop) {
2187 caja_application_open_desktop (self);
2188 }
2189
2190 /* Monitor the preference to show or hide the desktop */
2191 g_signal_connect_swapped (mate_background_preferences, "changed::" MATE_BG_KEY_SHOW_DESKTOP,
2192 G_CALLBACK (desktop_changed_callback),
2193 self);
2194 }
2195
2196 static gboolean
caja_application_save_accel_map(gpointer data)2197 caja_application_save_accel_map (gpointer data)
2198 {
2199 if (save_of_accel_map_requested) {
2200 char *accel_map_filename;
2201 accel_map_filename = caja_get_accel_map_file ();
2202 if (accel_map_filename) {
2203 gtk_accel_map_save (accel_map_filename);
2204 g_free (accel_map_filename);
2205 }
2206 save_of_accel_map_requested = FALSE;
2207 }
2208
2209 return FALSE;
2210 }
2211
2212 static void
queue_accel_map_save_callback(GtkAccelMap * object,gchar * accel_path,guint accel_key,GdkModifierType accel_mods,gpointer user_data)2213 queue_accel_map_save_callback (GtkAccelMap *object, gchar *accel_path,
2214 guint accel_key, GdkModifierType accel_mods,
2215 gpointer user_data)
2216 {
2217 if (!save_of_accel_map_requested) {
2218 save_of_accel_map_requested = TRUE;
2219 g_timeout_add_seconds (CAJA_ACCEL_MAP_SAVE_DELAY,
2220 caja_application_save_accel_map, NULL);
2221 }
2222 }
2223
2224 static void
init_gtk_accels(void)2225 init_gtk_accels (void)
2226 {
2227 char *accel_map_filename;
2228
2229 /* load accelerator map, and register save callback */
2230 accel_map_filename = caja_get_accel_map_file ();
2231 if (accel_map_filename) {
2232 gtk_accel_map_load (accel_map_filename);
2233 g_free (accel_map_filename);
2234 }
2235
2236 g_signal_connect (gtk_accel_map_get (), "changed",
2237 G_CALLBACK (queue_accel_map_save_callback), NULL);
2238 }
2239
2240
2241 static void
caja_application_startup(GApplication * app)2242 caja_application_startup (GApplication *app)
2243 {
2244 CajaApplication *self = CAJA_APPLICATION (app);
2245 gboolean exit_with_last_window;
2246 exit_with_last_window = TRUE;
2247
2248 /* chain up to the GTK+ implementation early, so gtk_init()
2249 * is called for us.
2250 */
2251 G_APPLICATION_CLASS (caja_application_parent_class)->startup (app);
2252
2253 /* Start the File Manager DBus Interface */
2254 fdb_manager = caja_freedesktop_dbus_new (self);
2255
2256 /* Initialize preferences. This is needed so that proper
2257 * defaults are available before any preference peeking
2258 * happens.
2259 */
2260 caja_global_preferences_init ();
2261
2262 /* initialize the session manager client */
2263 caja_application_smclient_startup (self);
2264
2265 /* register views */
2266 fm_icon_view_register ();
2267 fm_desktop_icon_view_register ();
2268 fm_list_view_register ();
2269 fm_compact_view_register ();
2270 fm_widget_view_register ();
2271 #if ENABLE_EMPTY_VIEW
2272 fm_empty_view_register ();
2273 #endif /* ENABLE_EMPTY_VIEW */
2274
2275 /* register sidebars */
2276 caja_places_sidebar_register ();
2277 caja_information_panel_register ();
2278 fm_tree_view_register ();
2279 caja_history_sidebar_register ();
2280 caja_notes_viewer_register (); /* also property page */
2281 caja_emblem_sidebar_register ();
2282 caja_bookmarks_sidebar_register ();
2283
2284 /* register property pages */
2285 caja_image_properties_page_register ();
2286
2287 /* initialize theming */
2288 init_icons_and_styles ();
2289 init_gtk_accels ();
2290
2291 /* initialize caja modules */
2292 caja_module_setup ();
2293
2294 /* attach menu-provider module callback */
2295 menu_provider_init_callback ();
2296
2297 /* Initialize notifications for eject operations */
2298 notify_init (PACKAGE);
2299
2300 /* Watch for unmounts so we can close open windows */
2301 /* TODO-gio: This should be using the UNMOUNTED feature of GFileMonitor instead */
2302 self->priv->volume_monitor = g_volume_monitor_get ();
2303 g_signal_connect_object ( self->priv->volume_monitor, "mount_removed",
2304 G_CALLBACK (mount_removed_callback), self, 0);
2305 g_signal_connect_object ( self->priv->volume_monitor, "mount_pre_unmount",
2306 G_CALLBACK (mount_removed_callback), self, 0);
2307 g_signal_connect_object ( self->priv->volume_monitor, "mount_added",
2308 G_CALLBACK (mount_added_callback), self, 0);
2309 g_signal_connect_object ( self->priv->volume_monitor, "volume_added",
2310 G_CALLBACK (volume_added_callback), self, 0);
2311 g_signal_connect_object ( self->priv->volume_monitor, "volume_removed",
2312 G_CALLBACK (volume_removed_callback), self, 0);
2313 g_signal_connect_object ( self->priv->volume_monitor, "drive_connected",
2314 G_CALLBACK (drive_connected_callback), self, 0);
2315
2316 /* listen for eject button presses */
2317 self->automount_idle_id =
2318 g_idle_add_full (G_PRIORITY_LOW,
2319 automount_all_volumes_idle_cb,
2320 self, NULL);
2321
2322 /* Check the user's ~/.caja directories and post warnings
2323 * if there are problems.
2324 */
2325 check_required_directories (self);
2326 init_desktop (self);
2327
2328 /* exit_with_last_window is already set to TRUE, and we need to keep that value
2329 * on other desktops, running from the command line, or when running caja as root.
2330 * Otherwise, we read the value from the configuration.
2331 */
2332
2333 if (running_in_mate () && !running_as_root())
2334 {
2335 GApplication *instance;
2336
2337 exit_with_last_window = g_settings_get_boolean (caja_preferences,
2338 CAJA_PREFERENCES_EXIT_WITH_LAST_WINDOW);
2339 /*Keep this inside the running as mate/not as root block */
2340 /*So other desktop don't get unkillable caja instances holding open */
2341 instance = g_application_get_default ();
2342 if (exit_with_last_window == FALSE){
2343 g_application_hold (G_APPLICATION (instance));
2344 }
2345 }
2346
2347 }
2348
2349 static void
caja_application_quit_mainloop(GApplication * app)2350 caja_application_quit_mainloop (GApplication *app)
2351 {
2352 caja_icon_info_clear_caches ();
2353 caja_application_save_accel_map (NULL);
2354
2355 G_APPLICATION_CLASS (caja_application_parent_class)->quit_mainloop (app);
2356 }
2357
2358 static void
caja_application_class_init(CajaApplicationClass * class)2359 caja_application_class_init (CajaApplicationClass *class)
2360 {
2361 GObjectClass *object_class;
2362 GApplicationClass *application_class;
2363
2364 object_class = G_OBJECT_CLASS (class);
2365 object_class->finalize = caja_application_finalize;
2366
2367 application_class = G_APPLICATION_CLASS (class);
2368 application_class->startup = caja_application_startup;
2369 application_class->quit_mainloop = caja_application_quit_mainloop;
2370 application_class->open = caja_application_open;
2371 application_class->local_command_line = caja_application_local_command_line;
2372
2373 }
2374
2375 CajaApplication *
caja_application_new(void)2376 caja_application_new (void)
2377 {
2378 return g_object_new (CAJA_TYPE_APPLICATION,
2379 "application-id", "org.mate.Caja",
2380 "register-session", TRUE,
2381 "flags", G_APPLICATION_HANDLES_OPEN,
2382 NULL);
2383 }
2384
2385