[webkit-gtk] Gtk and html content in the same scroll view

Robert Schroll rschroll at gmail.com
Mon Sep 21 19:43:04 PDT 2015


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:])





More information about the webkit-gtk mailing list