diff options
author | Christian Dywan <christian@twotoasts.de> | 2018-08-22 01:07:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-22 01:07:25 +0200 |
commit | 57fa97773fc1f708fe572e8ed9fd9bf7a2c8f740 (patch) | |
tree | e91b68b392f514105ac17a4e070bad138746d0da | |
parent | b363061ac6406e6b7f99cec1809531719d015aa5 (diff) | |
download | midori-git-57fa97773fc1f708fe572e8ed9fd9bf7a2c8f740.tar.gz |
Implement speed dial based on recent history (#15)
![screenshot from 2018-08-18 20-45-09](https://user-images.githubusercontent.com/1204189/44302400-03a58a80-a328-11e8-8c4f-88be485e7920.png)
The speed dial is implemented as an "internal" scheme handler, which won't require special-casing on the UX side except using "internal:speed-dial" as a default URI in Midori.Tab and recognizing it as "empty" in Midori.Urlbar.
All items are populated automatically from the history and use favicons.
-rw-r--r-- | core/app.vala | 99 | ||||
-rw-r--r-- | core/tab.vala | 4 | ||||
-rw-r--r-- | core/urlbar.vala | 4 | ||||
-rw-r--r-- | data/about.css | 50 | ||||
-rw-r--r-- | data/speed-dial.html | 24 | ||||
-rw-r--r-- | gresource.xml | 1 |
6 files changed, 163 insertions, 19 deletions
diff --git a/core/app.vala b/core/app.vala index 1fdd4d48..2c0e3b35 100644 --- a/core/app.vala +++ b/core/app.vala @@ -60,22 +60,17 @@ namespace Midori { Gtk.Window.set_default_icon_name (Config.PROJECT_NAME); var context = WebKit.WebContext.get_default (); + context.register_uri_scheme ("internal", (request) => { + request.ref (); + internal_scheme.begin (request); + }); + context.register_uri_scheme ("favicon", (request) => { + request.ref (); + favicon_scheme.begin (request); + }); context.register_uri_scheme ("stock", (request) => { - string icon_name = request.get_path ().substring (1, -1); - int icon_size = 48; - Gtk.icon_size_lookup ((Gtk.IconSize)Gtk.IconSize.DIALOG, out icon_size, null); - try { - var icon = Gtk.IconTheme.get_default ().load_icon (icon_name, icon_size, Gtk.IconLookupFlags.FORCE_SYMBOLIC); - var output = new MemoryOutputStream (null, realloc, free); - icon.save_to_stream (output, "png"); - output.close (); - uint8[] data = output.steal_data (); - data.length = (int)output.get_data_size (); - var stream = new MemoryInputStream.from_data (data, free); - request.finish (stream, -1, null); - } catch (Error error) { - critical ("Failed to load icon %s: %s", icon_name, error.message); - } + request.ref (); + stock_scheme.begin (request); }); context.register_uri_scheme ("res", (request) => { try { @@ -83,6 +78,7 @@ namespace Midori { ResourceLookupFlags.NONE); request.finish (stream, -1, null); } catch (Error error) { + request.finish_error (error); critical ("Failed to load resource %s: %s", request.get_uri (), error.message); } }); @@ -119,6 +115,79 @@ namespace Midori { } } + async void internal_scheme (WebKit.URISchemeRequest request) { + try { + var shortcuts = yield HistoryDatabase.get_default ().query (null, 9); + string content = ""; + uint index = 0; + foreach (var shortcut in shortcuts) { + index++; + content += """ + <div class="shortcut"> + <a href="%s" accesskey="%u"> + <img src="%s" /> + <span class="title">%s</span> + </a> + </div>""".printf (shortcut.uri, index, "favicon:///" + shortcut.uri, shortcut.title); + } + string stylesheet = (string)resources_lookup_data ("/data/about.css", + ResourceLookupFlags.NONE).get_data (); + string html = ((string)resources_lookup_data ("/data/speed-dial.html", + ResourceLookupFlags.NONE).get_data ()) + .replace ("{title}", _("Speed Dial")) + .replace ("{icon}", "view-grid") + .replace ("{content}", content) + .replace ("{stylesheet}", stylesheet); + var stream = new MemoryInputStream.from_data (html.data, free); + request.finish (stream, html.length, "text/html"); + } catch (Error error) { + request.finish_error (error); + critical ("Failed to render %s: %s", request.get_uri (), error.message); + } + request.unref (); + } + + void request_finish_pixbuf (WebKit.URISchemeRequest request, Gdk.Pixbuf pixbuf) throws Error { + var output = new MemoryOutputStream (null, realloc, free); + pixbuf.save_to_stream (output, "png"); + output.close (); + uint8[] data = output.steal_data (); + data.length = (int)output.get_data_size (); + var stream = new MemoryInputStream.from_data (data, free); + request.finish (stream, -1, null); + } + + async void favicon_scheme (WebKit.URISchemeRequest request) { + string page_uri = request.get_path ().substring (1, -1); + try { + var database = WebKit.WebContext.get_default ().get_favicon_database (); + var surface = yield database.get_favicon (page_uri, null); + if (surface != null) { + var image = (Cairo.ImageSurface)surface; + var icon = Gdk.pixbuf_get_from_surface (image, 0, 0, image.get_width (), image.get_height ()); + request_finish_pixbuf (request, icon); + } + } catch (Error error) { + request.finish_error (error); + debug ("Failed to render favicon for %s: %s", page_uri, error.message); + } + request.unref (); + } + + async void stock_scheme (WebKit.URISchemeRequest request) { + string icon_name = request.get_path ().substring (1, -1); + int icon_size = 48; + Gtk.icon_size_lookup ((Gtk.IconSize)Gtk.IconSize.DIALOG, out icon_size, null); + try { + var icon = Gtk.IconTheme.get_default ().load_icon (icon_name, icon_size, Gtk.IconLookupFlags.FORCE_SYMBOLIC); + request_finish_pixbuf (request, icon); + } catch (Error error) { + request.finish_error (error); + critical ("Failed to load icon %s: %s", icon_name, error.message); + } + request.unref (); + } + void win_new_activated (Action action, Variant? parameter) { var browser = incognito ? new Browser.incognito (this) diff --git a/core/tab.vala b/core/tab.vala index ef8916e7..1592e719 100644 --- a/core/tab.vala +++ b/core/tab.vala @@ -55,7 +55,7 @@ namespace Midori { get_settings ().enable_developer_extras = true; if (pinned) { - load_uri (uri ?? "about:blank"); + load_uri (uri ?? "internal:speed-dial"); Plugins.get_default ().plug (this); } else { load_uri_delayed.begin (uri, title); @@ -63,7 +63,7 @@ namespace Midori { } async void load_uri_delayed (string? uri, string? title) { - display_uri = uri ?? "about:blank"; + display_uri = uri ?? "internal:speed-dial"; display_title = title ?? display_uri; item = new DatabaseItem (display_uri, display_title, 0); diff --git a/core/urlbar.vala b/core/urlbar.vala index 8cba903a..7f54cb88 100644 --- a/core/urlbar.vala +++ b/core/urlbar.vala @@ -35,7 +35,7 @@ namespace Midori { } primary_icon_activatable = !blank; } } - bool blank { get { return uri == "about:blank"; } } + bool blank { get { return uri == "about:blank" || uri == "internal:speed-dial"; } } [GtkChild] Gtk.Popover? suggestions; @@ -164,7 +164,7 @@ namespace Midori { complete (); return true; case Gdk.Key.Escape: - text = uri; + text = blank ? "" : uri; // Propagate to allow Escape to stop loading return false; } diff --git a/data/about.css b/data/about.css index a346ef09..ab1d85ff 100644 --- a/data/about.css +++ b/data/about.css @@ -71,3 +71,53 @@ button { font-size: 14pt; text-align: right; } + +#grid { + margin: auto auto; +} + +.shortcut { + width: 27%; + max-width: 32%; + height: 30%; + margin: 1%; + display: inline-table; + box-sizing: border-box; + overflow: hidden; +} + +.shortcut a { + width: 100%; + height: 100%; + display: block; + text-decoration: none; +} + +.shortcut a img { + width: 50%; + height: 50%; + margin: auto; + margin-bottom: .5em; + display: block; + border-radius: 12px; + box-shadow: 0 1px 3px rgba(0,0,0,0.12), + 0 1px 2px rgba(0,0,0,0.24); +} + +.shortcut a:hover img { + box-shadow: 0 3px 5px rgba(0,0,0,0.24), + 0 3px 4px rgba(0,0,0,0.48); +} + +.shortcut a .title { + width: 90%; + color: #222222; + text-align: center; + text-overflow: ellipsis; + word-wrap: nowrap; + max-height: 2em; + line-height: 1em; + overflow: hidden; + display: block; + font-size: 70%; +} diff --git a/data/speed-dial.html b/data/speed-dial.html new file mode 100644 index 00000000..c1e89d36 --- /dev/null +++ b/data/speed-dial.html @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2018 Christian Dywan <christian@twotoats.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +--> +<html> + <head> + <title>{title}</title> + <link ref="shortcut icon" href="stock:///{icon}" /> + <style type="text/css"> + {stylesheet} + </style> + </head> + <body> + <div id="grid"> + {content} + </div> + </body> +</html> diff --git a/gresource.xml b/gresource.xml index 0aaa1b4e..86a438ed 100644 --- a/gresource.xml +++ b/gresource.xml @@ -13,6 +13,7 @@ <gresource prefix="/"> <file compressed="true">data/about.css</file> <file compressed="true">data/error.html</file> + <file compressed="true">data/speed-dial.html</file> <file compressed="true">data/gtk3.css</file> <file compressed="true">data/logo-shade.svg</file> <file compressed="true">data/history/Create.sql</file> |