2008-04-30 Cosimo Cecchi <cosimoc@gnome.org>
[nautilus.git] / src / nautilus-application.c
blob04875acb75b68264b828efa18d1f8a2d4e5b5af4
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /*
4 * Nautilus
6 * Copyright (C) 1999, 2000 Red Hat, Inc.
7 * Copyright (C) 2000, 2001 Eazel, Inc.
9 * Nautilus 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.
14 * Nautilus 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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Authors: Elliot Lee <sopwith@redhat.com>,
24 * Darin Adler <darin@bentspoon.com>
28 #include <config.h>
29 #include "nautilus-application.h"
32 #include "file-manager/fm-ditem-page.h"
33 #include "file-manager/fm-desktop-icon-view.h"
34 #include "file-manager/fm-icon-view.h"
35 #include "file-manager/fm-list-view.h"
36 #include "file-manager/fm-tree-view.h"
37 #if ENABLE_EMPTY_VIEW
38 #include "file-manager/fm-empty-view.h"
39 #endif /* ENABLE_EMPTY_VIEW */
40 #include "nautilus-information-panel.h"
41 #include "nautilus-history-sidebar.h"
42 #include "nautilus-places-sidebar.h"
43 #include "nautilus-notes-viewer.h"
44 #include "nautilus-emblem-sidebar.h"
45 #include "nautilus-image-properties-page.h"
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <string.h>
50 #include "nautilus-desktop-window.h"
51 #include "nautilus-main.h"
52 #include "nautilus-spatial-window.h"
53 #include "nautilus-navigation-window.h"
54 #include "nautilus-shell-interface.h"
55 #include "nautilus-shell.h"
56 #include "nautilus-window-bookmarks.h"
57 #include "libnautilus-private/nautilus-file-operations.h"
58 #include "nautilus-window-private.h"
59 #include "nautilus-window-manage-views.h"
60 #include <libxml/xmlsave.h>
61 #include <glib/gstdio.h>
62 #include <glib/gi18n.h>
63 #include <gio/gio.h>
64 #include <bonobo/bonobo-main.h>
65 #include <bonobo/bonobo-object.h>
66 #include <eel/eel-gtk-extensions.h>
67 #include <eel/eel-gtk-macros.h>
68 #include <eel/eel-stock-dialogs.h>
69 #include <gdk/gdkx.h>
70 #include <gtk/gtkwindow.h>
71 #include <libgnome/gnome-config.h>
72 #include <libgnomeui/gnome-authentication-manager.h>
73 #include <libgnomeui/gnome-client.h>
74 #include <libnautilus-private/nautilus-debug-log.h>
75 #include <libnautilus-private/nautilus-file-utilities.h>
76 #include <libnautilus-private/nautilus-global-preferences.h>
77 #include <libnautilus-private/nautilus-module.h>
78 #include <libnautilus-private/nautilus-undo-manager.h>
79 #include <libnautilus-private/nautilus-desktop-link-monitor.h>
80 #include <libnautilus-private/nautilus-directory-private.h>
81 #include <libnautilus-private/nautilus-signaller.h>
82 #include <libnautilus-extension/nautilus-menu-provider.h>
83 #include <bonobo-activation/bonobo-activation.h>
84 #include <libnautilus-private/nautilus-autorun.h>
86 #ifdef HAVE_STARTUP_NOTIFICATION
87 #define SN_API_NOT_YET_FROZEN Yes_i_know_DO_IT
88 #include <libsn/sn-launchee.h>
89 #endif
91 /* Needed for the is_kdesktop_present check */
92 #include <gdk/gdkx.h>
93 #include <X11/Xlib.h>
95 #define FACTORY_IID "OAFIID:Nautilus_Factory"
96 #define SEARCH_LIST_VIEW_IID "OAFIID:Nautilus_File_Manager_Search_List_View"
97 #define SHELL_IID "OAFIID:Nautilus_Shell"
98 #define TREE_VIEW_IID "OAFIID:Nautilus_File_Manager_Tree_View"
100 /* Keeps track of all the desktop windows. */
101 static GList *nautilus_application_desktop_windows;
103 /* Keeps track of all the nautilus windows. */
104 static GList *nautilus_application_window_list;
106 /* Keeps track of all the object windows */
107 static GList *nautilus_application_spatial_window_list;
109 static void desktop_changed_callback (gpointer user_data);
110 static void desktop_location_changed_callback (gpointer user_data);
111 static void mount_removed_callback (GVolumeMonitor *monitor,
112 GMount *mount,
113 NautilusApplication *application);
114 static void mount_added_callback (GVolumeMonitor *monitor,
115 GMount *mount,
116 NautilusApplication *application);
117 static void volume_added_callback (GVolumeMonitor *monitor,
118 GVolume *volume,
119 NautilusApplication *application);
120 static void drive_connected_callback (GVolumeMonitor *monitor,
121 GDrive *drive,
122 NautilusApplication *application);
123 static void drive_listen_for_eject_button (GDrive *drive,
124 NautilusApplication *application);
125 static void update_session (gpointer callback_data);
126 static void init_session (void);
127 static gboolean is_kdesktop_present (void);
129 BONOBO_CLASS_BOILERPLATE (NautilusApplication, nautilus_application,
130 BonoboGenericFactory, BONOBO_TYPE_GENERIC_FACTORY)
132 static CORBA_Object
133 create_object (PortableServer_Servant servant,
134 const CORBA_char *iid,
135 CORBA_Environment *ev)
137 BonoboObject *object;
138 NautilusApplication *application;
140 if (strcmp (iid, SHELL_IID) == 0) {
141 application = NAUTILUS_APPLICATION (bonobo_object_from_servant (servant));
142 object = BONOBO_OBJECT (nautilus_shell_new (application));
143 } else {
144 object = CORBA_OBJECT_NIL;
147 return CORBA_Object_duplicate (BONOBO_OBJREF (object), ev);
150 GList *
151 nautilus_application_get_window_list (void)
153 return nautilus_application_window_list;
156 GList *
157 nautilus_application_get_spatial_window_list (void)
159 return nautilus_application_spatial_window_list;
162 unsigned int
163 nautilus_application_get_n_windows (void)
165 return g_list_length (nautilus_application_window_list) +
166 g_list_length (nautilus_application_desktop_windows);
169 static void
170 startup_volume_mount_cb (GObject *source_object,
171 GAsyncResult *res,
172 gpointer user_data)
174 g_volume_mount_finish (G_VOLUME (source_object), res, NULL);
177 static void
178 automount_all_volumes (NautilusApplication *application)
180 GList *volumes, *l;
181 GMount *mount;
182 GVolume *volume;
184 if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_MEDIA_AUTOMOUNT)) {
185 /* automount all mountable volumes at start-up */
186 volumes = g_volume_monitor_get_volumes (application->volume_monitor);
187 for (l = volumes; l != NULL; l = l->next) {
188 volume = l->data;
190 if (!g_volume_should_automount (volume) ||
191 !g_volume_can_mount (volume)) {
192 continue;
195 mount = g_volume_get_mount (volume);
196 if (mount != NULL) {
197 g_object_unref (mount);
198 continue;
201 /* pass NULL as GMountOperation to avoid user interaction */
202 g_volume_mount (volume, 0, NULL, NULL, startup_volume_mount_cb, NULL);
204 eel_g_object_list_free (volumes);
209 static void
210 nautilus_application_instance_init (NautilusApplication *application)
212 /* Create an undo manager */
213 application->undo_manager = nautilus_undo_manager_new ();
215 application->shell = nautilus_shell_new (application);
217 /* register views */
218 fm_icon_view_register ();
219 fm_desktop_icon_view_register ();
220 fm_list_view_register ();
221 #if ENABLE_EMPTY_VIEW
222 fm_empty_view_register ();
223 #endif /* ENABLE_EMPTY_VIEW */
225 /* register sidebars */
226 nautilus_places_sidebar_register ();
227 nautilus_information_panel_register ();
228 fm_tree_view_register ();
229 nautilus_history_sidebar_register ();
230 nautilus_notes_viewer_register (); /* also property page */
231 nautilus_emblem_sidebar_register ();
233 /* register property pages */
234 nautilus_image_properties_page_register ();
237 NautilusApplication *
238 nautilus_application_new (void)
240 NautilusApplication *application;
242 application = g_object_new (NAUTILUS_TYPE_APPLICATION, NULL);
244 bonobo_generic_factory_construct_noreg (BONOBO_GENERIC_FACTORY (application),
245 FACTORY_IID,
246 NULL);
248 return application;
251 static void
252 nautilus_application_destroy (BonoboObject *object)
254 NautilusApplication *application;
256 application = NAUTILUS_APPLICATION (object);
258 nautilus_bookmarks_exiting ();
260 g_object_unref (application->undo_manager);
262 if (application->volume_monitor) {
263 g_object_unref (application->volume_monitor);
264 application->volume_monitor = NULL;
267 if (application->shell_registered) {
268 bonobo_activation_unregister_active_server (SHELL_IID, BONOBO_OBJREF (application->shell));
270 bonobo_object_unref (application->shell);
272 if (application->automount_idle_id != 0) {
273 g_source_remove (application->automount_idle_id);
274 application->automount_idle_id = 0;
277 EEL_CALL_PARENT (BONOBO_OBJECT_CLASS, destroy, (object));
280 static gboolean
281 check_required_directories (NautilusApplication *application)
283 char *user_directory;
284 char *desktop_directory;
285 GSList *directories;
286 gboolean ret;
288 g_assert (NAUTILUS_IS_APPLICATION (application));
290 ret = TRUE;
292 user_directory = nautilus_get_user_directory ();
293 desktop_directory = nautilus_get_desktop_directory ();
295 directories = NULL;
297 if (!g_file_test (user_directory, G_FILE_TEST_IS_DIR)) {
298 directories = g_slist_prepend (directories, user_directory);
301 if (!g_file_test (desktop_directory, G_FILE_TEST_IS_DIR)) {
302 directories = g_slist_prepend (directories, desktop_directory);
305 if (directories != NULL) {
306 int failed_count;
307 GString *directories_as_string;
308 GSList *l;
309 char *error_string;
310 const char *detail_string;
311 GtkDialog *dialog;
313 ret = FALSE;
315 failed_count = g_slist_length (directories);
317 directories_as_string = g_string_new ((const char *)directories->data);
318 for (l = directories->next; l != NULL; l = l->next) {
319 g_string_append_printf (directories_as_string, ", %s", (const char *)l->data);
322 if (failed_count == 1) {
323 error_string = g_strdup_printf (_("Nautilus could not create the required folder \"%s\"."),
324 directories_as_string->str);
325 detail_string = _("Before running Nautilus, please create the following folder, or "
326 "set permissions such that Nautilus can create it.");
327 } else {
328 error_string = g_strdup_printf (_("Nautilus could not create the following required folders: "
329 "%s."), directories_as_string->str);
330 detail_string = _("Before running Nautilus, please create these folders, or "
331 "set permissions such that Nautilus can create them.");
334 dialog = eel_show_error_dialog (error_string, detail_string, NULL);
335 /* We need the main event loop so the user has a chance to see the dialog. */
336 nautilus_main_event_loop_register (GTK_OBJECT (dialog));
338 g_string_free (directories_as_string, TRUE);
339 g_free (error_string);
342 g_slist_free (directories);
343 g_free (user_directory);
344 g_free (desktop_directory);
346 return ret;
349 static Nautilus_URIList *
350 nautilus_make_uri_list_from_shell_strv (const char * const *strv)
352 int length, i;
353 Nautilus_URIList *uri_list;
354 GFile *file;
355 char *translated_uri;
357 length = g_strv_length ((char **) strv);
359 uri_list = Nautilus_URIList__alloc ();
360 uri_list->_maximum = length;
361 uri_list->_length = length;
362 uri_list->_buffer = CORBA_sequence_Nautilus_URI_allocbuf (length);
363 for (i = 0; i < length; i++) {
364 file = g_file_new_for_commandline_arg (strv[i]);
365 translated_uri = g_file_get_uri (file);
366 g_object_unref (file);
367 uri_list->_buffer[i] = CORBA_string_dup (translated_uri);
368 g_free (translated_uri);
369 translated_uri = NULL;
371 CORBA_sequence_set_release (uri_list, CORBA_TRUE);
373 return uri_list;
376 static void
377 menu_provider_items_updated_handler (NautilusMenuProvider *provider, GtkWidget* parent_window, gpointer data)
380 g_signal_emit_by_name (nautilus_signaller_get_current (),
381 "popup_menu_changed");
384 static void
385 menu_provider_init_callback (void)
387 GList *items;
388 GList *providers;
389 GList *l;
391 providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER);
392 items = NULL;
394 for (l = providers; l != NULL; l = l->next) {
395 NautilusMenuProvider *provider = NAUTILUS_MENU_PROVIDER (l->data);
397 g_signal_connect_after (G_OBJECT (provider), "items_updated",
398 (GCallback)menu_provider_items_updated_handler,
399 NULL);
402 nautilus_module_extension_list_free (providers);
405 static gboolean
406 automount_all_volumes_idle_cb (gpointer data)
408 NautilusApplication *application = NAUTILUS_APPLICATION (data);
410 automount_all_volumes (application);
412 application->automount_idle_id = 0;
413 return FALSE;
416 static void
417 finish_startup (NautilusApplication *application)
419 GList *drives;
421 /* initialize nautilus modules */
422 nautilus_module_init ();
424 nautilus_module_add_type (FM_TYPE_DITEM_PAGE);
426 /* attach menu-provider module callback */
427 menu_provider_init_callback ();
429 /* Initialize the desktop link monitor singleton */
430 nautilus_desktop_link_monitor_get ();
432 /* Watch for mounts so we can restore open windows This used
433 * to be for showing new window on mount, but is not used
434 * anymore */
436 /* Watch for unmounts so we can close open windows */
437 /* TODO-gio: This should be using the UNMOUNTED feature of GFileMonitor instead */
438 application->volume_monitor = g_volume_monitor_get ();
439 g_signal_connect_object (application->volume_monitor, "mount_removed",
440 G_CALLBACK (mount_removed_callback), application, 0);
441 g_signal_connect_object (application->volume_monitor, "mount_pre_unmount",
442 G_CALLBACK (mount_removed_callback), application, 0);
443 g_signal_connect_object (application->volume_monitor, "mount_added",
444 G_CALLBACK (mount_added_callback), application, 0);
445 g_signal_connect_object (application->volume_monitor, "volume_added",
446 G_CALLBACK (volume_added_callback), application, 0);
447 g_signal_connect_object (application->volume_monitor, "drive_connected",
448 G_CALLBACK (drive_connected_callback), application, 0);
450 /* listen for eject button presses */
451 drives = g_volume_monitor_get_connected_drives (application->volume_monitor);
452 g_list_foreach (drives, (GFunc) drive_listen_for_eject_button, application);
453 g_list_foreach (drives, (GFunc) g_object_unref, NULL);
454 g_list_free (drives);
456 application->automount_idle_id =
457 g_idle_add_full (G_PRIORITY_LOW,
458 automount_all_volumes_idle_cb,
459 application, NULL);
462 static void
463 initialize_kde_trash_hack (void)
465 char *trash_dir;
466 char *desktop_dir, *desktop_uri, *kde_trash_dir;
467 char *dir, *basename;
468 char *kde_conf_file;
469 char *key;
470 gboolean def;
472 trash_dir = NULL;
474 desktop_uri = nautilus_get_desktop_directory_uri_no_create ();
475 desktop_dir = g_filename_from_uri (desktop_uri, NULL, NULL);
476 g_free (desktop_uri);
478 if (g_file_test (desktop_dir, G_FILE_TEST_EXISTS)) {
479 /* Look for trash directory */
480 kde_conf_file = g_build_filename (g_get_home_dir(), ".kde/share/config/kdeglobals", NULL);
481 key = g_strconcat ("=", kde_conf_file, "=/Paths/Trash", NULL);
482 kde_trash_dir = gnome_config_get_string_with_default (key, &def);
483 gnome_config_drop_file (kde_conf_file);
484 g_free (kde_conf_file);
485 g_free (key);
487 if (kde_trash_dir == NULL) {
488 kde_conf_file = "/usr/share/config/kdeglobals";
489 key = g_strconcat ("=", kde_conf_file, "=/Paths/Trash", NULL);
490 kde_trash_dir = gnome_config_get_string_with_default (key, &def);
491 gnome_config_drop_file (kde_conf_file);
492 g_free (key);
495 if (kde_trash_dir != NULL) {
496 basename = g_path_get_basename (kde_trash_dir);
497 g_free (kde_trash_dir);
499 dir = g_build_filename (desktop_dir, basename, NULL);
501 if (g_file_test (dir, G_FILE_TEST_IS_DIR)) {
502 trash_dir = g_strdup (basename);
504 g_free (basename);
505 g_free (dir);
508 if (trash_dir != NULL) {
509 nautilus_set_kde_trash_name (trash_dir);
512 g_free (trash_dir);
514 g_free (desktop_dir);
518 static Bonobo_RegistrationResult
519 nautilus_bonobo_activation_register_for_display (const char *iid,
520 Bonobo_Unknown ref)
522 const char *display_name;
523 GSList *reg_env ;
524 Bonobo_RegistrationResult result;
526 display_name = gdk_display_get_name (gdk_display_get_default());
527 reg_env = bonobo_activation_registration_env_set (NULL,
528 "DISPLAY", display_name);
529 result = bonobo_activation_register_active_server (iid, ref, reg_env);
530 bonobo_activation_registration_env_free (reg_env);
531 return result;
534 void
535 nautilus_application_startup (NautilusApplication *application,
536 gboolean kill_shell,
537 gboolean restart_shell,
538 gboolean no_default_window,
539 gboolean no_desktop,
540 gboolean browser_window,
541 const char *startup_id,
542 const char *geometry,
543 const char *session_to_load,
544 const char *urls[])
546 CORBA_Environment ev;
547 Nautilus_Shell shell;
548 Bonobo_RegistrationResult result;
549 const char *message, *detailed_message;
550 GtkDialog *dialog;
551 Nautilus_URIList *url_list;
552 const CORBA_char *corba_startup_id;
553 const CORBA_char *corba_geometry;
554 int num_failures;
556 num_failures = 0;
558 /* Check the user's ~/.nautilus directories and post warnings
559 * if there are problems.
561 if (!kill_shell && !check_required_directories (application)) {
562 return;
565 initialize_kde_trash_hack ();
567 CORBA_exception_init (&ev);
569 /* Start up the factory. */
570 while (TRUE) {
571 /* Try to register the file manager view factory. */
572 result = nautilus_bonobo_activation_register_for_display
573 (SHELL_IID, BONOBO_OBJREF (application->shell));
575 switch (result) {
576 case Bonobo_ACTIVATION_REG_SUCCESS:
577 /* We are registered and all is right with the world. */
578 application->shell_registered = TRUE;
579 finish_startup (application);
580 message = NULL;
581 detailed_message = NULL;
582 break;
583 case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE:
584 /* Another copy of nautilus already is running and registered. */
585 message = NULL;
586 detailed_message = NULL;
587 break;
588 case Bonobo_ACTIVATION_REG_NOT_LISTED:
589 /* Can't register myself due to trouble locating the
590 * Nautilus_Shell.server file. This has happened when you
591 * launch Nautilus with an LD_LIBRARY_PATH that
592 * doesn't include the directory containing the oaf
593 * library. It could also happen if the
594 * Nautilus_Shell.server file was not present for some
595 * reason. Sometimes killing oafd and gconfd fixes
596 * this problem but we don't exactly understand why,
597 * since neither of the above causes explain it.
599 message = _("Nautilus cannot be used now. "
600 "Running the command \"bonobo-slay\""
601 " from the console may fix the problem. If not,"
602 " you can try rebooting the computer or"
603 " installing Nautilus again.");
604 /* FIXME bugzilla.gnome.org 42536: The guesses and stuff here are lame. */
605 detailed_message = _("Nautilus cannot be used now. "
606 "Running the command \"bonobo-slay\" "
607 "from the console may fix the problem. If not, "
608 "you can try rebooting the computer or "
609 "installing Nautilus again.\n\n"
610 "Bonobo could not locate the Nautilus_shell.server file. "
611 "One cause of this seems to be an LD_LIBRARY_PATH "
612 "that does not include the bonobo-activation library's directory. "
613 "Another possible cause would be bad install "
614 "with a missing Nautilus_Shell.server file.\n\n"
615 "Running \"bonobo-slay\" will kill all "
616 "Bonobo Activation and GConf processes, which may be needed by "
617 "other applications.\n\n"
618 "Sometimes killing bonobo-activation-server and gconfd fixes "
619 "the problem, but we do not know why.\n\n"
620 "We have also seen this error when a faulty "
621 "version of bonobo-activation was installed.");
622 break;
623 default:
624 /* This should never happen. */
625 g_warning ("bad error code from bonobo_activation_active_server_register");
626 case Bonobo_ACTIVATION_REG_ERROR:
627 /* Some misc. error (can never happen with current
628 * version of bonobo-activation). Show dialog and terminate the
629 * program.
631 /* FIXME bugzilla.gnome.org 42537: Looks like this does happen with the
632 * current OAF. I guess I read the code wrong. Need to figure out when and make a
633 * good message.
635 message = _("Nautilus cannot be used now, due to an unexpected error.");
636 detailed_message = _("Nautilus cannot be used now, due to an unexpected error "
637 "from Bonobo when attempting to register the file manager view server.");
638 break;
641 /* Get the shell object. */
642 if (message == NULL) {
643 shell = bonobo_activation_activate_from_id (SHELL_IID, Bonobo_ACTIVATION_FLAG_EXISTING_ONLY, NULL, NULL);
644 if (!CORBA_Object_is_nil (shell, &ev)) {
645 break;
648 /* If we couldn't find ourselves it's a bad problem so
649 * we better stop looping.
651 if (result == Bonobo_ACTIVATION_REG_SUCCESS) {
652 /* FIXME bugzilla.gnome.org 42538: When can this happen? */
653 message = _("Nautilus cannot be used now, due to an unexpected error.");
654 detailed_message = _("Nautilus cannot be used now, due to an unexpected error "
655 "from Bonobo when attempting to locate the factory. "
656 "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
657 } else {
658 num_failures++;
659 if (num_failures > 20) {
660 message = _("Nautilus cannot be used now, due to an unexpected error.");
661 detailed_message = _("Nautilus cannot be used now, due to an unexpected error "
662 "from Bonobo when attempting to locate the shell object. "
663 "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
669 if (message != NULL) {
670 dialog = eel_show_error_dialog_with_details (message, NULL, detailed_message, NULL);
671 /* We need the main event loop so the user has a chance to see the dialog. */
672 nautilus_main_event_loop_register (GTK_OBJECT (dialog));
673 goto out;
677 if (kill_shell) {
678 Nautilus_Shell_quit (shell, &ev);
679 } else if (restart_shell) {
680 Nautilus_Shell_restart (shell, &ev);
681 } else {
682 /* If KDE desktop is running, then force no_desktop */
683 if (is_kdesktop_present ()) {
684 no_desktop = TRUE;
687 if (!no_desktop && eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
688 Nautilus_Shell_start_desktop (shell, &ev);
691 /* Monitor the preference to show or hide the desktop */
692 eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_SHOW_DESKTOP,
693 desktop_changed_callback,
694 application,
695 G_OBJECT (application));
697 /* Monitor the preference to have the desktop */
698 /* point to the Unix home folder */
699 eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
700 desktop_location_changed_callback,
701 NULL,
702 G_OBJECT (application));
704 /* CORBA C mapping doesn't allow NULL to be passed
705 for string parameters */
706 corba_geometry = (geometry != NULL) ? geometry : "";
707 corba_startup_id = (startup_id != NULL) ? startup_id : "";
709 /* Create the other windows. */
710 if (urls != NULL) {
711 url_list = nautilus_make_uri_list_from_shell_strv (urls);
712 Nautilus_Shell_open_windows (shell, url_list, corba_startup_id, corba_geometry, browser_window, &ev);
713 CORBA_free (url_list);
714 } else if (!no_default_window) {
715 g_assert (session_to_load == NULL);
716 Nautilus_Shell_open_default_window (shell, corba_startup_id, corba_geometry, browser_window, &ev);
719 if (session_to_load != NULL) {
720 Nautilus_Shell_load_session (shell, session_to_load, &ev);
723 /* Add ourselves to the session */
724 init_session ();
727 out:
728 CORBA_exception_free (&ev);
732 static void
733 selection_get_cb (GtkWidget *widget,
734 GtkSelectionData *selection_data,
735 guint info,
736 guint time)
738 /* No extra targets atm */
741 static GtkWidget *
742 get_desktop_manager_selection (GdkDisplay *display, int screen)
744 char selection_name[32];
745 GdkAtom selection_atom;
746 Window selection_owner;
747 GtkWidget *selection_widget;
749 g_snprintf (selection_name, sizeof (selection_name), "_NET_DESKTOP_MANAGER_S%d", screen);
750 selection_atom = gdk_atom_intern (selection_name, FALSE);
752 selection_owner = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
753 gdk_x11_atom_to_xatom_for_display (display,
754 selection_atom));
755 if (selection_owner != None) {
756 return NULL;
759 selection_widget = gtk_invisible_new_for_screen (gdk_display_get_screen (display, screen));
760 /* We need this for gdk_x11_get_server_time() */
761 gtk_widget_add_events (selection_widget, GDK_PROPERTY_CHANGE_MASK);
763 if (gtk_selection_owner_set_for_display (display,
764 selection_widget,
765 selection_atom,
766 gdk_x11_get_server_time (selection_widget->window))) {
768 g_signal_connect (selection_widget, "selection_get",
769 G_CALLBACK (selection_get_cb), NULL);
770 return selection_widget;
773 gtk_widget_destroy (selection_widget);
775 return NULL;
778 static void
779 desktop_unrealize_cb (GtkWidget *widget,
780 GtkWidget *selection_widget)
782 gtk_widget_destroy (selection_widget);
785 static gboolean
786 selection_clear_event_cb (GtkWidget *widget,
787 GdkEventSelection *event,
788 NautilusDesktopWindow *window)
790 gtk_widget_destroy (GTK_WIDGET (window));
792 nautilus_application_desktop_windows =
793 g_list_remove (nautilus_application_desktop_windows, window);
795 return TRUE;
798 static void
799 nautilus_application_create_desktop_windows (NautilusApplication *application)
801 static gboolean create_in_progress = FALSE;
802 GdkDisplay *display;
803 NautilusDesktopWindow *window;
804 GtkWidget *selection_widget;
805 int screens, i;
807 g_return_if_fail (nautilus_application_desktop_windows == NULL);
808 g_return_if_fail (NAUTILUS_IS_APPLICATION (application));
810 if (create_in_progress) {
811 return;
814 create_in_progress = TRUE;
816 display = gdk_display_get_default ();
817 screens = gdk_display_get_n_screens (display);
819 for (i = 0; i < screens; i++) {
820 selection_widget = get_desktop_manager_selection (display, i);
821 if (selection_widget != NULL) {
822 window = nautilus_desktop_window_new (application,
823 gdk_display_get_screen (display, i));
825 g_signal_connect (selection_widget, "selection_clear_event",
826 G_CALLBACK (selection_clear_event_cb), window);
828 g_signal_connect (window, "unrealize",
829 G_CALLBACK (desktop_unrealize_cb), selection_widget);
831 /* We realize it immediately so that the NAUTILUS_DESKTOP_WINDOW_ID
832 property is set so gnome-settings-daemon doesn't try to set the
833 background. And we do a gdk_flush() to be sure X gets it. */
834 gtk_widget_realize (GTK_WIDGET (window));
835 gdk_flush ();
838 nautilus_application_desktop_windows =
839 g_list_prepend (nautilus_application_desktop_windows, window);
843 create_in_progress = FALSE;
846 void
847 nautilus_application_open_desktop (NautilusApplication *application)
849 if (nautilus_application_desktop_windows == NULL) {
850 nautilus_application_create_desktop_windows (application);
852 /* Make sure we update the session when the desktop is created */
853 update_session (gnome_master_client ());
857 void
858 nautilus_application_close_desktop (void)
860 if (nautilus_application_desktop_windows != NULL) {
861 g_list_foreach (nautilus_application_desktop_windows,
862 (GFunc) gtk_widget_destroy, NULL);
863 g_list_free (nautilus_application_desktop_windows);
864 nautilus_application_desktop_windows = NULL;
866 /* Make sure we update the session when the desktop goes away */
867 update_session (gnome_master_client ());
871 void
872 nautilus_application_close_all_navigation_windows (void)
874 GList *list_copy;
875 GList *l;
877 list_copy = g_list_copy (nautilus_application_window_list);
878 for (l = list_copy; l != NULL; l = l->next) {
879 NautilusWindow *window;
881 window = NAUTILUS_WINDOW (l->data);
883 if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) {
884 nautilus_window_close (window);
887 g_list_free (list_copy);
890 static NautilusSpatialWindow *
891 nautilus_application_get_existing_spatial_window (GFile *location)
893 GList *l;
895 for (l = nautilus_application_get_spatial_window_list ();
896 l != NULL; l = l->next) {
897 GFile *window_location;
899 window_location = nautilus_window_get_location (NAUTILUS_WINDOW (l->data));
900 if (window_location != NULL) {
901 if (g_file_equal (location, window_location)) {
902 g_object_unref (window_location);
903 return NAUTILUS_SPATIAL_WINDOW (l->data);
905 g_object_unref (window_location);
908 return NULL;
911 static NautilusSpatialWindow *
912 find_parent_spatial_window (NautilusSpatialWindow *window)
914 NautilusFile *file;
915 NautilusFile *parent_file;
916 GFile *location;
918 location = nautilus_window_get_location (NAUTILUS_WINDOW (window));
919 if (location == NULL) {
920 return NULL;
922 file = nautilus_file_get (location);
923 g_object_unref (location);
925 if (!file) {
926 return NULL;
929 parent_file = nautilus_file_get_parent (file);
930 nautilus_file_unref (file);
931 while (parent_file) {
932 NautilusSpatialWindow *parent_window;
934 location = nautilus_file_get_location (parent_file);
935 parent_window = nautilus_application_get_existing_spatial_window (location);
936 g_object_unref (location);
938 /* Stop at the desktop directory if it's not explicitely opened
939 * in a spatial window of its own.
941 if (nautilus_file_is_desktop_directory (parent_file) && !parent_window) {
942 nautilus_file_unref (parent_file);
943 return NULL;
946 if (parent_window) {
947 nautilus_file_unref (parent_file);
948 return parent_window;
950 file = parent_file;
951 parent_file = nautilus_file_get_parent (file);
952 nautilus_file_unref (file);
955 return NULL;
958 void
959 nautilus_application_close_parent_windows (NautilusSpatialWindow *window)
961 NautilusSpatialWindow *parent_window;
962 NautilusSpatialWindow *new_parent_window;
964 g_return_if_fail (NAUTILUS_IS_SPATIAL_WINDOW (window));
966 parent_window = find_parent_spatial_window (window);
968 while (parent_window) {
970 new_parent_window = find_parent_spatial_window (parent_window);
971 nautilus_window_close (NAUTILUS_WINDOW (parent_window));
972 parent_window = new_parent_window;
976 void
977 nautilus_application_close_all_spatial_windows (void)
979 GList *list_copy;
980 GList *l;
982 list_copy = g_list_copy (nautilus_application_spatial_window_list);
983 for (l = list_copy; l != NULL; l = l->next) {
984 NautilusWindow *window;
986 window = NAUTILUS_WINDOW (l->data);
988 if (NAUTILUS_IS_SPATIAL_WINDOW (window)) {
989 nautilus_window_close (window);
992 g_list_free (list_copy);
995 static void
996 nautilus_application_destroyed_window (GtkObject *object, NautilusApplication *application)
998 nautilus_application_window_list = g_list_remove (nautilus_application_window_list, object);
1001 static gboolean
1002 nautilus_window_delete_event_callback (GtkWidget *widget,
1003 GdkEvent *event,
1004 gpointer user_data)
1006 NautilusWindow *window;
1008 window = NAUTILUS_WINDOW (widget);
1009 nautilus_window_close (window);
1011 return TRUE;
1015 static NautilusWindow *
1016 create_window (NautilusApplication *application,
1017 GType window_type,
1018 const char *startup_id,
1019 GdkScreen *screen)
1021 NautilusWindow *window;
1023 g_return_val_if_fail (NAUTILUS_IS_APPLICATION (application), NULL);
1025 window = NAUTILUS_WINDOW (gtk_widget_new (window_type,
1026 "app", application,
1027 "screen", screen,
1028 NULL));
1029 /* Must be called after construction finished */
1030 nautilus_window_constructed (window);
1032 g_signal_connect_data (window, "delete_event",
1033 G_CALLBACK (nautilus_window_delete_event_callback), NULL, NULL,
1034 G_CONNECT_AFTER);
1036 g_signal_connect_object (window, "destroy",
1037 G_CALLBACK (nautilus_application_destroyed_window), application, 0);
1039 nautilus_application_window_list = g_list_prepend (nautilus_application_window_list, window);
1041 /* Do not yet show the window. It will be shown later on if it can
1042 * successfully display its initial URI. Otherwise it will be destroyed
1043 * without ever having seen the light of day.
1046 return window;
1049 static void
1050 spatial_window_destroyed_callback (void *user_data, GObject *window)
1052 nautilus_application_spatial_window_list = g_list_remove (nautilus_application_spatial_window_list, window);
1056 NautilusWindow *
1057 nautilus_application_present_spatial_window (NautilusApplication *application,
1058 NautilusWindow *requesting_window,
1059 const char *startup_id,
1060 GFile *location,
1061 GdkScreen *screen)
1063 return nautilus_application_present_spatial_window_with_selection (application,
1064 requesting_window,
1065 startup_id,
1066 location,
1067 NULL,
1068 screen);
1071 #ifdef HAVE_STARTUP_NOTIFICATION
1073 static void
1074 sn_error_trap_push (SnDisplay *display,
1075 Display *xdisplay)
1077 gdk_error_trap_push ();
1080 static void
1081 sn_error_trap_pop (SnDisplay *display,
1082 Display *xdisplay)
1084 gdk_error_trap_pop ();
1087 static void
1088 end_startup_notification (GtkWidget *widget,
1089 const char *startup_id)
1091 SnDisplay *sn_display;
1092 SnLauncheeContext *context;
1093 GdkDisplay *display;
1094 GdkScreen *screen;
1096 if (startup_id == NULL) {
1097 return;
1100 if (!GTK_WIDGET_REALIZED (widget)) {
1101 gtk_widget_realize (widget);
1104 context = NULL;
1105 sn_display = NULL;
1107 /* Set up window for launch notification */
1108 /* FIXME In principle all transient children of this
1109 * window should get the same startup_id
1112 screen = gtk_widget_get_screen (widget);
1113 display = gdk_screen_get_display (screen);
1115 sn_display = sn_display_new (gdk_x11_display_get_xdisplay (display),
1116 sn_error_trap_push,
1117 sn_error_trap_pop);
1119 context = sn_launchee_context_new (sn_display,
1120 gdk_screen_get_number (screen),
1121 startup_id);
1123 /* Handle the setup for the window if the startup_id is valid;
1124 * I don't think it can hurt to do this even if it was
1125 * invalid, but why do the extra work...
1127 if (strncmp (sn_launchee_context_get_startup_id (context), "_TIME", 5) != 0) {
1128 sn_launchee_context_setup_window (context,
1129 GDK_WINDOW_XWINDOW (widget->window));
1132 /* Now, set the _NET_WM_USER_TIME for the new window to the timestamp
1133 * that caused the window to be launched.
1135 if (sn_launchee_context_get_id_has_timestamp (context)) {
1136 gulong startup_id_timestamp;
1137 startup_id_timestamp = sn_launchee_context_get_timestamp (context);
1138 gdk_x11_window_set_user_time (widget->window, startup_id_timestamp);
1141 sn_launchee_context_complete (context);
1142 sn_launchee_context_unref (context);
1143 sn_display_unref (sn_display);
1146 #endif
1148 NautilusWindow *
1149 nautilus_application_present_spatial_window_with_selection (NautilusApplication *application,
1150 NautilusWindow *requesting_window,
1151 const char *startup_id,
1152 GFile *location,
1153 GList *new_selection,
1154 GdkScreen *screen)
1156 NautilusWindow *window;
1157 GList *l;
1158 char *uri;
1160 g_return_val_if_fail (NAUTILUS_IS_APPLICATION (application), NULL);
1162 for (l = nautilus_application_get_spatial_window_list ();
1163 l != NULL; l = l->next) {
1164 NautilusWindow *existing_window;
1165 GFile *existing_location;
1167 existing_window = NAUTILUS_WINDOW (l->data);
1168 existing_location = existing_window->details->pending_location;
1170 if (existing_location == NULL) {
1171 existing_location = existing_window->details->location;
1174 if (g_file_equal (existing_location, location)) {
1175 #ifdef HAVE_STARTUP_NOTIFICATION
1176 end_startup_notification (GTK_WIDGET (existing_window),
1177 startup_id);
1178 #endif
1180 gtk_window_present (GTK_WINDOW (existing_window));
1181 if (new_selection &&
1182 existing_window->content_view != NULL) {
1183 nautilus_view_set_selection (existing_window->content_view, new_selection);
1186 uri = g_file_get_uri (location);
1187 nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
1188 "present EXISTING spatial window=%p: %s",
1189 existing_window, uri);
1190 g_free (uri);
1191 return existing_window;
1195 window = create_window (application, NAUTILUS_TYPE_SPATIAL_WINDOW, startup_id, screen);
1196 #ifdef HAVE_STARTUP_NOTIFICATION
1197 end_startup_notification (GTK_WIDGET (window),
1198 startup_id);
1199 #endif
1200 if (requesting_window) {
1201 /* Center the window over the requesting window by default */
1202 int orig_x, orig_y, orig_width, orig_height;
1203 int new_x, new_y, new_width, new_height;
1205 gtk_window_get_position (GTK_WINDOW (requesting_window),
1206 &orig_x, &orig_y);
1207 gtk_window_get_size (GTK_WINDOW (requesting_window),
1208 &orig_width, &orig_height);
1209 gtk_window_get_default_size (GTK_WINDOW (window),
1210 &new_width, &new_height);
1212 new_x = orig_x + (orig_width - new_width) / 2;
1213 new_y = orig_y + (orig_height - new_height) / 2;
1215 if (orig_width - new_width < 10) {
1216 new_x += 10;
1217 new_y += 10;
1220 gtk_window_move (GTK_WINDOW (window), new_x, new_y);
1223 nautilus_application_spatial_window_list = g_list_prepend (nautilus_application_spatial_window_list, window);
1224 g_object_weak_ref (G_OBJECT (window),
1225 spatial_window_destroyed_callback, NULL);
1227 nautilus_window_go_to_with_selection (window, location, new_selection);
1229 uri = g_file_get_uri (location);
1230 nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
1231 "present NEW spatial window=%p: %s",
1232 window, uri);
1233 g_free (uri);
1235 return window;
1238 static gboolean
1239 another_navigation_window_already_showing (NautilusWindow *the_window)
1241 GList *list, *item;
1243 list = nautilus_application_get_window_list ();
1244 for (item = list; item != NULL; item = item->next) {
1245 if (item->data != the_window &&
1246 NAUTILUS_IS_NAVIGATION_WINDOW (item->data)) {
1247 return TRUE;
1251 return FALSE;
1254 NautilusWindow *
1255 nautilus_application_create_navigation_window (NautilusApplication *application,
1256 const char *startup_id,
1257 GdkScreen *screen)
1259 NautilusWindow *window;
1260 char *geometry_string;
1261 gboolean maximized;
1263 g_return_val_if_fail (NAUTILUS_IS_APPLICATION (application), NULL);
1265 window = create_window (application, NAUTILUS_TYPE_NAVIGATION_WINDOW, startup_id, screen);
1266 #ifdef HAVE_STARTUP_NOTIFICATION
1267 end_startup_notification (GTK_WIDGET (window),
1268 startup_id);
1269 #endif
1271 maximized = eel_preferences_get_boolean
1272 (NAUTILUS_PREFERENCES_NAVIGATION_WINDOW_MAXIMIZED);
1273 if (maximized) {
1274 gtk_window_maximize (GTK_WINDOW (window));
1275 } else {
1276 gtk_window_unmaximize (GTK_WINDOW (window));
1279 geometry_string = eel_preferences_get
1280 (NAUTILUS_PREFERENCES_NAVIGATION_WINDOW_SAVED_GEOMETRY);
1281 if (geometry_string != NULL &&
1282 geometry_string[0] != 0) {
1283 /* Ignore saved window position if a window with the same
1284 * location is already showing. That way the two windows
1285 * wont appear at the exact same location on the screen.
1287 eel_gtk_window_set_initial_geometry_from_string
1288 (GTK_WINDOW (window),
1289 geometry_string,
1290 NAUTILUS_WINDOW_MIN_WIDTH,
1291 NAUTILUS_WINDOW_MIN_HEIGHT,
1292 another_navigation_window_already_showing (window));
1294 g_free (geometry_string);
1296 nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
1297 "create new navigation window=%p",
1298 window);
1300 return window;
1303 /* callback for changing the directory the desktop points to */
1304 static void
1305 desktop_location_changed_callback (gpointer user_data)
1307 if (nautilus_application_desktop_windows != NULL) {
1308 g_list_foreach (nautilus_application_desktop_windows,
1309 (GFunc) nautilus_desktop_window_update_directory, NULL);
1313 /* callback for showing or hiding the desktop based on the user's preference */
1314 static void
1315 desktop_changed_callback (gpointer user_data)
1317 NautilusApplication *application;
1319 application = NAUTILUS_APPLICATION (user_data);
1320 if ( eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
1321 nautilus_application_open_desktop (application);
1322 } else {
1323 nautilus_application_close_desktop ();
1327 static gboolean
1328 window_can_be_closed (NautilusWindow *window)
1330 if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) {
1331 return TRUE;
1334 return FALSE;
1337 static void
1338 volume_added_callback (GVolumeMonitor *monitor,
1339 GVolume *volume,
1340 NautilusApplication *application)
1342 if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_MEDIA_AUTOMOUNT) &&
1343 g_volume_should_automount (volume) &&
1344 g_volume_can_mount (volume)) {
1345 nautilus_file_operations_mount_volume (NULL, volume, TRUE);
1349 static void
1350 drive_eject_cb (GObject *source_object,
1351 GAsyncResult *res,
1352 gpointer user_data)
1354 GError *error;
1355 char *primary;
1356 char *name;
1357 error = NULL;
1358 if (!g_drive_eject_finish (G_DRIVE (source_object), res, &error)) {
1359 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
1360 name = g_drive_get_name (G_DRIVE (source_object));
1361 primary = g_strdup_printf (_("Unable to eject %s"), name);
1362 g_free (name);
1363 eel_show_error_dialog (primary,
1364 error->message,
1365 NULL);
1366 g_free (primary);
1368 g_error_free (error);
1372 static void
1373 drive_eject_button_pressed (GDrive *drive,
1374 NautilusApplication *application)
1376 g_drive_eject (drive, 0, NULL, drive_eject_cb, NULL);
1379 static void
1380 drive_listen_for_eject_button (GDrive *drive, NautilusApplication *application)
1382 g_signal_connect (drive,
1383 "eject-button",
1384 G_CALLBACK (drive_eject_button_pressed),
1385 application);
1388 static void
1389 drive_connected_callback (GVolumeMonitor *monitor,
1390 GDrive *drive,
1391 NautilusApplication *application)
1393 drive_listen_for_eject_button (drive, application);
1396 static void
1397 autorun_show_window (GMount *mount, gpointer user_data)
1399 GFile *location;
1400 NautilusApplication *application = user_data;
1402 location = g_mount_get_root (mount);
1404 /* Ther should probably be an easier way to do this */
1405 if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_BROWSER)) {
1406 NautilusWindow *window;
1407 window = nautilus_application_create_navigation_window (application,
1408 NULL,
1409 gdk_screen_get_default ());
1410 nautilus_window_go_to (window, location);
1412 } else {
1413 nautilus_application_present_spatial_window (application,
1414 NULL,
1415 NULL,
1416 location,
1417 gdk_screen_get_default ());
1419 g_object_unref (location);
1422 static void
1423 mount_added_callback (GVolumeMonitor *monitor,
1424 GMount *mount,
1425 NautilusApplication *application)
1427 NautilusDirectory *directory;
1428 GFile *root;
1430 root = g_mount_get_root (mount);
1431 directory = nautilus_directory_get_existing (root);
1432 g_object_unref (root);
1433 if (directory != NULL) {
1434 nautilus_directory_force_reload (directory);
1435 nautilus_directory_unref (directory);
1438 nautilus_autorun (mount, autorun_show_window, application);
1441 /* Called whenever a mount is unmounted. Check and see if there are
1442 * any windows open displaying contents on the mount. If there are,
1443 * close them. It would also be cool to save open window and position
1444 * info.
1446 * This is also called on pre_unmount.
1448 static void
1449 mount_removed_callback (GVolumeMonitor *monitor,
1450 GMount *mount,
1451 NautilusApplication *application)
1453 GList *window_list, *node, *close_list;
1454 NautilusWindow *window;
1455 GFile *root;
1457 close_list = NULL;
1459 /* Check and see if any of the open windows are displaying contents from the unmounted mount */
1460 window_list = nautilus_application_get_window_list ();
1462 root = g_mount_get_root (mount);
1463 /* Construct a list of windows to be closed. Do not add the non-closable windows to the list. */
1464 for (node = window_list; node != NULL; node = node->next) {
1465 window = NAUTILUS_WINDOW (node->data);
1466 if (window != NULL && window_can_be_closed (window)) {
1467 GFile *location;
1469 location = nautilus_window_get_location (window);
1471 if (g_file_has_prefix (location, root)) {
1472 close_list = g_list_prepend (close_list, window);
1474 g_object_unref (location);
1478 /* Handle the windows in the close list. */
1479 for (node = close_list; node != NULL; node = node->next) {
1480 window = NAUTILUS_WINDOW (node->data);
1481 if (NAUTILUS_IS_SPATIAL_WINDOW (window)) {
1482 nautilus_window_close (window);
1483 } else {
1484 nautilus_window_go_home (window);
1488 g_list_free (close_list);
1491 static void
1492 removed_from_session (GnomeClient *client, gpointer data)
1494 nautilus_main_event_loop_quit (FALSE);
1497 static char *
1498 icon_to_string (GIcon *icon)
1500 const char * const *names;
1501 GFile *file;
1503 if (icon == NULL) {
1504 return NULL;
1505 } else if (G_IS_THEMED_ICON (icon)) {
1506 names = g_themed_icon_get_names (G_THEMED_ICON (icon));
1507 return g_strjoinv (":", (char **)names);
1508 } else if (G_IS_FILE_ICON (icon)) {
1509 file = g_file_icon_get_file (G_FILE_ICON (icon));
1510 return g_file_get_path (file);
1512 return NULL;
1515 static GIcon *
1516 icon_from_string (const char *string)
1518 GFile *file;
1519 GIcon *icon;
1520 gchar **names;
1522 if (g_path_is_absolute (string)) {
1523 file = g_file_new_for_path (string);
1524 icon = g_file_icon_new (file);
1525 g_object_unref (file);
1526 return icon;
1527 } else {
1528 names = g_strsplit (string, ":", 0);
1529 icon = g_themed_icon_new_from_names (names, -1);
1530 g_strfreev (names);
1531 return icon;
1533 return NULL;
1536 char *
1537 nautilus_application_save_session_to_file (void)
1539 xmlDocPtr doc;
1540 xmlNodePtr root_node, history_node;
1541 GList *l;
1542 char *dir, *filename;
1543 unsigned n_processed;
1544 int fd;
1545 xmlSaveCtxtPtr ctx;
1547 doc = xmlNewDoc ("1.0");
1549 root_node = xmlNewNode (NULL, "session");
1550 xmlDocSetRootElement (doc, root_node);
1552 history_node = xmlNewChild (root_node, NULL, "history", NULL);
1554 n_processed = 0;
1555 for (l = nautilus_get_history_list (); l != NULL; l = l->next) {
1556 NautilusBookmark *bookmark;
1557 xmlNodePtr bookmark_node;
1558 GIcon *icon;
1559 char *tmp;
1561 bookmark = l->data;
1563 bookmark_node = xmlNewChild (history_node, NULL, "bookmark", NULL);
1565 tmp = nautilus_bookmark_get_name (bookmark);
1566 xmlNewProp (bookmark_node, "name", tmp);
1567 g_free (tmp);
1569 icon = nautilus_bookmark_get_icon (bookmark);
1570 tmp = icon_to_string (icon);
1571 g_object_unref (icon);
1572 if (tmp) {
1573 xmlNewProp (bookmark_node, "icon", tmp);
1574 g_free (tmp);
1577 tmp = nautilus_bookmark_get_uri (bookmark);
1578 xmlNewProp (bookmark_node, "uri", tmp);
1579 g_free (tmp);
1581 if (nautilus_bookmark_get_has_custom_name (bookmark)) {
1582 xmlNewProp (bookmark_node, "has_custom_name", "TRUE");
1585 if (++n_processed > 50) { /* prevent history list from growing arbitrarily large. */
1586 break;
1590 for (l = nautilus_application_window_list; l != NULL; l = l->next) {
1591 xmlNodePtr win_node;
1592 NautilusWindow *window;
1593 char *tmp;
1595 window = l->data;
1597 win_node = xmlNewChild (root_node, NULL, "window", NULL);
1599 xmlNewProp (win_node, "type", NAUTILUS_IS_NAVIGATION_WINDOW (window) ? "navigation" : "spatial");
1601 if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) { /* spatial windows store their state as file metadata */
1602 tmp = eel_gtk_window_get_geometry_string (GTK_WINDOW (window));
1603 xmlNewProp (win_node, "geometry", tmp);
1604 g_free (tmp);
1606 if (GTK_WIDGET (window)->window &&
1607 gdk_window_get_state (GTK_WIDGET (window)->window) & GDK_WINDOW_STATE_MAXIMIZED) {
1608 xmlNewProp (win_node, "maximized", "TRUE");
1611 if (GTK_WIDGET (window)->window &&
1612 gdk_window_get_state (GTK_WIDGET (window)->window) & GDK_WINDOW_STATE_STICKY) {
1613 xmlNewProp (win_node, "sticky", "TRUE");
1616 if (GTK_WIDGET (window)->window &&
1617 gdk_window_get_state (GTK_WIDGET (window)->window) & GDK_WINDOW_STATE_ABOVE) {
1618 xmlNewProp (win_node, "keep-above", "TRUE");
1622 tmp = nautilus_window_get_location_uri (window);
1623 xmlNewProp (win_node, "location", tmp);
1624 g_free (tmp);
1627 dir = nautilus_get_user_directory ();
1628 filename = g_build_filename (dir, "saved-session-XXXXXX", NULL);
1629 g_free (dir);
1631 fd = g_mkstemp (filename);
1632 if (fd < 0) {
1633 g_message ("failed to open session file %s", filename);
1634 g_free (filename);
1635 filename = NULL;
1636 goto out;
1639 xmlIndentTreeOutput = 1;
1640 ctx = xmlSaveToFd (fd, NULL, XML_SAVE_FORMAT);
1641 if (xmlSaveDoc (ctx, doc) < 0 ||
1642 xmlSaveFlush (ctx) < 0) {
1643 g_message ("failed to save session to %s", filename);
1644 g_free (filename);
1645 filename = NULL;
1648 xmlSaveClose(ctx);
1649 close (fd);
1651 out:
1652 xmlFreeDoc (doc);
1654 return filename;
1657 void
1658 nautilus_application_load_session (NautilusApplication *application,
1659 const char *filename)
1661 xmlDocPtr doc;
1662 gboolean bail;
1664 g_assert (filename != NULL);
1666 bail = TRUE;
1668 if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
1669 xmlNodePtr root_node;
1671 doc = xmlReadFile (filename, NULL, 0);
1672 if (doc != NULL && (root_node = xmlDocGetRootElement (doc)) != NULL) {
1673 xmlNodePtr node;
1675 bail = FALSE;
1677 for (node = root_node->children; node != NULL; node = node->next) {
1679 if (!strcmp (node->name, "text")) {
1680 continue;
1681 } else if (!strcmp (node->name, "history")) {
1682 xmlNodePtr bookmark_node;
1683 gboolean emit_change;
1685 emit_change = FALSE;
1687 for (bookmark_node = node->children; bookmark_node != NULL; bookmark_node = bookmark_node->next) {
1688 if (!strcmp (bookmark_node->name, "text")) {
1689 continue;
1690 } else if (!strcmp (bookmark_node->name, "bookmark")) {
1691 xmlChar *name, *icon_str, *uri;
1692 gboolean has_custom_name;
1693 GIcon *icon;
1694 GFile *location;
1696 uri = xmlGetProp (bookmark_node, "uri");
1697 name = xmlGetProp (bookmark_node, "name");
1698 has_custom_name = xmlHasProp (bookmark_node, "has_custom_name") ? TRUE : FALSE;
1699 icon_str = xmlGetProp (bookmark_node, "icon");
1700 icon = NULL;
1701 if (icon_str) {
1702 icon = icon_from_string (icon_str);
1704 location = g_file_new_for_uri (uri);
1706 emit_change |= nautilus_add_to_history_list_no_notify (location, name, has_custom_name, icon);
1708 g_object_unref (location);
1710 if (icon) {
1711 g_object_unref (icon);
1713 xmlFree (name);
1714 xmlFree (uri);
1715 xmlFree (icon_str);
1716 } else {
1717 g_message ("unexpected bookmark node %s while parsing %s", bookmark_node->name, filename);
1718 bail = TRUE;
1719 continue;
1723 if (emit_change) {
1724 nautilus_send_history_list_changed ();
1726 } else if (!strcmp (node->name, "window")) {
1727 NautilusWindow *window;
1728 xmlChar *type, *location_uri;
1729 GFile *location;
1731 type = xmlGetProp (node, "type");
1732 if (type == NULL) {
1733 g_message ("empty type node while parsing %s", filename);
1734 bail = TRUE;
1735 continue;
1738 location_uri = xmlGetProp (node, "location");
1739 if (location_uri == NULL) {
1740 g_message ("empty location node while parsing %s", filename);
1741 bail = TRUE;
1742 xmlFree (type);
1743 continue;
1746 if (!strcmp (type, "navigation")) {
1747 xmlChar *geometry;
1749 window = nautilus_application_create_navigation_window (application, NULL, gdk_screen_get_default ());
1751 geometry = xmlGetProp (node, "geometry");
1752 if (geometry != NULL) {
1753 eel_gtk_window_set_initial_geometry_from_string
1754 (GTK_WINDOW (window),
1755 geometry,
1756 NAUTILUS_WINDOW_MIN_WIDTH,
1757 NAUTILUS_WINDOW_MIN_HEIGHT,
1758 FALSE);
1760 xmlFree (geometry);
1762 if (xmlHasProp (node, "maximized")) {
1763 gtk_window_maximize (GTK_WINDOW (window));
1764 } else {
1765 gtk_window_unmaximize (GTK_WINDOW (window));
1768 if (xmlHasProp (node, "sticky")) {
1769 gtk_window_stick (GTK_WINDOW (window));
1770 } else {
1771 gtk_window_unstick (GTK_WINDOW (window));
1774 if (xmlHasProp (node, "keep-above")) {
1775 gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
1776 } else {
1777 gtk_window_set_keep_above (GTK_WINDOW (window), FALSE);
1780 location = g_file_new_for_uri (location_uri);
1781 nautilus_window_open_location (window, location, FALSE);
1782 g_object_unref (location);
1783 } else if (!strcmp (type, "spatial")) {
1784 location = g_file_new_for_uri (location_uri);
1785 window = nautilus_application_present_spatial_window (application, NULL, NULL, location, gdk_screen_get_default ());
1786 g_object_unref (location);
1787 } else {
1788 g_message ("unknown window type \"%s\" while parsing %s", type, filename);
1789 bail = TRUE;
1792 xmlFree (type);
1793 xmlFree (location_uri);
1794 } else {
1795 g_message ("unexpected node %s while parsing %s", node->name, filename);
1796 bail = TRUE;
1797 continue;
1802 if (doc != NULL) {
1803 xmlFreeDoc (doc);
1807 if (bail) {
1808 g_message ("failed to load session from %s", filename);
1809 } else {
1810 struct stat buf;
1812 /* only remove file if it is regular, user-owned and the user has write access. */
1814 if (g_stat (filename, &buf) == 0 &&
1815 S_ISREG (buf.st_mode) &&
1816 (buf.st_mode & S_IWUSR) &&
1817 buf.st_uid == geteuid()) {
1818 g_remove (filename);
1823 static gint
1824 save_session (GnomeClient *client, gint phase, GnomeSaveStyle save_style, gint shutdown,
1825 GnomeInteractStyle interact_style, gint fast, gpointer data)
1827 char *argv[3] = { NULL };
1829 argv[0] = "nautilus";
1831 argv[2] = nautilus_application_save_session_to_file ();
1832 if (argv[2] != NULL) {
1833 argv[1] = "--load-session";
1836 gnome_client_set_restart_command (client,
1837 G_N_ELEMENTS (argv),
1838 argv);
1840 if (argv[2] != NULL) {
1841 g_free (argv[2]);
1844 return TRUE;
1847 static void
1848 set_session_restart (GnomeClient *client, gboolean restart)
1850 gnome_client_set_priority (client, 40);
1852 if (restart && g_getenv ("NAUTILUS_DEBUG") == NULL) {
1853 /* Don't respawn in debug mode */
1854 gnome_client_set_restart_style (client, GNOME_RESTART_IMMEDIATELY);
1855 } else {
1856 gnome_client_set_restart_style (client, GNOME_RESTART_IF_RUNNING);
1860 static void
1861 update_session (gpointer callback_data)
1863 set_session_restart (callback_data,
1864 /* Only ever add ourselves to the session
1865 * if we have a desktop window. Prevents the
1866 * session thrashing that's seen otherwise
1868 nautilus_application_desktop_windows != NULL);
1871 static void
1872 init_session (void)
1874 GnomeClient *client;
1876 client = gnome_master_client ();
1878 g_signal_connect (client, "save_yourself",
1879 G_CALLBACK (save_session), NULL);
1881 g_signal_connect (client, "die",
1882 G_CALLBACK (removed_from_session), NULL);
1884 update_session (client);
1887 #ifdef UGLY_HACK_TO_DETECT_KDE
1889 static gboolean
1890 get_self_typed_prop (Window xwindow,
1891 Atom atom,
1892 gulong *val)
1894 Atom type;
1895 int format;
1896 gulong nitems;
1897 gulong bytes_after;
1898 gulong *num;
1899 int err;
1901 gdk_error_trap_push ();
1902 type = None;
1903 XGetWindowProperty (gdk_display,
1904 xwindow,
1905 atom,
1906 0, G_MAXLONG,
1907 False, atom, &type, &format, &nitems,
1908 &bytes_after, (guchar **)&num);
1910 err = gdk_error_trap_pop ();
1911 if (err != Success) {
1912 return FALSE;
1915 if (type != atom) {
1916 return FALSE;
1919 if (val)
1920 *val = *num;
1922 XFree (num);
1924 return TRUE;
1927 static gboolean
1928 has_wm_state (Window xwindow)
1930 return get_self_typed_prop (xwindow,
1931 XInternAtom (gdk_display, "WM_STATE", False),
1932 NULL);
1935 static gboolean
1936 look_for_kdesktop_recursive (Window xwindow)
1939 Window ignored1, ignored2;
1940 Window *children;
1941 unsigned int n_children;
1942 unsigned int i;
1943 gboolean retval;
1945 /* If WM_STATE is set, this is a managed client, so look
1946 * for the class hint and end recursion. Otherwise,
1947 * this is probably just a WM frame, so keep recursing.
1949 if (has_wm_state (xwindow)) {
1950 XClassHint ch;
1952 gdk_error_trap_push ();
1953 ch.res_name = NULL;
1954 ch.res_class = NULL;
1956 XGetClassHint (gdk_display, xwindow, &ch);
1958 gdk_error_trap_pop ();
1960 if (ch.res_name)
1961 XFree (ch.res_name);
1963 if (ch.res_class) {
1964 if (strcmp (ch.res_class, "kdesktop") == 0) {
1965 XFree (ch.res_class);
1966 return TRUE;
1968 else
1969 XFree (ch.res_class);
1972 return FALSE;
1975 retval = FALSE;
1977 gdk_error_trap_push ();
1979 XQueryTree (gdk_display,
1980 xwindow,
1981 &ignored1, &ignored2, &children, &n_children);
1983 if (gdk_error_trap_pop ()) {
1984 return FALSE;
1987 i = 0;
1988 while (i < n_children) {
1989 if (look_for_kdesktop_recursive (children[i])) {
1990 retval = TRUE;
1991 break;
1994 ++i;
1997 if (children)
1998 XFree (children);
2000 return retval;
2002 #endif /* UGLY_HACK_TO_DETECT_KDE */
2004 static gboolean
2005 is_kdesktop_present (void)
2007 #ifdef UGLY_HACK_TO_DETECT_KDE
2008 /* FIXME this is a pretty lame hack, should be replaced
2009 * eventually with e.g. a requirement that desktop managers
2010 * support a manager selection, ICCCM sec 2.8
2012 return look_for_kdesktop_recursive (GDK_ROOT_WINDOW ());
2013 #else
2014 return FALSE;
2015 #endif
2018 static void
2019 nautilus_application_class_init (NautilusApplicationClass *class)
2021 BONOBO_OBJECT_CLASS (class)->destroy = nautilus_application_destroy;
2022 BONOBO_GENERIC_FACTORY_CLASS (class)->epv.createObject = create_object;