diff options
Diffstat (limited to 'embed')
-rw-r--r-- | embed/ephy-embed.c | 37 | ||||
-rw-r--r-- | embed/ephy-embed.h | 8 | ||||
-rw-r--r-- | embed/mozilla/mozilla-embed.cpp | 322 |
3 files changed, 357 insertions, 10 deletions
diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c index ae6ea6d74..882c9bfd6 100644 --- a/embed/ephy-embed.c +++ b/embed/ephy-embed.c @@ -485,7 +485,18 @@ ephy_embed_base_init (gpointer g_class) "The embed's title", _("Blank page"), G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); - + g_object_interface_install_property (g_class, + g_param_spec_string ("status message", + "Status Message", + "The embed's statusbar message", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + g_object_interface_install_property (g_class, + g_param_spec_string ("link-message", + "Link Message", + "The embed's link message", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); initialized = TRUE; } @@ -685,7 +696,7 @@ ephy_embed_get_location (EphyEmbed *embed, * * Return value: the URL of the link over which the mouse is hovering **/ -char * +const char * ephy_embed_get_link_message (EphyEmbed *embed) { EphyEmbedIface *iface = EPHY_EMBED_GET_IFACE (embed); @@ -1196,3 +1207,25 @@ ephy_embed_get_address (EphyEmbed *embed) return iface->get_address (embed); } +/** + * ephy_embed_get_status_message: + * @embed: an #EphyEmbed + * + * Returns the message displayed in @embed's #EphyWindow's + * #EphyStatusbar. If the user is hovering the mouse over a hyperlink, + * this function will return the same value as + * ephy_embed_get_link_message(). Otherwise, it will return a network + * status message, or NULL. + * + * The message returned has a limited lifetime, and so should be copied with + * g_strdup() if it must be stored. + * + * Return value: The current statusbar message + **/ +const char * +ephy_embed_get_status_message (EphyEmbed *embed) +{ + EphyEmbedIface *iface = EPHY_EMBED_GET_IFACE (embed); + return iface->get_status_message (embed); +} + diff --git a/embed/ephy-embed.h b/embed/ephy-embed.h index 70058eec6..0dc9cfa72 100644 --- a/embed/ephy-embed.h +++ b/embed/ephy-embed.h @@ -199,7 +199,7 @@ struct _EphyEmbedIface const char * (* get_title) (EphyEmbed *embed); char * (* get_location) (EphyEmbed *embed, gboolean toplevel); - char * (* get_link_message) (EphyEmbed *embed); + const char * (* get_link_message) (EphyEmbed *embed); char * (* get_js_status) (EphyEmbed *embed); int (* shistory_n_items) (EphyEmbed *embed); void (* shistory_get_nth) (EphyEmbed *embed, @@ -251,6 +251,7 @@ struct _EphyEmbedIface const char *address, EphyEmbedAddressExpire expire); const char * (* get_address) (EphyEmbed *embed); + const char * (* get_status_message) (EphyEmbed *embed); }; GType ephy_embed_net_state_get_type (void); @@ -283,7 +284,7 @@ const char *ephy_embed_get_title (EphyEmbed *embed); char *ephy_embed_get_location (EphyEmbed *embed, gboolean toplevel); -char *ephy_embed_get_link_message (EphyEmbed *embed); +const char *ephy_embed_get_link_message (EphyEmbed *embed); char *ephy_embed_get_js_status (EphyEmbed *embed); @@ -364,6 +365,9 @@ void ephy_embed_set_typed_address (EphyEmbed *embed, /* Address */ const char * ephy_embed_get_address (EphyEmbed *embed); +/* Status messages */ +const char * ephy_embed_get_status_message (EphyEmbed *embed); + /* Encoding */ char *ephy_embed_get_encoding (EphyEmbed *embed); diff --git a/embed/mozilla/mozilla-embed.cpp b/embed/mozilla/mozilla-embed.cpp index 7adbcceb6..6f8b5c612 100644 --- a/embed/mozilla/mozilla-embed.cpp +++ b/embed/mozilla/mozilla-embed.cpp @@ -89,8 +89,13 @@ static void mozilla_embed_zoom_change_cb (EphyEmbed *embed, 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 impl_set_typed_address (EphyEmbed *embed, const char *address, EphyEmbedAddressExpire expire); @@ -108,6 +113,8 @@ typedef enum } MozillaEmbedLoadState; #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 { @@ -135,6 +142,12 @@ struct MozillaEmbedPrivate int cur_requests; int total_requests; char *status_message; + char *link_message; + + /* File watch */ + GnomeVFSMonitorHandle *monitor; + guint reload_scheduled_id; + guint reload_delay_ticks; }; #define WINDOWWATCHER_CONTRACTID "@mozilla.org/embedcomp/window-watcher;1" @@ -144,10 +157,12 @@ enum PROP_0, PROP_ADDRESS, PROP_DOCUMENT_TYPE, + PROP_LINK_MESSAGE, PROP_LOAD_PROGRESS, PROP_LOAD_STATUS, PROP_NAVIGATION, PROP_SECURITY, + PROP_STATUS_MESSAGE, PROP_TITLE, PROP_TYPED_ADDRESS, PROP_ZOOM @@ -266,6 +281,9 @@ mozilla_embed_get_property (GObject *object, case PROP_ZOOM: g_value_set_float (value, priv->zoom); 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; @@ -275,6 +293,9 @@ mozilla_embed_get_property (GObject *object, case PROP_NAVIGATION: g_value_set_flags (value, priv->nav_flags); 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; @@ -304,8 +325,10 @@ mozilla_embed_set_property (GObject *object, case PROP_DOCUMENT_TYPE: 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; @@ -343,6 +366,8 @@ mozilla_embed_class_init (MozillaEmbedClass *klass) 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, "message"); + g_object_class_override_property (object_class, PROP_LINK_MESSAGE, "link-message"); g_type_class_add_private (object_class, sizeof(MozillaEmbedPrivate)); } @@ -384,6 +409,9 @@ mozilla_embed_init (MozillaEmbed *embed) 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); priv->document_type = EPHY_EMBED_DOCUMENT_HTML; priv->security_level = EPHY_EMBED_STATE_IS_UNKNOWN; @@ -437,6 +465,8 @@ mozilla_embed_finalize (GObject *object) 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); @@ -629,12 +659,6 @@ impl_get_title (EphyEmbed *embed) } static char * -impl_get_link_message (EphyEmbed *embed) -{ - return gtk_moz_embed_get_link_message (GTK_MOZ_EMBED (embed)); -} - -static char * impl_get_js_status (EphyEmbed *embed) { return gtk_moz_embed_get_js_status (GTK_MOZ_EMBED (embed)); @@ -1101,6 +1125,33 @@ impl_get_address (EphyEmbed *embed) 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 void mozilla_embed_set_address (MozillaEmbed *embed, char *address) { @@ -1127,14 +1178,272 @@ mozilla_embed_set_address (MozillaEmbed *embed, char *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) +{ + char *status_message; + char **splitted_message; + MozillaEmbedPrivate *priv = embed->priv; + + g_free (priv->link_message); + status_message = ephy_string_blank_chr (link_message); + + if (status_message && g_str_has_prefix (status_message, "mailto:")) + { + int i = 1; + char *p; + GString *tmp; + + /* We first want to eliminate all the things after "?", like + * cc, subject and alike. + */ + + p = strchr (status_message, '?'); + if (p != NULL) *p = '\0'; + + /* Then we also want to check if there is more than an email address + * in the mailto: list. + */ + + splitted_message = g_strsplit_set (status_message, ";", -1); + tmp = g_string_new (g_strdup_printf (_("Send an email message to ā%sā"), + (splitted_message[0] + 7))); + + while (splitted_message [i] != NULL) + { + g_string_append_printf (tmp, ", ā%sā", splitted_message[i]); + i++; + } + + priv->link_message = g_string_free (tmp, FALSE); + + g_free (status_message); + g_strfreev (splitted_message); + } + else + { + priv->link_message = status_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_free (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); + } + + mozilla_embed_set_link_message (membed, NULL); +#if 0 + mozilla_embed_set_icon_address (embed, NULL); +#endif + 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 gboolean @@ -1872,6 +2181,7 @@ ephy_embed_iface_init (EphyEmbedIface *iface) 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; } static void |