diff options
author | Xan Lopez <xan@src.gnome.org> | 2007-11-06 03:54:57 +0800 |
---|---|---|
committer | Xan Lopez <xan@src.gnome.org> | 2007-11-06 03:54:57 +0800 |
commit | d73b100991cd2b294365bf5cc5f9627fdaa979a9 (patch) | |
tree | cd096d98d921e1ea18bdd6e3f2d80a7bdb64bb07 /embed/ephy-base-embed.c | |
parent | d166fac07ccf16fba79aadb092d9c0ad95d3ab02 (diff) | |
download | gsoc2013-epiphany-d73b100991cd2b294365bf5cc5f9627fdaa979a9.tar gsoc2013-epiphany-d73b100991cd2b294365bf5cc5f9627fdaa979a9.tar.gz gsoc2013-epiphany-d73b100991cd2b294365bf5cc5f9627fdaa979a9.tar.bz2 gsoc2013-epiphany-d73b100991cd2b294365bf5cc5f9627fdaa979a9.tar.lz gsoc2013-epiphany-d73b100991cd2b294365bf5cc5f9627fdaa979a9.tar.xz gsoc2013-epiphany-d73b100991cd2b294365bf5cc5f9627fdaa979a9.tar.zst gsoc2013-epiphany-d73b100991cd2b294365bf5cc5f9627fdaa979a9.zip |
Move all common functionality from MozillaEmbed to EphyBaseEmbed.
svn path=/trunk/; revision=7628
Diffstat (limited to 'embed/ephy-base-embed.c')
-rw-r--r-- | embed/ephy-base-embed.c | 1438 |
1 files changed, 1413 insertions, 25 deletions
diff --git a/embed/ephy-base-embed.c b/embed/ephy-base-embed.c index ade799d82..5c6167aa8 100644 --- a/embed/ephy-base-embed.c +++ b/embed/ephy-base-embed.c @@ -1,5 +1,7 @@ /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* + * Copyright © 2000-2004 Marco Pesenti Gritti + * Copyright © 2003-2007 Christian Persch * Copyright © 2007 Xan Lopez * * This program is free software; you can redistribute it and/or modify @@ -19,43 +21,96 @@ */ #include "config.h" + +#include <glib/gi18n.h> +#include <libgnomevfs/gnome-vfs.h> +#include <libgnomevfs/gnome-vfs-uri.h> +#include <string.h> + +#include "ephy-debug.h" #include "ephy-embed.h" +#include "ephy-embed-shell.h" #include "ephy-embed-type-builtins.h" +#include "ephy-embed-utils.h" +#include "ephy-favicon-cache.h" +#include "ephy-history.h" +#include "ephy-string.h" #include "ephy-zoom.h" #include "ephy-base-embed.h" +#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 _EphyBaseEmbedPrivate { + 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; }; -enum +#if 0 +typedef struct { - 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 -}; + char *url; + char *name; + char *features; +} PopupInfo; +#endif +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 + }; + +#define EPHY_BASE_EMBED_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_BASE_EMBED, EphyBaseEmbedPrivate)) + +static void ephy_base_embed_file_monitor_cancel (EphyBaseEmbed *embed); static void ephy_base_embed_dispose (GObject *object); static void ephy_base_embed_finalize (GObject *object); static void ephy_embed_iface_init (EphyEmbedIface *iface); @@ -73,7 +128,7 @@ ephy_base_embed_size_request (GtkWidget *widget, GTK_WIDGET_CLASS (ephy_base_embed_parent_class)->size_request (widget, requisition); child = GTK_BIN (widget)->child; - + if (child && GTK_WIDGET_VISIBLE (child)) { GtkRequisition child_requisition; @@ -96,11 +151,122 @@ ephy_base_embed_size_allocate (GtkWidget *widget, } static void -ephy_base_embed_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +impl_set_typed_address (EphyEmbed *embed, + const char *address, + EphyEmbedAddressExpire expire) +{ + EphyBaseEmbedPrivate *priv = EPHY_BASE_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_typed_address (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->typed_address; +} + +static const char* +impl_get_loading_title (EphyEmbed *embed) +{ + EphyBaseEmbedPrivate *priv = EPHY_BASE_EMBED (embed)->priv; + + return priv->loading_title; +} + +static gboolean +impl_get_is_blank (EphyEmbed *embed) +{ + EphyBaseEmbedPrivate *priv = EPHY_BASE_EMBED (embed)->priv; + + return priv->is_blank; +} + +static const char* +impl_get_icon_address (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->icon_address; +} + +static GdkPixbuf* +impl_get_icon (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->icon; +} + +static const char * +impl_get_title (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->title; +} + +static EphyEmbedDocumentType +impl_get_document_type (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->document_type; +} + +static int +impl_get_load_percent (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->load_percent; +} + +static gboolean +impl_get_load_status (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->is_loading; +} + +static EphyEmbedNavigationFlags +impl_get_navigation_flags (EphyEmbed *embed) +{ + return EPHY_BASE_EMBED (embed)->priv->nav_flags; +} + +static const char* +impl_get_address (EphyEmbed *embed) +{ + EphyBaseEmbedPrivate *priv = EPHY_BASE_EMBED (embed)->priv; + return priv->address ? priv->address : "about:blank"; +} + +static const char* +impl_get_status_message (EphyEmbed *embed) +{ + EphyBaseEmbedPrivate *priv = EPHY_BASE_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) { + return EPHY_BASE_EMBED (embed)->priv->link_message; } static void @@ -109,6 +275,97 @@ ephy_base_embed_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { + switch (prop_id) + { + case PROP_ICON_ADDRESS: + ephy_base_embed_set_icon_address (EPHY_BASE_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: + //ephy_base_embed_set_popups_allowed (MOZILLA_EMBED (object), g_value_get_boolean (value)); + break; + case PROP_ADDRESS: + case PROP_TITLE: + 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: + break; + } +} + +static void +ephy_base_embed_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyBaseEmbedPrivate *priv = EPHY_BASE_EMBED (object)->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: + break; + } } static void @@ -246,14 +503,139 @@ ephy_base_embed_class_init (EphyBaseEmbedClass *klass) } static void +icon_cache_changed_cb (EphyFaviconCache *cache, + const char *address, + EphyBaseEmbed *embed) +{ + const char *icon_address; + + g_return_if_fail (address != NULL); + + icon_address = ephy_embed_get_icon_address (EPHY_EMBED (embed)); + + /* is this for us? */ + if (icon_address != NULL && + strcmp (icon_address, address) == 0) + { + ephy_base_embed_load_icon (EPHY_BASE_EMBED (embed)); + } +} + +static void +ge_document_type_cb (EphyEmbed *embed, + EphyEmbedDocumentType type, + EphyBaseEmbed *bembed) +{ + if (bembed->priv->document_type != type) + { + bembed->priv->document_type = type; + + g_object_notify (G_OBJECT (embed), "document-type"); + } +} + +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 +ge_zoom_change_cb (EphyEmbed *embed, + float zoom, + EphyBaseEmbed *bembed) +{ + char *address; + + if (bembed->priv->zoom != zoom) + { + if (bembed->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); + + bembed->priv->zoom = zoom; + + g_object_notify (G_OBJECT (embed), "zoom"); + } +} + +static void +ge_favicon_cb (EphyEmbed *membed, + const char *address, + EphyBaseEmbed *bembed) +{ + ephy_base_embed_set_icon_address (bembed, address); +} + +static void ephy_base_embed_init (EphyBaseEmbed *self) { + EphyBaseEmbedPrivate *priv; + EphyFaviconCache *cache; + + priv = self->priv = EPHY_BASE_EMBED_GET_PRIVATE (self); + + g_signal_connect_object (self, "ge_document_type", + G_CALLBACK (ge_document_type_cb), + self, (GConnectFlags) 0); + + g_signal_connect_object (self, "ge_zoom_change", + G_CALLBACK (ge_zoom_change_cb), + self, (GConnectFlags) 0); + + g_signal_connect_object (self, "ge_favicon", + G_CALLBACK (ge_favicon_cb), + self, (GConnectFlags)0); + + cache = EPHY_FAVICON_CACHE + (ephy_embed_shell_get_favicon_cache (embed_shell)); + g_signal_connect_object (G_OBJECT (cache), "changed", + G_CALLBACK (icon_cache_changed_cb), + self, (GConnectFlags)0); + + priv->document_type = EPHY_EMBED_DOCUMENT_HTML; + priv->security_level = EPHY_EMBED_STATE_IS_UNKNOWN; + priv->zoom = 1.0; + priv->address_expire = EPHY_EMBED_ADDRESS_EXPIRE_NOW; + priv->is_blank = TRUE; } static void ephy_base_embed_dispose (GObject *object) { - EphyBaseEmbed *self = (EphyBaseEmbed *)object; + ephy_base_embed_file_monitor_cancel (EPHY_BASE_EMBED (object)); G_OBJECT_CLASS (ephy_base_embed_parent_class)->dispose (object); } @@ -261,7 +643,25 @@ ephy_base_embed_dispose (GObject *object) static void ephy_base_embed_finalize (GObject *object) { - EphyBaseEmbed *self = (EphyBaseEmbed *)object; + EphyBaseEmbedPrivate *priv = EPHY_BASE_EMBED (object)->priv; + + if (priv->icon != NULL) + { + g_object_unref (priv->icon); + priv->icon = NULL; + } + +#if 0 + popups_manager_reset (embed); +#endif + + g_free (priv->icon_address); + g_free (priv->status_message); + g_free (priv->link_message); + g_free (priv->address); + g_free (priv->typed_address); + g_free (priv->title); + g_free (priv->loading_title); G_OBJECT_CLASS (ephy_base_embed_parent_class)->finalize (object); } @@ -269,4 +669,992 @@ ephy_base_embed_finalize (GObject *object) static void ephy_embed_iface_init (EphyEmbedIface *iface) { + iface->get_title = impl_get_title; + iface->get_address = impl_get_address; + iface->get_typed_address = impl_get_typed_address; + iface->set_typed_address = impl_set_typed_address; + iface->get_loading_title = impl_get_loading_title; + iface->get_is_blank = impl_get_is_blank; + iface->get_icon = impl_get_icon; + iface->get_icon_address = impl_get_icon_address; + iface->get_document_type = impl_get_document_type; + iface->get_load_status = impl_get_load_status; + iface->get_load_percent = impl_get_load_percent; + iface->get_navigation_flags = impl_get_navigation_flags; + iface->get_link_message = impl_get_link_message; + iface->get_status_message = impl_get_status_message; +} + +void +ephy_base_embed_set_address (EphyBaseEmbed *embed, char *address) +{ + EphyBaseEmbedPrivate *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 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; +} + +void +ephy_base_embed_set_title (EphyBaseEmbed *embed, + char *title) +{ + EphyBaseEmbedPrivate *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 +ensure_page_info (EphyBaseEmbed *embed, const char *address) +{ + EphyBaseEmbedPrivate *priv = embed->priv; + + if ((priv->address == NULL || priv->address[0] == '\0') && + priv->address_expire == EPHY_EMBED_ADDRESS_EXPIRE_NOW) + { + ephy_base_embed_set_address (embed, g_strdup (address)); + } + + /* FIXME huh?? */ + if (priv->title == NULL || priv->title[0] == '\0') + { + ephy_base_embed_set_title (embed, NULL); + } +} +static void +update_net_state_message (EphyBaseEmbed *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 void +update_navigation_flags (EphyBaseEmbed *membed) +{ + EphyBaseEmbedPrivate *priv = membed->priv; + EphyEmbed *embed = EPHY_EMBED (membed); + guint flags = 0; + + if (ephy_embed_can_go_up (embed)) + { + flags |= EPHY_EMBED_NAV_UP; + } + + if (ephy_embed_can_go_back (embed)) + { + flags |= EPHY_EMBED_NAV_BACK; + } + + if (ephy_embed_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 int +build_load_percent (int requests_done, int requests_total) +{ + int percent= 0; + + if (requests_total > 0) + { + percent = (requests_done * 100) / requests_total; + percent = CLAMP (percent, 0, 100); + } + + return percent; +} + +static void +ephy_base_embed_set_load_percent (EphyBaseEmbed *embed, int percent) +{ + EphyBaseEmbedPrivate *priv = embed->priv; + + if (percent != priv->load_percent) + { + priv->load_percent = percent; + + g_object_notify (G_OBJECT (embed), "load-progress"); + } +} + +static void +build_progress_from_requests (EphyBaseEmbed *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); + + ephy_base_embed_set_load_percent (embed, load_percent); + } +} + +static void +ephy_base_embed_set_load_status (EphyBaseEmbed *embed, gboolean status) +{ + EphyBaseEmbedPrivate *priv = embed->priv; + guint is_loading; + + is_loading = status != FALSE; + + if (is_loading != priv->is_loading) + { + priv->is_loading = is_loading; + + g_object_notify (G_OBJECT (embed), "load-status"); + } +} + +void +ephy_base_embed_update_from_net_state (EphyBaseEmbed *embed, + const char *uri, + EphyEmbedNetState state) +{ + EphyBaseEmbedPrivate *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; + + ephy_base_embed_set_load_percent (embed, 0); + ephy_base_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); + + ephy_base_embed_set_load_percent (embed, 100); + ephy_base_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); + } + + update_navigation_flags (embed); + } + + build_progress_from_requests (embed, state); +} + +void +ephy_base_embed_set_loading_title (EphyBaseEmbed *embed, + const char *title, + gboolean is_address) +{ + EphyBaseEmbedPrivate *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 +ephy_base_embed_file_monitor_cancel (EphyBaseEmbed *embed) +{ + EphyBaseEmbedPrivate *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_base_embed_file_monitor_reload_cb (EphyBaseEmbed *embed) +{ + EphyBaseEmbedPrivate *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'", ephy_embed_get_address (EPHY_EMBED (embed))); + + ephy_embed_reload (EPHY_EMBED (embed), TRUE); + + /* don't run again */ + return FALSE; +} + +static void +ephy_base_embed_file_monitor_cb (GnomeVFSMonitorHandle *handle, + const gchar *monitor_uri, + const gchar *info_uri, + GnomeVFSMonitorEventType event_type, + EphyBaseEmbed *embed) +{ + gboolean uri_is_directory; + gboolean should_reload; + char* local_path; + EphyBaseEmbedPrivate *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_base_embed_file_monitor_reload_cb, embed); + } + } +} + +static void +ephy_base_embed_update_file_monitor (EphyBaseEmbed *embed, + const gchar *address) +{ + EphyBaseEmbedPrivate *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; + } + + ephy_base_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) ephy_base_embed_file_monitor_cb, + embed) == GNOME_VFS_OK) + { + LOG ("Installed monitor for file '%s'", address); + + priv->monitor = handle; + } +} + +void +ephy_base_embed_location_changed (EphyBaseEmbed *embed, + char *location) +{ + GObject *object = G_OBJECT (embed); + + g_object_freeze_notify (object); + + /* do this up here so we still have the old address around */ + ephy_base_embed_update_file_monitor (embed, 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) + { + ephy_base_embed_set_address (embed, NULL); + ephy_base_embed_set_title (embed, NULL); + } + else + { + char *embed_address; + + /* we do this to get rid of an eventual password in the URL */ + embed_address = ephy_embed_get_location (EPHY_EMBED (embed), TRUE); + ephy_base_embed_set_address (embed, embed_address); + ephy_base_embed_set_loading_title (embed, embed_address, TRUE); + } + + ephy_base_embed_set_link_message (embed, NULL); + ephy_base_embed_set_icon_address (embed, NULL); + update_navigation_flags (embed); + + g_object_notify (object, "title"); + + g_object_thaw_notify (object); +} + +void +ephy_base_embed_set_link_message (EphyBaseEmbed *embed, + char *link_message) +{ + EphyBaseEmbedPrivate *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"); +} + +void +ephy_base_embed_load_icon (EphyBaseEmbed *embed) +{ + EphyBaseEmbedPrivate *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"); +} + +void +ephy_base_embed_set_icon_address (EphyBaseEmbed *embed, + const char *address) +{ + GObject *object = G_OBJECT (embed); + EphyBaseEmbedPrivate *priv = embed->priv; + /* EphyHistory *history; + EphyBookmarks *eb;*/ + + 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);*/ + + ephy_base_embed_load_icon (embed); + } + + g_object_notify (object, "icon-address"); +} + +void +ephy_base_embed_set_security_level (EphyBaseEmbed *embed, + EphyEmbedSecurityLevel level) +{ + EphyBaseEmbedPrivate *priv = embed->priv; + + if (priv->security_level != level) + { + priv->security_level = level; + + g_object_notify (G_OBJECT (embed), "security-level"); + } +} + +void +ephy_base_embed_restore_zoom_level (EphyBaseEmbed *membed, + const char *address) +{ + EphyBaseEmbedPrivate *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; + } + } +} + +/* Popup stuff if zeroed for now */ + +#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 |