[epiphany] ephy-session: save and restore web view session state



commit c45ae0b29287353f3798428b7131d8ac2127da62
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Thu Jan 14 17:59:13 2016 +0100

    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

 configure.ac       |    2 +-
 embed/ephy-embed.c |   23 +++++++++++--
 embed/ephy-embed.h |    3 +-
 src/ephy-session.c |   91 +++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 105 insertions(+), 14 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 8a5c14e..e140eeb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c
index 7fadba1..4982a91 100644
--- a/embed/ephy-embed.c
+++ b/embed/ephy-embed.c
@@ -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);
 }
 
 /**
diff --git a/embed/ephy-embed.h b/embed/ephy-embed.h
index c676512..f552921 100644
--- a/embed/ephy-embed.h
+++ b/embed/ephy-embed.h
@@ -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);
 
diff --git a/src/ephy-session.c b/src/ephy-session.c
index f081eee..21dcae1 100644
--- a/src/ephy-session.c
+++ b/src/ephy-session.c
@@ -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)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]