1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */
6 * Copyright (C) 1999, 2000 Red Hat, Inc.
7 * Copyright (C) 1999, 2000 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>,
25 * John Sullivan <sullivan@eazel.com>
29 /* nautilus-main.c: Implementation of the routines that drive program lifecycle and main window creation/destruction. */
32 #include "nautilus-main.h"
34 #include "nautilus-application.h"
35 #include "nautilus-self-check-functions.h"
36 #include "nautilus-window.h"
37 #include <bonobo-activation/bonobo-activation.h>
38 #include <bonobo/bonobo-main.h>
41 #include <eel/eel-debug.h>
42 #include <eel/eel-glib-extensions.h>
43 #include <eel/eel-self-checks.h>
45 #include <gtk/gtkmain.h>
46 #include <gtk/gtkiconfactory.h>
47 #include <gtk/gtksignal.h>
49 #include <glib/gi18n.h>
50 #include <gio/gdesktopappinfo.h>
51 #include <libgnome/gnome-init.h>
52 #include <libgnomeui/gnome-ui-init.h>
53 #include <libgnomeui/gnome-client.h>
54 #include <libnautilus-private/nautilus-debug-log.h>
55 #include <libnautilus-private/nautilus-directory-metafile.h>
56 #include <libnautilus-private/nautilus-global-preferences.h>
57 #include <libnautilus-private/nautilus-lib-self-check-functions.h>
58 #include <libnautilus-private/nautilus-icon-names.h>
59 #include <libxml/parser.h>
68 #include <exempi/xmp.h>
71 /* Keeps track of everyone who wants the main event loop kept active */
72 static GSList
*event_loop_registrants
;
75 is_event_loop_needed (void)
77 return event_loop_registrants
!= NULL
;
81 quit_if_in_main_loop (gpointer callback_data
)
85 g_assert (callback_data
== NULL
);
87 level
= gtk_main_level ();
89 /* We can be called even outside the main loop,
90 * so check that we are in a loop before calling quit.
96 /* We need to be called again if we quit a nested loop. */
101 eel_gtk_main_quit_all (void)
103 /* Calling gtk_main_quit directly only kills the current/top event loop.
104 * This idler will be run by the current event loop, killing it, and then
105 * by the next event loop, ...
107 g_idle_add (quit_if_in_main_loop
, NULL
);
111 event_loop_unregister (GtkObject
*object
)
113 event_loop_registrants
= g_slist_remove (event_loop_registrants
, object
);
114 if (!is_event_loop_needed ()) {
115 eel_gtk_main_quit_all ();
120 initial_event_loop_needed (gpointer data
)
122 if (!is_event_loop_needed ()) {
123 eel_gtk_main_quit_all ();
129 nautilus_main_event_loop_register (GtkObject
*object
)
131 g_signal_connect (object
, "destroy", G_CALLBACK (event_loop_unregister
), NULL
);
132 event_loop_registrants
= g_slist_prepend (event_loop_registrants
, object
);
136 nautilus_main_is_event_loop_mainstay (GtkObject
*object
)
138 return g_slist_length (event_loop_registrants
) == 1
139 && event_loop_registrants
->data
== object
;
143 nautilus_main_event_loop_quit (gboolean
explicit)
146 /* Explicit --quit, make sure we don't restart */
147 gnome_client_set_restart_style (gnome_master_client (),
148 GNOME_RESTART_IF_RUNNING
);
150 while (event_loop_registrants
!= NULL
) {
151 gtk_object_destroy (event_loop_registrants
->data
);
155 /* Copied from libnautilus/nautilus-program-choosing.c; In this case,
156 * though, it's really needed because we have no real alternative when
157 * no DESKTOP_STARTUP_ID (with its accompanying timestamp) is
161 slowly_and_stupidly_obtain_timestamp (Display
*xdisplay
)
167 XSetWindowAttributes attrs
;
172 attrs
.override_redirect
= True
;
173 attrs
.event_mask
= PropertyChangeMask
| StructureNotifyMask
;
176 XCreateWindow (xdisplay
,
177 RootWindow (xdisplay
, 0),
182 (Visual
*)CopyFromParent
,
183 CWOverrideRedirect
| CWEventMask
,
186 atom_name
= XInternAtom (xdisplay
, "WM_NAME", TRUE
);
187 g_assert (atom_name
!= None
);
188 atom_type
= XInternAtom (xdisplay
, "STRING", TRUE
);
189 g_assert (atom_type
!= None
);
191 name
= "Fake Window";
192 XChangeProperty (xdisplay
,
195 8, PropModeReplace
, name
, strlen (name
));
198 XWindowEvent (xdisplay
,
203 XDestroyWindow(xdisplay
, xwindow
);
205 return event
.xproperty
.time
;
209 dump_debug_log (void)
213 filename
= g_build_filename (g_get_home_dir (), "nautilus-debug-log.txt", NULL
);
214 nautilus_debug_log_dump (filename
, NULL
); /* NULL GError */
218 static int debug_log_pipes
[2];
221 debug_log_io_cb (GIOChannel
*io
, GIOCondition condition
, gpointer data
)
225 while (read (debug_log_pipes
[0], &a
, 1) != 1)
228 nautilus_debug_log (TRUE
, NAUTILUS_DEBUG_LOG_DOMAIN_USER
,
229 "user requested dump of debug log");
236 sigusr1_handler (int sig
)
238 while (write (debug_log_pipes
[1], "a", 1) != 1)
242 /* This is totally broken as we're using non-signal safe
243 * calls in sigfatal_handler. Disable by default. */
244 #ifdef USE_SEGV_HANDLER
246 /* sigaction structures for the old handlers of these signals */
247 static struct sigaction old_segv_sa
;
248 static struct sigaction old_abrt_sa
;
249 static struct sigaction old_trap_sa
;
250 static struct sigaction old_fpe_sa
;
251 static struct sigaction old_bus_sa
;
254 sigfatal_handler (int sig
)
258 /* FIXME: is this totally busted? We do malloc() inside these functions,
259 * and yet we are inside a signal handler...
261 nautilus_debug_log (TRUE
, NAUTILUS_DEBUG_LOG_DOMAIN_USER
,
262 "debug log dumped due to signal %d", sig
);
267 func
= old_segv_sa
.sa_handler
;
271 func
= old_abrt_sa
.sa_handler
;
275 func
= old_trap_sa
.sa_handler
;
279 func
= old_fpe_sa
.sa_handler
;
283 func
= old_bus_sa
.sa_handler
;
292 if (func
!= NULL
&& func
!= SIG_IGN
&& func
!= SIG_DFL
)
298 setup_debug_log_signals (void)
303 if (pipe (debug_log_pipes
) == -1)
304 g_error ("Could not create pipe() for debug log");
306 io
= g_io_channel_unix_new (debug_log_pipes
[0]);
307 g_io_add_watch (io
, G_IO_IN
, debug_log_io_cb
, NULL
);
309 sa
.sa_handler
= sigusr1_handler
;
310 sigemptyset (&sa
.sa_mask
);
312 sigaction (SIGUSR1
, &sa
, NULL
);
314 /* This is totally broken as we're using non-signal safe
315 * calls in sigfatal_handler. Disable by default. */
316 #ifdef USE_SEGV_HANDLER
317 sa
.sa_handler
= sigfatal_handler
;
318 sigemptyset (&sa
.sa_mask
);
321 sigaction(SIGSEGV
, &sa
, &old_segv_sa
);
322 sigaction(SIGABRT
, &sa
, &old_abrt_sa
);
323 sigaction(SIGTRAP
, &sa
, &old_trap_sa
);
324 sigaction(SIGFPE
, &sa
, &old_fpe_sa
);
325 sigaction(SIGBUS
, &sa
, &old_bus_sa
);
329 static GLogFunc default_log_handler
;
332 log_override_cb (const gchar
*log_domain
,
333 GLogLevelFlags log_level
,
334 const gchar
*message
,
338 gboolean is_milestone
;
340 is_debug
= ((log_level
& G_LOG_LEVEL_DEBUG
) != 0);
341 is_milestone
= !is_debug
;
343 nautilus_debug_log (is_milestone
, NAUTILUS_DEBUG_LOG_DOMAIN_GLOG
, "%s", message
);
346 (* default_log_handler
) (log_domain
, log_level
, message
, user_data
);
350 setup_debug_log_glog (void)
352 default_log_handler
= g_log_set_default_handler (log_override_cb
, NULL
);
356 setup_debug_log (void)
358 char *config_filename
;
360 config_filename
= g_build_filename (g_get_home_dir (), "nautilus-debug-log.conf", NULL
);
361 nautilus_debug_log_load_configuration (config_filename
, NULL
); /* NULL GError */
362 g_free (config_filename
);
364 setup_debug_log_signals ();
365 setup_debug_log_glog ();
369 main (int argc
, char *argv
[])
372 gboolean restart_shell
;
373 gboolean no_default_window
;
374 gboolean browser_window
;
376 gboolean autostart_mode
;
377 const char *startup_id
, *autostart_id
;
378 char *startup_id_copy
;
379 char *session_to_load
;
381 const gchar
**remaining
;
382 gboolean perform_self_check
;
383 GOptionContext
*context
;
384 NautilusApplication
*application
;
386 GnomeProgram
*program
;
388 const GOptionEntry options
[] = {
389 #ifndef NAUTILUS_OMIT_SELF_CHECK
390 { "check", 'c', 0, G_OPTION_ARG_NONE
, &perform_self_check
,
391 N_("Perform a quick set of self-check tests."), NULL
},
393 { "geometry", 'g', 0, G_OPTION_ARG_STRING
, &geometry
,
394 N_("Create the initial window with the given geometry."), N_("GEOMETRY") },
395 { "no-default-window", 'n', 0, G_OPTION_ARG_NONE
, &no_default_window
,
396 N_("Only create windows for explicitly specified URIs."), NULL
},
397 { "no-desktop", '\0', 0, G_OPTION_ARG_NONE
, &no_desktop
,
398 N_("Do not manage the desktop (ignore the preference set in the preferences dialog)."), NULL
},
399 { "browser", '\0', 0, G_OPTION_ARG_NONE
, &browser_window
,
400 N_("open a browser window."), NULL
},
401 { "quit", 'q', 0, G_OPTION_ARG_NONE
, &kill_shell
,
402 N_("Quit Nautilus."), NULL
},
403 { "restart", '\0', G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_NONE
, &restart_shell
,
404 N_("Restart Nautilus."), NULL
},
405 { G_OPTION_REMAINING
, 0, 0, G_OPTION_ARG_STRING_ARRAY
, &remaining
, NULL
, N_("[URI...]") },
406 { "load-session", 'l', 0, G_OPTION_ARG_STRING
, &session_to_load
,
407 /* Translators: --no-default-window is a nautilus command line parameter, don't modify it. */
408 N_("Load a saved session from the specified file. Implies \"--no-default-window\"."), N_("FILENAME") },
413 g_thread_init (NULL
);
415 setlocale (LC_ALL
, "");
417 /* This will be done by gtk+ later, but for now, force it to GNOME */
418 g_desktop_app_info_set_desktop_env ("GNOME");
420 if (g_getenv ("NAUTILUS_DEBUG") != NULL
) {
421 eel_make_warnings_and_criticals_stop_in_debugger ();
424 /* Initialize gettext support */
425 bindtextdomain (GETTEXT_PACKAGE
, GNOMELOCALEDIR
);
426 bind_textdomain_codeset (GETTEXT_PACKAGE
, "UTF-8");
427 textdomain (GETTEXT_PACKAGE
);
429 startup_id
= g_getenv ("DESKTOP_STARTUP_ID");
430 startup_id_copy
= NULL
;
431 if (startup_id
!= NULL
&& *startup_id
!= '\0') {
432 /* Clear the DESKTOP_STARTUP_ID, but make sure to copy it first */
433 startup_id_copy
= g_strdup (startup_id
);
434 g_unsetenv ("DESKTOP_STARTUP_ID");
437 autostart_id
= g_getenv ("DESKTOP_AUTOSTART_ID");
438 if (autostart_id
!= NULL
&& *autostart_id
!= '\0') {
439 autostart_mode
= TRUE
;
442 /* we'll do it ourselves due to complicated factory setup */
443 gtk_window_set_auto_startup_notification (FALSE
);
445 /* Get parameters. */
448 session_to_load
= NULL
;
450 no_default_window
= FALSE
;
452 perform_self_check
= FALSE
;
453 restart_shell
= FALSE
;
454 browser_window
= FALSE
;
456 g_set_application_name (_("File Manager"));
457 context
= g_option_context_new (_("\n\nBrowse the file system with the file manager"));
459 g_option_context_add_main_entries (context
, options
, GETTEXT_PACKAGE
);
465 program
= gnome_program_init ("nautilus", VERSION
,
466 LIBGNOMEUI_MODULE
, argc
, argv
,
467 GNOME_PROGRAM_STANDARD_PROPERTIES
,
468 GNOME_PARAM_GOPTION_CONTEXT
, context
,
469 GNOME_PARAM_HUMAN_READABLE_NAME
, _("Nautilus"),
472 /* We do this after gnome_program_init(), since that function sets up
473 * its own handler for SIGSEGV and others --- we want to chain to those
478 if (session_to_load
!= NULL
) {
479 no_default_window
= TRUE
;
482 /* If in autostart mode (aka started by gnome-session), we need to ensure
483 * nautilus starts with the correct options.
485 if (autostart_mode
) {
486 no_default_window
= TRUE
;
490 /* Do this here so that gdk_display is initialized */
491 if (startup_id_copy
== NULL
) {
492 /* Create a fake one containing a timestamp that we can use */
494 timestamp
= slowly_and_stupidly_obtain_timestamp (gdk_display
);
495 startup_id_copy
= g_strdup_printf ("_TIME%lu",
499 /* Set default icon for all nautilus windows */
500 gtk_window_set_default_icon_name (NAUTILUS_ICON_FOLDER
);
502 /* Need to set this to the canonical DISPLAY value, since
503 thats where we're registering per-display components */
504 bonobo_activation_set_activation_env_value ("DISPLAY",
505 gdk_display_get_name (gdk_display_get_default()));
508 if (perform_self_check
&& remaining
!= NULL
) {
509 /* translators: %s is an option (e.g. --check) */
510 fprintf (stderr
, _("nautilus: %s cannot be used with URIs.\n"),
514 if (perform_self_check
&& (kill_shell
|| restart_shell
)) {
515 fprintf (stderr
, _("nautilus: --check cannot be used with other options.\n"));
518 if (kill_shell
&& remaining
!= NULL
) {
519 fprintf (stderr
, _("nautilus: %s cannot be used with URIs.\n"),
523 if (restart_shell
&& remaining
!= NULL
) {
524 fprintf (stderr
, _("nautilus: %s cannot be used with URIs.\n"),
528 if (geometry
!= NULL
&& remaining
!= NULL
&& remaining
[0] != NULL
&& remaining
[1] != NULL
) {
529 fprintf (stderr
, _("nautilus: --geometry cannot be used with more than one URI.\n"));
533 /* Initialize the services that we use. */
536 /* Initialize preferences. This is needed so that proper
537 * defaults are available before any preference peeking
540 nautilus_global_preferences_init ();
542 eel_preferences_set_is_invisible
543 (NAUTILUS_PREFERENCES_SHOW_DESKTOP
, TRUE
);
544 eel_preferences_set_is_invisible
545 (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR
, TRUE
);
548 bonobo_activate (); /* do now since we need it before main loop */
552 /* Do either the self-check or the real work. */
553 if (perform_self_check
) {
554 #ifndef NAUTILUS_OMIT_SELF_CHECK
555 /* Run the checks (each twice) for nautilus and libnautilus-private. */
557 nautilus_run_self_checks ();
558 nautilus_run_lib_self_checks ();
559 eel_exit_if_self_checks_failed ();
561 nautilus_run_self_checks ();
562 nautilus_run_lib_self_checks ();
563 eel_exit_if_self_checks_failed ();
566 /* Run the nautilus application. */
567 application
= nautilus_application_new ();
568 nautilus_application_startup
570 kill_shell
, restart_shell
, no_default_window
, no_desktop
,
576 g_free (startup_id_copy
);
578 /* The application startup does things in an idle, so
579 we need to check whether the main loop is needed in an idle
581 g_idle_add (initial_event_loop_needed
, NULL
);
585 nautilus_icon_info_clear_caches ();
587 if (application
!= NULL
) {
588 bonobo_object_unref (application
);
591 eel_debug_shut_down ();
593 /* If told to restart, exec() myself again. This is used when
594 * the program is told to restart with CORBA, for example when
595 * an update takes place.
598 if (g_getenv ("_NAUTILUS_RESTART_SESSION_FILENAME") != NULL
) {
599 argv_copy
= g_new0 (char *, 4);
600 argv_copy
[0] = g_strdup (argv
[0]);
601 argv_copy
[1] = g_strdup ("--load-session");
602 argv_copy
[2] = g_strdup (g_getenv ("_NAUTILUS_RESTART_SESSION_FILENAME"));
604 g_unsetenv ("_NAUTILUS_RESTART_SESSION_FILENAME");
606 execvp (argv
[0], argv_copy
);
608 g_strfreev (argv_copy
);
611 g_object_unref (G_OBJECT (program
));