jrick / go-webkit2

Go bindings for WebKitGtk WebKit2 API
ISC License
4 stars 2 forks source link

Tips about implementing Web Extensions (needed for webkitdomgtk)? #1

Open xuoe opened 10 years ago

xuoe commented 10 years ago

Hi Josh,

Cool stuff here and over at conformal/gotk3/*!

I've started implementing parts of webkitdomgtk using gotk3/glib, but I've hit an impasse: there is no easy way to get access to a WebKitDOMDocument. In wk1, one would simply have to call webkit_web_view_get_dom_document on the WebKitWebView to do that, while in wk2 there's a webkit_web_view_get_page_id function, which is not very useful, as it simply returns an unsigned long. So, I did some digging and I came across Carlos Campos' article about writing Web Extensions (and a Node.js binding, by Jérémy Lal). Apparently, separate bindings have to be written for WebKitWebExtension (webkit2/webkit-web-extension.h), but I can't seem to figure out how to do that.

So far, the header file looks like this:

// web_extension.h
static WebKitWebPage *
toWebKitWebPage(void *p)
{
    return (WEBKIT_WEB_PAGE(p));
}

static WebKitWebExtension *
toWebKitWebExtension(void *p)
{
    return (WEBKIT_WEB_EXTENSION(p));
}

// http://blogs.igalia.com/carlosgc/2013/09/10/webkit2gtk-web-process-extensions/
static void
web_page_created_callback (WebKitWebExtension *extension,
                           WebKitWebPage      *web_page,
                           gpointer            user_data)
{
    web_page_created(extension, web_page);
}

G_MODULE_EXPORT void
webkit_web_extension_initialize (WebKitWebExtension *extension)
{
    g_signal_connect (extension, "page-created", 
                      G_CALLBACK (web_page_created_callback),
                      NULL);
}

extern void web_page_created(WebKitWebExtension *e, WebKitWebPage *p);

I'm thinking of using web_page_create as a bridge from C to Go and adapt WebKitWebExtension and WebKitWebPage in Go, like so:

// web_extension.go

//export web_page_created
func web_page_created(e *C.WebKitWebExtension, p *C.WebKitWebPage) {
    ge := newWebExtension(unsafe.Pointer(e))
    gp := newWebPage(unsafe.Pointer(p))
    // what now?
}

func newWebExtension(p unsafe.Pointer) *WebExtension {
    obj := &glib.Object{GObject: glib.ToGObject(p)}
    obj.RefSink()
    runtime.SetFinalizer(obj, (*glib.Object).Unref)
    return wrapWebExtension(obj);
}

func wrapWebExtension(obj *glib.Object) *WebExtension {
    return &WebExtension{obj}
}

// newWebPage works the same way.

The callback never gets called though, and I'm pretty sure that's because it's not set up properly. Those steps described by Carlos in his article about setting up a web extensions directory and writing a Makefile, do you think they apply here as well? Also, could glib.Object's Connect method be used here instead of the g_signal_connect function, i.e., newWebExtension(...).Connect("page-created", ...)?

In addition to not knowing how to proceed from here, I might also be doing things incorrectly. Consequently, I'd appreciate any pointers you might have about this thing. Thanks!

jrick commented 10 years ago

Sorry for the delayed response.

It does look to be set up improperly. The callback function is expected to be an exported symbol that is dynamically loaded by the WebKitWebProcess at startup. In the link you provided, it looks like this shared library is built and installed to a special directory, and all shlibs which export this symbol are run when the web process starts.

AFAIK, doing this is not possible with the go and cgo tools. You will probably have to put these functions in a separate C file to be built and installed to that special directory (I don't speak automake so not sure what that dir is) and then play with your LDFLAGS in the cgo directives so it links to that library as well.

Unfortunately I don't yet have a WebKitGTK 2.6 to play to try this, but hopefully this helps you a bit.

jrick commented 10 years ago

Also I'm not sure why it would make sense to use the glib package's Connect method to connect that signal. It's being called by C code so I don't see any reason for it to stack swap to Go and back just to make a C call.

jrick commented 10 years ago

One last thing to note is that cgo (the tool) has the option -objdir which will "put all generated files in directory". I'm not sure if it's possible to fiddle with this when cgo is called by go (the tool) when building the package, but it's worth a look.

xuoe commented 10 years ago

Alright, thanks for the pointers. I'll see if I can figure it out. In any case, I've implemented about 60% of the webkitdomgtk binding and I plan to push it in a few days, as the DOM stands by itself (it should work with wk1, for example). If I can't figure out the Web Extension thing by then, maybe someone else will be able to. :)