/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright © 2000-2004 Marco Pesenti Gritti * Copyright © 2003, 2004, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "config.h" #include #include #include #include #include #include "ephy-shell.h" #include "ephy-type-builtins.h" #include "ephy-embed-container.h" #include "ephy-embed-shell.h" #include "ephy-embed-single.h" #include "ephy-embed-utils.h" #include "eel-gconf-extensions.h" #include "ephy-prefs.h" #include "ephy-file-helpers.h" #include "ephy-favicon-cache.h" #include "ephy-web-view.h" #include "ephy-embed-utils.h" #include "ephy-window.h" #include "ephy-bookmarks-ui.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 "ephy-lockdown.h" #include "downloader-view.h" #include "egg-toolbars-model.h" #include "ephy-toolbars-model.h" #include "ephy-toolbar.h" #include "ephy-prefs.h" #include "ephy-gui.h" #include "ephy-stock-icons.h" #include "ephy-web-view.h" #ifdef ENABLE_NETWORK_MANAGER #include "ephy-net-monitor.h" #endif #define EPHY_SHELL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SHELL, EphyShellPrivate)) struct _EphyShellPrivate { EphySession *session; GObject *lockdown; EphyBookmarks *bookmarks; EggToolbarsModel *toolbars_model; EggToolbarsModel *fs_toolbars_model; EphyExtensionsManager *extensions_manager; #ifdef ENABLE_NETWORK_MANAGER EphyNetMonitor *net_monitor; #endif GtkWidget *bme; GtkWidget *history_window; GObject *pdm_dialog; GObject *prefs_dialog; GList *del_on_exit; guint embed_single_connected : 1; }; EphyShell *ephy_shell = NULL; static void ephy_shell_class_init (EphyShellClass *klass); static void ephy_shell_init (EphyShell *shell); static void ephy_shell_dispose (GObject *object); static void ephy_shell_finalize (GObject *object); static GObject *impl_get_embed_single (EphyEmbedShell *embed_shell); G_DEFINE_TYPE (EphyShell, ephy_shell, EPHY_TYPE_EMBED_SHELL) static void ephy_shell_class_init (EphyShellClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); EphyEmbedShellClass *embed_shell_class = EPHY_EMBED_SHELL_CLASS (klass); object_class->dispose = ephy_shell_dispose; object_class->finalize = ephy_shell_finalize; embed_shell_class->get_embed_single = impl_get_embed_single; g_type_class_add_private (object_class, sizeof(EphyShellPrivate)); } static EphyEmbed * ephy_shell_new_window_cb (EphyEmbedSingle *single, EphyEmbed *parent_embed, EphyWebViewChrome chromemask, EphyShell *shell) { GtkWidget *parent = NULL; gboolean is_popup; EphyNewTabFlags flags = EPHY_NEW_TAB_DONT_SHOW_WINDOW | EPHY_NEW_TAB_APPEND_LAST | EPHY_NEW_TAB_IN_NEW_WINDOW | EPHY_NEW_TAB_JUMP; LOG ("ephy_shell_new_window_cb tab chrome %d", chromemask); if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_JAVASCRIPT_CHROME)) { chromemask = EPHY_WEB_VIEW_CHROME_ALL; } if (parent_embed != NULL) { /* this will either be a EphyWindow, or the embed itself * (in case it's about to be destroyed, which means it's already * removed from its tab) */ parent = gtk_widget_get_toplevel (GTK_WIDGET (parent_embed)); } /* what's a popup ? ATM, any window opened with menubar toggled on * is *not* a popup */ is_popup = (chromemask & EPHY_WEB_VIEW_CHROME_MENUBAR) == 0; return ephy_shell_new_tab_full (shell, EPHY_IS_WINDOW (parent) ? EPHY_WINDOW (parent) : NULL, NULL, NULL, flags, chromemask, is_popup, 0); } static gboolean ephy_shell_add_sidebar_cb (EphyEmbedSingle *embed_single, const char *url, const char *title, EphyShell *shell) { EphySession *session; EphyWindow *window; GtkWidget *dialog; session = EPHY_SESSION (ephy_shell_get_session (shell)); g_return_val_if_fail (EPHY_IS_SESSION (session), FALSE); window = ephy_session_get_active_window (session); dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Sidebar extension required")); gtk_window_set_title (GTK_WINDOW (dialog), _("Sidebar Extension Required")); gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("The link you clicked needs the sidebar extension to be " "installed.")); g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); gtk_widget_show (dialog); return TRUE; } #ifdef ENABLE_NETWORK_MANAGER static void ephy_shell_sync_network_status (EphyNetMonitor *net_monitor, GParamSpec *pspec, EphyShell *shell) { EphyShellPrivate *priv = shell->priv; EphyEmbedSingle *single; gboolean net_status; if (!priv->embed_single_connected) return; single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (EPHY_EMBED_SHELL (shell))); net_status = ephy_net_monitor_get_net_status (net_monitor); ephy_embed_single_set_network_status (single, net_status); } #endif /* ENABLE_NETWORK_MANAGER */ static GObject* impl_get_embed_single (EphyEmbedShell *embed_shell) { EphyShell *shell = EPHY_SHELL (embed_shell); EphyShellPrivate *priv = shell->priv; GObject *embed_single; embed_single = EPHY_EMBED_SHELL_CLASS (ephy_shell_parent_class)->get_embed_single (embed_shell); if (embed_single != NULL && priv->embed_single_connected == FALSE) { g_signal_connect_object (embed_single, "new-window", G_CALLBACK (ephy_shell_new_window_cb), shell, G_CONNECT_AFTER); g_signal_connect_object (embed_single, "add-sidebar", G_CALLBACK (ephy_shell_add_sidebar_cb), shell, G_CONNECT_AFTER); priv->embed_single_connected = TRUE; #ifdef ENABLE_NETWORK_MANAGER /* Now we need the net monitor */ ephy_shell_get_net_monitor (shell); ephy_shell_sync_network_status (priv->net_monitor, NULL, shell); #endif } return embed_single; } 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); } static void ephy_shell_dispose (GObject *object) { EphyShell *shell = EPHY_SHELL (object); EphyShellPrivate *priv = shell->priv; LOG ("EphyShell disposing"); if (shell->priv->extensions_manager != NULL) { LOG ("Unref extension manager"); /* this will unload the extensions */ g_object_unref (priv->extensions_manager); priv->extensions_manager = NULL; } if (priv->session != NULL) { LOG ("Unref session manager"); g_object_unref (priv->session); priv->session = NULL; } if (priv->lockdown != NULL) { LOG ("Unref lockdown controller"); g_object_unref (priv->lockdown); priv->lockdown = NULL; } if (priv->toolbars_model != NULL) { LOG ("Unref toolbars model"); g_object_unref (priv->toolbars_model); priv->toolbars_model = NULL; } if (priv->fs_toolbars_model != NULL) { LOG ("Unref fullscreen toolbars model"); g_object_unref (priv->fs_toolbars_model); priv->fs_toolbars_model = NULL; } if (priv->bme != NULL) { LOG ("Unref Bookmarks Editor"); gtk_widget_destroy (GTK_WIDGET (priv->bme)); priv->bme = NULL; } if (priv->history_window != NULL) { LOG ("Unref History Window"); gtk_widget_destroy (GTK_WIDGET (priv->history_window)); priv->history_window = NULL; } if (priv->pdm_dialog != NULL) { LOG ("Unref PDM Dialog"); g_object_unref (priv->pdm_dialog); priv->pdm_dialog = NULL; } if (priv->prefs_dialog != NULL) { LOG ("Unref prefs dialog"); g_object_unref (priv->prefs_dialog); priv->prefs_dialog = NULL; } if (priv->bookmarks != NULL) { LOG ("Unref bookmarks"); g_object_unref (priv->bookmarks); priv->bookmarks = NULL; } #ifdef ENABLE_NETWORK_MANAGER if (priv->net_monitor != NULL) { LOG ("Unref net monitor"); g_signal_handlers_disconnect_by_func (priv->net_monitor, G_CALLBACK (ephy_shell_sync_network_status), shell); g_object_unref (priv->net_monitor); priv->net_monitor = NULL; } #endif /* ENABLE_NETWORK_MANAGER */ G_OBJECT_CLASS (ephy_shell_parent_class)->dispose (object); } static void ephy_shell_finalize (GObject *object) { G_OBJECT_CLASS (ephy_shell_parent_class)->finalize (object); LOG ("Ephy shell finalised"); } /** * ephy_shell_get_default: * * Retrieve the default #EphyShell object * * Return value: (transfer none): the default #EphyShell **/ EphyShell * ephy_shell_get_default (void) { return ephy_shell; } static gboolean url_is_empty (const char *location) { gboolean is_empty = FALSE; if (location == NULL || location[0] == '\0' || strcmp (location, "about:blank") == 0) { is_empty = TRUE; } return is_empty; } static gboolean load_homepage (EphyEmbed *embed) { char *home; gboolean is_empty; home = eel_gconf_get_string(CONF_GENERAL_HOMEPAGE); if (home == NULL || home[0] == '\0') { g_free (home); home = g_strdup ("about:blank"); } is_empty = url_is_empty (home); ephy_web_view_load_url (EPHY_WEB_VIEW (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed)), home); g_free (home); return is_empty; } /** * ephy_shell_new_tab_full: * @shell: a #EphyShell * @parent_window: the target #EphyWindow or %NULL * @previous_embed: the referrer embed, or %NULL * @request: a #WebKitNetworkRequest to load or %NULL * @chrome: a #EphyEmbedChrome mask to use if creating a new window * @is_popup: whether the new window is a popup * @user_time: a timestamp, or 0 * * Create a new tab and the parent window when necessary. * Use this function to open urls in new window/tabs. * * Return value: (transfer none): the created #EphyEmbed **/ EphyEmbed * ephy_shell_new_tab_full (EphyShell *shell, EphyWindow *parent_window, EphyEmbed *previous_embed, WebKitNetworkRequest *request, EphyNewTabFlags flags, EphyWebViewChrome chrome, gboolean is_popup, guint32 user_time) { EphyWindow *window; EphyEmbed *embed = NULL; gboolean in_new_window = TRUE; gboolean open_page = FALSE; gboolean jump_to; gboolean active_is_blank = FALSE; GtkWidget *nb; int position = -1; gboolean is_empty = FALSE; EphyToolbar *toolbar; if (flags & EPHY_NEW_TAB_OPEN_PAGE) open_page = TRUE; 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); g_return_val_if_fail (in_new_window || !is_popup, NULL); g_return_val_if_fail (open_page == (gboolean)(request != NULL), NULL); jump_to = (flags & EPHY_NEW_TAB_JUMP) != 0; LOG ("Opening new tab parent-window %p parent-embed %p in-new-window:%s jump-to:%s", parent_window, previous_embed, in_new_window ? "t" : "f", jump_to ? "t" : "f"); if (!in_new_window && parent_window != NULL) { window = parent_window; } else { window = ephy_window_new_with_chrome (chrome, is_popup); } toolbar = EPHY_TOOLBAR (ephy_window_get_toolbar (window)); if ((flags & EPHY_NEW_TAB_APPEND_AFTER) && previous_embed != NULL) { nb = ephy_window_get_notebook (window); /* FIXME this assumes the tab is the direct notebook child */ position = gtk_notebook_page_num (GTK_NOTEBOOK (nb), GTK_WIDGET (previous_embed)) + 1; } if (flags & EPHY_NEW_TAB_FROM_EXTERNAL) { /* If the active embed is blank, use that to open the url and jump to it */ embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window)); if (embed != NULL) { if (ephy_web_view_get_is_blank (ephy_embed_get_web_view (embed)) && ephy_web_view_is_loading (ephy_embed_get_web_view (embed)) == FALSE) { active_is_blank = TRUE; } } } if (active_is_blank == FALSE) { embed = EPHY_EMBED (g_object_new (EPHY_TYPE_EMBED, NULL)); g_assert (embed != NULL); gtk_widget_show (GTK_WIDGET (embed)); ephy_embed_container_add_child (EPHY_EMBED_CONTAINER (window), embed, position, jump_to); } if (previous_embed != NULL) { ephy_web_view_copy_back_history (ephy_embed_get_web_view (previous_embed), ephy_embed_get_web_view (embed)); } ephy_gui_window_update_user_time (GTK_WIDGET (window), user_time); if ((flags & EPHY_NEW_TAB_DONT_SHOW_WINDOW) == 0) { gtk_widget_show (GTK_WIDGET (window)); } if (flags & EPHY_NEW_TAB_FULLSCREEN_MODE) { gtk_window_fullscreen (GTK_WINDOW (window)); } if (flags & EPHY_NEW_TAB_HOME_PAGE || flags & EPHY_NEW_TAB_NEW_PAGE) { ephy_web_view_set_typed_address (ephy_embed_get_web_view (embed), ""); ephy_toolbar_activate_location (toolbar); is_empty = load_homepage (embed); } else if (flags & EPHY_NEW_TAB_OPEN_PAGE) { ephy_web_view_load_request (ephy_embed_get_web_view (embed), request); is_empty = url_is_empty (webkit_network_request_get_uri (request)); } /* Make sure the initial focus is somewhere sensible and not, for * example, on the reload button. */ if (in_new_window || jump_to) { /* If the location entry is blank, focus that, except if the * page was a copy */ if (is_empty) { /* empty page, focus location entry */ toolbar = EPHY_TOOLBAR (ephy_window_get_toolbar (window)); ephy_toolbar_activate_location (toolbar); } else if (embed != NULL) { /* non-empty page, focus the page. but make sure the widget is realised first! */ gtk_widget_realize (GTK_WIDGET (embed)); gtk_widget_grab_focus (GTK_WIDGET (embed)); } } return embed; } /** * ephy_shell_new_tab: * @shell: a #EphyShell * @parent_window: the target #EphyWindow or %NULL * @previous_embed: the referrer embed, 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. * * Return value: (transfer none): the created #EphyEmbed **/ EphyEmbed * ephy_shell_new_tab (EphyShell *shell, EphyWindow *parent_window, EphyEmbed *previous_embed, const char *url, EphyNewTabFlags flags) { EphyEmbed *embed; WebKitNetworkRequest *request = url ? webkit_network_request_new (url) : NULL; embed = ephy_shell_new_tab_full (shell, parent_window, previous_embed, request, flags, EPHY_WEB_VIEW_CHROME_ALL, FALSE, 0); if (request) g_object_unref (request); return embed; } /** * ephy_shell_get_session: * @shell: the #EphyShell * * Returns current session. * * Return value: (transfer none): 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); } /** * ephy_shell_get_lockdown: * @shell: the #EphyShell * * Returns the lockdown controller. * * Return value: the lockdown controller **/ static GObject * ephy_shell_get_lockdown (EphyShell *shell) { g_return_val_if_fail (EPHY_IS_SHELL (shell), NULL); if (shell->priv->lockdown == NULL) { EphyExtensionsManager *manager; shell->priv->lockdown = g_object_new (EPHY_TYPE_LOCKDOWN, NULL); manager = EPHY_EXTENSIONS_MANAGER (ephy_shell_get_extensions_manager (shell)); ephy_extensions_manager_register (manager, G_OBJECT (shell->priv->lockdown)); } return G_OBJECT (shell->priv->session); } /** * ephy_shell_get_bookmarks: * * Return value: (transfer none): **/ EphyBookmarks * ephy_shell_get_bookmarks (EphyShell *shell) { if (shell->priv->bookmarks == NULL) { shell->priv->bookmarks = ephy_bookmarks_new (); } return shell->priv->bookmarks; } /** * ephy_shell_get_toolbars_model: * * Return value: (transfer none): **/ 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) { EggTbModelFlags flags; 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_toolbars (shell->priv->fs_toolbars_model, xml); g_return_val_if_fail (success, NULL); flags = egg_toolbars_model_get_flags (shell->priv->fs_toolbars_model, 0); egg_toolbars_model_set_flags (shell->priv->fs_toolbars_model, 0, flags | EGG_TB_MODEL_NOT_REMOVABLE); } return G_OBJECT (shell->priv->fs_toolbars_model); } else { if (shell->priv->toolbars_model == NULL) { shell->priv->toolbars_model = ephy_toolbars_model_new (); ephy_bookmarks_ui_attach_toolbar_model (shell->priv->toolbars_model); ephy_toolbars_model_load (EPHY_TOOLBARS_MODEL (shell->priv->toolbars_model)); } return G_OBJECT (shell->priv->toolbars_model); } } /** * ephy_shell_get_extensions_manager: * * Return value: (transfer none): **/ 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); /* FIXME */ ephy_shell_get_lockdown (es); ephy_embed_shell_get_adblock_manager (embed_shell); } return G_OBJECT (es->priv->extensions_manager); } /** * ephy_shell_get_net_monitor: * * Return value: (transfer none): **/ GObject * ephy_shell_get_net_monitor (EphyShell *shell) { #ifdef ENABLE_NETWORK_MANAGER EphyShellPrivate *priv = shell->priv; if (priv->net_monitor == NULL) { priv->net_monitor = ephy_net_monitor_new (); g_signal_connect (priv->net_monitor, "notify::network-status", G_CALLBACK (ephy_shell_sync_network_status), shell); } return G_OBJECT (priv->net_monitor); #else return NULL; #endif /* ENABLE_NETWORK_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); } /** * ephy_shell_get_bookmarks_editor: * * Return value: (transfer none): **/ 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; } /** * ephy_shell_get_history_window: * * Return value: (transfer none): **/ 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; } /** * ephy_shell_get_pdm_dialog: * * Return value: (transfer none): **/ GObject * ephy_shell_get_pdm_dialog (EphyShell *shell) { if (shell->priv->pdm_dialog == NULL) { GObject **dialog; shell->priv->pdm_dialog = g_object_new (EPHY_TYPE_PDM_DIALOG, NULL); dialog = &shell->priv->pdm_dialog; g_object_add_weak_pointer (shell->priv->pdm_dialog, (gpointer *) dialog); } return shell->priv->pdm_dialog; } /** * ephy_shell_get_prefs_dialog: * * Return value: (transfer none): **/ GObject * ephy_shell_get_prefs_dialog (EphyShell *shell) { if (shell->priv->prefs_dialog == NULL) { GObject **dialog; shell->priv->prefs_dialog = g_object_new (EPHY_TYPE_PREFS_DIALOG, NULL); dialog = &shell->priv->prefs_dialog; g_object_add_weak_pointer (shell->priv->prefs_dialog, (gpointer *) dialog); } return shell->priv->prefs_dialog; } void _ephy_shell_create_instance (void) { g_assert (ephy_shell == NULL); ephy_shell = EPHY_SHELL (g_object_new (EPHY_TYPE_SHELL, NULL)); /* FIXME weak ref */ g_assert (ephy_shell != NULL); }