Skip to content

Instantly share code, notes, and snippets.

@mattdangerw
Last active December 1, 2019 06:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattdangerw/df1c737acf403b8e7799 to your computer and use it in GitHub Desktop.
Save mattdangerw/df1c737acf403b8e7799 to your computer and use it in GitHub Desktop.
Gtk Webkit Overlay
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
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>\
</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 context = WebKit2.WebContext.get_default();
context.connect('initialize-web-extensions', () => {
context.set_web_extensions_directory('.');
});
let webview = new WebKit2.WebView();
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);
button.add_events(Gdk.EventMask.SCROLL_MASK);
button.connect('scroll-event', (widget, event) => {
webview.emit('scroll-event', event);
return Gdk.EVENT_STOP;
});
let rect = [-999, -999, 100, 100];
let connection = Gio.DBus.session;
connection.signal_subscribe(null,
'com.endlessm.WebViewDemo',
null,
null,
null,
0,
(one, two, three, four, five, params) => {
rect = params.deep_unpack()[0];
overlay.queue_resize();
});
overlay.connect('get-child-position', (overlay, button, allocation) => {
printerr(rect);
[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();
// Compile with
// gcc webkitplugin.c `pkg-config --cflags --libs webkit2gtk-web-extension-4.0` -shared -fPIC -o webkitplugin.so
#include <string.h>
#include <webkit2/webkit-web-extension.h>
#include <webkitdom/webkitdom.h>
#define BUS_INTERFACE_NAME "com.endlessm.WebViewDemo"
static GDBusConnection *connection;
static GDBusInterfaceInfo *interface;
static guint bus_id;
static WebKitWebExtension *extension;
static WebKitWebPage *page;
static guint queued_update;
static const gchar introspection_xml[] =
"<node>"
"<interface name='" BUS_INTERFACE_NAME "'>"
"<signal name='Changed'>"
"<arg name='dom_element_rectangle' type='(iiii)'/>"
"</signal>"
"</interface>"
"</node>";
static gboolean
update_div_position (WebKitDOMDOMWindow *window)
{
if (bus_id == 0)
return FALSE;
WebKitDOMDocument *document = webkit_web_page_get_dom_document (page);
WebKitDOMElement *target = webkit_dom_document_get_element_by_id (document, "target");
WebKitDOMElement *body = WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document));
glong scroll_left = webkit_dom_element_get_scroll_left (body);
glong scroll_top = webkit_dom_element_get_scroll_top (body);
gdouble left = webkit_dom_element_get_offset_left (target) - scroll_left;
gdouble top = webkit_dom_element_get_offset_top (target) - scroll_top;
GError *error = NULL;
GVariant *params = g_variant_new ("((iiii))",
(gint)left,
(gint)top,
(gint)webkit_dom_element_get_offset_width (target),
(gint)webkit_dom_element_get_offset_height (target));
g_dbus_connection_emit_signal (connection,
NULL,
"/com/endlessm/webviewdemo",
BUS_INTERFACE_NAME,
"Changed",
params,
&error);
queued_update = 0;
return FALSE;
}
static void
on_resize (WebKitDOMDOMWindow *window)
{
if (queued_update == 0)
queued_update = g_idle_add ((GSourceFunc)update_div_position, window);
}
static void
on_document_loaded (WebKitWebPage *p)
{
WebKitDOMDocument *document = webkit_web_page_get_dom_document (page);
WebKitDOMDOMWindow *window = webkit_dom_document_get_default_view (document);
update_div_position (window);
webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (window), "resize", G_CALLBACK (on_resize), false, NULL);
webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (window), "scroll", G_CALLBACK (update_div_position), false, NULL);
}
static void
on_page_created (WebKitWebExtension *extension,
WebKitWebPage *p)
{
page = p;
g_signal_connect (page, "document-loaded", G_CALLBACK (on_document_loaded), NULL);
}
static void
on_bus_acquired (GDBusConnection *con,
const gchar *name)
{
GError *error = NULL;
connection = con;
GDBusNodeInfo *node = g_dbus_node_info_new_for_xml (introspection_xml, &error);
if (node == NULL)
goto fail;
interface = g_dbus_node_info_lookup_interface (node,
BUS_INTERFACE_NAME);
if (interface == NULL)
goto fail;
bus_id = g_dbus_connection_register_object (connection,
"/com/endlessm/webviewdemo",
interface,
NULL,
NULL,
NULL,
&error);
if (bus_id == 0)
goto fail;
return;
fail:
if (error != NULL)
{
g_critical ("Error hooking up web extension DBus interface: %s",
error->message);
g_clear_error (&error);
}
else
{
g_critical ("Unknown error hooking up web extension DBus interface");
}
}
static void
on_name_lost (GDBusConnection *connection,
const gchar *name)
{
if (connection == NULL) {
g_error("Couldn't connect to DBus for name %s", name);
return;
}
if (!g_dbus_connection_unregister_object (connection, bus_id))
g_critical ("Trouble unregistering object");
}
void
webkit_web_extension_initialize (WebKitWebExtension *ext)
{
extension = ext;
g_print ("IN THE WEB EXTENSION!!\n");
g_signal_connect (extension, "page-created",
G_CALLBACK (on_page_created), NULL);
g_bus_own_name (G_BUS_TYPE_SESSION,
"com.endlessm.webviewdemo",
G_BUS_NAME_OWNER_FLAGS_NONE,
(GBusAcquiredCallback) on_bus_acquired,
NULL,
(GBusNameLostCallback) on_name_lost,
NULL,
NULL);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment