14. Juni 2011

An HTML based Chat Window with WebKit, jQuery, and tricks

Over the weekend I was working on the OVW chat window. The chat window is very similar to the avatar display and also very different. The similarities are:

  • both are display modules
  • both use WebKit
Because they are both display modules, I could take the avatar display module code and strip away the avatar part to keep only nicknames. The chat window needs only nicknames. Later there will be images and more features. But for the start we need only text. The chat module has the same structure as the avatar module. It subscribes to a small number of virtual presence model events and then turns around and paints the display in HTML.

See the ui-layout-* CSS-classes? They are used by jQuery UI Layout. There is a bit of configuration necessary, but only a bit: http://code.google.com/p/ovw/source/browse/trunk/Apollo/bin/Win32/Debug/modules/Chat/Chat.html?r=255#153

As always, styling is very simple. Need bold nicknames? Here they are:
#ChatOut .cNickname { font-weight:bold; }
On the other hand, chat window and avatar display are very different:
  • chat is a dialog where the Chat.html code is in an IFRAME
  • avatar display paints directly, has no dialog frame
Calling the avatar display I can simply call a JavaScript function in WebKit. But in case of a Dialog with IFRAME, things are a bit more complicated. The IFRAME is a HTML window inside the HTML window. The WebView module has only a handle to the outer HTML/JavaScript. There is no direct access to the JavaScript of the inner HTML. I can call a JavaScript function in WebKit, but the function is executed in the context of the dialog wrapper. This is OK, if I want to control the dialog functions. But talking to the inner HTML is more difficult.

I am sure there are way to get to an embedded IFRAME from C++. But I did not want to get too deep into enumerating WebKit objects from C++. I needed a way to call JavaScript in the embedded IFRAME from the parent frame. Luckily we are in the same security domain, so calling JavaScript across frames is no problem. My solution is to call a function in the Dialog, which calls a function in the IFRAME, which evals the code I want to execute in the IFRAME.
function ContentEval(sCode)

return document.getElementById('Content').contentWindow.EvalJS(sCode);
Not very nice. A bit dirty, but it works. Also not very fast. Anyway, there are not many messages which take this route. Just adding participants and chat lines. I am confident, that we find a better way to do this later.


UPDATE: a week later, I have direct access to embedded frames. I am searching the frame by it's DOM-ID, then call the function inside the frame. I do GetFrameByPath to find the frame, because the frame may be inside another frame. Frames inside frames will be identified by a "/" separated list of DOM-IDs. That's my so called frame-path: http://code.google.com/p/ovw/source/browse/trunk/Apollo/bin/Win32/Debug/modules/Chat/Chat.html?r=414#200

The GetFrameByPath function is a mess of COM auto-pointers and QueryInterface. The ugly face of C++. Thank FSM someone invented better ways.

7. Juni 2011

More OVW Progress

Another week of evenings and weekend worth of progress on the next weblin generation (OVW). I am now working on browser tracking, support for multiple tabs and the multiple views for the same scene.

1. Firefox Add-on

Unfortunately, the rather simple weblin way of tracking browsers is not sufficient anymore. We want tabs (more about tabs and windows at the OVW blog).

Reliable information about visible tabs is only available inside the browser. So I need real browser addons. I started with Firefox some time ago. The addon keeps track of all tabs, when they open/close, become visible and when they navigate. It sends all the information over a local TCP connection to the client (using a simple remote procedure call protocol). This sounds complicated and it is, because the socket implementation in Firefox has its quirks. I could tell stories. But the beauty of a TCP connection is, that if the browser crashes or disappears, then the client will notice when the TCP connection goes down. It will then leave all rooms automatically, even if the browser addon does not say goodbye.

2. Tracking Browser Coordinates

Unfortunately, I don't get a real window handle (HWND) inside the browser. I need a native component to get a HWND for the tab. Why HWND? because I want to track the coordinates of the tab: resize and move events. I could add a native DLL to the addon, but then the addon is not cross-platform. Since I have a native part anyway (the client), I rather make the platform dependent processing in the client.

I implemented a BrowserInfo-module which finds the tab's HWND in the window list and does GetWindowRect() to get coordinates. The module also arranges the window stacking order with SetWindowPos() so that the avatar display is always directly on top of it's browser. That's good old Win32 coding. While most of the code is cross-platform, this part must be adapted to other operating systems, i.e. MacOS.

3. Model View Controller

I am very happy with the Model-View-Controller architecture. The "view" is only responsible for showing avatars. It can be closed and opened and re-creates everything from the model. The view uses the WebKit and JavaScript heavily.

The virtual presence module manages entering and leaving chat rooms, participants and chat lines. This is the "model". The view gets events from the model when participants enter/leave/chat. The view can always query the model. The model has only data structures. The view creates visible avatars.

And best of all: there can be multiple views for the same model. This means, that 2 browser windows can show the same scene.


1. Juni 2011

Open Virtual World Progress

The Open Virtual World project makes significant progress. I am now using WebKit for all user interface components. WebKit is the HTML rendering engine that drives Google Chrome, Safari, and many mobile browsers, because it is easy to integrate and has a good open source license. WebKit is a C++ library and it has a brand new transparency feature. WebKit with transparency is perfect to paint avatars over browser windows.

I can use all the cool Web technologies: CSS, jQuery, canvas. I could even make make my user interface with Flash, SVG, 3D CSS Transforms, WebGL/3D. A CSS style on a text element is much faster to implement than with old graphics libraries. And it is portable to other platforms. Development almost feels like rapid prototyping. The way we are used to program Web frontends. It is a Web frontend, but for a native application. A true cross platform GUI.

This is a comparison of OVW avatars (left) and weblin avatars (right). Weblin avatars are painted to the screen by old school InvalidateRect, WM_PAINT, BitBlt techniques. OVW avatars are rendered by HTML and JavaScript.

Javascript means, that I can use jQuery, which makes effects very easy. Say, I move an avatar with the mouse and let it go. The Weblin avatar slowly slides down to the browser border. In weblin this was animated with a WM_TIMER, and painting the avatar at different positions until it reached the bottom. Then stop the timer. Now, with jQuery I just write one line of JavaScript like:
$(this).animate( { bottom: '0px' }, 800 );
Voilà, the avatar slides down.

There is more at the Open Virtual World blog:
I use Webkit also for windows and dialogs. There are no native windows. Everything is a transparent Win32 window without window border, but with a WebKit inside. All you see is programmed in HTML. Need a semi transparent shadow around your window? Just make a
and use a CSS "box-shadow".

WebKit rox.

Code is at code.google.com.