/* * Copyright © 2000-2004 Marco Pesenti Gritti * Copyright © 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ #include "mozilla-config.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "EphyBrowser.h" #include "EphyUtils.h" #include "EventContext.h" #include "ephy-command-manager.h" #include "ephy-debug.h" #include "ephy-embed-shell.h" #include "ephy-embed-single.h" #include "ephy-embed-utils.h" #include "ephy-favicon-cache.h" #include "ephy-history.h" #include "ephy-string.h" #include "mozilla-embed-event.h" #include "mozilla-embed.h" static void mozilla_embed_class_init (MozillaEmbedClass *klass); static void mozilla_embed_init (MozillaEmbed *gs); static void mozilla_embed_destroy (GtkObject *object); static void mozilla_embed_finalize (GObject *object); static void mozilla_embed_dispose (GObject *object); static void ephy_embed_iface_init (EphyEmbedIface *iface); static void mozilla_embed_location_changed_cb (GtkMozEmbed *embed, MozillaEmbed *membed); static void mozilla_embed_net_state_all_cb (GtkMozEmbed *embed, const char *aURI, gint state, guint status, MozillaEmbed *membed); static gboolean mozilla_embed_dom_mouse_click_cb(GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed); static gboolean mozilla_embed_dom_mouse_down_cb (GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed); static gboolean mozilla_embed_dom_key_press_cb (GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed); static void mozilla_embed_new_window_cb (GtkMozEmbed *embed, GtkMozEmbed **newEmbed, guint chrome_mask, MozillaEmbed *membed); static void mozilla_embed_security_change_cb (GtkMozEmbed *embed, gpointer request, PRUint32 state, MozillaEmbed *membed); static void mozilla_embed_document_type_cb (EphyEmbed *embed, EphyEmbedDocumentType type, MozillaEmbed *membed); static void mozilla_embed_zoom_change_cb (EphyEmbed *embed, float zoom, MozillaEmbed *membed); static void mozilla_embed_title_change_cb (EphyEmbed *embed, MozillaEmbed *membed); static void mozilla_embed_link_message_cb (EphyEmbed *embed, MozillaEmbed *membed); static void mozilla_embed_set_title (MozillaEmbed *embed, char *title); static void mozilla_embed_set_loading_title (MozillaEmbed *embed, const char *title, gboolean is_address); static void mozilla_embed_icon_cache_changed_cb (EphyFaviconCache *cache, const char *address, MozillaEmbed *embed); static void mozilla_embed_set_icon_address (MozillaEmbed *embed, const char *address); static void mozilla_embed_favicon_cb (EphyEmbed *embed, const char *address, MozillaEmbed *membed); static gboolean mozilla_embed_open_uri_cb (EphyEmbed *embed, const char *uri, MozillaEmbed *membed); static void mozilla_embed_file_monitor_cancel (MozillaEmbed *embed); #if 0 static guint popup_blocker_n_hidden (MozillaEmbed *embed); static gboolean mozilla_embed_get_popups_allowed (MozillaEmbed *embed); static void mozilla_embed_set_popups_allowed (MozillaEmbed *embed, gboolean allowed); #endif static void mozilla_embed_file_monitor_cancel (MozillaEmbed *embed); static void impl_set_typed_address (EphyEmbed *embed, const char *address, EphyEmbedAddressExpire expire); static EphyEmbedSecurityLevel mozilla_embed_security_level (PRUint32 state); #define MOZILLA_EMBED_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), MOZILLA_TYPE_EMBED, MozillaEmbedPrivate)) typedef enum { MOZILLA_EMBED_LOAD_STARTED, MOZILLA_EMBED_LOAD_REDIRECTING, MOZILLA_EMBED_LOAD_LOADING, MOZILLA_EMBED_LOAD_STOPPED } MozillaEmbedLoadState; #define MAX_HIDDEN_POPUPS 5 #define MAX_TITLE_LENGTH 512 /* characters */ #define RELOAD_DELAY 250 /* ms */ #define RELOAD_DELAY_MAX_TICKS 40 /* RELOAD_DELAY * RELOAD_DELAY_MAX_TICKS = 10 s */ struct MozillaEmbedPrivate { EphyBrowser *browser; MozillaEmbedLoadState load_state; EphyEmbedAddressExpire address_expire; /* guint address_expire : 2; ? */ EphyEmbedSecurityLevel security_level; /* guint security_level : 3; ? */ EphyEmbedDocumentType document_type; EphyEmbedNavigationFlags nav_flags; float zoom; /* Flags */ guint is_blank : 1; guint is_loading : 1; guint is_setting_zoom : 1; gint8 load_percent; char *address; char *typed_address; char *title; char *loading_title; int cur_requests; int total_requests; char *status_message; char *link_message; char *icon_address; GdkPixbuf *icon; /* File watch */ GnomeVFSMonitorHandle *monitor; guint reload_scheduled_id; guint reload_delay_ticks; GSList *hidden_popups; GSList *shown_popups; }; #define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1" enum { PROP_0, PROP_ADDRESS, PROP_DOCUMENT_TYPE, PROP_HIDDEN_POPUP_COUNT, PROP_ICON, PROP_ICON_ADDRESS, PROP_LINK_MESSAGE, PROP_LOAD_PROGRESS, PROP_LOAD_STATUS, PROP_NAVIGATION, PROP_POPUPS_ALLOWED, PROP_SECURITY, PROP_STATUS_MESSAGE, PROP_TITLE, PROP_TYPED_ADDRESS, PROP_ZOOM }; typedef struct { char *url; char *name; char *features; } PopupInfo; static void impl_manager_do_command (EphyCommandManager *manager, const char *command) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(manager)->priv; mpriv->browser->DoCommand (command); } static gboolean impl_manager_can_do_command (EphyCommandManager *manager, const char *command) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(manager)->priv; nsresult rv; PRBool enabled; rv = mpriv->browser->GetCommandState (command, &enabled); return NS_SUCCEEDED (rv) ? enabled : FALSE; } static void ephy_command_manager_iface_init (EphyCommandManagerIface *iface) { iface->do_command = impl_manager_do_command; iface->can_do_command = impl_manager_can_do_command; } G_DEFINE_TYPE_WITH_CODE (MozillaEmbed, mozilla_embed, GTK_TYPE_MOZ_EMBED, G_IMPLEMENT_INTERFACE (EPHY_TYPE_EMBED, ephy_embed_iface_init) G_IMPLEMENT_INTERFACE (EPHY_TYPE_COMMAND_MANAGER, ephy_command_manager_iface_init)) static void mozilla_embed_grab_focus (GtkWidget *widget) { GtkWidget *child; child = gtk_bin_get_child (GTK_BIN (widget)); if (child != NULL) { gtk_widget_grab_focus (child); } else { g_warning ("Need to realize the embed before grabbing focus!\n"); } } static void impl_close (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (embed)->priv; mpriv->browser->Close (); } static void mozilla_embed_realize (GtkWidget *widget) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (widget)->priv; GTK_WIDGET_CLASS (mozilla_embed_parent_class)->realize (widget); /* Initialise our helper class */ nsresult rv; rv = mpriv->browser->Init (GTK_MOZ_EMBED (widget)); if (NS_FAILED (rv)) { g_warning ("EphyBrowser initialization failed for %p\n", widget); return; } } static GObject * mozilla_embed_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { g_object_ref (embed_shell); /* we depend on single because of mozilla initialization */ ephy_embed_shell_get_embed_single (embed_shell); return G_OBJECT_CLASS (mozilla_embed_parent_class)->constructor (type, n_construct_properties, construct_params); } static void mozilla_embed_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MozillaEmbed *embed = MOZILLA_EMBED (object); MozillaEmbedPrivate *priv = embed->priv; switch (prop_id) { case PROP_ADDRESS: g_value_set_string (value, priv->address); break; case PROP_DOCUMENT_TYPE: g_value_set_enum (value, priv->document_type); break; case PROP_HIDDEN_POPUP_COUNT: g_value_set_int (value, 0); // g_value_set_int (value, popup_blocker_n_hidden (embed)); break; case PROP_ICON: g_value_set_object (value, priv->icon); break; case PROP_ICON_ADDRESS: g_value_set_string (value, priv->icon_address); break; case PROP_LINK_MESSAGE: g_value_set_string (value, priv->link_message); break; case PROP_LOAD_PROGRESS: g_value_set_int (value, priv->load_percent); break; case PROP_LOAD_STATUS: g_value_set_boolean (value, priv->is_loading); break; case PROP_NAVIGATION: g_value_set_flags (value, priv->nav_flags); break; case PROP_POPUPS_ALLOWED: g_value_set_boolean (value, FALSE); // g_value_set_boolean (value, mozilla_embed_get_popups_allowed (embed)); break; case PROP_SECURITY: g_value_set_enum (value, priv->security_level); break; case PROP_STATUS_MESSAGE: g_value_set_string (value, priv->status_message); break; case PROP_TITLE: g_value_set_string (value, priv->title); break; case PROP_TYPED_ADDRESS: g_value_set_string (value, priv->typed_address); break; case PROP_ZOOM: g_value_set_float (value, priv->zoom); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void mozilla_embed_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_ICON_ADDRESS: mozilla_embed_set_icon_address (MOZILLA_EMBED (object), g_value_get_string (value)); break; case PROP_TYPED_ADDRESS: impl_set_typed_address (EPHY_EMBED (object), g_value_get_string (value), EPHY_EMBED_ADDRESS_EXPIRE_NOW); break; case PROP_POPUPS_ALLOWED: //mozilla_embed_set_popups_allowed (MOZILLA_EMBED (object), g_value_get_boolean (value)); break; case PROP_ADDRESS: case PROP_DOCUMENT_TYPE: case PROP_HIDDEN_POPUP_COUNT: case PROP_ICON: case PROP_LOAD_PROGRESS: case PROP_LOAD_STATUS: case PROP_LINK_MESSAGE: case PROP_NAVIGATION: case PROP_SECURITY: case PROP_STATUS_MESSAGE: case PROP_ZOOM: /* read only */ break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void mozilla_embed_class_init (MozillaEmbedClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); mozilla_embed_parent_class = (GObjectClass *) g_type_class_peek_parent (klass); object_class->constructor = mozilla_embed_constructor; object_class->finalize = mozilla_embed_finalize; object_class->dispose = mozilla_embed_dispose; object_class->get_property = mozilla_embed_get_property; object_class->set_property = mozilla_embed_set_property; gtk_object_class->destroy = mozilla_embed_destroy; widget_class->grab_focus = mozilla_embed_grab_focus; widget_class->realize = mozilla_embed_realize; g_object_class_override_property (object_class, PROP_DOCUMENT_TYPE, "document-type"); g_object_class_override_property (object_class, PROP_SECURITY, "security-level"); g_object_class_override_property (object_class, PROP_ZOOM, "zoom"); g_object_class_override_property (object_class, PROP_LOAD_PROGRESS, "load-progress"); g_object_class_override_property (object_class, PROP_LOAD_STATUS, "load-status"); g_object_class_override_property (object_class, PROP_NAVIGATION, "navigation"); g_object_class_override_property (object_class, PROP_ADDRESS, "address"); g_object_class_override_property (object_class, PROP_TYPED_ADDRESS, "typed-address"); g_object_class_override_property (object_class, PROP_TITLE, "title"); g_object_class_override_property (object_class, PROP_STATUS_MESSAGE, "status-message"); g_object_class_override_property (object_class, PROP_LINK_MESSAGE, "link-message"); g_object_class_override_property (object_class, PROP_ICON, "icon"); g_object_class_override_property (object_class, PROP_ICON_ADDRESS, "icon-address"); g_object_class_override_property (object_class, PROP_POPUPS_ALLOWED, "popups-allowed"); g_object_class_override_property (object_class, PROP_HIDDEN_POPUP_COUNT, "hidden-popup-count"); g_type_class_add_private (object_class, sizeof(MozillaEmbedPrivate)); } static void mozilla_embed_init (MozillaEmbed *embed) { EphyFaviconCache *cache; MozillaEmbedPrivate *priv; embed->priv = MOZILLA_EMBED_GET_PRIVATE (embed); priv = embed->priv; priv->browser = new EphyBrowser (); g_signal_connect_object (embed, "location", G_CALLBACK (mozilla_embed_location_changed_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "net_state_all", G_CALLBACK (mozilla_embed_net_state_all_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "dom_mouse_click", G_CALLBACK (mozilla_embed_dom_mouse_click_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "dom_mouse_down", G_CALLBACK (mozilla_embed_dom_mouse_down_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "dom-key-press", G_CALLBACK (mozilla_embed_dom_key_press_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "new_window", G_CALLBACK (mozilla_embed_new_window_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "security_change", G_CALLBACK (mozilla_embed_security_change_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "ge_document_type", G_CALLBACK (mozilla_embed_document_type_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "ge_zoom_change", G_CALLBACK (mozilla_embed_zoom_change_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "title", G_CALLBACK (mozilla_embed_title_change_cb), embed, (GConnectFlags) 0); g_signal_connect_object (embed, "link_message", G_CALLBACK (mozilla_embed_link_message_cb), embed, (GConnectFlags)0); g_signal_connect_object (embed, "ge_favicon", G_CALLBACK (mozilla_embed_favicon_cb), embed, (GConnectFlags)0); g_signal_connect_object (embed, "open_uri", G_CALLBACK (mozilla_embed_open_uri_cb), embed,(GConnectFlags) 0); cache = EPHY_FAVICON_CACHE (ephy_embed_shell_get_favicon_cache (embed_shell)); g_signal_connect_object (G_OBJECT (cache), "changed", G_CALLBACK (mozilla_embed_icon_cache_changed_cb), embed, (GConnectFlags)0); priv->document_type = EPHY_EMBED_DOCUMENT_HTML; priv->security_level = EPHY_EMBED_STATE_IS_UNKNOWN; priv->zoom = 1.0; priv->is_setting_zoom = FALSE; priv->load_percent = 0; priv->is_loading = FALSE; priv->typed_address = NULL; priv->address = NULL; priv->address_expire = EPHY_EMBED_ADDRESS_EXPIRE_NOW; priv->title = NULL; priv->loading_title = NULL; priv->is_blank = TRUE; priv->total_requests = 0; priv->cur_requests = 0; priv->icon_address = NULL; priv->icon = NULL; priv->status_message = NULL; priv->link_message = NULL; } gpointer _mozilla_embed_get_ephy_browser (MozillaEmbed *embed) { g_return_val_if_fail (embed->priv->browser != NULL, NULL); return embed->priv->browser; } static void mozilla_embed_destroy (GtkObject *object) { MozillaEmbed *embed = MOZILLA_EMBED (object); if (embed->priv->browser) { embed->priv->browser->Destroy(); } GTK_OBJECT_CLASS (mozilla_embed_parent_class)->destroy (object); } static void mozilla_embed_dispose (GObject *object) { mozilla_embed_file_monitor_cancel (MOZILLA_EMBED (object)); G_OBJECT_CLASS (mozilla_embed_parent_class)->dispose (object); } static void mozilla_embed_finalize (GObject *object) { MozillaEmbed *embed = MOZILLA_EMBED (object); if (embed->priv->browser) { delete embed->priv->browser; embed->priv->browser = nsnull; } if (embed->priv->icon != NULL) { g_object_unref (embed->priv->icon); embed->priv->icon = NULL; } #if 0 popups_manager_reset (embed); #endif g_free (embed->priv->icon_address); g_free (embed->priv->address); g_free (embed->priv->typed_address); g_free (embed->priv->title); g_free (embed->priv->loading_title); g_free (embed->priv->status_message); g_free (embed->priv->link_message); G_OBJECT_CLASS (mozilla_embed_parent_class)->finalize (object); g_object_unref (embed_shell); } #if 0 static void ephy_tab_content_change_cb (EphyEmbed *embed, const char *address, EphyTab *tab) { popups_manager_reset (tab); g_object_notify (G_OBJECT (tab), "popups-allowed"); } static void ephy_tab_new_window_cb (EphyEmbed *embed, EphyEmbed *new_embed, EphyTab *tab) { EphyWindow *window; g_return_if_fail (new_embed != NULL); window = EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (new_embed))); g_return_if_fail (window != NULL); popups_manager_add_window (tab, window); } static void ephy_tab_popup_blocked_cb (EphyEmbed *embed, const char *url, const char *name, const char *features, EphyTab *tab) { popups_manager_add (tab, url, name, features); } static void popups_manager_free_info (PopupInfo *popup) { g_free (popup->url); g_free (popup->name); g_free (popup->features); g_free (popup); } static void popups_manager_add (MozillaEmbed *embed, const char *url, const char *name, const char *features) { MozillaEmbedPrivate *priv = embed->priv; PopupInfo *popup; LOG ("popups_manager_add: embed %p, url %s, features %s", embed, url, features); popup = g_new0 (PopupInfo, 1); popup->url = (url == NULL) ? NULL : g_strdup (url); popup->name = g_strdup (name); popup->features = g_strdup (features); priv->hidden_popups = g_slist_prepend (priv->hidden_popups, popup); if (popup_blocker_n_hidden (embed) > MAX_HIDDEN_POPUPS) /* bug #160863 */ { /* Remove the oldest popup */ GSList *l = embed->priv->hidden_popups; while (l->next->next != NULL) { l = l->next; } popup = (PopupInfo *) l->next->data; popups_manager_free_info (popup); l->next = NULL; } else { g_object_notify (G_OBJECT (embed), "hidden-popup-count"); } } static gboolean popups_manager_remove_window (MozillaEmbed *embed, EphyWindow *window) { embed->priv->shown_popups = g_slist_remove (embed->priv->shown_popups, window); return FALSE; } static void disconnect_popup (EphyWindow *window, MozillaEmbed *embed) { g_signal_handlers_disconnect_by_func (window, G_CALLBACK (popups_manager_remove_window), embed); } static void popups_manager_add_window (MozillaEmbed *embed, EphyWindow *window) { LOG ("popups_manager_add_window: embed %p, window %p", embed, window); embed->priv->shown_popups = g_slist_prepend (embed->priv->shown_popups, window); g_signal_connect_swapped (window, "destroy", G_CALLBACK (popups_manager_remove_window), embed); } static gboolean mozilla_embed_get_popups_allowed (MozillaEmbed *embed) { EphyPermissionManager *permission_manager; EphyPermission response; EphyEmbed *embed; char *location; gboolean allow; permission_manager = EPHY_PERMISSION_MANAGER (ephy_embed_shell_get_embed_single (embed_shell)); g_return_val_if_fail (EPHY_IS_PERMISSION_MANAGER (permission_manager), FALSE); location = ephy_embed_get_location (embed, TRUE); if (location == NULL) return FALSE; /* FALSE, TRUE… same thing */ response = ephy_permission_manager_test_permission (permission_manager, location, EPT_POPUP); switch (response) { case EPHY_PERMISSION_ALLOWED: allow = TRUE; break; case EPHY_PERMISSION_DENIED: allow = FALSE; break; case EPHY_PERMISSION_DEFAULT: default: allow = eel_gconf_get_boolean (CONF_SECURITY_ALLOW_POPUPS); break; } g_free (location); LOG ("mozilla_embed_get_popups_allowed: embed %p, allowed: %d", embed, allow); return allow; } static void popups_manager_show (PopupInfo *popup, MozillaEmbed *embed) { EphyEmbed *embed; EphyEmbedSingle *single; /* Only show popup with non NULL url */ if (popup->url != NULL) { embed = ephy_embed_get_embed (embed); single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)); ephy_embed_single_open_window (single, embed, popup->url, popup->name, popup->features); } popups_manager_free_info (popup); } static void popups_manager_show_all (MozillaEmbed *embed) { LOG ("popup_blocker_show_all: embed %p", embed); g_slist_foreach (embed->priv->hidden_popups, (GFunc) popups_manager_show, embed); g_slist_free (embed->priv->hidden_popups); embed->priv->hidden_popups = NULL; g_object_notify (G_OBJECT (embed), "hidden-popup-count"); } static char * popups_manager_new_window_info (EphyWindow *window) { MozillaEmbed *embed; EphyEmbedChrome chrome; gboolean is_popup; char *features; g_object_get (window, "chrome", &chrome, "is-popup", &is_popup, NULL); g_return_val_if_fail (is_popup, g_strdup ("")); embed = ephy_window_get_active_embed (window); g_return_val_if_fail (embed != NULL, g_strdup ("")); features = g_strdup_printf ("width=%d,height=%d,menubar=%d,status=%d,toolbar=%d", embed->priv->width, embed->priv->height, (chrome & EPHY_EMBED_CHROME_MENUBAR) > 0, (chrome & EPHY_EMBED_CHROME_STATUSBAR) > 0, (chrome & EPHY_EMBED_CHROME_TOOLBAR) > 0); return features; } static void popups_manager_hide (EphyWindow *window, MozillaEmbed *parent_embed) { EphyEmbed *embed; char *location; char *features; embed = ephy_window_get_active_embed (window); g_return_if_fail (EPHY_IS_EMBED (embed)); location = ephy_embed_get_location (embed, TRUE); if (location == NULL) return; features = popups_manager_new_window_info (window); popups_manager_add (parent_embed, location, "" /* FIXME? maybe _blank? */, features); gtk_widget_destroy (GTK_WIDGET (window)); g_free (location); g_free (features); } static void popups_manager_hide_all (MozillaEmbed *embed) { LOG ("popup_blocker_hide_all: embed %p", embed); g_slist_foreach (embed->priv->shown_popups, (GFunc) popups_manager_hide, embed); g_slist_free (embed->priv->shown_popups); embed->priv->shown_popups = NULL; } static void mozilla_embed_set_popups_allowed (MozillaEmbed *embed, gboolean allowed) { char *location; EphyEmbed *embed; EphyPermissionManager *manager; EphyPermission permission; embed = ephy_embed_get_embed (embed); location = ephy_embed_get_location (embed, TRUE); g_return_if_fail (location != NULL); manager = EPHY_PERMISSION_MANAGER (ephy_embed_shell_get_embed_single (embed_shell)); g_return_if_fail (EPHY_IS_PERMISSION_MANAGER (manager)); permission = allowed ? EPHY_PERMISSION_ALLOWED : EPHY_PERMISSION_DENIED; ephy_permission_manager_add_permission (manager, location, EPT_POPUP, permission); if (allowed) { popups_manager_show_all (embed); } else { popups_manager_hide_all (embed); } g_free (location); } static guint popup_blocker_n_hidden (MozillaEmbed *embed) { return g_slist_length (embed->priv->hidden_popups); } static void popups_manager_reset (MozillaEmbed *embed) { g_slist_foreach (embed->priv->hidden_popups, (GFunc) popups_manager_free_info, NULL); g_slist_free (embed->priv->hidden_popups); embed->priv->hidden_popups = NULL; g_slist_foreach (embed->priv->shown_popups, (GFunc) disconnect_popup, embed); g_slist_free (embed->priv->shown_popups); embed->priv->shown_popups = NULL; g_object_notify (G_OBJECT (embed), "hidden-popup-count"); } #endif static void impl_load_url (EphyEmbed *embed, const char *url) { gtk_moz_embed_load_url (GTK_MOZ_EMBED(embed), url); } static char * impl_get_location (EphyEmbed *embed, gboolean toplevel); static void impl_load (EphyEmbed *embed, const char *url, EphyEmbedLoadFlags flags, EphyEmbed *preview_embed) { EphyBrowser *browser; browser = MOZILLA_EMBED(embed)->priv->browser; g_return_if_fail (browser != NULL); nsCOMPtr uri; if (preview_embed != NULL) { EphyBrowser *pbrowser; pbrowser = MOZILLA_EMBED(preview_embed)->priv->browser; if (pbrowser != NULL) { pbrowser->GetDocumentURI (getter_AddRefs (uri)); } } #ifdef HAVE_GECKO_1_8_1 if (flags & EPHY_EMBED_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { browser->LoadURI (url, nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP, uri); } else #endif /* HAVE_GECKO_1_8_1 */ { browser->LoadURI (url, nsIWebNavigation::LOAD_FLAGS_NONE, uri); } } static void impl_stop_load (EphyEmbed *embed) { gtk_moz_embed_stop_load (GTK_MOZ_EMBED(embed)); } static gboolean impl_can_go_back (EphyEmbed *embed) { return gtk_moz_embed_can_go_back (GTK_MOZ_EMBED(embed)); } static gboolean impl_can_go_forward (EphyEmbed *embed) { return gtk_moz_embed_can_go_forward (GTK_MOZ_EMBED(embed)); } static gboolean mozilla_embed_get_uri_parent (MozillaEmbed *membed, const char *aUri, nsCString &aParent) { nsresult rv; nsCString encoding; rv = membed->priv->browser->GetEncoding (encoding); if (NS_FAILED (rv)) return FALSE; nsCOMPtr uri; rv = EphyUtils::NewURI (getter_AddRefs(uri), nsCString(aUri), encoding.get()); if (NS_FAILED(rv) || !uri) return FALSE; /* Don't support going 'up' with chrome url's, mozilla handily * fixes them up for us, so it doesn't work properly, see * rdf/chrome/src/nsChromeProtocolHandler.cpp::NewURI() * (the Canonify() call) */ nsCString scheme; rv = uri->GetScheme (scheme); if (NS_FAILED(rv) || !scheme.Length()) return FALSE; if (strcmp (scheme.get(), "chrome") == 0) return FALSE; nsCString path; rv = uri->GetPath(path); if (NS_FAILED(rv) || !path.Length()) return FALSE; if (strcmp (path.get (), "/") == 0) return FALSE; const char *slash = strrchr (path.BeginReading(), '/'); if (!slash) return FALSE; if (slash[1] == '\0') { /* ends with a slash - a directory, go to parent */ rv = uri->Resolve (nsCString(".."), aParent); } else { /* it's a file, go to the directory */ rv = uri->Resolve (nsCString("."), aParent); } return NS_SUCCEEDED (rv); } static gboolean impl_can_go_up (EphyEmbed *embed) { MozillaEmbed *membed = MOZILLA_EMBED (embed); char *address; gboolean result; address = ephy_embed_get_location (embed, TRUE); if (address == NULL) return FALSE; nsCString parent; result = mozilla_embed_get_uri_parent (membed, address, parent); g_free (address); return result; } static GSList * impl_get_go_up_list (EphyEmbed *embed) { MozillaEmbed *membed = MOZILLA_EMBED (embed); GSList *l = NULL; char *address, *s; address = ephy_embed_get_location (embed, TRUE); if (address == NULL) return NULL; s = address; nsCString parent; while (mozilla_embed_get_uri_parent (membed, s, parent)) { s = g_strdup (parent.get()); l = g_slist_prepend (l, s); } g_free (address); return g_slist_reverse (l); } static void impl_go_back (EphyEmbed *embed) { gtk_moz_embed_go_back (GTK_MOZ_EMBED(embed)); } static void impl_go_forward (EphyEmbed *embed) { gtk_moz_embed_go_forward (GTK_MOZ_EMBED(embed)); } static void impl_go_up (EphyEmbed *embed) { MozillaEmbed *membed = MOZILLA_EMBED (embed); char *uri; uri = ephy_embed_get_location (embed, TRUE); if (uri == NULL) return; gboolean rv; nsCString parent_uri; rv = mozilla_embed_get_uri_parent (membed, uri, parent_uri); g_free (uri); g_return_if_fail (rv != FALSE); ephy_embed_load_url (embed, parent_uri.get ()); } static const char * impl_get_title (EphyEmbed *embed) { return MOZILLA_EMBED (embed)->priv->title; } static char * impl_get_js_status (EphyEmbed *embed) { return gtk_moz_embed_get_js_status (GTK_MOZ_EMBED (embed)); } static char * impl_get_location (EphyEmbed *embed, gboolean toplevel) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; nsCOMPtr uri; if (toplevel) { rv = mpriv->browser->GetDocumentURI (getter_AddRefs (uri)); } else { rv = mpriv->browser->GetTargetDocumentURI (getter_AddRefs (uri)); } if (NS_FAILED (rv)) return NULL; nsCOMPtr furi; rv = uri->Clone (getter_AddRefs (furi)); /* Some nsIURI impls return NS_OK even though they didn't put anything in the outparam!! */ if (NS_FAILED (rv) || !furi) furi.swap(uri); /* Hide password part */ nsCString user; furi->GetUsername (user); furi->SetUserPass (user); nsCString url; furi->GetSpec (url); return url.Length() ? g_strdup (url.get()) : NULL; } static void impl_reload (EphyEmbed *embed, gboolean force) { guint32 mflags = GTK_MOZ_EMBED_FLAG_RELOADNORMAL; if (force) { mflags = GTK_MOZ_EMBED_FLAG_RELOADBYPASSPROXYANDCACHE; } gtk_moz_embed_reload (GTK_MOZ_EMBED(embed), mflags); } static void impl_set_zoom (EphyEmbed *embed, float zoom) { EphyBrowser *browser; nsresult rv; g_return_if_fail (zoom > 0.0); browser = MOZILLA_EMBED(embed)->priv->browser; g_return_if_fail (browser != NULL); rv = browser->SetZoom (zoom); if (NS_SUCCEEDED (rv)) { g_signal_emit_by_name (embed, "ge_zoom_change", zoom); } } static float impl_get_zoom (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; float f; nsresult rv; rv = mpriv->browser->GetZoom (&f); if (NS_SUCCEEDED (rv)) { return f; } return 1.0; } static void impl_scroll_lines (EphyEmbed *embed, int num_lines) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; mpriv->browser->ScrollLines (num_lines); } static void impl_scroll_pages (EphyEmbed *embed, int num_pages) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; mpriv->browser->ScrollPages (num_pages); } static void impl_scroll_pixels (EphyEmbed *embed, int dx, int dy) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; mpriv->browser->ScrollPixels (dx, dy); } static int impl_shistory_n_items (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; int count, index; rv = mpriv->browser->GetSHInfo (&count, &index); return NS_SUCCEEDED(rv) ? count : 0; } static void impl_shistory_get_nth (EphyEmbed *embed, int nth, gboolean is_relative, char **aUrl, char **aTitle) { nsresult rv; nsCString url; PRUnichar *title; MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; if (is_relative) { nth += ephy_embed_shistory_get_pos (embed); } rv = mpriv->browser->GetSHUrlAtIndex(nth, url); *aUrl = (NS_SUCCEEDED (rv) && url.Length()) ? g_strdup(url.get()) : NULL; rv = mpriv->browser->GetSHTitleAtIndex(nth, &title); if (title) { nsCString cTitle; NS_UTF16ToCString (nsString(title), NS_CSTRING_ENCODING_UTF8, cTitle); *aTitle = g_strdup (cTitle.get()); nsMemory::Free (title); } else { *aTitle = NULL; } } static int impl_shistory_get_pos (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; int count, index; rv = mpriv->browser->GetSHInfo (&count, &index); return NS_SUCCEEDED(rv) ? index : 0; } static void impl_shistory_go_nth (EphyEmbed *embed, int nth) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; mpriv->browser->GoToHistoryIndex (nth); } static void impl_shistory_copy (EphyEmbed *source, EphyEmbed *dest, gboolean copy_back, gboolean copy_forward, gboolean copy_current) { MozillaEmbedPrivate *spriv = MOZILLA_EMBED(source)->priv; MozillaEmbedPrivate *dpriv = MOZILLA_EMBED(dest)->priv; spriv->browser->CopySHistory(dpriv->browser, copy_back, copy_forward, copy_current); } static void impl_get_security_level (EphyEmbed *embed, EphyEmbedSecurityLevel *level, char **description) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (embed)->priv; if (level) *level = EPHY_EMBED_STATE_IS_UNKNOWN; if (description) *description = NULL; nsresult rv; PRUint32 state; nsCString desc; rv = mpriv->browser->GetSecurityInfo (&state, desc); if (NS_FAILED (rv)) return; if (level) *level = mozilla_embed_security_level (state); if (description) *description = g_strdup (desc.get()); } static void impl_show_page_certificate (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED (embed)->priv; mpriv->browser->ShowCertificate (); } static void impl_print (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; mpriv->browser->Print (); } static void impl_set_print_preview_mode (EphyEmbed *embed, gboolean preview_mode) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; mpriv->browser->SetPrintPreviewMode (preview_mode); } static int impl_print_preview_n_pages (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; int num; rv = mpriv->browser->PrintPreviewNumPages(&num); return NS_SUCCEEDED (rv) ? num : 0; } static void impl_print_preview_navigate (EphyEmbed *embed, EphyEmbedPrintPreviewNavType type, int page) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; mpriv->browser->PrintPreviewNavigate(type, page); } static void impl_set_encoding (EphyEmbed *embed, const char *encoding) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; nsCString currEnc; g_return_if_fail (encoding != NULL); rv = mpriv->browser->GetEncoding (currEnc); if (NS_FAILED (rv)) return; if (strcmp (currEnc.get(), encoding) != 0 || encoding[0] == '\0' && !ephy_embed_has_automatic_encoding (embed)) { rv = mpriv->browser->ForceEncoding (encoding); if (NS_FAILED (rv)) return; } gtk_moz_embed_reload (GTK_MOZ_EMBED (embed), GTK_MOZ_EMBED_FLAG_RELOADCHARSETCHANGE); } static char * impl_get_encoding (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; nsCString encoding; rv = mpriv->browser->GetEncoding (encoding); if (NS_FAILED (rv) || !encoding.Length()) { return NULL; } return g_strdup (encoding.get()); } static gboolean impl_has_automatic_encoding (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; nsCString encoding; rv = mpriv->browser->GetForcedEncoding (encoding); if (NS_FAILED (rv) || !encoding.Length()) { return TRUE; } return FALSE; } static gboolean impl_has_modified_forms (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; nsresult rv; PRBool modified; rv = mpriv->browser->GetHasModifiedForms (&modified); return NS_SUCCEEDED (rv) ? modified : FALSE; } static EphyEmbedDocumentType impl_get_document_type (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; return mpriv->document_type; } static int impl_get_load_percent (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; return mpriv->load_percent; } static void mozilla_embed_set_load_percent (MozillaEmbed *embed, int percent) { MozillaEmbedPrivate *mpriv = embed->priv; if (percent != mpriv->load_percent) { mpriv->load_percent = percent; g_object_notify (G_OBJECT (embed), "load-progress"); } } static gboolean impl_get_load_status (EphyEmbed *embed) { MozillaEmbedPrivate *mpriv = MOZILLA_EMBED(embed)->priv; return mpriv->is_loading; } static void mozilla_embed_set_load_status (MozillaEmbed *embed, gboolean status) { MozillaEmbedPrivate *mpriv = embed->priv; guint is_loading; is_loading = status != FALSE; if (is_loading != mpriv->is_loading) { mpriv->is_loading = is_loading; g_object_notify (G_OBJECT (embed), "load-status"); } } static void mozilla_embed_update_navigation_flags (MozillaEmbed *membed) { MozillaEmbedPrivate *priv = membed->priv; EphyEmbed *embed = EPHY_EMBED (membed); guint flags = 0; if (impl_can_go_up (embed)) { flags |= EPHY_EMBED_NAV_UP; } if (impl_can_go_back (embed)) { flags |= EPHY_EMBED_NAV_BACK; } if (impl_can_go_forward (embed)) { flags |= EPHY_EMBED_NAV_FORWARD; } if (priv->nav_flags != (EphyEmbedNavigationFlags)flags) { priv->nav_flags = (EphyEmbedNavigationFlags)flags; g_object_notify (G_OBJECT (embed), "navigation"); } } static EphyEmbedNavigationFlags impl_get_navigation_flags (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; return priv->nav_flags; } static const char* impl_get_typed_address (EphyEmbed *embed) { return MOZILLA_EMBED (embed)->priv->typed_address; } static void impl_set_typed_address (EphyEmbed *embed, const char *address, EphyEmbedAddressExpire expire) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; g_free (priv->typed_address); priv->typed_address = g_strdup (address); if (expire == EPHY_EMBED_ADDRESS_EXPIRE_CURRENT && !priv->is_loading) { priv->address_expire = EPHY_EMBED_ADDRESS_EXPIRE_NOW; } else { priv->address_expire = expire; } g_object_notify (G_OBJECT (embed), "typed-address"); } static const char* impl_get_address (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; return priv->address ? priv->address : "about:blank"; } static const char* impl_get_status_message (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; if (priv->link_message && priv->link_message[0] != '\0') { return priv->link_message; } else if (priv->status_message) { return priv->status_message; } else { return NULL; } } static const char* impl_get_link_message (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; return priv->link_message; } static gboolean impl_get_is_blank (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; return priv->is_blank; } static const char* impl_get_loading_title (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; return priv->loading_title; } static const char* impl_get_icon_address (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; return priv->icon_address; } static GdkPixbuf* impl_get_icon (EphyEmbed *embed) { MozillaEmbedPrivate *priv = MOZILLA_EMBED (embed)->priv; return priv->icon; } static void mozilla_embed_set_address (MozillaEmbed *embed, char *address) { MozillaEmbedPrivate *priv = embed->priv; GObject *object = G_OBJECT (embed); g_free (priv->address); priv->address = address; priv->is_blank = address == NULL || strcmp (address, "about:blank") == 0; if (priv->is_loading && priv->address_expire == EPHY_EMBED_ADDRESS_EXPIRE_NOW && priv->typed_address != NULL) { g_free (priv->typed_address); priv->typed_address = NULL; g_object_notify (object, "typed-address"); } g_object_notify (object, "address"); } static void mozilla_embed_file_monitor_cancel (MozillaEmbed *embed) { MozillaEmbedPrivate *priv = embed->priv; if (priv->monitor != NULL) { LOG ("Cancelling file monitor"); gnome_vfs_monitor_cancel (priv->monitor); priv->monitor = NULL; } if (priv->reload_scheduled_id != 0) { LOG ("Cancelling scheduled reload"); g_source_remove (priv->reload_scheduled_id); priv->reload_scheduled_id = 0; } priv->reload_delay_ticks = 0; } static gboolean ephy_file_monitor_reload_cb (MozillaEmbed *embed) { MozillaEmbedPrivate *priv = embed->priv; if (priv->reload_delay_ticks > 0) { priv->reload_delay_ticks--; /* Run again */ return TRUE; } if (priv->is_loading) { /* Wait a bit to reload if we're still loading! */ priv->reload_delay_ticks = RELOAD_DELAY_MAX_TICKS / 2; /* Run again */ return TRUE; } priv->reload_scheduled_id = 0; //LOG ("Reloading file '%s'", impl_get_address (embed)); impl_reload (EPHY_EMBED (embed), TRUE); /* don't run again */ return FALSE; } static void mozilla_embed_file_monitor_cb (GnomeVFSMonitorHandle *handle, const gchar *monitor_uri, const gchar *info_uri, GnomeVFSMonitorEventType event_type, MozillaEmbed *embed) { gboolean uri_is_directory; gboolean should_reload; char* local_path; MozillaEmbedPrivate *priv = embed->priv; LOG ("File '%s' has changed, scheduling reload", monitor_uri); local_path = gnome_vfs_get_local_path_from_uri(monitor_uri); uri_is_directory = g_file_test(local_path, G_FILE_TEST_IS_DIR); g_free(local_path); switch (event_type) { /* These events will always trigger a reload: */ case GNOME_VFS_MONITOR_EVENT_CHANGED: case GNOME_VFS_MONITOR_EVENT_CREATED: should_reload = TRUE; break; /* These events will only trigger a reload for directories: */ case GNOME_VFS_MONITOR_EVENT_DELETED: case GNOME_VFS_MONITOR_EVENT_METADATA_CHANGED: should_reload = uri_is_directory; break; /* These events don't trigger a reload: */ case GNOME_VFS_MONITOR_EVENT_STARTEXECUTING: case GNOME_VFS_MONITOR_EVENT_STOPEXECUTING: default: should_reload = FALSE; break; } if (should_reload) { /* We make a lot of assumptions here, but basically we know * that we just have to reload, by construction. * Delay the reload a little bit so we don't endlessly * reload while a file is written. */ if (priv->reload_delay_ticks == 0) { priv->reload_delay_ticks = 1; } else { /* Exponential backoff */ priv->reload_delay_ticks = MIN (priv->reload_delay_ticks * 2, RELOAD_DELAY_MAX_TICKS); } if (priv->reload_scheduled_id == 0) { priv->reload_scheduled_id = g_timeout_add (RELOAD_DELAY, (GSourceFunc) ephy_file_monitor_reload_cb, embed); } } } static void mozilla_embed_update_file_monitor (MozillaEmbed *embed, const gchar *address) { MozillaEmbedPrivate *priv = embed->priv; GnomeVFSMonitorHandle *handle = NULL; gboolean local; char* local_path; GnomeVFSMonitorType monitor_type; if (priv->monitor != NULL && priv->address != NULL && address != NULL && strcmp (priv->address, address) == 0) { /* same address, no change needed */ return; } mozilla_embed_file_monitor_cancel (embed); local = g_str_has_prefix (address, "file://"); if (local == FALSE) return; local_path = gnome_vfs_get_local_path_from_uri(address); monitor_type = g_file_test(local_path, G_FILE_TEST_IS_DIR) ? GNOME_VFS_MONITOR_DIRECTORY : GNOME_VFS_MONITOR_FILE; g_free(local_path); if (gnome_vfs_monitor_add (&handle, address, monitor_type, (GnomeVFSMonitorCallback) mozilla_embed_file_monitor_cb, embed) == GNOME_VFS_OK) { LOG ("Installed monitor for file '%s'", address); priv->monitor = handle; } } static void mozilla_embed_set_link_message (MozillaEmbed *embed, char *link_message) { MozillaEmbedPrivate *priv = embed->priv; g_free (priv->link_message); priv->link_message = ephy_embed_utils_link_message_parse (link_message); g_object_notify (G_OBJECT (embed), "status-message"); g_object_notify (G_OBJECT (embed), "link-message"); } static void mozilla_embed_location_changed_cb (GtkMozEmbed *embed, MozillaEmbed *membed) { char *location; GObject *object = G_OBJECT (embed); location = gtk_moz_embed_get_location (embed); g_signal_emit_by_name (membed, "ge_location", location); g_object_freeze_notify (object); /* do this up here so we still have the old address around */ mozilla_embed_update_file_monitor (membed, location); /* Do not expose about:blank to the user, an empty address bar will do better */ if (location == NULL || location[0] == '\0' || strcmp (location, "about:blank") == 0) { mozilla_embed_set_address (membed, NULL); mozilla_embed_set_title (membed, NULL); } else { char *embed_address; /* we do this to get rid of an eventual password in the URL */ embed_address = impl_get_location (EPHY_EMBED (embed), TRUE); mozilla_embed_set_address (membed, embed_address); mozilla_embed_set_loading_title (membed, embed_address, TRUE); } g_free (location); mozilla_embed_set_link_message (membed, NULL); mozilla_embed_set_icon_address (membed, NULL); mozilla_embed_update_navigation_flags (membed); g_object_notify (object, "title"); g_object_thaw_notify (object); } static void mozilla_embed_link_message_cb (EphyEmbed *embed, MozillaEmbed *membed) { char *link_message = gtk_moz_embed_get_link_message (GTK_MOZ_EMBED (membed)); mozilla_embed_set_link_message (membed, link_message); g_free (link_message); } static void mozilla_embed_load_icon (MozillaEmbed *embed) { MozillaEmbedPrivate *priv = embed->priv; EphyEmbedShell *shell; EphyFaviconCache *cache; if (priv->icon_address == NULL || priv->icon != NULL) return; shell = ephy_embed_shell_get_default (); cache = EPHY_FAVICON_CACHE (ephy_embed_shell_get_favicon_cache (shell)); /* ephy_favicon_cache_get returns a reference already */ priv->icon = ephy_favicon_cache_get (cache, priv->icon_address); g_object_notify (G_OBJECT (embed), "icon"); } static void mozilla_embed_icon_cache_changed_cb (EphyFaviconCache *cache, const char *address, MozillaEmbed *embed) { MozillaEmbedPrivate *priv = embed->priv; g_return_if_fail (address != NULL); /* is this for us? */ if (priv->icon_address != NULL && strcmp (priv->icon_address, address) == 0) { mozilla_embed_load_icon (embed); } } static void mozilla_embed_set_icon_address (MozillaEmbed *embed, const char *address) { GObject *object = G_OBJECT (embed); MozillaEmbedPrivate *priv = embed->priv; /* EphyBookmarks *eb;*/ EphyHistory *history; g_free (priv->icon_address); priv->icon_address = g_strdup (address); if (priv->icon != NULL) { g_object_unref (priv->icon); priv->icon = NULL; g_object_notify (object, "icon"); } if (priv->icon_address) { /* FIXME: we need to put this somewhere inside src?/ history = EPHY_HISTORY (ephy_embed_shell_get_global_history (embed_shell)); ephy_history_set_icon (history, priv->address, priv->icon_address); eb = ephy_shell_get_bookmarks (ephy_shell); ephy_bookmarks_set_icon (eb, priv->address, priv->icon_address);*/ mozilla_embed_load_icon (embed); } g_object_notify (object, "icon-address"); } static void mozilla_embed_favicon_cb (EphyEmbed *embed, const char *address, MozillaEmbed *membed) { mozilla_embed_set_icon_address (membed, address); } static gboolean address_has_web_scheme (const char *address) { gboolean has_web_scheme; if (address == NULL) return FALSE; has_web_scheme = (g_str_has_prefix (address, "http:") || g_str_has_prefix (address, "https:") || g_str_has_prefix (address, "ftp:") || g_str_has_prefix (address, "file:") || g_str_has_prefix (address, "data:") || g_str_has_prefix (address, "about:") || g_str_has_prefix (address, "gopher:")); return has_web_scheme; } static void mozilla_embed_restore_zoom_level (MozillaEmbed *membed, const char *address) { MozillaEmbedPrivate *priv = membed->priv; /* restore zoom level */ if (address_has_web_scheme (address)) { EphyHistory *history; EphyNode *host; GValue value = { 0, }; float zoom = 1.0, current_zoom; history = EPHY_HISTORY (ephy_embed_shell_get_global_history (embed_shell)); host = ephy_history_get_host (history, address); if (host != NULL && ephy_node_get_property (host, EPHY_NODE_HOST_PROP_ZOOM, &value)) { zoom = g_value_get_float (&value); g_value_unset (&value); } current_zoom = ephy_embed_get_zoom (EPHY_EMBED (membed)); if (zoom != current_zoom) { priv->is_setting_zoom = TRUE; ephy_embed_set_zoom (EPHY_EMBED (membed), zoom); priv->is_setting_zoom = FALSE; } } } static void update_load_state (MozillaEmbed *membed, gint state) { MozillaEmbedPrivate *priv = membed->priv; if (state & GTK_MOZ_EMBED_FLAG_IS_DOCUMENT && state & (GTK_MOZ_EMBED_FLAG_START | GTK_MOZ_EMBED_FLAG_STOP)) { g_signal_emit_by_name (membed, "ge-document-type", priv->browser->GetDocumentType ()); } if (state & GTK_MOZ_EMBED_FLAG_RESTORING && priv->load_state == MOZILLA_EMBED_LOAD_STARTED) { priv->load_state = MOZILLA_EMBED_LOAD_LOADING; char *address; address = gtk_moz_embed_get_location (GTK_MOZ_EMBED (membed)); g_signal_emit_by_name (membed, "ge-content-change", address); mozilla_embed_restore_zoom_level (membed, address); g_free (address); } if (state & GTK_MOZ_EMBED_FLAG_IS_NETWORK) { if (state & GTK_MOZ_EMBED_FLAG_START) { priv->load_state = MOZILLA_EMBED_LOAD_STARTED; } else if (state & GTK_MOZ_EMBED_FLAG_STOP) { priv->load_state = MOZILLA_EMBED_LOAD_STOPPED; } } else if (state & GTK_MOZ_EMBED_FLAG_START && state & GTK_MOZ_EMBED_FLAG_IS_REQUEST) { if (priv->load_state == MOZILLA_EMBED_LOAD_REDIRECTING) { priv->load_state = MOZILLA_EMBED_LOAD_STARTED; } else if (priv->load_state != MOZILLA_EMBED_LOAD_LOADING) { priv->load_state = MOZILLA_EMBED_LOAD_LOADING; char *address; address = gtk_moz_embed_get_location (GTK_MOZ_EMBED (membed)); g_signal_emit_by_name (membed, "ge_content_change", address); mozilla_embed_restore_zoom_level (membed, address); g_free (address); } } else if (state & GTK_MOZ_EMBED_FLAG_REDIRECTING && priv->load_state == MOZILLA_EMBED_LOAD_STARTED) { priv->load_state = MOZILLA_EMBED_LOAD_REDIRECTING; } } static void update_net_state_message (MozillaEmbed *embed, const char *uri, EphyEmbedNetState flags) { GnomeVFSURI *vfs_uri = NULL; const char *msg = NULL; const char *host = NULL; if (uri != NULL) { vfs_uri = gnome_vfs_uri_new (uri); } if (vfs_uri != NULL) { host = gnome_vfs_uri_get_host_name (vfs_uri); } if (host == NULL || host[0] == '\0') goto out; /* IS_REQUEST and IS_NETWORK can be both set */ if (flags & EPHY_EMBED_STATE_IS_REQUEST) { if (flags & EPHY_EMBED_STATE_REDIRECTING) { msg = _("Redirecting to “%s”…"); } else if (flags & EPHY_EMBED_STATE_TRANSFERRING) { msg = _("Transferring data from “%s”…"); } else if (flags & EPHY_EMBED_STATE_NEGOTIATING) { msg = _("Waiting for authorization from “%s”…"); } } if (flags & EPHY_EMBED_STATE_IS_NETWORK) { if (flags & EPHY_EMBED_STATE_START) { msg = _("Loading “%s”…"); } } if ((flags & EPHY_EMBED_STATE_IS_NETWORK) && (flags & EPHY_EMBED_STATE_STOP)) { g_free (embed->priv->status_message); embed->priv->status_message = NULL; g_object_notify (G_OBJECT (embed), "status-message"); } else if (msg != NULL) { g_free (embed->priv->status_message); g_free (embed->priv->loading_title); embed->priv->status_message = g_strdup_printf (msg, host); embed->priv->loading_title = g_strdup_printf (msg, host); g_object_notify (G_OBJECT (embed), "status-message"); g_object_notify (G_OBJECT (embed), "title"); } out: if (vfs_uri != NULL) { gnome_vfs_uri_unref (vfs_uri); } } static int build_load_percent (int requests_done, int requests_total) { int percent= 0; if (requests_total > 0) { percent = (requests_done * 100) / requests_total; /* Mozilla sometimes report more done requests than total requests. Their progress widget clamp the value */ percent = CLAMP (percent, 0, 100); } return percent; } static void build_progress_from_requests (MozillaEmbed *embed, EphyEmbedNetState state) { int load_percent; if (state & EPHY_EMBED_STATE_IS_REQUEST) { if (state & EPHY_EMBED_STATE_START) { embed->priv->total_requests ++; } else if (state & EPHY_EMBED_STATE_STOP) { embed->priv->cur_requests ++; } load_percent = build_load_percent (embed->priv->cur_requests, embed->priv->total_requests); mozilla_embed_set_load_percent (embed, load_percent); } } static void ensure_page_info (MozillaEmbed *embed, const char *address) { MozillaEmbedPrivate *priv = embed->priv; if ((priv->address == NULL || priv->address[0] == '\0') && priv->address_expire == EPHY_EMBED_ADDRESS_EXPIRE_NOW) { mozilla_embed_set_address (embed, g_strdup (address)); } /* FIXME huh?? */ if (priv->title == NULL || priv->title[0] == '\0') { mozilla_embed_set_title (embed, NULL); } } static void update_embed_from_net_state (MozillaEmbed *embed, const char *uri, EphyEmbedNetState state) { MozillaEmbedPrivate *priv = embed->priv; update_net_state_message (embed, uri, state); if (state & EPHY_EMBED_STATE_IS_NETWORK) { if (state & EPHY_EMBED_STATE_START) { GObject *object = G_OBJECT (embed); g_object_freeze_notify (object); priv->total_requests = 0; priv->cur_requests = 0; mozilla_embed_set_load_percent (embed, 0); mozilla_embed_set_load_status (embed, TRUE); ensure_page_info (embed, uri); g_object_notify (object, "title"); g_object_thaw_notify (object); } else if (state & EPHY_EMBED_STATE_STOP) { GObject *object = G_OBJECT (embed); g_object_freeze_notify (object); mozilla_embed_set_load_percent (embed, 100); mozilla_embed_set_load_status (embed, FALSE); g_free (priv->loading_title); priv->loading_title = NULL; priv->address_expire = EPHY_EMBED_ADDRESS_EXPIRE_NOW; g_object_notify (object, "title"); g_object_thaw_notify (object); } mozilla_embed_update_navigation_flags (embed); } build_progress_from_requests (embed, state); } static void mozilla_embed_net_state_all_cb (GtkMozEmbed *embed, const char *aURI, gint state, guint status, MozillaEmbed *membed) { EphyEmbedNetState estate = EPHY_EMBED_STATE_UNKNOWN; int i; struct { guint state; EphyEmbedNetState embed_state; } conversion_map [] = { { GTK_MOZ_EMBED_FLAG_START, EPHY_EMBED_STATE_START }, { GTK_MOZ_EMBED_FLAG_STOP, EPHY_EMBED_STATE_STOP }, { GTK_MOZ_EMBED_FLAG_REDIRECTING, EPHY_EMBED_STATE_REDIRECTING }, { GTK_MOZ_EMBED_FLAG_TRANSFERRING, EPHY_EMBED_STATE_TRANSFERRING }, { GTK_MOZ_EMBED_FLAG_NEGOTIATING, EPHY_EMBED_STATE_NEGOTIATING }, { GTK_MOZ_EMBED_FLAG_IS_REQUEST, EPHY_EMBED_STATE_IS_REQUEST }, { GTK_MOZ_EMBED_FLAG_IS_DOCUMENT, EPHY_EMBED_STATE_IS_DOCUMENT }, { GTK_MOZ_EMBED_FLAG_IS_NETWORK, EPHY_EMBED_STATE_IS_NETWORK }, { GTK_MOZ_EMBED_FLAG_RESTORING, EPHY_EMBED_STATE_RESTORING }, { 0, EPHY_EMBED_STATE_UNKNOWN } }; for (i = 0; conversion_map[i].state != 0; i++) { if (state & conversion_map[i].state) { estate = (EphyEmbedNetState) (estate | conversion_map[i].embed_state); } } update_load_state (membed, state); update_embed_from_net_state (membed, aURI, (EphyEmbedNetState)estate); g_signal_emit_by_name (membed, "ge_net_state", aURI, /* FIXME: (gulong) */ estate); } static gboolean mozilla_embed_emit_mouse_signal (MozillaEmbed *embed, gpointer dom_event, const char *signal_name) { MozillaEmbedPrivate *mpriv = embed->priv; MozillaEmbedEvent *info; EventContext event_context; gint return_value = FALSE; nsresult rv; if (dom_event == NULL) return FALSE; nsCOMPtr ev = static_cast(dom_event); NS_ENSURE_TRUE (ev, FALSE); nsCOMPtr dev = do_QueryInterface (ev); NS_ENSURE_TRUE (dev, FALSE); info = mozilla_embed_event_new (static_cast(dev)); event_context.Init (mpriv->browser); rv = event_context.GetMouseEventInfo (ev, MOZILLA_EMBED_EVENT (info)); if (NS_FAILED (rv)) { g_object_unref (info); return FALSE; } nsCOMPtr domDoc; rv = event_context.GetTargetDocument (getter_AddRefs(domDoc)); if (NS_SUCCEEDED (rv)) { mpriv->browser->PushTargetDocument (domDoc); g_signal_emit_by_name (embed, signal_name, info, &return_value); mpriv->browser->PopTargetDocument (); } g_object_unref (info); return return_value; } static gboolean mozilla_embed_dom_mouse_click_cb (GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed) { return mozilla_embed_emit_mouse_signal (membed, dom_event, "ge_dom_mouse_click"); } static gboolean mozilla_embed_dom_mouse_down_cb (GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed) { return mozilla_embed_emit_mouse_signal (membed, dom_event, "ge_dom_mouse_down"); } static gint mozilla_embed_dom_key_press_cb (GtkMozEmbed *embed, gpointer dom_event, MozillaEmbed *membed) { gint retval = FALSE; if (dom_event == NULL) return FALSE; nsCOMPtr ev = static_cast(dom_event); NS_ENSURE_TRUE (ev, FALSE); if (!EventContext::CheckKeyPress (ev)) return FALSE; GdkEvent *event = gtk_get_current_event (); if (event == NULL) return FALSE; /* shouldn't happen! */ g_return_val_if_fail (GDK_KEY_PRESS == event->type, FALSE); g_signal_emit_by_name (embed, "ge-search-key-press", event, &retval); gdk_event_free (event); return retval; } EphyEmbedChrome _mozilla_embed_translate_chrome (GtkMozEmbedChromeFlags flags) { static const struct { guint mozilla_flag; guint ephy_flag; } conversion_map [] = { { GTK_MOZ_EMBED_FLAG_MENUBARON, EPHY_EMBED_CHROME_MENUBAR }, { GTK_MOZ_EMBED_FLAG_TOOLBARON, EPHY_EMBED_CHROME_TOOLBAR }, { GTK_MOZ_EMBED_FLAG_STATUSBARON, EPHY_EMBED_CHROME_STATUSBAR }, { GTK_MOZ_EMBED_FLAG_PERSONALTOOLBARON, EPHY_EMBED_CHROME_BOOKMARKSBAR }, }; guint mask = 0, i; for (i = 0; i < G_N_ELEMENTS (conversion_map); i++) { if (flags & conversion_map[i].mozilla_flag) { mask |= conversion_map[i].ephy_flag; } } return (EphyEmbedChrome) mask; } static void mozilla_embed_new_window_cb (GtkMozEmbed *embed, GtkMozEmbed **newEmbed, guint chrome_mask, MozillaEmbed *membed) { GtkMozEmbedChromeFlags chrome = (GtkMozEmbedChromeFlags) chrome_mask; EphyEmbed *new_embed = NULL; GObject *single; EphyEmbedChrome mask; if (chrome & GTK_MOZ_EMBED_FLAG_OPENASCHROME) { *newEmbed = _mozilla_embed_new_xul_dialog (); return; } mask = _mozilla_embed_translate_chrome (chrome); single = ephy_embed_shell_get_embed_single (embed_shell); g_signal_emit_by_name (single, "new-window", embed, mask, &new_embed); g_assert (new_embed != NULL); gtk_moz_embed_set_chrome_mask (GTK_MOZ_EMBED (new_embed), chrome); g_signal_emit_by_name (membed, "ge-new-window", new_embed); *newEmbed = GTK_MOZ_EMBED (new_embed); } static void mozilla_embed_set_security_level (MozillaEmbed *embed, EphyEmbedSecurityLevel level) { MozillaEmbedPrivate *priv = embed->priv; if (priv->security_level != level) { priv->security_level = level; g_object_notify (G_OBJECT (embed), "security-level"); } } static void mozilla_embed_security_change_cb (GtkMozEmbed *embed, gpointer requestptr, PRUint32 state, MozillaEmbed *membed) { mozilla_embed_set_security_level (membed, mozilla_embed_security_level (state)); } static void mozilla_embed_document_type_cb (EphyEmbed *embed, EphyEmbedDocumentType type, MozillaEmbed *membed) { if (membed->priv->document_type != type) { membed->priv->document_type = type; g_object_notify (G_OBJECT (membed), "document-type"); } } static void mozilla_embed_zoom_change_cb (EphyEmbed *embed, float zoom, MozillaEmbed *membed) { char *address; if (membed->priv->zoom != zoom) { if (membed->priv->is_setting_zoom) { return; } address = ephy_embed_get_location (embed, TRUE); if (address_has_web_scheme (address)) { EphyHistory *history; EphyNode *host; history = EPHY_HISTORY (ephy_embed_shell_get_global_history (embed_shell)); host = ephy_history_get_host (history, address); if (host != NULL) { ephy_node_set_property_float (host, EPHY_NODE_HOST_PROP_ZOOM, zoom); } } g_free (address); membed->priv->zoom = zoom; g_object_notify (G_OBJECT (membed), "zoom"); } } static char * get_title_from_address (const char *address) { GnomeVFSURI *uri; char *title; if (address == NULL) return NULL; uri = gnome_vfs_uri_new (address); if (uri == NULL) return g_strdup (address); title = gnome_vfs_uri_to_string (uri, (GnomeVFSURIHideOptions) (GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD | GNOME_VFS_URI_HIDE_HOST_PORT | GNOME_VFS_URI_HIDE_TOPLEVEL_METHOD | GNOME_VFS_URI_HIDE_FRAGMENT_IDENTIFIER)); gnome_vfs_uri_unref (uri); return title; } static void mozilla_embed_set_loading_title (MozillaEmbed *embed, const char *title, gboolean is_address) { MozillaEmbedPrivate *priv = embed->priv; char *freeme = NULL; g_free (priv->loading_title); priv->loading_title = NULL; if (is_address) { title = freeme = get_title_from_address (title); } if (title != NULL && title[0] != '\0') { /* translators: %s here is the address of the web page */ priv->loading_title = g_strdup_printf (_("Loading “%s”…"), title); } else { priv->loading_title = g_strdup (_("Loading…")); } g_free (freeme); } static void mozilla_embed_set_title (MozillaEmbed *embed, char *title) { MozillaEmbedPrivate *priv = embed->priv; if (!priv->is_blank && (title == NULL || g_strstrip (title)[0] == '\0')) { g_free (title); title = get_title_from_address (priv->address); /* Fallback */ if (title == NULL || title[0] == '\0') { g_free (title); title = NULL; priv->is_blank = TRUE; } } else if (priv->is_blank && title != NULL) { g_free (title); title = NULL; } g_free (priv->title); priv->title = ephy_string_shorten (title, MAX_TITLE_LENGTH); g_object_notify (G_OBJECT (embed), "title"); } static void mozilla_embed_title_change_cb (EphyEmbed *embed, MozillaEmbed *membed) { GObject *object = G_OBJECT (embed); char *title; title = gtk_moz_embed_get_title (GTK_MOZ_EMBED (embed)); g_object_freeze_notify (object); mozilla_embed_set_title (membed, title); mozilla_embed_set_loading_title (membed, title, FALSE); g_object_thaw_notify (object); } static gboolean mozilla_embed_open_uri_cb (EphyEmbed *embed, const char *uri, MozillaEmbed *membed) { MozillaEmbedPrivate *priv = membed->priv; /* Set the address here if we have a blank page. * See bug #147840. */ if (priv->is_blank) { mozilla_embed_set_address (membed, g_strdup (uri)); mozilla_embed_set_loading_title (membed, uri, TRUE); } /* allow load to proceed */ return FALSE; } static EphyEmbedSecurityLevel mozilla_embed_security_level (PRUint32 state) { EphyEmbedSecurityLevel level; switch (state) { case nsIWebProgressListener::STATE_IS_INSECURE: level = EPHY_EMBED_STATE_IS_INSECURE; break; case nsIWebProgressListener::STATE_IS_BROKEN: level = EPHY_EMBED_STATE_IS_BROKEN; break; case nsIWebProgressListener::STATE_IS_SECURE| nsIWebProgressListener::STATE_SECURE_HIGH: level = EPHY_EMBED_STATE_IS_SECURE_HIGH; break; case nsIWebProgressListener::STATE_IS_SECURE| nsIWebProgressListener::STATE_SECURE_MED: level = EPHY_EMBED_STATE_IS_SECURE_MED; break; case nsIWebProgressListener::STATE_IS_SECURE| nsIWebProgressListener::STATE_SECURE_LOW: level = EPHY_EMBED_STATE_IS_SECURE_LOW; break; default: level = EPHY_EMBED_STATE_IS_UNKNOWN; break; } return level; } static void ephy_embed_iface_init (EphyEmbedIface *iface) { iface->load_url = impl_load_url; iface->load = impl_load; iface->stop_load = impl_stop_load; iface->can_go_back = impl_can_go_back; iface->can_go_forward =impl_can_go_forward; iface->can_go_up = impl_can_go_up; iface->get_go_up_list = impl_get_go_up_list; iface->go_back = impl_go_back; iface->go_forward = impl_go_forward; iface->go_up = impl_go_up; iface->get_title = impl_get_title; iface->get_location = impl_get_location; iface->get_link_message = impl_get_link_message; iface->get_js_status = impl_get_js_status; iface->reload = impl_reload; iface->set_zoom = impl_set_zoom; iface->get_zoom = impl_get_zoom; iface->scroll_lines = impl_scroll_lines; iface->scroll_pages = impl_scroll_pages; iface->scroll_pixels = impl_scroll_pixels; iface->shistory_n_items = impl_shistory_n_items; iface->shistory_get_nth = impl_shistory_get_nth; iface->shistory_get_pos = impl_shistory_get_pos; iface->shistory_go_nth = impl_shistory_go_nth; iface->shistory_copy = impl_shistory_copy; iface->get_security_level = impl_get_security_level; iface->show_page_certificate = impl_show_page_certificate; iface->close = impl_close; iface->set_encoding = impl_set_encoding; iface->get_encoding = impl_get_encoding; iface->has_automatic_encoding = impl_has_automatic_encoding; iface->print = impl_print; iface->set_print_preview_mode = impl_set_print_preview_mode; iface->print_preview_n_pages = impl_print_preview_n_pages; iface->print_preview_navigate = impl_print_preview_navigate; iface->has_modified_forms = impl_has_modified_forms; iface->get_document_type = impl_get_document_type; iface->get_load_percent = impl_get_load_percent; iface->get_load_status = impl_get_load_status; iface->get_navigation_flags = impl_get_navigation_flags; iface->get_typed_address = impl_get_typed_address; iface->set_typed_address = impl_set_typed_address; iface->get_address = impl_get_address; iface->get_status_message = impl_get_status_message; iface->get_is_blank = impl_get_is_blank; iface->get_loading_title = impl_get_loading_title; iface->get_icon = impl_get_icon; iface->get_icon_address = impl_get_icon_address; } static void xul_visibility_cb (GtkWidget *embed, gboolean visibility, GtkWidget *window) { if (visibility) { gtk_widget_show (window); } else { gtk_widget_hide (window); } } static void xul_size_to_cb (GtkWidget *embed, gint width, gint height, gpointer dummy) { gtk_widget_set_size_request (embed, width, height); } static void xul_new_window_cb (GtkMozEmbed *embed, GtkMozEmbed **retval, guint chrome_mask, gpointer dummy) { g_assert (chrome_mask & GTK_MOZ_EMBED_FLAG_OPENASCHROME); *retval = _mozilla_embed_new_xul_dialog (); } static void xul_title_cb (GtkMozEmbed *embed, GtkWindow *window) { char *title; title = gtk_moz_embed_get_title (embed); gtk_window_set_title (window, title); g_free (title); } GtkMozEmbed * _mozilla_embed_new_xul_dialog (void) { GtkWidget *window, *embed; g_object_ref (embed_shell); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_object_set_data_full (G_OBJECT (window), "EmbedShellRef", embed_shell, (GDestroyNotify) g_object_unref); g_signal_connect_object (embed_shell, "prepare_close", G_CALLBACK (gtk_widget_destroy), window, (GConnectFlags) G_CONNECT_SWAPPED); embed = gtk_moz_embed_new (); gtk_widget_show (embed); gtk_container_add (GTK_CONTAINER (window), embed); g_signal_connect_object (embed, "destroy_browser", G_CALLBACK (gtk_widget_destroy), window, G_CONNECT_SWAPPED); g_signal_connect_object (embed, "visibility", G_CALLBACK (xul_visibility_cb), window, (GConnectFlags) 0); g_signal_connect_object (embed, "size_to", G_CALLBACK (xul_size_to_cb), NULL, (GConnectFlags) 0); g_signal_connect_object (embed, "new_window", G_CALLBACK (xul_new_window_cb), NULL, (GConnectFlags) 0); g_signal_connect_object (embed, "title", G_CALLBACK (xul_title_cb), window, (GConnectFlags) 0); return GTK_MOZ_EMBED (embed); }