Initial import of ephy (rev# 7126) from svn
[ephy-soc.git] / src / .svn / text-base / ephy-main.c.svn-base
blobb3f0dc30c1c66bbff93337e302edb7a247c2e693
1 /*
2  *  Copyright © 2000-2002 Marco Pesenti Gritti
3  *  Copyright © 2006 Christian Persch
4  *
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)
8  *  any later version.
9  *
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.
14  *
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.
18  *
19  *  $Id$
20  */
22 #include "config.h"
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>
42 #include <gdk/gdkx.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>
54 #include <errno.h>
55 #include <string.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,
94           "", N_("URL …")},
95         { NULL }
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 },
103         { NULL }
105 #endif /* GNOME_ENABLE_DEBUG */
107 /* adapted from gtk+/gdk/x11/gdkdisplay-x11.c */
108 static guint32
109 get_startup_id (void)
111         const char *startup_id, *time_str;
112         guint32 retval = 0;
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>
119         */
120         time_str = g_strrstr (startup_id, "_TIME");
121         if (time_str != NULL)
122         {
123                 gulong value;
124                 gchar *end;
125                 errno = 0;
126         
127                 /* Skip past the "_TIME" part */
128                 time_str += 5;
129         
130                 value = strtoul (time_str, &end, 0);
131                 if (end != time_str && errno == 0)
132                 {
133                         retval = (guint32) value;
134                 }
135         }
137         return retval;
140 /* Copied from libnautilus/nautilus-program-choosing.c; Needed in case
141  * we have no DESKTOP_STARTUP_ID (with its accompanying timestamp).
142  */
143 static Time
144 slowly_and_stupidly_obtain_timestamp (Display *xdisplay)
146         Window xwindow;
147         XEvent event;
148         
149         {
150                 XSetWindowAttributes attrs;
151                 Atom atom_name;
152                 Atom atom_type;
153                 char* name;
154                 
155                 attrs.override_redirect = True;
156                 attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
157                 
158                 xwindow =
159                         XCreateWindow (xdisplay,
160                                        RootWindow (xdisplay, 0),
161                                        -100, -100, 1, 1,
162                                        0,
163                                        CopyFromParent,
164                                        CopyFromParent,
165                                        CopyFromParent,
166                                        CWOverrideRedirect | CWEventMask,
167                                        &attrs);
168                 
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);
173                 
174                 name = "Fake Window";
175                 XChangeProperty (xdisplay, 
176                                  xwindow, atom_name,
177                                  atom_type,
178                                  8, PropModeReplace, (unsigned char *)name, strlen (name));
179         }
180         
181         XWindowEvent (xdisplay,
182                       xwindow,
183                       PropertyChangeMask,
184                       &event);
185         
186         XDestroyWindow(xdisplay, xwindow);
187         
188         return event.xproperty.time;
191 static void
192 handle_url (GtkAboutDialog *about,
193             const char *link,
194             gpointer data)
196         ephy_shell_new_tab (ephy_shell_get_default (),
197                             NULL, NULL, link,
198                             EPHY_NEW_TAB_OPEN_PAGE);
201 static void
202 handle_email (GtkAboutDialog *about,
203               const char *link,
204               gpointer data)
206         char *address;
208         address = g_strdup_printf ("mailto:%s", link);
209         gnome_vfs_url_show (address);
210         g_free (address);
213 static void
214 shell_weak_notify (gpointer data,
215                    GObject *zombie)
217         if (gtk_main_level ())
218         {
219                 gtk_main_quit ();
220         }
223 static void
224 unref_proxy_reply_cb (DBusGProxy *proxy,
225                       GError *error,
226                       gpointer user_data)
228         if (error != NULL)
229         {
230                 g_warning ("An error occured while calling remote method: %s", error->message);
231                 g_error_free (error);/* FIXME??? */
232         }
234         g_object_unref (proxy);
236         if (gtk_main_level ())
237         {
238                 gtk_main_quit ();
239         }
242 static gboolean
243 open_urls (DBusGProxy *proxy,
244            guint32 user_time,
245            GError **error)
247         static const char *empty_arguments[] = { "", NULL };
248         GString *options;
249         char **uris;
251         options = g_string_sized_new (64);
253         if (open_in_new_window)
254         {
255                 g_string_append (options, "new-window,");
256         }
257         if (open_in_new_tab)
258         {
259                 g_string_append (options, "new-tab,");
260         }
262         if (arguments == NULL)
263         {
264                 uris = (char **) empty_arguments;
265         }
266         else
267         {
268                 uris = (char **) arguments;
269         }
271         org_gnome_Epiphany_load_ur_ilist_async
272                 (proxy, (const char **) uris, options->str, user_time,
273                  unref_proxy_reply_cb, NULL);
274         
275         if (arguments != NULL)
276         {
277                 g_strfreev (arguments);
278                 arguments = NULL;
279         }
281         g_string_free (options, TRUE);
283         return TRUE;
286 static gboolean
287 call_dbus_proxy (DBusGProxy *proxy,
288                  guint32 user_time,
289                  GError **error)
291         EphyShell *shell;
292         gboolean retval = TRUE;
294         shell = ephy_shell_get_default ();
296         if (open_as_bookmarks_editor)
297         {
298                 org_gnome_Epiphany_open_bookmarks_editor_async
299                         (proxy, user_time,
300                          unref_proxy_reply_cb, shell);
301         }
302         else if (session_filename != NULL)
303         {
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;
310         }
311         else
312         {
313                 retval = open_urls (proxy, user_time, error);
314         }
316         /* FIXME why? */
317         dbus_g_connection_flush (ephy_dbus_get_bus (ephy_dbus_get_default (), EPHY_DBUS_SESSION));
319         return retval;
322 static void
323 queue_commands (guint32 user_time)
325         EphyShell *shell;
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!
336          */
337         ephy_session_queue_command (session,
338                                     EPHY_SESSION_CMD_RESUME_SESSION,
339                                     NULL, NULL, user_time, TRUE);
341         if (open_as_bookmarks_editor)
342         {
343                 ephy_session_queue_command (session,
344                                             EPHY_SESSION_CMD_OPEN_BOOKMARKS_EDITOR,
345                                             NULL, NULL, user_time, FALSE);
346         }
347         else if (session_filename != NULL)
348         {
349                 ephy_session_queue_command (session,
350                                             EPHY_SESSION_CMD_LOAD_SESSION,
351                                             session_filename, NULL,
352                                             user_time, FALSE);
354                 g_free (session_filename);
355                 session_filename = NULL;
356         }
357         /* Don't queue any window openings if no extra arguments given,
358          * since session autoresume will open one for us.
359          */
360         else if (arguments != NULL)
361         {
362                 GString *options;
364                 options = g_string_sized_new (64);
366                 if (open_in_new_window)
367                 {
368                         g_string_append (options, "new-window,");
369                 }
370                 if (open_in_new_tab)
371                 {
372                         g_string_append (options, "new-tab,");
373                 }
375                 ephy_session_queue_command (session,
376                                             EPHY_SESSION_CMD_OPEN_URIS,
377                                             options->str,
378                                             arguments,
379                                             user_time, FALSE);
381                 g_strfreev (arguments);
382                 arguments = NULL;
383         }
386 static void
387 show_error_message (GError **error)
389         GtkWidget *dialog;
391         /* FIXME better texts!!! */
392         dialog = gtk_message_dialog_new (NULL,
393                                          GTK_DIALOG_MODAL,
394                                          GTK_MESSAGE_ERROR,
395                                          GTK_BUTTONS_CLOSE,
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"),
400                  (*error)->message);
402         g_clear_error (error);
404         gtk_dialog_run (GTK_DIALOG (dialog));
408 main (int argc,
409       char *argv[])
411         GnomeProgram *program;
412         GOptionContext *option_context;
413         GOptionGroup *option_group;
414         DBusGProxy *proxy;
415         GError *error = NULL;
416         guint32 user_time;
417         const char *env;
418         gboolean enable_pango;
419 #ifndef GNOME_PARAM_GOPTION_CONTEXT
420         GPtrArray *fake_argv_array;
421 #endif
423 #ifdef ENABLE_NLS
424         /* Initialize the i18n stuff */
425         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
426         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
427         textdomain (GETTEXT_PACKAGE);
428 #endif
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.
436          */
437         LIBXML_TEST_VERSION;
439         /* If we're given -remote arguments, translate them */
440         if (argc >= 2 &&
441             strcmp (argv[1], "-remote") == 0)
442         {
443                 const char *opening, *closing;
444                 char *command, *argument;
445                 char **arguments;
447                 if (argc != 3)
448                 {
449                         g_print ("-remote allows exactly one argument\n");
450                         exit (1);
451                 }
453                 opening = strchr (argv[2], '(');
454                 closing = strchr (argv[2], ')');
456                 if (opening == NULL ||
457                     closing == NULL ||
458                     opening == argv[2] ||
459                     opening + 1 >= closing)
460                 {
461                         g_print ("Invalid argument for -remote\n");
462                         exit (1);
463                 }
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.
469                  */
470                 if (g_ascii_strcasecmp (command, "openURL") != 0)
471                 {
472                         g_print ("-remote command \"%s\" not supported\n", command);
473                         g_free (command);
474                         exit (1);
475                 }
477                 g_free (command);
479                 argument = g_strstrip (g_strndup (opening + 1, closing - opening - 1));
480                 arguments = g_strsplit (argument, ",", -1);
481                 g_free (argument);
482                 if (arguments == NULL)
483                 {
484                         g_print ("Invalid argument for -remote\n");
486                         exit (1);
487                 }
489                 /* replace arguments */
490                 argv[1] = g_strstrip (g_strdup (arguments[0]));
491                 argc = 2;
493                 g_strfreev (arguments);
494         }
496         /* Initialise our debug helpers */
497         ephy_debug_init ();
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"),
506                                            NULL, NULL);
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",
518                                            NULL, NULL);
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,
528                                       NULL);
530         /* libgnome keeps a reference to the global program, so drop
531          * our reference here, to simplify cleanup on the many exit paths.
532          */
533         g_object_unref (program);
535         /* Some argument sanity checks*/
536         if (arguments != NULL && (session_filename != NULL || open_as_bookmarks_editor))
537         {
538                 g_print ("Cannot use --bookmarks-editor or --load-session with URL arguments\n");
539                 exit (1);
540         }
542         if (profile_directory != NULL && private_instance == FALSE)
543         {
544                 g_print ("--profile can only be used in combination with --private-instance\n");
545                 exit (1);
546         }
548         if (arguments != NULL &&
549             eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_ARBITRARY_URL))
550         {
551                 g_print ("URL loading is locked down\n");
552                 exit (1);
553         }
555         /* Make URIs from arguments, to support filename args */
556         if (arguments != NULL)
557         {
558                 guint i;
560                 for (i = 0; arguments[i] != NULL; ++i)
561                 {
562                         char *uri, *path;
563 #ifdef PATH_MAX
564                         char rpath[PATH_MAX];
565 #else
566                         char *rpath = NULL;
567 #endif
569                         path = realpath (arguments[i], rpath);
570                         if (path != NULL)
571                         {
572                                 uri = g_locale_to_utf8 (path, -1, 
573                                                         NULL, NULL, &error);
574 #ifndef PATH_MAX
575                                 free (path);
576 #endif
577                         }
578                         else
579                         {
580                                 uri = g_locale_to_utf8 (arguments[i], -1, 
581                                                         NULL, NULL, &error);
582                         }
584                         if (uri != NULL)
585                         {
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.
590                                  */
591                                 if (path != NULL)
592                                 {
593                                         arguments[i] = gnome_vfs_make_uri_from_shell_arg (uri);
594                                         g_free (uri);
595                                 }
596                                 else
597                                 {
598                                         arguments[i] = uri;
599                                 }
600                         }
601                         else
602                         {
603                                 g_print ("Could not convert '%s' to UTF-8: %s!\n",
604                                          arguments[i], error->message);
605                                 g_error_free (error);
606                                 exit (1);
607                         }
608                 }
609         }
611         /* Get a timestamp manually if need be */
612         if (user_time == 0)
613         {
614                 user_time = slowly_and_stupidly_obtain_timestamp (gdk_display);
615         }
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))
626         {
627                 _ephy_dbus_release ();
629                 show_error_message (&error);
631                 exit (1);
632         }
634         /* If we're remoting, no need to start up any further services,
635          * just forward the call.
636          */
637         if (!private_instance &&
638             !_ephy_dbus_is_name_owner ())
639         {
640                 /* Create DBUS proxy */
641                 proxy = ephy_dbus_get_proxy (ephy_dbus_get_default (), EPHY_DBUS_SESSION);
642                 if (proxy == NULL)
643                 {
644                         error = g_error_new (STARTUP_ERROR_QUARK,
645                                              0,
646                                              "Unable to get DBus proxy; aborting activation."); /* FIXME i18n */
648                         _ephy_dbus_release ();
650                         show_error_message (&error);
652                         exit (1);
653                 }
655                 if (!call_dbus_proxy (proxy, user_time, &error))
656                 {
657                         _ephy_dbus_release ();
659                         show_error_message (&error);
661                         exit (1);
662                 }
664                 /* Wait for the response */
665                 gtk_main ();
667                 _ephy_dbus_release ();
669                 gdk_notify_startup_complete ();
671                 exit (0);
672         }
674         /* We're not remoting; start our services */
676         if (!ephy_file_helpers_init (profile_directory,
677                                      private_instance,
678                                      keep_temp_directory,
679                                      &error))
680         {
681                 _ephy_dbus_release ();
683                 show_error_message (&error);
685                 exit (1);
686         }
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 &&
698                        env[0] != '\0' &&
699                        g_ascii_strtoull (env, NULL, 10) != 0;
701         if (eel_gconf_get_boolean (CONF_GECKO_ENABLE_PANGO))
702         {
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");
705         }
706         else if (!enable_pango)
707         {
708                 g_setenv ("MOZ_DISABLE_PANGO", "1", TRUE);
709         }
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);
723         gtk_main ();
725         /* Shutdown */
726         eel_gconf_monitor_remove ("/apps/epiphany/general");
727         gnome_accelerators_sync ();
728         ephy_state_save ();
729         ephy_file_helpers_shutdown ();
730         gnome_vfs_shutdown ();
731         xmlCleanupParser ();
733         _ephy_dbus_release ();
735         return 0;