[webkit-gtk] Gtk and html content in the same scroll view
Matthew Watson
mattdangerw at gmail.com
Tue Sep 22 14:02:44 PDT 2015
Thanks! This looks like a WebKit1 solution right?
We were looking for a way to do this with WebKit2, which gets a lot
trickier because webkit handles all scrolling internally and you can't
access the dom without registering a plugin inside the WebProcess.
Adapted the approach in a hacky gjs script with WebKit2. It does work, but
does not perform well. Resize is very slow, and the gtk content will get
out of sync with html. Can try registering an actual plugin; this script
just communicates through the page uri which is gross. But I'm worried that
trying to have any decent scrolling synced between two separate processes
is a fools errand to being with.
const Gtk = imports.gi.Gtk;
const WebKit2 = imports.gi.WebKit2;
Gtk.init(null, 0);
const HTML = '\
<html>\
<head>\
<style type="text/css">\
body {\
font-size: 50px;\
}\
#target {\
height: 100;\
background-color: red;\
}\
</style>\
<script>\
var update = function () {\
var rect =
document.getElementById("target").getBoundingClientRect();\
window.location.hash = [rect.left, rect.top, rect.width,
rect.height].join("#");\
};\
window.addEventListener("resize", update);\
window.addEventListener("DOMContentLoaded", update);\
window.addEventListener("scroll", update);\
</script>\
</head>\
<body>\
<p>Web content. Web content. Web content. Web content.</p>\
<p>Web content. Web content. Web content. Web content.</p>\
<p>Web content. Web content. Web content. Web content.</p>\
<div id="target"></div>\
<p>Web content. Web content. Web content. Web content.</p>\
<p>Web content. Web content. Web content. Web content.</p>\
<p>Web content. Web content. Web content. Web content.</p>\
</body>\
</html>\
';
let webview = new WebKit2.WebView({
hexpand: true,
});
webview.get_settings().enable_write_console_messages_to_stdout = true;
webview.load_html(HTML, '');
let button = new Gtk.Button({
label: 'This is a gtk button. It tries to cover the red div.',
expand: true,
});
let overlay = new Gtk.Overlay();
overlay.add(webview);
overlay.add_overlay(button);
let rect = [-999, -999, 100, 100];
webview.connect('notify::uri', function () {
if (webview.uri.indexOf('#') >= 0) {
rect = webview.uri.split('#').slice(1).map((v) => parseInt(v));
overlay.queue_resize();
}
});
overlay.connect('get-child-position', (overlay, button, allocation) => {
[allocation.x, allocation.y, allocation.width, allocation.height] =
rect;
return true;
});
let test_window = new Gtk.Window({
default_width: 1000,
default_height: 600,
});
test_window.add(overlay);
test_window.connect('destroy', () => {
Gtk.main_quit();
});
test_window.show_all();
Gtk.main();
On Mon, Sep 21, 2015 at 7:43 PM Robert Schroll <rschroll at gmail.com> wrote:
> On Mon, Sep 21, 2015 at 8:54 PM, Matthew Watson <mattdangerw at gmail.com>
> wrote:
> > I'm working on a gtk app that displays some article content inside a
> > WeKitWebView. We recently got a request from our design team to take
> > some gtk widgets we had written separately and append them after our
> > article content in the same scroll area.
>
> In Geary, we faced a similar situation: We wanted a GTK composer to sit
> in-line with HTML elements in a webview. We initially tried to do this
> with a plugin widget, but that didn't work, for reasons I don't
> remember offhand.
>
> Instead, we came up with a solution where the GTK widget sits in an
> overlay on top of the webview. The overlay duplicates the adjustments
> of the webview and moves the overlaid widgets appropriately. The heart
> of it is this ScrollableOverlay [1], but you'll also probably want to
> see the webview [2] and the overlaid widget [3]. It may be easier to
> understand what's going on if you look at the commits [4]. We have to
> deal with the case where the widget can change its size, so there's
> quite a lot of communication going on between the various elements to
> keep everything in sync. (There's a div in the HTML content whose size
> is matched to the widget's, so there's space for it amongst the other
> content.) If your widget is constant sized, you should be able to
> avoid much of this.
>
> Below, I've pasted in a python file that I made while I was designing
> this system. It sticks a Gtk.Button over top of div#embed. Hopefully
> it'll make some sense.
>
> Robert
>
>
> [1]
>
> https://git.gnome.org/browse/geary/tree/src/client/composer/scrollable-overlay.vala
> [2]
>
> https://git.gnome.org/browse/geary/tree/src/client/conversation-viewer/conversation-viewer.vala
> [3]
>
> https://git.gnome.org/browse/geary/tree/src/client/composer/composer-widget.vala
> [4]
>
> https://git.gnome.org/browse/geary/commit/?id=a1bf7070d5de3f0323507e665c918ae5bfb0c155
> and following commits.
>
> -------- webkitoverlay.py --------
> import os
> from gi.repository import Gtk, WebKit, GObject
>
> HTML = """<html>
> <head>
> <title>This is a title</title>
> <style>
> #embed {
> width: 150px;
> height: 50px;
> background: red;
> border: 5px solid yellow;
> }
> </style>
> </head>
>
> <body>
> <h1>Here it is...</h1>
> <img src="http://www.google.com/notapicture" style="width: 48px;
> height: 48px; background: green;" />
> <img src="http://www.example.com/blah" />
> <p>Other text</p>
> <div id="embed">Embed goes here!</div>
> <p>Other text</p>
> <p>Other text</p>
> <p>Other text</p>
> <p>Other text</p>
> <p>Other text</p>
> <p>Other text</p>
> <p>Other text</p>
> <p>Other text</p>
> </body>
> </html>"""
>
> class WebKitWindow(Gtk.Window):
>
> def __init__(self, filename=""):
> Gtk.Window.__init__(self)
>
> self.set_title("Epub Reader")
> self.connect('destroy', self.on_quit)
> self.set_default_size(300,400)
>
> self.overlay = Gtk.Overlay()
> self.add(self.overlay)
>
> sw = Gtk.ScrolledWindow()
> sw.set_policy(Gtk.PolicyType.AUTOMATIC,
> Gtk.PolicyType.AUTOMATIC)
> self.overlay.add(sw)
>
> self.view = WebKit.WebView()
> sw.add(self.view)
>
> self.button = Gtk.Button(label="Hello")
> self.button.set_valign(Gtk.Align.FILL)
> self.button.set_halign(Gtk.Align.FILL)
> self.button.connect('clicked', self.on_click)
> self.overlay.add_overlay(self.button)
> self.overlay.connect('get-child-position',
> self.on_child_position)
>
> self.show_all()
> self.view.load_string(HTML, "text/html", "UTF-8", "file://")
>
> self.view.get_hadjustment().connect('value-changed',
> self.on_scroll)
> self.view.get_vadjustment().connect('value-changed',
> self.on_scroll)
>
> print self.overlay.get_request_mode()
> print sw.get_request_mode()
> print self.view.get_request_mode()
>
> Gtk.main()
>
> def on_click(self, *args):
> print "Click!"
> self.button.get_parent().remove(self.button)
> print self.view.get_size_request()
>
> def on_child_position(self, overlay, widget, allocation):
> if widget != self.button:
> return False
>
> doc = self.view.get_dom_document()
> div = doc.query_selector('#embed')
> if div:
> # Offset includes borders
> allocation.height = div.get_offset_height()
> allocation.width = div.get_offset_width()
> allocation.x = div.get_offset_left() -
> self.view.get_hadjustment().get_value()
> allocation.y = div.get_offset_top() -
> self.view.get_vadjustment().get_value()
> return True
> else:
> return False
>
> def on_size_request(self, *args):
> print "Size request"
>
> def on_scroll(self, *args):
> print "Scroll"
> self.overlay.queue_resize()
>
> def on_quit(self, *args):
> Gtk.main_quit()
>
>
> if __name__ == '__main__':
> import sys
> WebKitWindow(*sys.argv[1:])
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.webkit.org/pipermail/webkit-gtk/attachments/20150922/fc8a39e5/attachment.html>
More information about the webkit-gtk
mailing list