Journal for July 2005

ASP.NET Graphical Designer screenshot

Okay, it's not quite as exciting as the title suggests. I've been hacking away on the Services and Component Model, and have reached the stage where I can display controls, select them from a drop-down list, change their properties, and have the change reflected on the design surface. You can't interact with the design surface directly yet, and the controls aren't really in a document, just a collection of controls. But it looks pretty!

Update, 28-7-05: Noticed I'd put this in the wrong category.

It lives!

The inbound (Mono -> Gecko) C++ DOM function is working fine and I can recieve a C# call in JavaScript; now I just need to pass it off to the actual function.

There was a bit of trouble initially as I couldn't obtain an nsIWebBrowser pointer from gtk_moz_embed_get_nsIWebBrowser. This turned out to be because the Gecko# WebControl hadn't been shown yet (i.e. window.ShowAll()), but I didn't figure this out as other functions like gtk_moz_embed_get_location worked fine.

Here's Blagovest Dachev's XUL GUI demo hosted in my container, with a simple C#->JS call demonstration. For anyone who hasn't seen the Mono Summer of Code page, Blago's working on the Mozilla half of this project.

Shouldn't be hard now to get the outbound side working. I'll have to test how long the JavaScript status messages can be, or I'll have to finish the outbound C++ glue. Marshalling 'out' parameters isn't too easy, especially when I don't want to place any artificial limits on the size of the data that can be passed around, so I'll return the arguments from the function as a string pointer return value. I don't expect the names of the callee and callback functions to be more than a few hundred characters in the extreme case, so they should be able to be sent in the JavaScript status message.

However, splitting the call in two parts like this could have consequences; there's no telling what multithreading could do to concurrency. I guess some kind of unique identifier is in order.

I also need to finish all of the error and exception handling at some point, though it seems robust enough at the moment.

Gecko# interaction

Implementing the ASP.NET GUI designer with Mozilla's Gecko web rendering engine is an obvious decision: it's open-source, has strong standards support and a large feature set, is highly extensible and flexible thanks to its XPCOM component system, and using Gecko# it can be embedded in a GTK# GUI. Mozilla is becoming an application platform, with XUL for declaratively writting GUIs, and JavaScript for program logic.

Gecko# wraps GtkMozEmbed, which is a C GTK widget, hiding Mozilla's native C++. Understandably this widget isn't bloated by wrapping the Mozilla DOM or other internals: it claims to exposes enough functionality for "about 80% of uses". Essentially this means a basic web browser.

However, to do anything interesting I need to interact with Gecko# from my C# code, and vice versa. There are two obvious ways to approach this:

  • Expose everything
    Open up the whole of Mozilla's internals to Mono code, or at least the DOM and XPConnect for JavaScript interaction. This would be ideal, as it's the most flexible, and would find many other uses. However, wrapping enough functionality to do anything useful is a very significant task in itself.
  • Message-passing
    Simply restrict all of the Mozilla interaction code to JavaScript functions, which can be triggered from C# via a message-passing scheme of some kind. Pragmatic, and not inelegant, as JavaScript is a first-class citizen in the Mozilla world, and is used to write large parts of Mozilla.

So, assuming I choose the second for speed and ease of development, how do I go about implementing it? This time, I have four choices:

  1. Abusing Gecko#
    Relatively harmlessly, we can raise C# events by changing the JavaScript status message.
    A more serious abuse is to stream the document into Gecko#, then stream in additional elements containing our messages. JavaScript can catch these with the DOMNodeInserted event and act accordingly. Or so I thought. While Gecko will render an open HTML stream, it's not so forgiving in the case of XUL. Oh dear.
  2. Mono-XPCOM bridge
    Yes, there is one, and it would be the most elegant solution... unfortunately it's not nearly complete enough to begin using for a project like this just now, and I'm not familiar enough with XPCOM to fix it up myself. I can see switching to this when it becomes stable enough.
  3. Web server
    This would cause the editor to effectively become an "AJAX" application. Ouch. A horrible hack, and a horribly-named technology. On the upside, this would be relatively quick and easy.
  4. C++ wrapper and P/Invoke
    Similar to the Gecko# abuse, but strangely, more elegant, despite the additional dependecies and build steps this method entails. The handle from Gecko# can be passed to a C/C++ wrapper via Platform Invoke. The wrapper function then uses GtkMozEmbed's "gtk_moz_embed_get_nsIWebBrowser" function to access Gecko's internals, does interesting thisgs to it with XPCOM, and optionally even returns values.

Well, I initially tried the fourth method, until I realised how much easier the first would be, and cursed XPCOM and the days it had taken from my life.

Fate has twisted sense of humour. Two days into the initial implementation of the editor's high-level architecture, as I began to flesh out the message passing system, I discovered the fickleness of Gecko#'s streams, and had to revert to XPCOM and P/Invoke.

More on this story later, once I have something working.