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