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