2 * Copyright © 2000-2002 Marco Pesenti Gritti
3 * Copyright © 2006 Christian Persch
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "ephy-shell.h"
25 #include "ephy-file-helpers.h"
26 #include "ephy-object-helpers.h"
27 #include "ephy-state.h"
28 #include "ephy-debug.h"
29 #include "ephy-stock-icons.h"
30 #include "eel-gconf-extensions.h"
31 #include "ephy-dbus-client-bindings.h"
32 #include "ephy-activation.h"
33 #include "ephy-session.h"
34 #include "ephy-shell.h"
35 #include "ephy-prefs.h"
36 #include "ephy-debug.h"
38 #include <libxml/xmlversion.h>
40 #include <glib/gi18n.h>
43 #include <gtk/gtkaboutdialog.h>
44 #include <gtk/gtkmain.h>
45 #include <gtk/gtkmessagedialog.h>
47 #include <libgnome/gnome-program.h>
48 #include <libgnomeui/gnome-ui-init.h>
50 #include <libgnomevfs/gnome-vfs-init.h>
51 #include <libgnomevfs/gnome-vfs-utils.h>
52 #include <libgnomeui/gnome-app-helper.h>
57 static GQuark startup_error_quark = 0;
58 #define STARTUP_ERROR_QUARK (startup_error_quark)
60 static gboolean open_in_new_tab = FALSE;
61 static gboolean open_in_new_window = FALSE;
62 static gboolean open_as_bookmarks_editor = FALSE;
63 /*static gboolean reload_plugins = FALSE;*/
65 static char *session_filename = NULL;
66 static char *bookmark_url = NULL;
67 static char *bookmarks_file = NULL;
68 static char **arguments = NULL;
70 /* Only set from options in debug builds */
71 static gboolean private_instance = FALSE;
72 static gboolean keep_temp_directory = FALSE;
73 static char *profile_directory = NULL;
75 static const GOptionEntry option_entries[] =
77 { "new-tab", 'n', 0, G_OPTION_ARG_NONE, &open_in_new_tab,
78 N_("Open a new tab in an existing browser window"), NULL },
79 { "new-window", 0, 0, G_OPTION_ARG_NONE, &open_in_new_window,
80 N_("Open a new browser window"), NULL },
81 { "bookmarks-editor", 'b', 0, G_OPTION_ARG_NONE, &open_as_bookmarks_editor,
82 N_("Launch the bookmarks editor"), NULL },
83 { "import-bookmarks", '\0', 0, G_OPTION_ARG_FILENAME, &bookmarks_file,
84 N_("Import bookmarks from the given file"), N_("FILE") },
85 { "load-session", 'l', 0, G_OPTION_ARG_FILENAME, &session_filename,
86 N_("Load the given session file"), N_("FILE") },
87 { "add-bookmark", 't', 0, G_OPTION_ARG_STRING, &bookmark_url,
88 N_("Add a bookmark"), N_("URL") },
89 { "private-instance", 'p', 0, G_OPTION_ARG_NONE, &private_instance,
90 N_("Start a private instance"), NULL },
91 { "profile", 0, 0, G_OPTION_ARG_STRING, &profile_directory,
92 N_("Profile directory to use in the private instance"), N_("DIR") },
93 { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &arguments,
98 #ifdef GNOME_ENABLE_DEBUG
99 static GOptionEntry debug_option_entries[] =
101 { "keep-tempdir", 0, 0, G_OPTION_ARG_NONE, &keep_temp_directory,
102 "Don't delete the temporary directory on exit", NULL },
105 #endif /* GNOME_ENABLE_DEBUG */
107 /* adapted from gtk+/gdk/x11/gdkdisplay-x11.c */
109 get_startup_id (void)
111 const char *startup_id, *time_str;
114 startup_id = g_getenv ("DESKTOP_STARTUP_ID");
115 if (startup_id == NULL) return 0;
117 /* Find the launch time from the startup_id, if it's there. Newer spec
118 * states that the startup_id is of the form <unique>_TIME<timestamp>
120 time_str = g_strrstr (startup_id, "_TIME");
121 if (time_str != NULL)
127 /* Skip past the "_TIME" part */
130 value = strtoul (time_str, &end, 0);
131 if (end != time_str && errno == 0)
133 retval = (guint32) value;
140 /* Copied from libnautilus/nautilus-program-choosing.c; Needed in case
141 * we have no DESKTOP_STARTUP_ID (with its accompanying timestamp).
144 slowly_and_stupidly_obtain_timestamp (Display *xdisplay)
150 XSetWindowAttributes attrs;
155 attrs.override_redirect = True;
156 attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
159 XCreateWindow (xdisplay,
160 RootWindow (xdisplay, 0),
166 CWOverrideRedirect | CWEventMask,
169 atom_name = XInternAtom (xdisplay, "WM_NAME", TRUE);
170 g_assert (atom_name != None);
171 atom_type = XInternAtom (xdisplay, "STRING", TRUE);
172 g_assert (atom_type != None);
174 name = "Fake Window";
175 XChangeProperty (xdisplay,
178 8, PropModeReplace, (unsigned char *)name, strlen (name));
181 XWindowEvent (xdisplay,
186 XDestroyWindow(xdisplay, xwindow);
188 return event.xproperty.time;
192 handle_url (GtkAboutDialog *about,
196 ephy_shell_new_tab (ephy_shell_get_default (),
198 EPHY_NEW_TAB_OPEN_PAGE);
202 handle_email (GtkAboutDialog *about,
208 address = g_strdup_printf ("mailto:%s", link);
209 gnome_vfs_url_show (address);
214 shell_weak_notify (gpointer data,
217 if (gtk_main_level ())
224 unref_proxy_reply_cb (DBusGProxy *proxy,
230 g_warning ("An error occured while calling remote method: %s", error->message);
231 g_error_free (error);/* FIXME??? */
234 g_object_unref (proxy);
236 if (gtk_main_level ())
243 open_urls (DBusGProxy *proxy,
247 static const char *empty_arguments[] = { "", NULL };
251 options = g_string_sized_new (64);
253 if (open_in_new_window)
255 g_string_append (options, "new-window,");
259 g_string_append (options, "new-tab,");
262 if (arguments == NULL)
264 uris = (char **) empty_arguments;
268 uris = (char **) arguments;
271 org_gnome_Epiphany_load_ur_ilist_async
272 (proxy, (const char **) uris, options->str, user_time,
273 unref_proxy_reply_cb, NULL);
275 if (arguments != NULL)
277 g_strfreev (arguments);
281 g_string_free (options, TRUE);
287 call_dbus_proxy (DBusGProxy *proxy,
292 gboolean retval = TRUE;
294 shell = ephy_shell_get_default ();
296 if (open_as_bookmarks_editor)
298 org_gnome_Epiphany_open_bookmarks_editor_async
300 unref_proxy_reply_cb, shell);
302 else if (session_filename != NULL)
304 org_gnome_Epiphany_load_session_async
305 (proxy, session_filename, user_time,
306 unref_proxy_reply_cb, shell);
308 g_free (session_filename);
309 session_filename = NULL;
313 retval = open_urls (proxy, user_time, error);
317 dbus_g_connection_flush (ephy_dbus_get_bus (ephy_dbus_get_default (), EPHY_DBUS_SESSION));
323 queue_commands (guint32 user_time)
326 EphySession *session;
328 shell = ephy_shell_get_default ();
329 g_assert (shell != NULL);
331 session = EPHY_SESSION (ephy_shell_get_session (shell));
332 g_assert (session != NULL);
334 /* We only get here when starting a new instance, so we
335 * first need to autoresume!
337 ephy_session_queue_command (session,
338 EPHY_SESSION_CMD_RESUME_SESSION,
339 NULL, NULL, user_time, TRUE);
341 if (open_as_bookmarks_editor)
343 ephy_session_queue_command (session,
344 EPHY_SESSION_CMD_OPEN_BOOKMARKS_EDITOR,
345 NULL, NULL, user_time, FALSE);
347 else if (session_filename != NULL)
349 ephy_session_queue_command (session,
350 EPHY_SESSION_CMD_LOAD_SESSION,
351 session_filename, NULL,
354 g_free (session_filename);
355 session_filename = NULL;
357 /* Don't queue any window openings if no extra arguments given,
358 * since session autoresume will open one for us.
360 else if (arguments != NULL)
364 options = g_string_sized_new (64);
366 if (open_in_new_window)
368 g_string_append (options, "new-window,");
372 g_string_append (options, "new-tab,");
375 ephy_session_queue_command (session,
376 EPHY_SESSION_CMD_OPEN_URIS,
381 g_strfreev (arguments);
387 show_error_message (GError **error)
391 /* FIXME better texts!!! */
392 dialog = gtk_message_dialog_new (NULL,
396 _("Could not start GNOME Web Browser"));
397 gtk_message_dialog_format_secondary_text
398 (GTK_MESSAGE_DIALOG (dialog),
399 _("Startup failed because of the following error:\n%s"),
402 g_clear_error (error);
404 gtk_dialog_run (GTK_DIALOG (dialog));
411 GnomeProgram *program;
412 GOptionContext *option_context;
413 GOptionGroup *option_group;
415 GError *error = NULL;
418 gboolean enable_pango;
419 #ifndef GNOME_PARAM_GOPTION_CONTEXT
420 GPtrArray *fake_argv_array;
424 /* Initialize the i18n stuff */
425 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
426 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
427 textdomain (GETTEXT_PACKAGE);
430 /* Threads have to be initialised before calling ANY glib function */
431 g_thread_init (NULL);
432 dbus_g_thread_init ();
434 /* check libxml2 API version epiphany was compiled with against the
435 * version we're running with.
439 /* If we're given -remote arguments, translate them */
441 strcmp (argv[1], "-remote") == 0)
443 const char *opening, *closing;
444 char *command, *argument;
449 g_print ("-remote allows exactly one argument\n");
453 opening = strchr (argv[2], '(');
454 closing = strchr (argv[2], ')');
456 if (opening == NULL ||
458 opening == argv[2] ||
459 opening + 1 >= closing)
461 g_print ("Invalid argument for -remote\n");
465 command = g_strstrip (g_strndup (argv[2], opening - argv[2]));
467 /* See http://lxr.mozilla.org/seamonkey/source/xpfe/components/xremote/src/XRemoteService.cpp
468 * for the commands that mozilla supports; we'll just support openURL here.
470 if (g_ascii_strcasecmp (command, "openURL") != 0)
472 g_print ("-remote command \"%s\" not supported\n", command);
479 argument = g_strstrip (g_strndup (opening + 1, closing - opening - 1));
480 arguments = g_strsplit (argument, ",", -1);
482 if (arguments == NULL)
484 g_print ("Invalid argument for -remote\n");
489 /* replace arguments */
490 argv[1] = g_strstrip (g_strdup (arguments[0]));
493 g_strfreev (arguments);
496 /* Initialise our debug helpers */
499 /* get this early, since gdk will unset the env var */
500 user_time = get_startup_id ();
502 option_context = g_option_context_new ("");
503 option_group = g_option_group_new ("epiphany",
504 N_("GNOME Web Browser"),
505 N_("GNOME Web Browser options"),
508 g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE);
510 g_option_group_add_entries (option_group, option_entries);
512 g_option_context_set_main_group (option_context, option_group);
514 #ifdef GNOME_ENABLE_DEBUG
515 option_group = g_option_group_new ("debug",
516 "Epiphany debug options",
517 "Epiphany debug options",
519 g_option_group_add_entries (option_group, debug_option_entries);
520 g_option_context_add_group (option_context, option_group);
521 #endif /* GNOME_ENABLE_DEBUG */
523 program = gnome_program_init (PACKAGE, VERSION,
524 LIBGNOMEUI_MODULE, argc, argv,
525 GNOME_PARAM_GOPTION_CONTEXT, option_context,
526 GNOME_PARAM_HUMAN_READABLE_NAME, _("Web Browser"),
527 GNOME_PARAM_APP_DATADIR, DATADIR,
530 /* libgnome keeps a reference to the global program, so drop
531 * our reference here, to simplify cleanup on the many exit paths.
533 g_object_unref (program);
535 /* Some argument sanity checks*/
536 if (arguments != NULL && (session_filename != NULL || open_as_bookmarks_editor))
538 g_print ("Cannot use --bookmarks-editor or --load-session with URL arguments\n");
542 if (profile_directory != NULL && private_instance == FALSE)
544 g_print ("--profile can only be used in combination with --private-instance\n");
548 if (arguments != NULL &&
549 eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_ARBITRARY_URL))
551 g_print ("URL loading is locked down\n");
555 /* Make URIs from arguments, to support filename args */
556 if (arguments != NULL)
560 for (i = 0; arguments[i] != NULL; ++i)
564 char rpath[PATH_MAX];
569 path = realpath (arguments[i], rpath);
572 uri = g_locale_to_utf8 (path, -1,
580 uri = g_locale_to_utf8 (arguments[i], -1,
586 g_free (arguments[i]);
588 /* If it's a file, use gnome_vfs_make_uri_from_shell_arg,
589 * so we get the right escaping.
593 arguments[i] = gnome_vfs_make_uri_from_shell_arg (uri);
603 g_print ("Could not convert '%s' to UTF-8: %s!\n",
604 arguments[i], error->message);
605 g_error_free (error);
611 /* Get a timestamp manually if need be */
614 user_time = slowly_and_stupidly_obtain_timestamp (gdk_display);
617 /* sets the name to appear in the window list applet when grouping windows */
618 g_set_application_name (_("Web Browser"));
620 /* Set default window icon */
621 gtk_window_set_default_icon_name (EPHY_STOCK_EPHY);
623 startup_error_quark = g_quark_from_static_string ("epiphany-startup-error");
625 if (!_ephy_dbus_startup (!private_instance, &error))
627 _ephy_dbus_release ();
629 show_error_message (&error);
634 /* If we're remoting, no need to start up any further services,
635 * just forward the call.
637 if (!private_instance &&
638 !_ephy_dbus_is_name_owner ())
640 /* Create DBUS proxy */
641 proxy = ephy_dbus_get_proxy (ephy_dbus_get_default (), EPHY_DBUS_SESSION);
644 error = g_error_new (STARTUP_ERROR_QUARK,
646 "Unable to get DBus proxy; aborting activation."); /* FIXME i18n */
648 _ephy_dbus_release ();
650 show_error_message (&error);
655 if (!call_dbus_proxy (proxy, user_time, &error))
657 _ephy_dbus_release ();
659 show_error_message (&error);
664 /* Wait for the response */
667 _ephy_dbus_release ();
669 gdk_notify_startup_complete ();
674 /* We're not remoting; start our services */
676 if (!ephy_file_helpers_init (profile_directory,
681 _ephy_dbus_release ();
683 show_error_message (&error);
688 eel_gconf_monitor_add ("/apps/epiphany/general");
689 ephy_stock_icons_init ();
691 /* Extensions may want these, so don't initialize in window-cmds */
692 gtk_about_dialog_set_url_hook (handle_url, NULL, NULL);
693 gtk_about_dialog_set_email_hook (handle_email, NULL, NULL);
695 /* Work around bug #328844, and avoid the gecko+pango performance problem */
696 env = g_getenv ("MOZ_ENABLE_PANGO");
697 enable_pango = env != NULL &&
699 g_ascii_strtoull (env, NULL, 10) != 0;
701 if (eel_gconf_get_boolean (CONF_GECKO_ENABLE_PANGO))
703 g_print ("NOTE: Enabling gecko pango renderer; this may cause performance degradation.\n"
704 "You can set " CONF_GECKO_ENABLE_PANGO " to \"false\" to disable it.\n");
706 else if (!enable_pango)
708 g_setenv ("MOZ_DISABLE_PANGO", "1", TRUE);
711 /* Work-around Flash Player crash */
712 g_setenv ("XLIB_SKIP_ARGB_VISUALS", "1", FALSE);
714 /* Now create the shell */
715 _ephy_shell_create_instance ();
717 queue_commands (user_time);
719 /* We'll release the initial reference on idle */
720 g_object_weak_ref (G_OBJECT (ephy_shell), shell_weak_notify, NULL);
721 ephy_object_idle_unref (ephy_shell);
726 eel_gconf_monitor_remove ("/apps/epiphany/general");
727 gnome_accelerators_sync ();
729 ephy_file_helpers_shutdown ();
730 gnome_vfs_shutdown ();
733 _ephy_dbus_release ();