/*
* Copyright (C) 2000-2004 Marco Pesenti Gritti
* Copyright (C) 2003, 2004 Christian Persch
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Id$
*/
#include "config.h"
#include "ephy-shell.h"
#include "ephy-type-builtins.h"
#include "ephy-embed-shell.h"
#include "eel-gconf-extensions.h"
#include "ephy-prefs.h"
#include "ephy-file-helpers.h"
#include "ephy-favicon-cache.h"
#include "ephy-window.h"
#include "ephy-bookmarks-import.h"
#include "ephy-bookmarks-editor.h"
#include "ephy-history-window.h"
#include "pdm-dialog.h"
#include "prefs-dialog.h"
#include "ephy-debug.h"
#include "ephy-extensions-manager.h"
#include "ephy-session.h"
#include "downloader-view.h"
#include "egg-toolbars-model.h"
#include "eggtypebuiltins.h"
#include "ephy-toolbars-model.h"
#include "ephy-toolbar.h"
#include "ephy-automation.h"
#include "print-dialog.h"
#ifdef ENABLE_DBUS
#include "ephy-dbus.h"
#endif
#include <string.h>
#include <bonobo/bonobo-main.h>
#include <glib/gi18n.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkmessagedialog.h>
#include <gtk/gtknotebook.h>
#include <dirent.h>
#include <unistd.h>
#include <libgnomeui/gnome-client.h>
#define AUTOMATION_IID "OAFIID:GNOME_Epiphany_Automation"
#define EPHY_SHELL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SHELL, EphyShellPrivate))
struct _EphyShellPrivate
{
BonoboGenericFactory *automation_factory;
EphySession *session;
EphyBookmarks *bookmarks;
EggToolbarsModel *toolbars_model;
guint toolbar_style_notifier_id;
EggToolbarsModel *fs_toolbars_model;
EphyExtensionsManager *extensions_manager;
GObject *dbus_service;
GtkWidget *bme;
GtkWidget *history_window;
GObject *pdm_dialog;
GObject *prefs_dialog;
GObject *print_setup_dialog;
GList *del_on_exit;
};
EphyShell *ephy_shell = NULL;
static void ephy_shell_class_init (EphyShellClass *klass);
static void ephy_shell_init (EphyShell *shell);
static void ephy_shell_finalize (GObject *object);
static GObjectClass *parent_class = NULL;
GQuark
ephy_shell_error_quark (void)
{
static GQuark q = 0;
if (q == 0)
{
q = g_quark_from_static_string ("ephy-shell-error-quark");
}
return q;
}
GType
ephy_shell_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0))
{
static const GTypeInfo our_info =
{
sizeof (EphyShellClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) ephy_shell_class_init,
NULL,
NULL, /* class_data */
sizeof (EphyShell),
0, /* n_preallocs */
(GInstanceInitFunc) ephy_shell_init
};
type = g_type_register_static (EPHY_TYPE_EMBED_SHELL,
"EphyShell",
&our_info, 0);
}
return type;
}
static void
ephy_shell_class_init (EphyShellClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = ephy_shell_finalize;
g_type_class_add_private (object_class, sizeof(EphyShellPrivate));
}
static BonoboObject *
ephy_automation_factory_cb (BonoboGenericFactory *this_factory,
const char *iid,
EphyShell *shell)
{
if (strcmp (iid, AUTOMATION_IID) == 0)
{
return BONOBO_OBJECT (g_object_new (EPHY_TYPE_AUTOMATION, NULL));
}
g_assert_not_reached ();
return NULL;
}
static BonoboGenericFactory *
ephy_automation_factory_new (EphyShell *shell)
{
BonoboGenericFactory *factory;
GClosure *factory_closure;
factory = g_object_new (bonobo_generic_factory_get_type (), NULL);
factory_closure = g_cclosure_new
(G_CALLBACK (ephy_automation_factory_cb), shell, NULL);
bonobo_generic_factory_construct_noreg
(factory, AUTOMATION_FACTORY_IID, factory_closure);
return factory;
}
static void
ephy_shell_init (EphyShell *shell)
{
EphyShell **ptr = &ephy_shell;
shell->priv = EPHY_SHELL_GET_PRIVATE (shell);
/* globally accessible singleton */
g_assert (ephy_shell == NULL);
ephy_shell = shell;
g_object_add_weak_pointer (G_OBJECT(ephy_shell),
(gpointer *)ptr);
/* Instantiate the automation factory */
shell->priv->automation_factory = ephy_automation_factory_new (shell);
}
static char *
path_from_command_line_arg (const char *arg)
{
char path[PATH_MAX];
if (realpath (arg, path) != NULL)
{
return g_strdup (path);
}
else
{
return g_strdup (arg);
}
}
static void
open_urls (GNOME_EphyAutomation automation,
const char **args, CORBA_Environment *ev,
gboolean new_tab, gboolean existing_window,
gboolean fullscreen)
{
int i;
if (args == NULL)
{
/* Homepage or resume */
GNOME_EphyAutomation_loadurl
(automation, "", fullscreen,
existing_window, new_tab, ev);
}
else
{
for (i = 0; args[i] != NULL; i++)
{
char *path;
path = path_from_command_line_arg (args[i]);
GNOME_EphyAutomation_loadurl
(automation, path, fullscreen,
existing_window, new_tab, ev);
g_free (path);
}
}
}
static gboolean
save_yourself_cb (GnomeClient *client,
gint phase,
GnomeSaveStyle save_style,
gboolean shutdown,
GnomeInteractStyle interact_style,
gboolean fast,
EphyShell *shell)
{
char *argv[] = { NULL, "--load-session", NULL };
char *discard_argv[] = { "rm", "-f", NULL };
EphySession *session;
char *tmp, *save_to;
LOG ("save_yourself_cb")
tmp = g_build_filename (ephy_dot_dir (),
"session_gnome-XXXXXX",
NULL);
save_to = ephy_file_tmp_filename (tmp, "xml");
g_free (tmp);
session = EPHY_SESSION (ephy_shell_get_session (shell));
argv[0] = g_get_prgname ();
argv[2] = save_to;
gnome_client_set_restart_command
(client, 3, argv);
discard_argv[2] = save_to;
gnome_client_set_discard_command (client, 3,
discard_argv);
ephy_session_save (session, save_to);
g_free (save_to);
return TRUE;
}
static void
die_cb (GnomeClient* client,
EphyShell *shell)
{
EphySession *session;
LOG ("die_cb")
session = EPHY_SESSION (ephy_shell_get_session (shell));
ephy_session_close (session);
}
static void
gnome_session_init (EphyShell *shell)
{
GnomeClient *client;
client = gnome_master_client ();
g_signal_connect (G_OBJECT (client),
"save_yourself",
G_CALLBACK (save_yourself_cb),
shell);
g_signal_connect (G_OBJECT (client),
"die",
G_CALLBACK (die_cb),
shell);
}
gboolean
ephy_shell_startup (EphyShell *shell,
EphyShellStartupFlags flags,
const char **args,
const char *string_arg,
GError **error)
{
CORBA_Environment ev;
GNOME_EphyAutomation automation;
Bonobo_RegistrationResult result;
ephy_ensure_dir_exists (ephy_dot_dir ());
CORBA_exception_init (&ev);
result = bonobo_activation_register_active_server
(AUTOMATION_FACTORY_IID, BONOBO_OBJREF (shell->priv->automation_factory), NULL);
switch (result)
{
case Bonobo_ACTIVATION_REG_SUCCESS:
break;
case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE:
break;
case Bonobo_ACTIVATION_REG_NOT_LISTED:
g_set_error (error, EPHY_SHELL_ERROR,
EPHY_SHELL_ERROR_MISSING_SERVER,
_("Bonobo couldn't locate the GNOME_Epiphany_Automation.server "
"file. You can use bonobo-activation-sysconf to configure "
"the search path for bonobo server files."));
break;
case Bonobo_ACTIVATION_REG_ERROR:
g_set_error (error, EPHY_SHELL_ERROR,
EPHY_SHELL_ERROR_FACTORY_REG_FAILED,
_("Epiphany can't be used now, due to an unexpected error "
"from Bonobo when attempting to register the automation "
"server"));
break;
default:
g_assert_not_reached ();
}
if (result == Bonobo_ACTIVATION_REG_SUCCESS ||
result == Bonobo_ACTIVATION_REG_ALREADY_ACTIVE)
{
automation = bonobo_activation_activate_from_id (AUTOMATION_IID,
0, NULL, &ev);
if (CORBA_Object_is_nil (automation, &ev))
{
g_set_error (error, EPHY_SHELL_ERROR,
EPHY_SHELL_ERROR_OBJECT_REG_FAILED,
_("Epiphany can't be used now, due to an unexpected error "
"from Bonobo when attempting to locate the automation "
"object."));
automation = NULL;
}
else if (flags & EPHY_SHELL_STARTUP_BOOKMARKS_EDITOR)
{
GNOME_EphyAutomation_openBookmarksEditor
(automation, &ev);
}
else if (flags & EPHY_SHELL_STARTUP_SESSION)
{
GNOME_EphyAutomation_loadSession
(automation, string_arg, &ev);
}
else if (flags & EPHY_SHELL_STARTUP_IMPORT_BOOKMARKS)
{
GNOME_EphyAutomation_importBookmarks
(automation, string_arg, &ev);
}
else if (flags & EPHY_SHELL_STARTUP_ADD_BOOKMARK)
{
GNOME_EphyAutomation_addBookmark
(automation, string_arg, &ev);
}
else
{
open_urls (automation, args, &ev,
flags & EPHY_SHELL_STARTUP_TABS,
flags & EPHY_SHELL_STARTUP_EXISTING_WINDOW,
flags & EPHY_SHELL_STARTUP_FULLSCREEN);
}
if (automation)
{
bonobo_object_release_unref (automation, &ev);
}
gnome_session_init (shell);
}
CORBA_exception_free (&ev);
gdk_notify_startup_complete ();
return !(result == Bonobo_ACTIVATION_REG_ALREADY_ACTIVE);
}
static void
ephy_shell_finalize (GObject *object)
{
EphyShell *shell = EPHY_SHELL (object);
g_assert (ephy_shell == NULL);
/* this will unload the extensions */
LOG ("Unref extension manager")
if (shell->priv->extensions_manager)
{
g_object_unref (shell->priv->extensions_manager);
}
#ifdef ENABLE_DBUS
LOG ("Shutting down DBUS service")
if (shell->priv->dbus_service)
{
g_object_unref (shell->priv->dbus_service);
}
#endif
LOG ("Unref session manager")
if (shell->priv->session)
{
g_object_unref (shell->priv->session);
}
LOG ("Unref toolbars model")
if (shell->priv->toolbars_model)
if (shell->priv->toolbar_style_notifier_id != 0)
{
eel_gconf_notification_remove (shell->priv->toolbar_style_notifier_id);
}
{
g_object_unref (shell->priv->toolbars_model);
}
LOG ("Unref fullscreen toolbars model")
if (shell->priv->fs_toolbars_model)
{
g_object_unref (shell->priv->fs_toolbars_model);
}
LOG ("Unref Bookmarks Editor");
if (shell->priv->bme)
{
gtk_widget_destroy (GTK_WIDGET (shell->priv->bme));
}
LOG ("Unref History Window");
if (shell->priv->history_window)
{
gtk_widget_destroy (GTK_WIDGET (shell->priv->history_window));
}
LOG ("Unref PDM Dialog")
if (shell->priv->pdm_dialog)
{
g_object_unref (shell->priv->pdm_dialog);
}
LOG ("Unref prefs dialog")
if (shell->priv->prefs_dialog)
{
g_object_unref (shell->priv->prefs_dialog);
}
LOG ("Unref print setup dialog")
if (shell->priv->print_setup_dialog)
{
g_object_unref (shell->priv->print_setup_dialog);
}
LOG ("Unref bookmarks")
if (shell->priv->bookmarks)
{
g_object_unref (shell->priv->bookmarks);
}
G_OBJECT_CLASS (parent_class)->finalize (object);
if (shell->priv->automation_factory)
{
bonobo_activation_unregister_active_server
(AUTOMATION_FACTORY_IID, BONOBO_OBJREF (shell->priv->automation_factory));
bonobo_object_unref (shell->priv->automation_factory);
}
LOG ("Ephy shell finalized")
}
EphyShell *
ephy_shell_new (void)
{
return EPHY_SHELL (g_object_new (EPHY_TYPE_SHELL, NULL));
}
static void
load_homepage (EphyEmbed *embed)
{
char *home;
home = eel_gconf_get_string(CONF_GENERAL_HOMEPAGE);
if (home == NULL || home[0] == '\0')
{
g_free (home);
home = g_strdup ("about:blank");
}
ephy_embed_load_url (embed, home);
g_free (home);
}
/**
* ephy_shell_new_tab:
* @shell: a #EphyShell
* @parent_window: the target #EphyWindow or %NULL
* @previous_tab: the referrer tab or %NULL
* @url: an url to load or %NULL
*
* Create a new tab and the parent window when necessary.
* Use this function to open urls in new window/tabs.
*
* ReturnValue: the created #EphyTab
**/
EphyTab *
ephy_shell_new_tab (EphyShell *shell,
EphyWindow *parent_window,
EphyTab *previous_tab,
const char *url,
EphyNewTabFlags flags)
{
EphyWindow *window;
EphyTab *tab;
EphyEmbed *embed;
gboolean in_new_window = TRUE;
gboolean jump_to;
EphyEmbed *previous_embed = NULL;
GtkWidget *nb;
int position = -1;
EphyToolbar *toolbar;
if (flags & EPHY_NEW_TAB_IN_NEW_WINDOW) in_new_window = TRUE;
if (flags & EPHY_NEW_TAB_IN_EXISTING_WINDOW) in_new_window = FALSE;
in_new_window = in_new_window && !eel_gconf_get_boolean (CONF_LOCKDOWN_FULLSCREEN);
jump_to = (flags & EPHY_NEW_TAB_JUMP) != 0;
LOG ("Opening new tab parent-window %p parent-tab %p in-new-window:%s jump-to:%s",
parent_window, previous_tab, in_new_window ? "t" : "f", jump_to ? "t" : "f")
if (!in_new_window && parent_window != NULL)
{
window = parent_window;
}
else
{
window = ephy_window_new ();
}
toolbar = EPHY_TOOLBAR (ephy_window_get_toolbar (window));
if (previous_tab != NULL)
{
previous_embed = ephy_tab_get_embed (previous_tab);
}
if ((flags & EPHY_NEW_TAB_APPEND_AFTER) && previous_tab != NULL)
{
nb = ephy_window_get_notebook (window);
position = gtk_notebook_page_num (GTK_NOTEBOOK (nb),
GTK_WIDGET (previous_tab)) + 1;
}
tab = ephy_tab_new ();
gtk_widget_show (GTK_WIDGET (tab));
embed = ephy_tab_get_embed (tab);
ephy_window_add_tab (window, tab, position, jump_to);
gtk_widget_show (GTK_WIDGET (window));
if (flags & EPHY_NEW_TAB_HOME_PAGE ||
flags & EPHY_NEW_TAB_NEW_PAGE)
{
ephy_tab_set_location (tab, "", EPHY_TAB_ADDRESS_EXPIRE_NEXT);
ephy_toolbar_activate_location (toolbar);
load_homepage (embed);
}
else if (flags & EPHY_NEW_TAB_OPEN_PAGE)
{
g_assert (url != NULL);
ephy_embed_load_url (embed, url);
}
if (flags & EPHY_NEW_TAB_FULLSCREEN_MODE)
{
gtk_window_fullscreen (GTK_WINDOW (window));
}
return tab;
}
/**
* ephy_shell_get_session:
* @shell: the #EphyShell
*
* Returns current session.
*
* Return value: the current session.
**/
GObject *
ephy_shell_get_session (EphyShell *shell)
{
g_return_val_if_fail (EPHY_IS_SHELL (shell), NULL);
if (shell->priv->session == NULL)
{
EphyExtensionsManager *manager;
shell->priv->session = g_object_new (EPHY_TYPE_SESSION, NULL);
manager = EPHY_EXTENSIONS_MANAGER
(ephy_shell_get_extensions_manager (shell));
ephy_extensions_manager_register (manager,
G_OBJECT (shell->priv->session));
}
return G_OBJECT (shell->priv->session);
}
EphyBookmarks *
ephy_shell_get_bookmarks (EphyShell *shell)
{
if (shell->priv->bookmarks == NULL)
{
shell->priv->bookmarks = ephy_bookmarks_new ();
}
return shell->priv->bookmarks;
}
static void
toolbar_style_notifier (GConfClient *client,
guint cnxn_id,
GConfEntry *entry,
EphyShell *shell)
{
EggToolbarsModel *model = shell->priv->toolbars_model;
GFlagsClass *flags_class;
const GFlagsValue *value;
EggTbModelFlags flags, new_flags = 0;
char *pref;
int i, n_toolbars;
g_return_if_fail (model != NULL);
pref = eel_gconf_get_string (CONF_INTERFACE_TOOLBAR_STYLE);
if (pref != NULL)
{
flags_class = g_type_class_ref (EGG_TYPE_TB_MODEL_FLAGS);
value = g_flags_get_value_by_nick (flags_class, pref);
if (value != NULL)
{
new_flags = value->value;
}
g_type_class_unref (flags_class);
}
new_flags &= EGG_TB_MODEL_STYLES_MASK;
n_toolbars = egg_toolbars_model_n_toolbars (model);
for (i = 0; i < n_toolbars; i++)
{
flags = egg_toolbars_model_get_flags (model, i);
flags &= ~EGG_TB_MODEL_STYLES_MASK;
flags |= new_flags;
egg_toolbars_model_set_flags (model, i, new_flags);
}
}
GObject *
ephy_shell_get_toolbars_model (EphyShell *shell, gboolean fullscreen)
{
LOG ("ephy_shell_get_toolbars_model fs=%d", fullscreen)
if (fullscreen)
{
if (shell->priv->fs_toolbars_model == NULL)
{
gboolean success;
const char *xml;
shell->priv->fs_toolbars_model = egg_toolbars_model_new ();
xml = ephy_file ("epiphany-fs-toolbar.xml");
g_return_val_if_fail (xml != NULL, NULL);
success = egg_toolbars_model_load
(shell->priv->fs_toolbars_model, xml);
g_return_val_if_fail (success, NULL);
}
return G_OBJECT (shell->priv->fs_toolbars_model);
}
else
{
if (shell->priv->toolbars_model == NULL)
{
EphyBookmarks *bookmarks;
GObject *bookmarksbar_model;
shell->priv->toolbars_model = ephy_toolbars_model_new ();
/* get the bookmarks toolbars model. we have to do this
* before loading the toolbars model from disk, since
* this will connect the get_item_* signals
*/
bookmarks = ephy_shell_get_bookmarks (shell);
bookmarksbar_model = ephy_bookmarks_get_toolbars_model (bookmarks);
/* ok, now we can load the model */
ephy_toolbars_model_load
(EPHY_TOOLBARS_MODEL (shell->priv->toolbars_model));
toolbar_style_notifier (NULL, 0, NULL, shell);
shell->priv->toolbar_style_notifier_id = eel_gconf_notification_add
(CONF_INTERFACE_TOOLBAR_STYLE,
(GConfClientNotifyFunc) toolbar_style_notifier, shell);
}
return G_OBJECT (shell->priv->toolbars_model);
}
}
GObject *
ephy_shell_get_extensions_manager (EphyShell *es)
{
g_return_val_if_fail (EPHY_IS_SHELL (es), NULL);
if (es->priv->extensions_manager == NULL)
{
/* Instantiate extensions manager */
es->priv->extensions_manager =
g_object_new (EPHY_TYPE_EXTENSIONS_MANAGER, NULL);
ephy_extensions_manager_startup (es->priv->extensions_manager);
}
return G_OBJECT (es->priv->extensions_manager);
}
static void
toolwindow_show_cb (GtkWidget *widget, EphyShell *es)
{
EphySession *session;
LOG ("Ref shell for %s", G_OBJECT_TYPE_NAME (widget))
session = EPHY_SESSION (ephy_shell_get_session (es));
ephy_session_add_window (ephy_shell->priv->session, GTK_WINDOW (widget));
g_object_ref (ephy_shell);
}
static void
toolwindow_hide_cb (GtkWidget *widget, EphyShell *es)
{
EphySession *session;
LOG ("Unref shell for %s", G_OBJECT_TYPE_NAME (widget))
session = EPHY_SESSION (ephy_shell_get_session (es));
ephy_session_remove_window (ephy_shell->priv->session, GTK_WINDOW (widget));
g_object_unref (ephy_shell);
}
GtkWidget *
ephy_shell_get_bookmarks_editor (EphyShell *shell)
{
EphyBookmarks *bookmarks;
if (shell->priv->bme == NULL)
{
bookmarks = ephy_shell_get_bookmarks (ephy_shell);
g_assert (bookmarks != NULL);
shell->priv->bme = ephy_bookmarks_editor_new (bookmarks);
g_signal_connect (shell->priv->bme, "show",
G_CALLBACK (toolwindow_show_cb), shell);
g_signal_connect (shell->priv->bme, "hide",
G_CALLBACK (toolwindow_hide_cb), shell);
}
return shell->priv->bme;
}
GtkWidget *
ephy_shell_get_history_window (EphyShell *shell)
{
EphyHistory *history;
if (shell->priv->history_window == NULL)
{
history = EPHY_HISTORY
(ephy_embed_shell_get_global_history (embed_shell));
g_assert (history != NULL);
shell->priv->history_window = ephy_history_window_new (history);
g_signal_connect (shell->priv->history_window, "show",
G_CALLBACK (toolwindow_show_cb), shell);
g_signal_connect (shell->priv->history_window, "hide",
G_CALLBACK (toolwindow_hide_cb), shell);
}
return shell->priv->history_window;
}
GObject *
ephy_shell_get_pdm_dialog (EphyShell *shell)
{
if (shell->priv->pdm_dialog == NULL)
{
shell->priv->pdm_dialog = g_object_new (EPHY_TYPE_PDM_DIALOG, NULL);
g_object_add_weak_pointer (shell->priv->pdm_dialog,
(gpointer *) &shell->priv->pdm_dialog);
}
return shell->priv->pdm_dialog;
}
GObject *
ephy_shell_get_prefs_dialog (EphyShell *shell)
{
if (shell->priv->prefs_dialog == NULL)
{
shell->priv->prefs_dialog = g_object_new (EPHY_TYPE_PREFS_DIALOG, NULL);
g_object_add_weak_pointer (shell->priv->prefs_dialog,
(gpointer *) &shell->priv->prefs_dialog);
}
return shell->priv->prefs_dialog;
}
GObject *
ephy_shell_get_print_setup_dialog (EphyShell *shell)
{
if (shell->priv->print_setup_dialog == NULL)
{
shell->priv->print_setup_dialog = G_OBJECT (ephy_print_setup_dialog_new ());
g_object_add_weak_pointer (shell->priv->print_setup_dialog,
(gpointer *) &shell->priv->print_setup_dialog);
}
return shell->priv->print_setup_dialog;
}
#ifdef ENABLE_DBUS
GObject *
ephy_shell_get_dbus_service (EphyShell *shell)
{
g_return_val_if_fail (EPHY_IS_SHELL (shell), NULL);
if (shell->priv->dbus_service == NULL)
{
shell->priv->dbus_service = g_object_new (EPHY_TYPE_DBUS, NULL);
ephy_dbus_startup (EPHY_DBUS (shell->priv->dbus_service));
}
return G_OBJECT (shell->priv->dbus_service);
}
#endif