%@ include file="prefix.html" %>
Nitrogen Release
by Adam Megacz
1. PrefaceThis document is a reference. It is not a specification or a tutorial. This document does not guide the user gently through examples (as a tutorial would), and it doesn't provide enough detail and formality for a third party to construct a compatible re-implementation of the XWT Core (as a specification would). Rather, the goal of this document is to completely describe every aspect of the environment that the XWT Core provides to client applications, from the bottom up. If you want to be an XWT expert, this is the right document to read. It is assumed that you are already familiar with XML and with either JavaScript or ECMAscript. If you are not familiar with ECMAscript, some reference materials are provided in Appendix G The shoehorn sequence (how the XWT Core gets onto the client's computer, and how it knows where to download the initial xwar from) is not described in this document, since it will be different for every platform that XWT is ported to. If you need to use or rely on some behavior you notice in the XWT Core, but which is not clearly defined here, please post to the users mailing list. 2. Key Concepts2.1 Definitions
2.2 SurfacesEach top-level window in an XWT UI is called a surface. There are two kinds of surfaces: frames, which usually have a platform-specific titlebar and border, and windows, which never have any additional platform-specific decorations. Whenever we refer to the size or position of a surface, we are referring to the size or position of the UI-accessible portion of the surface; this does not include any platform-specific decorations. This means that if you set the position of a frame to (0,0), the platform-specific titlebar will actually be off the screen on most platforms (it will be above and to the left of the top-left corner of the screen). Surfaces are not actual JavaScript objects; you cannot obtain a reference to a surface. However, each surface is uniquely identified by its root box, described in the next section. 2.3 BoxesA box is the fundamental unit from which all XWT user interfaces are built. Boxes can contain other boxes (known as children). Each Surface has a single box associated with it called the root box; the root box and its children (and its children's children, and so on) form the surface's box tree. There are three ways to think of a box: as a rendered visualization on the screen (the "Visual Representation"), as a JavaScript object (the "Object Representation"), and as an XML tag (the "XML Representation"). FIXME: diagram here All three representations are equally valid, and being able to figure out what an action in one representation would mean in terms of the other two representations is crucial to a solid understanding of XWT. The Object RepresentationEach box is a full-fledged ECMAscript object, and can store key-value pairs as properties. Some of these keys have special meaning, which will be explained later. Each box's numeric properties hold its child boxes. The Visual RepresentationEach box occupies a rectangular region on the surface. The visual appearance of a surface is created by rendering each box in its tree. Unless the clip attribute is false, each box will clip its childrens' visual representations to its own, so that the children appear "confined to" the parent. Children are rendered after their parents so they appear "on top of" their parents (they obscure them). Each box has two major visual components, each with subcomponents: FIXME: diagram
These eight components plus the size of a box fully specify its appearance. Every single box you see in XWT is drawn only on the basis of these components and its size. The XML RepresentationA template (discussed in the next section) is an XML file which acts as a blueprint for constructing a tree of boxes. We call this construction process applying, since unlike instantiation, you always apply a template to a pre-existing box, and you can apply multiple templates to the same box. Each XML tag corresponds to a single box, or to another template which will be applied to that box. For example, a scrollbar template, when applied, will construct a tree of boxes which has the visual appearance and behavior of a scrollbar. Although it is useful to think of the XML tags as being boxes, keep in mind that the XML representation is only a blueprint for constructing a tree of JavaScript objects. Once the template has been instantiated, the XML is effectively "thrown away", and JavaScript code is free to alter the boxes. 2.4 TemplatesEach template is an XML document whose root element is <xwt>. Any text content of the root element is ignored, and may safely be used for comments. The root element may have any of the following elements as children, each of which may appear no more than once, and which must appear in this order:
Here is a sample XWT file: <xwt xmlns="xwt.widget" xmlns:lib="xwt.lib"> This is a sample XWT file. Text up here is ignored. Copyright (C) 2004 Mustapha Mond. <static> // code here will be executed only once </static> <template cols="5"> <box id="container"/> <checkbox/> <box> /* This has to be commented out or else it will be treated as a script */ <lib:scrollbar/> </box> </template> </xwt> Applying an XML tag to a boxThe following description of the box application is extremely detailed and precise; it is intended for UI designers who need to know the exact order in which each event happens. FIXME: easier description. While this whole process sounds very complex, it actually works pretty intuitively. The description below is given in great detail since most applications will wind up being unintentionally dependent on subtle features of this process. However, most of the time you can just pretend that the XML tags and the boxes are the same thing. To apply an XML tag X to a box B, perform the following operations, in this order:
The last two steps are referred to as the initialization of the node. There are two important aspects of this ordering to be aware of:
2.5 Life Cycle of an XWT ApplicationA user begins by specifying the URL of an XWT application run. Usually this is done by visiting a web page which uses the shoehorn to install the core if it is not already on the user's machine, but you can also supply the URL on the command line. The XWT Core downloads the xwar for the application, loads it, applies the main.xwt template and renders it onto the screen, running any associated ECMAscript code. The user interacts with the application by clicking and moving the mouse, and by pressing keys on the keyboard. These actions trigger fragments of JavaScript code which are designated to handle events. This JavaScript code can then relay important information back to the server using XML-RPC or SOAP, or it can modify the structure and properties of the user interface to change its appearance, thereby giving feedback to the user. DIAGRAM: graphic here showing the circular feedback cycle. The XWT core quits when the last remaining surface has been destroyed. 3. Layout and RenderingThe size and position of every other box is determined by its properties, its childrens' sizes, and its parent's size and position. Box layout and rendering happens in four phases: packing, constraining, placing, and rendering. The Core is careful to only perform a phase on a box if the box has changed in a way that invalidates the work done the last time that phase was performed. The packing and constraining phases are performed in a single traversal of the tree (packing is preorder, constraining is postorder), and the placing and rendering phases are performed in a second traversal of the tree (first placing, then rendering, both preorder). For brevity, the rest of this chapter deals only with width and columns. Height and rows is treated identically and independently. Also, it is important to note that the term minimum width is not the same thing as the property minwidth, although they are closely related. The size of the root boxWhen the user resizes a window, XWT changes the root box's maxwidth and maxheight to match the size chosen by the user and then determines the root box's size using the same sizing rules it uses for other boxes. XWT will always attempt to prevent the user from making the surface smaller than the root box's minwidth and minheight. If the hshrink or vshrink flag is set, XWT will try to prevent the user from resizing the surface at all. However, not all platforms give XWT enough control to do this. The alignment pointWhen talking about positioning, we will often refer to the alignment point.
FIXME: diagram When positioning a child box, the alignment point is determined by the parent's align property. When positioning a visual element (a texture, path, or text string) within a box, the alignment point is determined by the box's own align property. A simple way to think about this is that whenever there are two boxes involved in the decision, you should use the parent's alignment point. 3.1 Packing
3.2 Constraining
3.3 Placing
3.4 RenderingBoxes are rendered in a depth-first, pre-order traversal. Note that this may cause a non-packed box to overlap its siblings.
4. Box Properties4.1 Rendering PropertiesEvery box has several special properties which control how it is drawn. In general, if you put an invalid value to a special property, no action will be taken -- the put will be ignored.
4.2 Layout Properties
4.3 Child Control PropertiesDuring a box initialization, script-private references to a box's descendants with id attributes are placed on the box. These references allow scripts on that box to easily refer to descendant nodes created by the template in which the script appears. For example, these two blocks of code have exactly the same effect:
The following special properties control how a box's children are laid out. If a box has a non-null redirect target, reads and writes to these properties will be forwarded to the redirect target. The redirect attribute is very useful for hiding the internal structure of a widget, and for allowing widgets to act as "smart" containers for other widgets. For example, a menu widget might have an invisible child as its redirect target; this way, when boxes representing items on the menu are added as children of the menu widget, they do not appear until the menu is pulled down.
4.4 Other Box Properties
4.5 Notification PropertiesThe following properties are used to notify a box of changes specific to that particular box.
4.6 Root Box PropertiesThe following special properties are only meaningful on the root box of a surface.
6. StreamsEvery object has a stream...Every object has a stream associated with it. A stream is a sequence of bytes that can be read or written to. By default an object has an empty stream (zero bytes). However, some objects (returned from special methods on the xwt object) have streams yielding data read from an url, file, or a component of a zip archive. In a future release, the stream associated with a box will be an .xwt template which, when applied, will fully reconstitute the box's state. ...but streams are not objectsDespite the ubiquity of streams, you cannot actually reference a stream, since it is not an object. Instead, you simply reference the object it belongs to. If you are familiar with Java, this is similar to how every Java object has a monitor associated with it, but you cannot directly manipulate the monitor (you can't pass around a reference to just the monitor). In the rest of the section we will sometimes refer to "getting properties from a stream" or "passing a stream to a function"; this is just shorthand for saying to perform those actions on the object the stream belongs to. 6.1 Creating StreamsCreating Streams from URLsYou can create a stream from a URL by calling var r = xwt.stream.url("http://..."); This will return an object whose stream draws data from the specified URL. Streams are loaded lazily whenever possible. Getting SubstreamsMost stream objects let you access substreams using the usual JavaScript operators [] and ., as well as the for..in syntax. // r1 and r2 are equivalent but not equal (!=) var r1 = xwt.stream.url("http://www.xwt.org/foo/bar.html"); var r2 = xwt.stream.url("http://www.xwt.org/foo")["bar.html"]; The Root StreamThe empty-string property on the xwt object is called the root stream. You can access this object as xwt.. or xwt[""]. Additionally, any expression which starts with a dot is treated as property to be retrieved from the root stream. The following three expressions are equivalent: xwt..foo xwt[""].foo .foo Static BlocksYou can access variables within the static block of a template by appending a double period (..) and the variable name to the stream used to load that template: <!-- org/xwt/themes/monopoly/scrollbar.xwt --> <xwt> <static> foo = 12; ... // elsewhere xwt.log.print(org.xwt.themes.monopoly.scrollbar..foo); // prints "12" 6.2 Formatting StreamsIf you attempt to send a stream as part of an XML-RPC call, the stream will be read in its entirity, Base64-encoded, and transmitted as a <base64/> element. XWT supports two special URL protocols. The first is data:, which inteprets the rest of the URL as a Base64 encoded sequence of bytes to use as a source. The other is utf8: which interpretets the rest of the string as a Unicode character sequence to be UTF-8 encoded as a string of bytes to use as a source. var r5 = xwt.stream.url("data:WFWE876WEh99sd76f"); var r6 = xwt.stream.url("utf8:this is a test"); You can read a UTF-8 encoded string from a stream like this: var myString = xwt.stream.fromUTF(xwt.stream.url("utf8:this is a test")); You can also parse XML from a stream using SAX like this: xwt.stream.xml.sax(xwt.stream.url("http://foo.com/foo.xml"), { beginElement : function(tagname, attributeKeyValuePairs) { ... }, endElement : function(tagname) { ... }, content : function(contentString) { ... } whitespace : function(whitespaceString) { ... } }); 7. The XWT objectThe xwt object is present in the top-level scope of every script. It has the following properties: General
ECMA Library Objects
Logging
User Interface
Networking
Threads
Streams
Cryptography
8. Traps8.1 Simple TrapsYou can add a trap to a property by applying the ++= operator to a function with one argument. The trap will be invoked whenever that property is written to. <box> foo ++= function(z) { xwt.log.info("foo is " + z); } </box> If another script were to set the property "foo" on the box above to the value 5, the function above would be invoked with the argument 5. The function would then log the string "foo is 5". Within a trap, the expression trapee can be used to get a reference to the box on which the trap was placed. The expression trapname returns the name of the trap executing the current function. This is useful when a function is applied to multiple traps. For example: <box> func ++= function(z) { xwt.log.info("called trap " + trapname); } foo ++= func; bar ++= func; </box> 8.2 Removing TrapsYou can remove a trap by using the --= operator with the same function you added as a trap: <box> var myfunc = function(z) { /* ... */ } // add the trap func ++= myfunc; // ... // remove the trap func --= myfunc; </box> 8.3 Multiple Traps on the Same PropertyWhen the property is written to, each of the trap functions placed on it will be invoked in the opposite order that they were placed on the box -- the most recently placed trap will execute first. This last-to-first execution of traps is called cascading. After the last trap is invoked, the value is stored on the box (remember, boxes are objects, so they can hold properties just like all other ECMAscript objects). 8.4 Manual CascadesThere are two additional tricks you can use when placing traps. The first is a manual cascade. If you want to cascade to lower traps in the middle of a function, or you want to cascade with a different value than the value passed to you (in effect "lying" to lower traps), you can use cascade. For example: <box color="black"> color ++= function(c) { xwt.log.info("refusing to change colors!"); cascade = "black"; } </box> This effectively creates a box whose color cannot be changed, and which complains loudly if you try to do so. Do not try to do something like this: <box color="black"> color ++= function(z) { color = "black"; // INFINITE LOOP! BAD!!! } </box> To prevent automatic cascading, return true from your function: <box color="black"> color ++= function(z) { return true; // the box's color will not change } </box> 8.4 Read TrapsThe other trick is a read-trap. Read traps are just like normal traps, except that you use a function that takes zero arguments instead of one. Read traps also do not automatically cascade. <box> doublewidth ++= function() { return 2 * width; } </box> If another script attempts to read from the doublewidth property on this box, the value it gets will be twice the actual width of the box. Note that the actual doublewidth property on the box never gets written to, since the trap does not cascade. You can manually cascade on read traps as well: <box> text ++= function() { return "my text is " + cascade; } </box> Read traps are only rarely needed -- most of the time a write trap should be enough. 8.5 Prohibited TrapsTo prevent confusing and hard-to-debug behaviors, scripts may not place traps on any of the properties described in the sections Box Layout Properties, Child-Control Properties, or Other Box Properties except for childadded, childremoved and surface. FIXME: remove? 8.6 Exceptions and TrapsIf an uncaught exception is thrown from a trap, XWT will log the exception, but will not propagate it to the code which triggered the trap. If the trap was a read trap, the value null will be returned. FIXME: is this right? 8.7 Architectural Significance of TrapsTraps are the backbone of XWT. Since almost all UI programming is event/demand driven, traps eliminate the need for separate member/getter/setter declarations, often cutting the amount of typing you have to do to a third of what it would normally be. 9. CloningCloning is a companion technique for traps; together they can be used to simulate any sort of environment you might need. When you call xwt.clone(o), XWT returns a new object (called the clone) which compares with equality (==) to the original object. Furthermore, both objects are "equal" as keys in hashtables, so: var hash = {}; var theclone = xwt.clone(o); hash[o] = 5; xwt.log.info(hash[theclone]); // prints "5" Any writes to properties on the clone will actually write to properties on the original object, and reads from properties on the clone will read properties on the original object. In fact, the only thing that can be used to distinguish the original from the clone is traps -- a trap placed on the clone is not placed on the original object as well. XWT self-emulationWhen the core first starts up, it clones the xwt object, creates a stream for the initial xwar, and then places a trap on the cloned xwt object so that its empty-string property returns the xwar stream. The cloned XWT object is then passed as the third (optional) argument to xwt.apply(), making it the default xwt object for the scripts that are executed as part of the template instantiation. var new_xwt = xwt.clone(xwt); var stream = xwt.bless(xwt.stream.url("http://...")); new_xwt[""] ++= function() { return stream; } xwt.apply(xwt.box, new_xwt..main, new_xwt); Note that we called xwt.bless() on the stream before tacking it on to the new XWT object. The bless function returns a clone of the object passed to it, with a few traps which are explained below. Additionally, any sub-streams retrieved by accessing properties of the blessed stream will also automatically be blessed (blessed streams are monadic). Blessing a stream serves three purposes:
XWT can self-emulate by using xwt.clone() on the XWT object; this technique is very similar to the use of ClassLoaders in Java. This is useful for a number of applications, including debuggers, IDEs, sandboxing untrusted code, remote-control, and others. For example: var newLoadFunction = function(url) { /* ... */ }; var new_xwt = xwt.clone(xwt); new_xwt.load ++= function() { return newLoadFunction; } xwt.apply(xwt.box, .main, new_xwt); 10. Contexts and Threading10.1 ContextsFrom the perspective of an application writer, XWT is strictly single-threaded. XWT is always in exactly one of the following three contexts:
There are two important restrictions on what can be done in particular contexts:
10.2 Background ThreadsXWT offers easy access to threads. Spawning a background thread is as simple as writing a function to the xwt.thread property: xwt.thread = function() { xwt.log.info("this is happening in a background thread!"); } The argument set passed to the function is currently undefined and is reserved for use in future versions of XWT. Scripts should not depend on the number or content of these arguments. XWT is cooperatively multitasked, so threads must not process for too long. This was a deliberate choice; cooperatively multitasked environments do not require complex locking primitives like mutexes and semaphores which are difficult for novices to understand. The disadvantage of cooperative multitasking is that one thread can hog the CPU. This is unlikely to happen in XWT for two reasons: first, all blocking I/O operations automatically yield the CPU, so the overall user interface never becomes unresponsive because it is waiting for a disk or network transfer. Second, since XWT is strictly a user interface platform, XWT scripts are unlikely to perform highly compute-intensive operations that keep the CPU busy for more than a few milliseconds. 11. EventsEvery execution of the Event Context begins with an event, which consists of a key/value pair, and a mouse position, which consists of an x and y coordinate. The possible keys are _Press[1-3], _Release[1-3], _Click[1-3], _DoubleClick[1-3], _Move, _KeyPressed, and _KeyReleased. Here are two example events:
An event is triggered by writing the key to the value on a box. This triggers any trap handlers which may be present. Once these handlers have executed, XWT figures out which child of the current box contains the mouse (taking into account that some boxes may cover up others) and writes the key and value to that box. If none of the box's children contain the mouse position, XWT removes the leading underscore from the key name and writes the value to that property. Once all the traps on that property have executed, the value is written to the box's parent. Intuitively, XWT delivers the underscored event to every box from the root to the target, and then delivers the non-underscored event to that same set of boxes in reverse order. So the event travels down the tree to the target, and then back up to the root. The following example prints out "first second third fourth" in that order. <box> _Press1 ++= function(b) { xwt.log.info("first"); } Press1 ++= function(b) { xwt.log.info("fourth"); } <box> _Press1 ++= function(b) { xwt.log.info("second"); } Press1 ++= function(b) { xwt.log.info("third"); } </box> </box> In general, you should use the non-underscore names to respond to user input and use the underscored names when you want to override child boxes' behavior or route events to particular boxes (for example, when implementing a focus protocol). This is why the underscored elements are delivered to parents before children (so parents can override their childrens' behavior), but non-underscored events are delivered to children before parents (since, visually, a mouse click is usually "intended" for the leaf box underneath the cursor). Stopping the ProcessAt any point in this sequence, a trap handler can choose not to cascade (by returning true from the trap handler function). This will immediately cease the propagation of the event. This is how you would indicate that an event has been "handled". Re-routing eventsAt any point in the Event Context, you can write to the mouse property on any box. The value written should be an object with two properties, x and y. For example: _Press1 ++= function(p) { mouse = { x: 32, y: 77 }; } The coordinates specified are relative to the box whose mouse property is being written to. There is no need to supply the inside property; it is computed automatically. Writing to the mouse property causes XWT to recompute the eventual target box, and also alter the values returned by mouse.x, mouse.y, and mouse.inside for any descendants of the current box. Writing to the mouse property also automatically prevents the event from returning to the box's parents -- it is equivalent to not cascading on the non-underscored event. This ensures that child boxes cannot trick their parent boxes into thinking that the mouse has moved. If you want the event to "skip over" the boxes between the trapee and the target, or if you want to re-route an event to a box which is not a descendant of the current box, simply write the value to the proper key on the target box. <box> _KeyPressed = function(k) { xwt.log.info("first"); } KeyPressed = function(k) { xwt.log.info("sixth"); } $recipient.target = $target; <box id="recipient"> _KeyPressed = function(k) { xwt.log.info("second"); thisbox.target.KeyPressed = k; // inhibit cascade to keep the event from going to $excluded return true; } KeyPressed = function(k) { xwt.log.info("fifth"); } <box id="excluded"> _KeyPressed = function(k) { xwt.log.info("this never happens"); } </box> </box> <box id="target"> _KeyPressed = function(k) { xwt.log.info("third"); } KeyPressed = function(k) { xwt.log.info("fourth"); } </box> </box> Synthesizing Your Own EventsYou can create "fake events" by simply writing to the mouse property and then writing a value to one of the underscored properties on a box. This will have exactly the same effect as if the use had actually pressed a key, clicked a button, or moved the mouse -- they are indistinguishable. Enter and LeaveXWT will trigger the Enter and Leave properties as it walks down the tree, based on the position of the mouse (or the faked position if the mouse property has been written to). However, Enter and Leave are not events since they do not implicitly cascade up or down the tree. Detailed Description of Events
12. Networking
|
xwt.assertion.failed | an assertion failed |
xwt.io | General I/O exceptions |
xwt.io.encoding | Error translating between character encodings. |
xwt.io.zip | Attempted to access a corrupt zip archive. |
xwt.io.eof | End of file encountered unexpectedly |
xwt.net.security.prohibitedHost | A piece of untrusted XWT code attempted to contact a restricted host. See Appendix A for details. |
xwt.net.dns.temporaryFailure | An attempt to resolve a hostname failed but it is not known for certain that the hostname is invalid. |
xwt.net.dns.unknownHost | An attempt to resolve a hostname failed because the hostname was invalid. |
xwt.net.socket.closed | A socket was closed unexpectedly. |
xwt.net.socket.connectionFailed | A connection could not be made to the remote host. |
xwt.net.url.malformed | Tried to parse a malformed URL. |
xwt.net.ssl | General SSL protocol errors. |
xwt.net.ssl.untrustedCertificate | The server's certificate was not signed by a CA trusted by XWT. |
xwt.net.http.xyz | Thrown when an HTTP error code is returned during an operation. The three characters xyz will be the three-digit HTTP status code. |
xwt.net.xmlrpc.null | The caller attempted to transmit the null value via XML-RPC. |
xwt.net.xmlrpc.circular | The caller attempted to transmit a circular data structure via XML-RPC. |
xwt.net.xmlrpc.specialObject | The caller attempted to transmit a "special" object via XML-RPC (for example, a Box or the XWT object). |
xwt.null.put | A JavaScript attempted to put to a property on the null value |
xwt.null.get | A JavaScript attempted to get from a property on the null value |
xwt.null.call | A JavaScript attempted to call the null value |
If an exception is thrown inside a trap, the exception will propagate to the script that triggered the trap.
If an uncaught exception is thrown while applying a template, or the requested template could not be found, an error will be logged and the box to which the template was being applied will be made invisible (visible = false). This ensures that half-applied widgets are never shown to the user.
Due to the expense and hassle imposed by the commercial PKI code signing architecture, and the fact that it doesn't really provide any security anyways, XWT user interfaces are distributed as unsigned, untrusted code. As such, they are handled very carefully by the XWT Core, and assumed to be potentially malicious.
XWT's security architecture is divided into defenses against four major classes of attacks:
XWT user interfaces are run in an extremely restrictive sandbox. The environment does not provide primitives for accessing any data outside the XWT core except via XML-RPC and SOAP calls. There are no facilities to allow XWT user interfaces to access the client's operating system or to interact with other applications on the same host (unless they provide a public XML-RPC or SOAP interface).
An XWT script may only access a file on the user's hard disk if the user explicitly chooses that file from an "open file" or "save file" dialog. There is one exception to this rule: if all templates currently loaded in the XWT core originated from the local filesystem, those templates can load additional xwars from the local filesystem.
The XWT Core is written in Java, so it is not possible for scripts to perform buffer overflow attacks against the core itself.
XWT applications may only read from the clipboard when the user middle-clicks (X11 paste), presses control-V (Windows paste), or presses alt-V (Macintosh paste; the command key is mapped to XWT "alt"). This ensures that XWT applications are only granted access to data that other applications have placed on the clipboard when the user specifically indicates that that information should be made available to the XWT application.
XWT user interfaces may only make XML-RPC or SOAP calls and load xwar archives via HTTP; they cannot execute arbitrary HTTP GET's or open regular TCP sockets.
XWT will not allow a script to connect to a non-public IP address (10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16, as specified in RFC 1918). There is one exception -- if all templates currently loaded in the core originated from the same IP address, those scripts may make calls to that IP address regardless of whether or not it is firewalled. If XWT does not have access to a DNS resolver (because it is using a proxy which performs DNS lookups), XWT will provide the proxy with the appropriate X-RequestOrigin header that the proxy needs in order to maintain security.
The only remaining possible attack is against a XML-RPC or SOAP service running on a firewalled host with a public address. Assigning such machines public IP addresses is a poor network security policy, and doing so squanders scarce public IPv4 addresses. As such, the onus is on the administrators of such machines to explicitly block access to clients reporting a User-Agent: header beginning with the three characters "XWT".
All top-level windows created by XWT are scarred -- a stripe and a lock is drawn across the corner of the window. There is no way for a user interface to remove this scar. XWT user interfaces may not create windows smaller than the size of the scar.
XWT user interfaces may transmit network data using HTTPS (SSL 3.0) for encryption. XWT will attempt 128-bit encryption, but will negotiate down to 40-bit if the server does not support strong crypto. XWT's SSL implementation is currently provided by TinySSL and The Legion of the Bouncy Castle.
All HTTPS connections must be authenticated by the server using a certificate whose name matches the domain name of the HTTPS URL. The certificate must be signed by a trusted root CA. XWT trusts the same 93 root CAs whose certificates are included as "trusted" in Microsoft Internet Explorer 5.5 SP2. This provides a minimal level of protection against man-in-the-middle attacks; you should not trust this connection with any data you would not normally trust an SSL-enabled web browser with.
XWT's scripts are written in a modified subset of ECMA-262, revision 3 (aka JavaScript 1.5). The interpreter strays from the spec in a few ways.
The following ECMA features are not supported:
Additionally, you must declare all root-scope variables (with var) before using them; failure to do so will result in an exception. Box properties are pre-defined in the scope that scripts are executed in.
} catch(e propname "foo.bar.baz") { // ... }Is equivalent to:
} catch(e) { if (e.propname != null && e.propname >= "foo.bar.baz" && e.propname < "foo.bar.baz/") { // ... } }Multiple extended-catch blocks can appear at the end of a single try block. However, at most one non-extended catch block may appear, and if it does appear, it must be the last one.
Very early in the loading process, XWT begins logging messages about what it is doing. Where this output is logged to differs by platform; currently it goes to standard output when running inside a JVM, and to $TMPDIR\xwt-log.txt on Win32 (where $TMPDIR is the value returned by GetTempPath()). The logs contain a lot of valuable debugging information and performance hints; if you are having trouble developing an XWT application, be sure to check the logs.
If XWT encounters a serious problem before it starts logging information, or if it is unable to open the log file, it will abort immediately with a critical abort, which will be displayed on the console for POSIX-native cores and in a dialog box for JVM-based and Win32-native cores.
You can invoke XWT directly from the command line during development. When using a JVM, the invocation format is:
java -jar path-to-xwt-jar [-sv] source-location [initial-template]
Where path-to-xwt-jar is the path to xwt.jar, which can be downloaded here.
On Win32, the invocation format is:
xwt.exe [-v] source-location [initial-template]
The file xwt.exe is placed in Windows' ActiveX cache directory the first time XWT is used on the machine. The ActiveX cache location depends on what version of Windows you are using; on newer versions of Windows it is C:\WINDOWS\DOWNLOADED PROGRAM FILES\. You can also extract xwt.exe from xwt.cab, which is available here.
The source-location parameter can be either the path to an xwar archive, the http url of an xwar archive, or the path to a directory comprising an unpacked xwar archive.
The initial-template parameter is the stream name of a template to be used as the initial template. If ommitted, it defaults to main.
The -v option causes XWT to enable verbose logging; this will cause it to log lots of information to the log file. This option will also substantially decrease XWT's performance.
XWT implements a subset of ECMAscript revision 3, which is equivalent to JavaScript 1.5. For information on the differences, please see Appendix C. Some useful tutorials include:
Grammar support is experimental in this release and may not work properly. It may change in incompatible ways or disappear completely from future releases
Grammars are defined with a statement in the following form:
a ::= b { c }
A grammar is really just another function; once defined you can't tell it apart from an ordinary function. A grammar takes one argument, which can be a string or stream. The argument is parsed and the result of executing the code block 'c' is returned.
The property 'a' is read; if the value is a grammar, a new production rule (ie a new alternative, as with '|') is added to that grammar (this is a destructive update). This allows you to add productions to pre-existing grammars (for example, adding a new type of expression to a programming language by extending the 'expr' grammar). If the old value is not a grammar, the value is discarded and a new grammar object is created.
The value 'b' is a pattern, which may consist of seven simple primitives:
The value 'c' and the braces surrounding it are an *optional* code block, in which the following identifiers are bound:
var foo ::= 'a' | 'b'; var bar ::= foo; var baz ::= 'c' | bar { /* foo is not defined here, but bar is */ };
Here is the metacircular definition of the grammar facility:
grammar ::= identifier '::=' pattern (';' | '{' code '}' ';'?) identifier ::= ('a'..'z' | 'A'..'Z' | '_' | '$') (identifier | '0'..'9')* char ::= '\0x0000'..'\0xffff' literal ::= '\'' char+ '\'' | '\'' char '\'' '..' '\'' char '\'' pattern ::= identifier | literal | '(' pattern ')' | pattern '+' | pattern '?' | pattern '*' | pattern pattern | pattern '|' pattern
Copyright (C) 2004 Adam Megacz, verbatim redistribution permitted.
XWT is a trademark of Adam Megacz