[epiphany] Alternative HTML-based implementation for the overview
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany] Alternative HTML-based implementation for the overview
- Date: Tue, 18 Feb 2014 13:38:30 +0000 (UTC)
commit 65a1e4d1d4a46dd5ff781a3d1fa78879e2efbc4c
Author: Lorenzo Tilve <ltilve igalia com>
Date: Mon Dec 9 11:58:52 2013 +0100
Alternative HTML-based implementation for the overview
Provides a basic alternative HTML implementation for the
overview, that can be accessed at 'about:html-overview'.
https://bugzilla.gnome.org/show_bug.cgi?id=723950
embed/ephy-about-handler.c | 87 +++++++++++++++++
embed/ephy-embed-shell.c | 37 +++++++
embed/web-extension/ephy-web-extension.c | 102 ++++++++++++++++++++-
src/Makefile.am | 1 +
src/epiphany.gresource.xml | 1 +
src/resources/overview.html | 151 ++++++++++++++++++++++++++++++
6 files changed, 378 insertions(+), 1 deletions(-)
---
diff --git a/embed/ephy-about-handler.c b/embed/ephy-about-handler.c
index fcadd07..13aeb92 100644
--- a/embed/ephy-about-handler.c
+++ b/embed/ephy-about-handler.c
@@ -26,6 +26,7 @@
#include "ephy-file-helpers.h"
#include "ephy-smaps.h"
#include "ephy-web-app-utils.h"
+#include "ephy-embed-private.h"
#include <gio/gio.h>
#include <gtk/gtk.h>
@@ -36,6 +37,8 @@ struct _EphyAboutHandlerPrivate {
EphySMaps *smaps;
};
+#define EPHY_PAGE_TEMPLATE_OVERVIEW "/org/gnome/epiphany/page-templates/overview.html"
+
G_DEFINE_TYPE (EphyAboutHandler, ephy_about_handler, G_TYPE_OBJECT)
static void
@@ -426,6 +429,88 @@ ephy_about_handler_handle_applications (EphyAboutHandler *handler,
return TRUE;
}
+static GString *
+ephy_about_handler_generate_overview_html (EphyOverviewStore *store)
+{
+ GtkTreeIter iter;
+ GString *data_str;
+ char *row_url, *row_title, *row_snapshot_base64;
+ GdkPixbuf *row_snapshot;
+ guchar *buffer;
+ gsize buffersize;
+ gboolean valid;
+
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
+ data_str = g_string_new (NULL);
+
+ while (valid) {
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ EPHY_OVERVIEW_STORE_URI, &row_url,
+ EPHY_OVERVIEW_STORE_TITLE, &row_title,
+ EPHY_OVERVIEW_STORE_SNAPSHOT, &row_snapshot,
+ -1);
+
+ /* FIXME: use a more efficient way to get the base64 snapshot */
+ gdk_pixbuf_save_to_buffer (row_snapshot, (gchar **) &buffer, &buffersize, "png", NULL, NULL);
+ row_snapshot_base64 = g_base64_encode (buffer, buffersize);
+ g_free (buffer);
+
+ g_string_append_printf (data_str,
+ "<li>" \
+ " <a class=\"overview-item\" title=\"%s\" href=\"%s\">" \
+ " <div class=\"close-button\" onclick=\"removeFromOverview(this.parentNode,event)\"
title=\"%s\">✖</div>" \
+ " <span class=\"thumbnail\" style=\"background-image: url(data:image/png;base64,%s);\"></span>" \
+ " <span class=\"title\">%s</span>" \
+ " </a>" \
+ "</li>",
+ g_markup_escape_text (row_title,-1), row_url, _("Remove from overview"),row_snapshot_base64,
row_title);
+
+ g_free (row_title);
+ g_free (row_url);
+ g_free (row_snapshot_base64);
+
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+ }
+ return data_str;
+}
+
+
+static gboolean
+ephy_about_handler_handle_html_overview (EphyAboutHandler *handler,
+ WebKitURISchemeRequest *request)
+{
+ GString *data_str;
+ GBytes *html_file;
+ GString *html = g_string_new ("");
+ gsize data_length;
+ EphyOverviewStore *store;
+ char *lang;
+
+ store = EPHY_OVERVIEW_STORE (ephy_embed_shell_get_frecent_store (ephy_embed_shell_get_default ()));
+
+ data_str = ephy_about_handler_generate_overview_html(store);
+ html_file = g_resources_lookup_data (EPHY_PAGE_TEMPLATE_OVERVIEW, 0, NULL);
+
+ lang = g_strdup (pango_language_to_string (gtk_get_default_language ()));
+ g_strdelimit (lang, "_-@", '\0');
+
+ g_string_printf (html,
+ g_bytes_get_data (html_file, NULL),
+ lang, lang,
+ ((gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) ? "rtl" : "ltr"),
+ _("Most visited"),
+ data_str->str);
+
+ data_length = html->len;
+ ephy_about_handler_finish_request (request, g_string_free (html, FALSE), data_length);
+
+ g_string_free (data_str,TRUE);
+ g_bytes_unref (html_file);
+ g_free (lang);
+
+ return TRUE;
+}
+
static gboolean
ephy_about_handler_handle_incognito (EphyAboutHandler *handler,
WebKitURISchemeRequest *request)
@@ -511,6 +596,8 @@ ephy_about_handler_handle_request (EphyAboutHandler *handler,
handled = ephy_about_handler_handle_epiphany (handler, request);
else if (!g_strcmp0 (path, "applications"))
handled = ephy_about_handler_handle_applications (handler, request);
+ else if (!g_strcmp0 (path, "html-overview"))
+ handled = ephy_about_handler_handle_html_overview (handler, request);
else if (!g_strcmp0 (path, "incognito"))
handled = ephy_about_handler_handle_incognito (handler, request);
else if (path == NULL || path[0] == '\0' || !g_strcmp0 (path, "Web") || !g_strcmp0 (path, "web"))
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index c902db2..0d744c3 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -58,6 +58,7 @@ struct _EphyEmbedShellPrivate
GList *web_extensions;
guint web_extensions_page_created_signal_id;
guint web_extensions_form_auth_save_signal_id;
+ guint web_extensions_remove_from_overview_signal_id;
};
enum
@@ -161,6 +162,26 @@ web_extension_page_created (GDBusConnection *connection,
}
static void
+web_extension_remove_from_overview (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ EphyEmbedShell *shell)
+{
+ GtkTreeIter iter;
+ EphyFrecentStore *store;
+ const char *url_to_remove;
+
+ g_variant_get (parameters, "(&s)", &url_to_remove);
+ store = ephy_embed_shell_get_frecent_store (ephy_embed_shell_get_default ());
+ if (ephy_overview_store_find_url (EPHY_OVERVIEW_STORE(store), url_to_remove, &iter)) {
+ ephy_frecent_store_set_hidden(store, &iter);
+ }
+}
+
+static void
web_extension_destroyed (EphyEmbedShell *shell,
GObject *web_extension)
{
@@ -356,6 +377,17 @@ ephy_embed_shell_setup_web_extensions_connection (EphyEmbedShell *shell)
(GDBusSignalCallback)web_extension_form_auth_save_requested,
shell,
NULL);
+ shell->priv->web_extensions_remove_from_overview_signal_id =
+ g_dbus_connection_signal_subscribe (shell->priv->bus,
+ NULL,
+ EPHY_WEB_EXTENSION_INTERFACE,
+ "RemoveItemFromOverview",
+ EPHY_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback)web_extension_remove_from_overview,
+ shell,
+ NULL);
}
static void
@@ -445,6 +477,11 @@ ephy_embed_shell_shutdown (GApplication* application)
priv->web_extensions_form_auth_save_signal_id = 0;
}
+ if (priv->web_extensions_remove_from_overview_signal_id > 0) {
+ g_dbus_connection_signal_unsubscribe (priv->bus, priv->web_extensions_remove_from_overview_signal_id);
+ priv->web_extensions_remove_from_overview_signal_id = 0;
+ }
+
g_list_foreach (priv->web_extensions, (GFunc)ephy_embed_shell_unwatch_web_extension, application);
ephy_embed_prefs_shutdown ();
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index d6c051f..d5197bd 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -34,7 +34,7 @@
#include <gtk/gtk.h>
#include <libsoup/soup.h>
#include <webkit2/webkit-web-extension.h>
-
+#include <JavaScriptCore/JavaScript.h>
/* FIXME: These global variables should be freed somehow. */
static UriTester *uri_tester;
@@ -69,6 +69,9 @@ static const char introspection_xml[] =
" <arg type='s' name='hostname' direction='out'/>"
" <arg type='s' name='username' direction='out'/>"
" </signal>"
+ " <signal name='RemoveItemFromOverview'>"
+ " <arg type='s' name='url' direction='out'/>"
+ " </signal>"
" <method name='FormAuthDataSaveConfirmationResponse'>"
" <arg type='u' name='request_id' direction='in'/>"
" <arg type='b' name='should_store' direction='in'/>"
@@ -238,6 +241,24 @@ request_decision_on_storing (EphyEmbedFormAuth *form_auth)
}
static void
+remove_from_overview_emit_signal (char *url)
+{
+ GError *error = NULL;
+
+ g_dbus_connection_emit_signal (dbus_connection,
+ NULL,
+ EPHY_WEB_EXTENSION_OBJECT_PATH,
+ EPHY_WEB_EXTENSION_INTERFACE,
+ "RemoveItemFromOverview",
+ g_variant_new ("(s)", url),
+ &error);
+ if (error) {
+ g_debug ("Error emitting signal RemoveItemFromOverview: %s\n", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
should_store_cb (const char *username,
const char *password,
gpointer user_data)
@@ -1151,6 +1172,80 @@ bus_acquired_cb (GDBusConnection *connection,
}
}
+
+static JSValueRef
+remove_from_overview_cb (JSContextRef context,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argument_count,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ JSStringRef result_string_js;
+ size_t max_size;
+ char *result_string;
+
+ result_string_js = JSValueToStringCopy (context, arguments[0], NULL);
+ max_size = JSStringGetMaximumUTF8CStringSize (result_string_js);
+
+ result_string = g_malloc (max_size);
+ JSStringGetUTF8CString (result_string_js, result_string, max_size);
+ remove_from_overview_emit_signal (result_string);
+
+ JSStringRelease (result_string_js);
+ g_free (result_string);
+
+ return JSValueMakeUndefined (context);
+}
+
+static const JSStaticFunction overview_staticfuncs[] =
+{
+ { "removeItemFromOverview", remove_from_overview_cb, kJSPropertyAttributeReadOnly |
kJSPropertyAttributeDontDelete },
+ { NULL, NULL, 0 }
+};
+
+static const JSClassDefinition overview_notification_def =
+{
+ 0, /* version */
+ kJSClassAttributeNone, /* attributes */
+ "Overview", /* className */
+ NULL, /* parentClass */
+ NULL, /* staticValues */
+ overview_staticfuncs, /* staticFunctions */
+ NULL, /* initialize */
+ NULL, /* finalize */
+ NULL, /* hasProperty */
+ NULL, /* getProperty */
+ NULL, /* setProperty */
+ NULL, /* deleteProperty */
+ NULL, /* getPropertyNames */
+ NULL, /* callAsFunction */
+ NULL, /* callAsConstructor */
+ NULL, /* hasInstance */
+ NULL /* convertToType */
+};
+
+static void
+window_object_cleared_cb (WebKitScriptWorld *world,
+ WebKitWebPage *web_page,
+ WebKitFrame *frame,
+ gpointer user_data)
+{
+ JSGlobalContextRef context;
+ JSObjectRef global_object;
+ JSClassRef class_def;
+ JSObjectRef class_object;
+ JSStringRef str;
+
+ context = webkit_frame_get_javascript_context_for_script_world (frame, world);
+ global_object = JSContextGetGlobalObject (context);
+
+ class_def = JSClassCreate (&overview_notification_def);
+ class_object = JSObjectMake (context, class_def, context);
+ str = JSStringCreateWithUTF8CString ("Overview");
+ JSObjectSetProperty (context, global_object, str, class_object, kJSPropertyAttributeNone, NULL);
+}
+
G_MODULE_EXPORT void
webkit_web_extension_initialize_with_user_data (WebKitWebExtension *extension,
GVariant *user_data)
@@ -1180,4 +1275,9 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *extension,
g_object_ref (extension),
(GDestroyNotify)g_object_unref);
g_free (service_name);
+
+ g_signal_connect (webkit_script_world_get_default (),
+ "window-object-cleared",
+ G_CALLBACK (window_object_cleared_cb),
+ NULL);
}
diff --git a/src/Makefile.am b/src/Makefile.am
index 29b60e3..9439f9f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -116,6 +116,7 @@ RESOURCE_FILES = \
resources/incognito.png \
resources/incognito-tinted.png \
resources/error.html \
+ resources/overview.html \
$(NULL)
epiphany-resources.c: epiphany.gresource.xml $(RESOURCE_FILES)
diff --git a/src/epiphany.gresource.xml b/src/epiphany.gresource.xml
index 946428c..6908b99 100644
--- a/src/epiphany.gresource.xml
+++ b/src/epiphany.gresource.xml
@@ -15,5 +15,6 @@
<file preprocess="xml-stripblanks">epiphany-bookmark-editor-ui.xml</file>
<file>epiphany.css</file>
<file alias="page-templates/error.html" compressed="true">error.html</file>
+ <file alias="page-templates/overview.html" compressed="true">overview.html</file>
</gresource>
</gresources>
diff --git a/src/resources/overview.html b/src/resources/overview.html
new file mode 100755
index 0000000..1a88869
--- /dev/null
+++ b/src/resources/overview.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<!--
+ 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.
+-->
+<html xml:lang="%s" lang="%s" dir="%s">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>%s</title>
+ <style type="text/css">
+ body {
+ background-color: #f6f6f4;
+ background-image: -webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0, #eeeeec),
+ color-stop(1, #f6f6f4)
+ );
+ background-size: 100% 5em;
+ background-repeat: no-repeat;
+ }
+
+ #overview {
+ padding: 60px 5px;
+ max-width: 1200px;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ #grid {
+ padding: 0;
+ }
+
+ #grid li {
+ list-style-type: none;
+ }
+
+ .overview-item {
+ width: 200px;
+ height: 200px;
+ float: left;
+ margin: 15px;
+ outline: 0;
+ transition: all 0.5s ease-in-out;
+ }
+
+ .title {
+ width: 100%;
+ height: 50px;
+ display: inline-block;
+ padding: 5px 0;
+ overflow: hidden;
+ font-family: Cantarell, sans-serif;
+ font-size: 11pt;
+ color: #2e3436;
+ text-overflow: ellipsis;
+ text-align: center;
+ }
+
+ .thumbnail {
+ width: 200px;
+ height: 150px;
+ display: block;
+ opacity: 0.6;
+ transition: opacity 0.2s ease-in-out;
+ background-repeat: no-repeat;
+ animation: fadeOut 0.5s;
+ }
+
+ .thumbnail:hover,
+ :focus .thumbnail {
+ opacity: 1.0;
+ }
+
+ .close-button {
+ -webkit-transition: opacity 250ms;
+ position: relative;
+ float: right;
+ top: -10px;
+ right: -5px;
+ opacity: 0;
+ z-index: 5;
+ color: #888;
+ font-size: 1.2em;
+ }
+
+ .overview-item:hover .close-button {
+ opacity: 1;
+ }
+
+ .removed .overview-item {
+ height: 0;
+ width: 0;
+ margin: 15px 0;
+ opacity: 0;
+ }
+
+ .removed .close-button {
+ display: none;
+ }
+ </style>
+
+ <script>
+
+ document.onkeypress = listenKeypress;
+
+ function listenKeypress(event) {
+ // Remove from overview when Del is pressed
+ if (event.which == 127) {
+ var focused = document.activeElement;
+ if (focused.className == "overview-item") {
+ removeFromOverview(focused, event);
+ }
+ }
+ }
+
+ function removeFromOverview(elem, event) {
+ var listItemNode = elem.parentElement;
+ event.preventDefault();
+ listItemNode.className +=" removed ";
+ Overview.removeItemFromOverview(elem.href);
+ }
+ </script>
+
+</head>
+
+<body>
+
+ <div id="overview">
+ <div id="grid">
+ <ul>
+ %s
+ </ul>
+ </div>
+ </div>
+
+</body>
+
+</html>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]