Commit c45ae0b2 authored by Carlos Garcia Campos's avatar Carlos Garcia Campos Committed by Carlos Garcia Campos

ephy-session: save and restore web view session state

Using the new WebKit API available in 2.11.3. The session state is
serialized and then encoded as Base-64 to be able to to save it in our
current session state XML file. Now, we always save the session on
close, since there are more things that might have changed in the state
like the scroll position that we don't monitor to schedule saves.

https://bugzilla.gnome.org/show_bug.cgi?id=119432
parent 7d83de2d
......@@ -74,7 +74,7 @@ GLIB_REQUIRED=2.44.0
GTK_REQUIRED=3.19.1
LIBXML_REQUIRED=2.6.12
LIBXSLT_REQUIRED=1.1.7
WEBKIT_GTK_REQUIRED=2.11.1
WEBKIT_GTK_REQUIRED=2.11.4
LIBSOUP_REQUIRED=2.48.0
GNOME_DESKTOP_REQUIRED=2.91.2
LIBSECRET_REQUIRED=0.14
......
......@@ -66,6 +66,7 @@ struct _EphyEmbed {
char *title;
WebKitURIRequest *delayed_request;
WebKitWebViewSessionState *delayed_state;
guint delayed_request_source_id;
GSList *messages;
......@@ -378,6 +379,7 @@ ephy_embed_dispose (GObject *object)
}
g_clear_object (&embed->delayed_request);
g_clear_pointer (&embed->delayed_state, webkit_web_view_session_state_unref);
G_OBJECT_CLASS (ephy_embed_parent_class)->dispose (object);
}
......@@ -633,6 +635,7 @@ load_delayed_request_if_mapped (gpointer user_data)
{
EphyEmbed *embed = EPHY_EMBED (user_data);
EphyWebView *web_view;
WebKitBackForwardListItem *item;
embed->delayed_request_source_id = 0;
......@@ -640,8 +643,17 @@ load_delayed_request_if_mapped (gpointer user_data)
return G_SOURCE_REMOVE;
web_view = ephy_embed_get_web_view (embed);
ephy_web_view_load_request (web_view, embed->delayed_request);
if (embed->delayed_state)
webkit_web_view_restore_session_state (WEBKIT_WEB_VIEW (web_view), embed->delayed_state);
item = webkit_back_forward_list_get_current_item (webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (web_view)));
if (item)
webkit_web_view_go_to_back_forward_list_item (WEBKIT_WEB_VIEW (web_view), item);
else
ephy_web_view_load_request (web_view, embed->delayed_request);
g_clear_object (&embed->delayed_request);
g_clear_pointer (&embed->delayed_state, webkit_web_view_session_state_unref);
/* This is to allow UI elements watching load status to show that the page is
* loading as soon as possible.
......@@ -873,20 +885,23 @@ ephy_embed_remove_top_widget (EphyEmbed *embed, GtkWidget *widget)
* ephy_embed_set_delayed_load_request:
* @embed: a #EphyEmbed
* @request: a #WebKitNetworkRequest
* @state: (nullable): a #WebKitWebViewSessionState
*
* Sets the #WebKitNetworkRequest that should be loaded when the tab this embed
* is on is switched to.
*/
void
ephy_embed_set_delayed_load_request (EphyEmbed *embed, WebKitURIRequest *request)
ephy_embed_set_delayed_load_request (EphyEmbed *embed, WebKitURIRequest *request, WebKitWebViewSessionState *state)
{
g_return_if_fail (EPHY_IS_EMBED (embed));
g_return_if_fail (WEBKIT_IS_URI_REQUEST (request));
g_clear_pointer (&embed->delayed_state, webkit_web_view_session_state_unref);
g_clear_object (&embed->delayed_request);
g_object_ref (request);
embed->delayed_request = request;
embed->delayed_request = g_object_ref (request);
if (state)
embed->delayed_state = webkit_web_view_session_state_ref (state);
}
/**
......
......@@ -41,7 +41,8 @@ void ephy_embed_remove_top_widget (EphyEmbed *embed,
void ephy_embed_entering_fullscreen (EphyEmbed *embed);
void ephy_embed_leaving_fullscreen (EphyEmbed *embed);
void ephy_embed_set_delayed_load_request (EphyEmbed *embed,
WebKitURIRequest *request);
WebKitURIRequest *request,
WebKitWebViewSessionState *state);
gboolean ephy_embed_has_load_pending (EphyEmbed *embed);
const char *ephy_embed_get_title (EphyEmbed *embed);
......
......@@ -557,9 +557,8 @@ ephy_session_close (EphySession *session)
*/
g_source_remove (priv->save_source_id);
priv->save_source_id = 0;
ephy_session_save_idle_cb (session);
}
ephy_session_save_idle_cb (session);
session->priv->dont_save = TRUE;
}
......@@ -575,6 +574,7 @@ typedef struct {
char *url;
char *title;
gboolean loading;
WebKitWebViewSessionState *state;
} SessionTab;
static SessionTab *
......@@ -599,6 +599,7 @@ session_tab_new (EphyEmbed *embed)
session_tab->title = g_strdup (ephy_embed_get_title (embed));
session_tab->loading = ephy_web_view_is_loading (web_view) && !ephy_embed_has_load_pending (embed);
session_tab->state = webkit_web_view_get_session_state (WEBKIT_WEB_VIEW (web_view));
return session_tab;
}
......@@ -608,6 +609,7 @@ session_tab_free (SessionTab *tab)
{
g_free (tab->url);
g_free (tab->title);
g_clear_pointer (&tab->state, webkit_web_view_session_state_unref);
g_slice_free (SessionTab, tab);
}
......@@ -730,6 +732,27 @@ write_tab (xmlTextWriterPtr writer,
if (ret < 0) return ret;
}
if (tab->state)
{
GBytes *bytes;
bytes = webkit_web_view_session_state_serialize (tab->state);
if (bytes)
{
gchar *base64;
gconstpointer data;
gsize data_length;
data = g_bytes_get_data (bytes, &data_length);
base64 = g_base64_encode (data, data_length);
ret = xmlTextWriterWriteAttribute (writer,
(const xmlChar *) "history",
(const xmlChar *) base64);
g_free (base64);
g_bytes_unref (bytes);
}
}
ret = xmlTextWriterEndElement (writer); /* embed */
return ret;
}
......@@ -880,6 +903,20 @@ out:
STOP_PROFILER ("Saving session")
}
static EphySession *
ephy_session_save_idle_started (EphySession *session)
{
g_application_hold (G_APPLICATION (ephy_shell_get_default ()));
return g_object_ref (session);
}
static void
ephy_session_save_idle_finished (EphySession *session)
{
g_application_release (G_APPLICATION (ephy_shell_get_default ()));
g_object_unref (session);
}
static gboolean
ephy_session_save_idle_cb (EphySession *session)
{
......@@ -901,7 +938,6 @@ ephy_session_save_idle_cb (EphySession *session)
policy = g_settings_get_enum (EPHY_SETTINGS_MAIN, EPHY_PREFS_RESTORE_SESSION_POLICY);
if (policy == EPHY_PREFS_RESTORE_SESSION_POLICY_NEVER)
{
g_application_release (G_APPLICATION (shell));
return G_SOURCE_REMOVE;
}
......@@ -910,10 +946,10 @@ ephy_session_save_idle_cb (EphySession *session)
if (ephy_shell_get_n_windows (shell) == 0)
{
session_delete (session);
g_application_release (G_APPLICATION (shell));
return G_SOURCE_REMOVE;
}
g_application_hold (G_APPLICATION (ephy_shell_get_default ()));
priv->save_cancellable = g_cancellable_new ();
data = save_data_new (session);
task = g_task_new (session, priv->save_cancellable,
......@@ -944,10 +980,10 @@ ephy_session_save (EphySession *session)
return;
}
g_application_hold (G_APPLICATION (ephy_shell_get_default ()));
priv->save_source_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE, 1,
(GSourceFunc)ephy_session_save_idle_cb,
g_object_ref (session), g_object_unref);
ephy_session_save_idle_started (session),
(GDestroyNotify)ephy_session_save_idle_finished);
}
static void
......@@ -1069,6 +1105,7 @@ session_parse_embed (SessionParserContext *context,
{
const char *url = NULL;
const char *title = NULL;
const char *history = NULL;
gboolean was_loading = FALSE;
gboolean is_blank_page = FALSE;
guint i;
......@@ -1089,6 +1126,10 @@ session_parse_embed (SessionParserContext *context,
{
was_loading = strcmp (values[i], "true") == 0;
}
else if (strcmp (names[i], "history") == 0)
{
history = values[i];
}
}
/* In the case that crash happens before we receive the URL from the server,
......@@ -1102,6 +1143,7 @@ session_parse_embed (SessionParserContext *context,
EphyEmbed *embed;
EphyWebView *web_view;
gboolean delay_loading;
WebKitWebViewSessionState* state = NULL;
delay_loading = g_settings_get_boolean (EPHY_SETTINGS_MAIN,
EPHY_PREFS_RESTORE_SESSION_DELAYING_LOADS);
......@@ -1114,17 +1156,50 @@ session_parse_embed (SessionParserContext *context,
0);
web_view = ephy_embed_get_web_view (embed);
if (history) {
guchar *data;
gsize data_length;
GBytes *history_data;
data = g_base64_decode (history, &data_length);
history_data = g_bytes_new_take (data, data_length);
state = webkit_web_view_session_state_new (history_data);
g_bytes_unref (history_data);
}
if (delay_loading)
{
WebKitURIRequest *request = webkit_uri_request_new (url);
ephy_embed_set_delayed_load_request (embed, request);
ephy_embed_set_delayed_load_request (embed, request, state);
ephy_web_view_set_placeholder (web_view, url, title);
g_object_unref (request);
}
else
{
ephy_web_view_load_url (web_view, url);
WebKitBackForwardList *bf_list;
WebKitBackForwardListItem *item;
if (state)
{
webkit_web_view_restore_session_state (WEBKIT_WEB_VIEW (web_view), state);
}
bf_list = webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (web_view));
item = webkit_back_forward_list_get_current_item (bf_list);
if (item)
{
webkit_web_view_go_to_back_forward_list_item (WEBKIT_WEB_VIEW (web_view), item);
}
else
{
ephy_web_view_load_url (web_view, url);
}
}
if (state)
{
webkit_web_view_session_state_unref (state);
}
}
else if (was_loading && url != NULL)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment