Sunday, July 17, 2005


Here's the screen shot I was promising. See the previous post for the XML markup that implements this applet. The operating system is MacOS X 10.2.x

Some of you may know me from my previous book, Gtk+ Programming in C, and to a lesser degree, Developing Imaging Applications with XIElib. Both were published by Prentice Hall. You can find out more about either book at http://www.sydlogan.com, and purchase copies at amazon.com or other booksellers (the XIElib title is no longer being published, and I doubt there is really a market for it anymore. But copies can be found if you really want one. In fact, if you *really* want a copy and are having a hard time finding one, drop me a line, I've got one or two I would be we willing to sell).

I'm even less well known for having written articles related to the two books above for various magazines during the mid to late 1990s. The most recent was a widget development article I did for C/C++ Users Journal back in 2002.

So, enough with the past. On to the present. The topic of my current effort is cross platform development in C++.

Basically, I will be writing about techniques that I learned during my tenure at Netscape during the development of the Mozilla/Netscape 6-7 codebase. I learned a lot working on the Netscape browser, and I plan to cover a wide variety of topics, including how to deal with source code management, build systems, makefiles, GUI toolkits, standards -- in a nutshell, everything that one must consider to do large scale cross-platform development.

So far, about 300 pages have been written and submitted to my editor for an initial review, so I am well into the project. My focus now is more on coding and less on writing -- I'm currently in the thick of developing a simple XML-based cross platform GUI layout manager and toolkit that embeds the mozilla JavaScript engine. If this sounds a lot to you like mozilla's XUL, then you are correct, except for one big difference -- I am writing all of this completely from scratch. Mozilla is just too gnarly to describe; by writing my own, I hope to keep the code *very* small, and in the end, this should make it easier to describe, while allowing me to get the important points regarding the design of such a system across to the reader.

XML markup isn't the only GUI discussed in the book; it includes perhaps the best available tutorial for the wxWidgets toolkit (http://www.wxwidgets.org).

Returning out attention back to the layout engine, I made great strides this weekend in getting Mozilla's JavaScript engine wired into my layout engine. Right now, the layout engine supports a very small set of widgets: editable text, static text, window, and button are it for now. I have a DOM up and running that represents the document and its attributes, and a concrete widget factory and implementations for the above widgets based on Cocoa running on MacOS X, written in Objective-C++. The XML parsing is done, at least for the elements that are supported so far. All of this in about 1800 lines of code (like I said, a far cry from XUL and mozilla's layout engine, which is orders of magnitude larger). Though I am sure my code will increase quite a bit in size, of course.

Here's a nice stack trace showing some of the excitement that happens when a button is pressed:


(gdb) b Button::ButtonPressed
Breakpoint 1 at 0x663c: file button.cpp, line 87.
(gdb) c
Continuing.
2005-07-17 05:36:37.431 layout[8564] Help! I've been clicked!

Breakpoint 1, Button::ButtonPressed() (this=0x3b5b70) at button.cpp:87
87 string val;
(gdb) n
89 attribute = GetAttributeByName(string("onclick"));
(gdb) n
90 if (attribute) {
(gdb) n
91 val = attribute->GetValue();
(gdb) n
93 }
(gdb) print val
$1 = {
static npos = 4294967295,
_M_dataplus = {
> = {},
members of _Alloc_hider:
_M_p = 0x32db5c "Button1Click();"
},
static _S_empty_rep_storage = {0, 0, 0, 0}
}
(gdb) where
#0 Button::ButtonPressed() (this=0x3b5b70) at button.cpp:93
#1 0x00229bf0 in ButtonPressSubject::NotifyButtonPress() (this=0x3b5ba8) at ../subject.cpp:13
#2 0x002284d0 in CocoaButtonImpl::HandleCommand() (this=0x3b5ba0) at cocoabuttonimpl.mm:55
#3 0x0022928c in -[ButtonAction onClick:] (self=0x4956c0, _cmd=0x234f84, sender=0x495a20) at cocoabuttonaction.mm:15
#4 0x930f9f5c in -[NSApplication sendAction:to:from:] ()
#5 0x9311a718 in -[NSControl sendAction:to:] ()
#6 0x9315eea4 in -[NSCell _sendActionFrom:] ()
#7 0x930f3968 in -[NSCell trackMouse:inRect:ofView:untilMouseUp:] ()
#8 0x9315eac0 in -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] ()
#9 0x9312e6b4 in -[NSControl mouseDown:] ()
#10 0x930c1698 in -[NSWindow sendEvent:] ()
#11 0x930a94ec in -[NSApplication sendEvent:] ()
#12 0x930b2418 in -[NSApplication run] ()
#13 0x002291b4 in CocoaAppImpl::MainLoop() (this=0x3a6780) at cocoaappimpl.mm:28
#14 0x00008648 in App::MainLoop() (this=0x3a3250) at app.cpp:23
#15 0x000039a4 in main (argc=2, argv=0xbffffb8c) at layout.cpp:259
(gdb)


Objective-C++ is just plain cool; look at the jump from #3 in the stack, which is from a pure Objective-C object, to the code in #2, which is implemented in a C++ class. It's stuff like this that makes my life easier.

As you can see, I grab the JS code associated with the button from a DOM attribute that was parsed from the XML (onclick="code"), and all that remains is calling the JS engine to execute the code (here, the code to execute is Button1Click(), take a look at the dump of val made in gdb).

Here is the XML for the UI:



<?xml version="1.0"?>

<!--
Copyright (C) 2004-2005 Syd Logan. All Rights Reserved.
-->

<!DOCTYPE window SYSTEM "simple.dtd">
<window name="main" title="&hello.title;" main="true" width="320" height="200" x="100" y="100" position="center, mouse" libraries="main,utils">
<script type="text/javascript" src="resources/content/simple.js"/>
<text editable="true" selectable="true" string="&text1.value;" width="100" height="40" x="10" y="70"/>
<text editable="false" selectable="false" string="&text2.value;" width="100" height="40" x="10" y="50"/>
<button onclick="Button1Click();" label="&button1.label;" width="100" height="40" x="10" y="10"/>
<button onclick="Button2Click();" label="&button2.label;" width="100" height="40" x="100" y="10"/>
</window>


The window described by this document displays static and editable text fields, and two buttons. The labels come from simple.dtd (not shown here), and the JS code associated with the onclick attributes of the buttons are implemented in the JS code that is pointed to by the script element. This is all very similar to XUL.

If I can figure out how to add images to this blog, I'll post a screen shot showing what the above XML code looks like when implemented by my layout engine.

One last thing -- notice that at this point that absolute position attributes (x, y) must be specified for each of the widgets to describe the layout of the window. My layout engine, at this point, implements only a static layout manager, thus this requirement for the XML to supply fixed positions. Of course, this stinks -- any decent modern GUI toolkit provides "box" or "grid" layout managers, both which support a far more powerful way of describing layouts. Don't worry -- I will certainly implement one (box) or both (box and grid) for this project.

But first things first; I need to get the JS engine embedding work done, and wire the button and editable text widgets to their handlers (this is in addition to a few other places where JS is required, e.g., onload handlers that must fire when a document has been loaded). Stay tuned.