Sidewinder is a new kind of desktop application framework. Like many frameworks it makes the task of producing desktop applications easier, but whilst other frameworks will use C#, Visual Basic or Java, Sidewinder uses high-level, standard languages, such as XHTML and XForms.
Sidewinder has a pluggable architecture, which means that it is able to use processors from different vendors for these standard languages. The XForms part is provided by formsPlayer.
In this handbook we'll look at how to use Sidewinder and formsPlayer to create powerful applications.
Sidewinder is a new kind of desktop application framework that uses web languages such as XHTML, SVG, XForms and Ajax, in place of more complex languages such as C++, C# or Java.
Sidewinder is built on a simple but powerful philosophy: Namely, that an enormous class of desktop applications being developed today make use of the internet, therefore the best languages to use to develop those applications are those devised for the web.
To achieve this, Sidewinder brings together standard languages such as XHTML, XForms, MathML, SVG and Ajax to create a flexible application development framework. But at the same time it provides all of the functionality we'd expect from desktop applications, such as docking to a screen edge, auto-hiding, transparency and opacity.
Sidewinder uses XHTML as a 'base' language into which other languages can be added. Any document passed into Sidewinder is validated at the same time as it is rendered.
Validation is performed using the base schemata from XHTML 1.1 Modularisation, into which schemata for XForms, SVG, XLink, XML Events and MathML have been added. Support for each language is pluggable, and new languages will be added.
Rendering takes place in parallel to validation rather than following it so as not to delay display of the document to the user.
And just as the languages that can be supported are pluggable, so too are other components that Sidewinder uses, such as renderers. Sidewinder currently detects both Internet Explorer and Gecko, and allows switching between the two renderers via a menu, even after a document has been loaded.
The Sidewinder Viewer is currently available for free download.
Up until now, powerful languages like XForms and SVG have been isolated from each other. But with Sidewinder's flexible pluggable architecture, the combination of XHTML, XForms, SVG, RDFa and Ajax become a web and desktop application language that is second to none.
Sidewinder is geared towards supporting the most up-to-date standards, and using them as a tool to build internet-focused desktop applications. Sidewinder recognises XHTML documents, and will use the latest XHTML 1.1 Modularisation schemas to validate the document whilst it is being rendered.
The validation schemas also incorporate other standard languages, including:
The actual rendering of each of these languages depends on the installation of plug-ins, which is discussed in a later section.
If Internet Explorer is passed a document with the MIME type application/xhtml+xml or one of the extensions .xhtml or .xht, then it will invoke Sidewinder in embedded mode.
Any document that is indicated to Sidewinder as being XHTML will go through validation. The schemata used have been built using the techniques described in XHTML Modularization 1.1 which provides a set of XHTML modules for re-use when building XML languages.
The schemata used by Sidewinder actually build on the core XHTML modules by adding XForms, SVG, MathML, RDFa and XLink. (The MathML schemas are currently disabled.)
Since the schemata may well contain errors, please use the forums to both check for updates in between releases, and to report any errors you discover.
To enable us to validate RDFa we need to add some features to the XHTML Modularization 1.1 schemata.
Note that in the following mark-up slightly older schemata than those used in XHTML Modularization 1.1 are shown; this will be modified shortly.
RDFa requires two elements, meta and link. The main ways in which they change from normal XHTML are:
meta takes an attribute of property instead of name;meta and link can be nested inside themselves and each other;meta and link can take inline text;meta and link can appear anywhere within a document.Since there were so many changes to be made it got to the point where a redefinition of the existing elements left so little of the original intact, that new modules were created for each. However, once that was done it became clear that the two modules were almost complete copies of each other, so they have been merged into a new module called xhtml11-rdfa-1.xsd.
This means that in xhtml11-modules-1.xsd the references to xhtml-meta-1.xsd and xhtml-link-1.xsd have been removed, and replaced with this single module.
All of the attributes that were needed for RDFa were moved out to a separate module, and placed in the 'common attribute' collection (see next section). Then all that is needed is for meta and link to use this collection exactly like other elements do. (Note that all the other attributes have been left intact for now.):
<xs:attributeGroup name="meta.attlist">
<xs:attributeGroup ref="Common.attrib"/>
<xs:attribute name="name" type="xs:NMTOKEN"/>
<xs:attribute name="scheme" type="xh11d:CDATA"/>
</xs:attributeGroup>
<xs:attributeGroup name="link.attlist">
<xs:attributeGroup ref="Common.attrib"/>
<xs:attribute name="media" type="xh11d:MediaDesc"/>
</xs:attributeGroup>
(At some point scheme may get deprecated since property is a CURIE, which means that the namespace prefix plays the role of a scheme.)
Defining the elements themselves then becomes a case of adding a common content model:
<xs:group name="rdfa.content">
<xs:choice>
<xs:element ref="meta" />
<xs:element ref="link" />
</xs:choice>
</xs:group>
And then making use of it in both elements:
<xs:complexType name="meta.type" mixed="true">
<xs:group ref="rdfa.content" minOccurs="0"
maxOccurs="unbounded" />
<xs:attributeGroup ref="meta.attlist"/>
</xs:complexType>
<xs:complexType name="link.type" mixed="true">
<xs:group ref="rdfa.content" minOccurs="0"
maxOccurs="unbounded" />
<xs:attributeGroup ref="link.attlist"/>
</xs:complexType>
<xs:element name="link" type="link.type"/>
<xs:element name="meta" type="meta.type"/>
Note that defining both elements in terms of each other fulfills the requirement that they can be nested to any depth. And by adding mixed="true" we also provide for inline text in both elements, although their meanings differ (inline text in meta sets the value for content, whilst inline text in link is the same as in a).
Finally, to allow the use of these two elements anywhere in the XHTML document we need to redefine the Misc.extra group in xhtml.xsd:
<xs:group name="Misc.extra">
<xs:choice>
<xs:group ref="xh11:Misc.extra" />
<xs:element ref="meta"/>
<xs:element ref="link"/>
</xs:choice>
</xs:group>
To incorporate the attributes a module called rdfa-10-rules.xsd was created, and in it an attribute group was added:
<xs:attributeGroup name="rdfa.attlist">
<xs:attribute name="about" type="CurieOrURI"/>
<xs:attribute name="content" type="xs:string" />
<xs:attribute name="datatype" type="Curie"/>
<xs:attribute name="href" type="CurieOrURI"/>
<xs:attribute name="property" type="Curie"/>
<xs:attribute name="rel" type="CurieOrLinkTypeList"/>
<xs:attribute name="rev" type="CurieOrLinkTypeList"/>
</xs:attributeGroup>
All of the data types listed here are included in the same module, and discussed in the next section. (They will however, be broken out into a separate 'types' document.)
As you saw in the previous section, some of the attributes that XHTML uses are not here--more XHTML-specific attributes have been kept back in the XHTML driver file.
To make use of these RDFa attributes we simply need to redefine Common.extra:
<xs:attributeGroup name="Common.extra">
<xs:attributeGroup ref="Common.extra"/>
<xs:attributeGroup ref="rdfa.attlist" />
<xs:attribute name="charset" type="xh11d:Charset"/>
<xs:attribute name="hreftype" type="xh11d:ContentType"/>
<xs:attribute name="hreflang" type="xh11d:LanguageCode"/>
<xs:attribute name="http-equiv" type="xs:NMTOKEN"/>
</xs:attributeGroup>
Common.extra is an empty definition in XHTML M12N but is part of Common.attribs which is applied to every element.
Note that hreftype is used here instead of type since otherwise there would be a conflict. This is the name proposed in XHTML 2.0.
As we saw in the previous section, the RDFa attributes rely on a set of datatypes, the most important being the CURIE.
Although this may change, for now a CURIE is defined as follows:
<xs:simpleType name="Curie">
<xs:restriction base="xs:string">
<xs:pattern value="[\i-[:]][\c-[:]]*:.+" />
</xs:restriction>
</xs:simpleType>
It's pretty straightforward, but to give a quick overview:
\i is the set of characters that can start an XML name, which is any letter, an '_' or a ':';[\i-[:]] means any character that is in the set \i but is not a colon...for obvious reasons;So the first character of our CURIE must be a letter or an underscore, i.e., not a number, colon, equals sign, etc. After that we can have any XML name character, which can now include numbers:
\c is the set of XML name characters that can appear after the first character;[\c-[:]] is the same set but without a colon;[\c-[:]]* means match as many as we can (zero or more);The prefix part has been made quite strict because it must match the namespace prefix rules. But after the colon we can be looser, hence:
.+ means one or more of any character.Note that we could say that the part after the colon can be any valid URI, and this does actually work fine. But since pretty much anything matches successfully, there didn't seem a lot of point. However, so that we have a record of it, making the part after the colon a valid URI can be done with the following expresson (line-breaks only added for layout):
[\i-[:]][\c-[:]]* : (([^:/\?#]+):)?(//([^/\?#]*))?([^\?#]*)(\?([^#]*))?(#(.*))?
An escaped CURIE is used in places where direct use can be ambiguous, and is currently achieved by placing square brackets around the CURIE. The definition is as follows:
<xs:simpleType name="CurieEsc">
<xs:restriction base="xs:string">
<xs:pattern value="\[[\i-[:]][\c-[:]]*:.+\]" />
</xs:restriction>
</xs:simpleType>
Note that there is no way with XML Schemas for this regular expression to reference our first expression, hence the repitition of the pattern for a CURIE.
Once we have our escaped CURIE we can use it to create a type that can contain both a URI and an escaped CURIE:
<xs:simpleType name="CurieOrURI">
<xs:union memberTypes="xs:anyURI CurieEsc" />
</xs:simpleType>
This type is used for about and href.
The rel and rev attributes are a little tricky since they can contain CURIEs as well as tokens that come from a standard list...which is made slightly more complicated by the fact that it is acceptible to have multiple values.
The first step is to create a 'CURIE or link type' definition, which allows either a CURIE or one of a restricted range of values:
<xs:simpleType name="CurieOrLinkType">
<xs:union memberTypes="Curie">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="alternate"/>
<xs:enumeration value="forward"/>
<xs:enumeration value="start"/>
<xs:enumeration value="next" />
.
.
.
<xs:enumeration value="profile" />
<xs:enumeration value="role" />
<xs:enumeration value="cite" />
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
Once we have this it's a simple matter to create a list of 'CURIE or link types':
<xs:simpleType name="CurieOrLinkTypeList">
<xs:list itemType="CurieOrLinkType" />
</xs:simpleType>
This definition would make the following valid:
<link rel="subsection ab:foreward prev" href="[cd:ef]" />
and the following invalid:
<link rel="blah ab:foreward" href="[cd:ef]" />
One of the problems with the schemas created for XHTML Modularization 1.1 is that attributes that play the same role in different places are not always rationalised. One example of this is the href attribute used on anchors and image maps, and another is the use of type on object, script and style.
In order to allow href to appear anyway in the document we need to remove it from the places where it is already set. We achieve this by creating replacements for xhtml-hypertext-1.xsd and xhtml-csismap-1.xsd in which any references to any of the attributes that have now been moved into the Common.attribs group, are dropped.
Sidewinder makes it easy to add support for other mark-up languages, as well as for other renderers--and even allows renderers to be switched at run-time. The current release supports both Gecko and Internet Explorer, making for a powerful testing environment.
Sidewinder supports the addition of processors that handle non-core mark-up languages, such as XForms, SVG and MathML.
XForms functionality can be added with the formsPlayer XForms processor from x-port.net.
If you have Sidewinder and formsPlayer installed, you can check that they are working by pointing Internet Explorer at the XForms samples on the Mozilla site, which are delivered as application/xhtml+xml. Sidewinder will be opened in embedded mode, with the XForms rendered correctly.
(The calculator, Flickr and tax forms work pretty much as in Mozilla, but there is a problem with how Sidewinder interprets the insurance form.)
SVG functionality can be added with the Adobe SVG Viewer.
MathML functionality can be added with MathPlayer from Design Science.
The Sidewinder architecture supports renderers built using a cascaded rendering approach. This means that documents received in one language can be rendered using another language, and a cascade renderer will manage any language mappings that are needed.
The current release of Sidewinder is geared towards XHTML 1.1. If Internet Explorer is selected as the renderer then the document will be converted to HTML 4.01. However, if Gecko has been selected, the document will be left intact.
(Gecko functionality is currently obtained by using the Gecko ActiveX control, which must be installed.)
If Sidewinder detects a renderer that it can use (currently Internet Explorer and the Gecko ActiveX control) then a corresponding menu option will be created on the Rendering menu:
The Rendering menu is also available when Sidewinder is running in embedded mode within Internet Explorer:
You can switch between renderers as you like--no page reloads will take place since Sidewinder manages the source document. And since Sidewinder also manages the navigation, you can navigate in one renderer, switch renderers, and then continue navigating in another--a major boon for testing.
Sidewinder can operate in three modes: embedded inside Internet Explorer, as a standalone browser and as a desktop application framework.
With Sidewinder you can browse ordinary web pages as normal, either in the standalone mode or embedded within Internet Explorer. But Sidewinder can go much further, and when using its unique desktop application mode, a simple XHTML document becomes a full internet-focused desktop application, that can dock to the side of the screen, auto-hide, be set transparent or opaque, and more.
Sidewinder can be invoked as a standalone browser from your Start menu; a menu item will have been added when Sidewinder was installed.
In this mode, Sidewinder has three dockable child windows:
Furthermore, the standalone browser mode contains a syntax-highlighted source view, which shall gradually evolve into a full featured editor.

When using Internet Explorer, navigating to a document that has an XHTML MIME type (i.e., a type of application/xhtml+xml) will cause Sidewinder to handle the document, embedded within IE. (A server will know that IE can accept XHTML documents because Sidewinder modifies the accept headers.)
In this mode Sidewinder turns an XHTML page into a full desktop application, with the option to dock the application to the side of the screen, make it auto-hide, have other applications that are underneath it show through, and so on.
For more information on what parameters can be used, see Appendix 1.


The easiest way to use Sidewinder is as a standalone desktop web applications viewer. A desktop web application--or what we often call an internet-facing desktop application--is simply an XHTML document that is running in a purpose-built container, rather than a standard web browser. Running web applications in this way is useful since it allows us to interact with the application as something distinct from our browsing experience.
For example, say we have a simple web page that tells us when the next train home is; we could open this page in our web browser and look at it periodically for updates, but why not take the same web page and dock it to the side of the screen, and make it automatically hide when we're not looking at it? This is the kind of functionality we would expect from a desktop application, and by using Sidewinder, it's now the kind of functionality we can use with our web applications.
Let's look at some examples.
In this example we'll show how to convert a simple XHTML form into a desktop web application. In fact there is so little to it that it barely warrants a page...all you need to do is rename any HTML or XHTML document so that the file extension is .webapp--or deliver an application from a server with the MIME type application/webapp+xml--and Sidewinder will be triggered to open and run your document as a desktop web application.
To begin we'll take the Flickr search form and rename the file so that its file extension is .webapp. Once you have saved the file, double-click it and Sidewinder will open it.
You can run also run this web application directly from our SVN server.
Now that we have a desktop web application that we can work on, we'll start to add some more features.
An easy way to convert your favourite web application into a desktop web application is to run Sidewinder from the command-line, and give it a URL to your document.
Open a command prompt, and change to the Sidewinder directory. If you have installed Sidewinder in the default locations, then you can type this:
cd "\program files\sidewinder\viewer 2.0"
Now execute the following command:
swviewer2 http://examples.adobe.com/flex2/inproduct/sdk/flexstore/flexstore.html#meta(width=1010,height=610)
Sidewinder will open as a basic Windows application with the Adobe Flash Flexstore demonstration running inside:
The Flexstore application functions as normal, but it can be treated as a desktop application in its own right, distinct from the browser:
When a web application is opened with Sidewinder its appearance defaults to that of a simple desktop application, with basic chrome. It is possible to control this appearance by specifying metadata properties, either in the document or as part of the URL.
To make an application dock itself to one of the edges of the desktop we use the property anchor with a value of true.
We can also indicate where we would like the application to start, by using the position property.
To auto-hide--i.e., slide off the desktop when the user moves their mouse away from the application--we use the property autohide with a value of true.
By adding the following settings to the Flickr Search web application we would dock the application to the top right of the screen, and make it auto-hide:
<link rel="stylesheet" href="flickr.css" type="text/css" />
<meta name="position" content="top-right" />
<meta name="anchor" content="true" />
<meta name="autohide" content="true" />
<xf:model>
Note that the location of a window with a position of 'top right' and one with a position of 'right top' will be the same. The difference is only apparent when docking; the first will be docked to the top edge, whilst the second will be docked to the right edge. This means that when auto-hiding, a window that is positioned 'top right' will slide off the top, whilst a window that is positioned 'right top' will slide off the right.
The modified application is available here.
If the webapp is being loaded via the command-line then we can open the basic (unmodified) web application using the following command:
swviewer2 http://svn.x-port.net/svn/public/samples/flickr/flickr.webapp#meta(position=top-right,anchor,autohide)
To make windows behind our desktop application 'show through' we can use the property transparency to give Sidewinder the value of a colour that will be set to 'transparent'. This has the effect of allowing any application that is behind our web application to be visible and respond to mouse-clicks--extremely useful if we want to give our application a different shape. The chrome is often removed when using transparency.
By adding the following settings to the Flickr Search web application our application would have none of the usual desktop application chrome, and the entire application would appear to grow and shrink as the user searched:
<meta name="autohide" content="true" />
<meta name="height" content="700" />
<meta name="chrome" content="false" />
<meta name="transparency" content="fffffe" />
<style type="text/css">
body
{
background-color : #fffffe;
}
html, body
{
margin : 0;
}
</style>
<xf:model>
The modified application is available here.
Alternatively, we can open the basic Flickr web application with the following command:
swviewer2 http://svn.x-port.net/svn/public/samples/flickr/flickr.webapp#meta(position=top-right,anchor,autohide,height=700,chrome=false,transparency=fffffe)
Note however that this won't quite work with the example we've been using, since a background of #fffffe needs to be added.
To make windows behind our desktop application partly visible we can use the property opacity. The value given is a percentage, and tells Sidewinder how much of the web application to show, and how much of any application sitting behind. This feature is useful when creating applications such as clocks where we'd like the information to be available all the time, but we don't want to lose screen space.
By adding the following settings to the Flickr Search web application other applications will now be partly visible 'through' our application:
<meta name="transparency" content="fffffe" />
<meta name="opacity" content="70" />
<style type="text/css">
The modified application is available here.
Alternatively, we can open the basic Flickr web application with the following command:
swviewer2 http://svn.x-port.net/svn/public/samples/flickr/flickr.webapp#meta(position=top-right,anchor,autohide,height=700,chrome=false,transparency=fffffe,opacity=70)
Note however that this won't quite work with the example we've been using, since a background of #fffffe needs to be added.
Sidewinder fully supports JavaScript as a way to create powerful, internet-facing, desktop applications. Sidewinder also includes a number of built-in objects that extend JavaScript in order to make GUI applications easier to build.
In this section we show how to use these features to blur the boundary between the desktop and the rest of the internet.
To run any of the examples in the following sections:
js file you just copied;Open With;SWViewer2.The Renderer object allows a number of different types of window to be created that in turn incorporate a Sidewinder renderer. Renderers are available for simple text or XHTML, and can be created to stand on their own, or as a dockable child of some parent window.
To create a renderer we simply use the new operator followed by the Create method. Create takes one parameter which is a JavaScript object containing information about how the window should behave. For example, to create an XHTML renderer window that:
we would write the following script:
var oRenderer = new Renderer;
oRenderer.Create(
{
Type : "xhtml",
Width : 850,
Height : 700,
Edge : "right",
Position : "top",
AutoHide : true,
Style : 0x20001D40
}
);
(The various parameters, including the Style values, will be explained in more detail in a later section.)
To create a web application that fills a renderer with your Google Calendar, we would do the following:
var oRenderer = new Renderer;
oRenderer.Create(
{
Type : "xhtml",
Width : 850,
Height : 700,
Edge : "right",
Position : "top",
AutoHide : true,
Style : 0x20001D40
}
);
oRenderer.Load("http://calendar.google.com");
oRenderer.Show();
This application would open a large window, docked to the top of your display, and that automatically hides when the mouse is moved away. The window will contain your Google Calendar login page, and once you have logged in your calendar will be available by moving the mouse to the top edge of the display.
The blog-monitoring site Technorati has a useful feature they've called Technorati Mini which allows a user to create a small browser window containing search results, which updates itself every minute--an ideal candidate for a Sidewinder desktop application.
To turn this into a desktop application that docks to the left side of your desktop, and saves real estate by autohiding, we would use the following JavaScript:
var oRenderer = new Renderer;
oRenderer.Create(
{
Type : "xhtml",
Width : 310,
Height : 470,
Edge : "left",
AutoHide : true,
Position : "top",
Opacity : 70,
Style : 0x20001D40
}
);
oRenderer.Load("http://www.technorati.com/mini/index.html?s=cheese");
oRenderer.Show();
A common use of Sidewinder is to host web applications that were designed to run in a web browser. Often these applications create new browser windows in order to provide part of their functionality, but in many situations it would be useful to have control over the creation of these windows and control their position, whether they dock or autohide, and so on.
Sidewinder allows us to do this via the renderer-request-newwindow event, which is dispatched whenever the hosted web application requests a new window. A scripted application can register for this event and when triggered, create a renderer object which will be returned to the web application. This renderer can have all of the usual features, such as autohide, opacity and so on.
To register for the event, we need an EventListener with a handleEvent function:
function handleEvent(event)
{
...
}
var listener = new EventListener;
listener.SetHandler(handleEvent);
koolim = new Renderer(
{
Type : "xhtml",
Title : "Sidewinder: Kool IM",
Style : 0x00000040|0x00000800|0x00001000|0x00400000|0x20000000,
Edge : "right",
Position : "middle",
AutoHide : true,
Width : 256
}
);
koolim.Create();
koolim.addEventListener("renderer-request-newwindow", listener, true);
Now, whenever any web application hosted by this renderer requests a new window (using window.open) our event handler will be invoked. To provide a renderer to be used by the web application, we implement the handleEvent method.
First we create some global variables, so that the JavaScript engine doesn't remove our windows when the function returns:
var message; var listener; var koolim; var listener; var param;
The handleEvent method itself first creates a renderer:
function handleEvent(event)
{
message = new Renderer(
{
Type : "xhtml",
Title : "Sidewinder: Message",
Style : 0x00000040|0x00000800|0x00001000|0x00400000|0x20000000,
Edge : "left",
Position : "top",
AutoHide : true,
Width : 298,
Height : 298
}
);
message.Create();
message.Show();
before returning it to Sidewinder via the Event object.
event.parameter.objectValue = message.GetRenderingImplementation(); }
The parameters to the renderer can be set as required. For example, the position of the window could be set, based on how many previous windows had been opened.
To illustrate the use of the renderer-request-newwindow event, we'll create a desktop application that uses the KoolIM chat client.
KoolIM is a very impressive web application that allows you to chat with people via any of the popular chat protocols. The KoolIM servers do all the work of translating the protocols, which means that the user interface need only communicate over HTTP to the KoolIM servers. It's therefore possible to build chat clients with HTML, which means that users do not need to install any special software and can use chat almost anywhere.
Since KoolIM supports so many protocols it's a strong candidate to be used as your main chat software, although it is limited to some extent by the browser. We can improve things somewhat by adding a renderer-request-newwindow handler that creates a new renderer whenever the KoolIM web application tries to open a new window, but since we have total control over the renderer object, we'll create one that docks to the left side of the screen, and automatically hides when the mouse is moved away.
The first part of our application just sets up some global variables so that the objects we create don't get deleted when our functions exit:
var message; var listener; var koolim; var listener;
Next we create an event handler, that will create a new renderer object when triggered, and will return the renderer as part of the Event object:
function handleEvent(event)
{
message = new Renderer(
{
Type : "xhtml",
Title : "Sidewinder: Message",
Style : 0x00000040|0x00000800|0x00001000|0x00400000|0x20000000,
Edge : "left",
Position : "top",
AutoHide : true,
Width : 298,
Height : 298
}
);
message.Create();
message.Show();
event.param.objectValue = message.GetRenderingImplementation();
}
The main function itself needs to create the main renderer:
function main()
{
koolim = new Renderer(
{
Type : "xhtml",
Title : "Sidewinder: Kool IM",
Style : 0x00000040|0x00000800|0x00001000|0x00400000|0x20000000,
Edge : "right",
Position : "middle",
AutoHide : true,
Width : 256
}
);
koolim.Create();
before creating an EventListener object and registering for the 'new window' event:
listener = new EventListener;
listener.SetHandler(handleEvent);
koolim.addEventListener("renderer-request-newwindow", listener, true);
Finally, we're ready to open the KoolIM web application:
koolim.Load("http://web1.koolim.com/client5/html/webim.html");
koolim.Show();
}
main();
(For detailed information on how to use the script below, see Using JavaScript to create internet-facing desktop applications.)
Sidewinder supports the use of compound documents--documents that are made up of more than one mark-up language--to define internet applications.
To achieve this, XHTML 1.1 Modularisation is used to import languages such as SVG and XForms into XHTML. We use the term xH to describe the compound language. The xH schemas are available from our Subversion server at:
http://svn.x-port.net/svn/public/schemas/xH/
Whilst Sidewinder handles the wiring of these languages, the actual processing of the different languages that might be part of a compound document is handled by specific language processors, such as formsPlayer for XForms, or Adobe's SVG Viewer for SVG. More details are in the section Adding languages.
Examples are available in our Subversion repository:
If you use the oXygen editor, you can use the xH schemas to make it easier to edit documents that use XHTML plus XForms, SVG and MathML, by following the following steps:
http://svn.x-port.net/svn/public/schemas/xH/
Options menu.Preferences....Editor branch in the tree view.Default Schema Association option.New to add a new association.OK.Apply.The XForms model is a powerful component which provides declarative syntax for defining data, actions and submission requests. This tutorial demonstrates how to use some of that power to drive the Google Maps JavaScript library with data from a UK public transport information feed; although any other feed that contains map co-ordinates in the data could be used instead.
Because this tutorial is purely concerned with the XForms model, we shall assume the existence of a number of JavaScript mapping functions. In addition, what follows also relies upon the existence of an HTML div element with @id="div-map" to act as a container for the map.
The first thing that the form must do is construct a map on the page. This is accomplished by the following actions:
<xf:action ev:event="xforms-ready">
<xf:dispatch name="rssmap-create" target="mdl-rssmap" />
</xf:action>
...
<xf:action ev:event="rssmap-create">
<xf:setvalue ref="instance('inst-dummy')" value="js:CreateMap('div-map')" />
<xf:setvalue
ref="instance('inst-dummy')"
value="js:CenterMap(number(instance('inst-constants')/centre-point/@latitude),
number(instance('inst-constants')/centre-point/@longitude),
number(instance('inst-constants')/zoom-factor))"
/>
</xf:action>
The model that we are building will use data from an RSS feed to drive the map. This requires two instances and a submission:
<xf:instance id="inst-request">
<request xmlns="" />
</xf:instance>
<xf:instance id="inst-response">
<response xmlns="" />
</xf:instance>
<xf:submission
id="sbm-feed"
ref="instance('inst-request')"
action="http://www.bbc.co.uk/travelnews/tpeg/en/pti/pti_tpeg.xml"
method="get"
replace="instance"
instance="inst-response"
/>
The first instance will remain empty, since our submission is not required to post any data. The second instance will be used to store the result of the submission; in this case, the feed from the URL http://www.bbc.co.uk/travelnews/tpeg/en/pti/pti_tpeg.xml.
Once the submission is implemented, we must write an action to handle the result data by overlaying it onto our map:
<xf:action ev:event="rssmap-overlay">
<xf:setvalue ref="instance('inst-dummy')" value="js:ClearMapPoints()" />
<xf:action iterate="instance('inst-response')//geo:lat[../geo:long]">
<xf:setvalue
ref="js:CreateMapPoint(number(.),
number(../geo:long),
string(../description),
instance('inst-dummy'))"
value="''"
/>
</xf:action>
<xf:action iterate="instance('inst-response')/tpeg_message/public_transport_information//WGS84">
<xf:setvalue
ref="js:CreateMapPoint(number(@latitude),
number(@longitude),
concat(../../../transport_operator_description/operator_name/@name,
': ',
../../../../summary),
instance('inst-dummy'))"
value="''"
/>
</xf:action>
</xf:action>
After clearing any existing map point, there are two actions that iterate through all of the map locations in the response data. The first of these actions handles RSS response data containing geo:lat and geo:long elements. The second handles tpegML response data containing WGS84 elements. This apparent duplication enables the form to work with data from both feed types, without any noticeable difference to the user.
The 'rssmap-overlay' action should be invoked when the submission has returned successfully, like this:
<xf:submission
id="sbm-feed"
ref="instance('inst-request')"
action="http://www.bbc.co.uk/travelnews/tpeg/en/pti/pti_tpeg.xml"
method="get"
replace="instance"
instance="inst-response"
>
<xf:action ev:event="xforms-submit-done">
<xf:dispatch name="rssmap-overlay" target="mdl-rssmap" />
</xf:action>
</xf:submission>
The next step is to invoke our submission when the form is loaded and then again at regular intervals. This ensures that the information on the map is kept up to date for as long as the form is open.
To invoke the submission on form load requires a send element to be added to our 'xforms-ready' action:
<xf:action ev:event="xforms-ready">
<xf:dispatch name="rssmap-create" target="mdl-rssmap" />
<xf:send submission="sbm-feed" />
</xf:action>
In order to then keep the map updated, we must first add an 'rssmap-refresh' action to the model:
<xf:action ev:event="rssmap-refresh"> <xf:send submission="sbm-feed" /> </xf:action>
Then we need to incorporate two short JavaScript functions into the form:
function InitialiseTimer(interval, refnode)
{
window.setInterval("UpdateMap();", interval);
return "";
}
function UpdateMap()
{
var evt = document.createEvent("Event");
evt.initEvent("rssmap-refresh", false, false);
var mdl = document.getElementById("mdl-rssmap");
mdl.dispatchEvent(evt);
}
We can now call the first of these two functions to set up our timer. The second one will then be called by the script interpreter after each interval and simply dispatches our 'rssmap-refresh' event to the model element, invoking our new action. These functions can now be called from our 'xforms-ready' action:
<xf:action ev:event="xforms-ready">
<xf:dispatch name="rssmap-create" target="mdl-rssmap" />
<xf:send submission="sbm-feed" />
<xf:setvalue
ref="instance('inst-dummy')"
value="js:InitialiseTimer(number(instance('inst-constants')/update-interval),
instance('inst-dummy'))"
/>
</xf:action>
All that is left to implement now is garbage collection. This can be achieved with a simple action for 'xforms-model-destruct':
<xf:action ev:event="xforms-model-destruct">
<xf:setvalue ref="instance('inst-dummy')" value="js:DestroyMap()" />
</xf:action>
If you wish to run the complete sample application, you must first install the latest versions of formsPlayer and the Sidewinder Viewer; once they are installed you can execute the the sample by clicking here.
You can also get the full source.
Sidewinder is built using a component-based architecture that enables re-use of key components inside your own applications.
The component responsible for XHTML renderering in the Sidewinder Viewer provides a set of COM interfaces enabling it to be embedded inside other applications. This tutorial demonstrates how to achieve this in a simple C# project, although the same techniques may be applied to other languages and projects too.
Before you can begin, you will need to install the latest version of the Sidewinder Viewer. Once you have done that, you must import two of our COM libraries into your project using the 'Add Reference' dialog. They are installed by the Sidewinder Viewer to the following locations:
[Program Files]\Common Files\Sidewinder\Renderer\Renderer4.dll
[Program Files]\Common Files\Sidewinder\DOM\DOM2Events.dll
The first of these, the Renderer, provides all of the XHTML rendering functionality. The second component, an implementation of the W3C's DOM Level 2 Events recommendation, facilitates communication between your application, the Renderer and the live document.
The first thing your application must do is instantiate and initialise a copy of the Renderer, storing a pointer to its IRender interface:
public class RenHost : System.Windows.Forms.Form
{
private RendererLib.IRender Renderer;
...
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
...
}
...
}
Your application may now customise various other characteristics of the Renderer component, such as setting the handle to its parent window, setting its initial size or instructing it to delegate any navigation requests to your container application. These properties and others are set by dispatching certain events to the Renderer's IEventTarget interface.
A new method along the following lines can simplify this process for you:
private void DispatchRendererEvent(string sType, int nParam1, int nParam2)
{
IRendererEvent evt = (IRendererEvent)new RendererEventClass();
evt.initRendererEvent(sType, false, false, nParam1, nParam2, "");
IEventTarget tgt = (IEventTarget)this.Renderer;
tgt.dispatchEvent((DOMEvent)evt);
}
It is not necessary to worry about what all of the different parameters mean at this point. Simply know that the code above allows you to dispatch a renderer event of type sType, along with some event-specific contextual parameters.
With this method in place, then, the first thing you might want to do is make the Renderer a child of one of your application's windows:
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
DispatchRendererEvent("renderer-set-parentwindow",
(int)this.Panel.Handle, 0);
DispatchRendererEvent("renderer-set-windowstyle", 2, 0);
...
}
You should also inform the Renderer of its intial size and position within its parent window, like this:
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
DispatchRendererEvent("renderer-set-parentwindow",
(int)this.Panel.Handle, 0);
DispatchRendererEvent("renderer-set-windowstyle", 2, 0);
DispatchRendererEvent("renderer-set-position", 0, 0);
DispatchRendererEvent("renderer-set-dimensions",
this.Panel.ClientRectangle.Width,
this.Panel.ClientRectangle.Height);
...
}
Once these initial window-related properties have been set, you must instruct the Renderer to perform its own window creation:
private void RenHost_Load(object sender, System.EventArgs e)
{
this.Renderer = (IRender)new RendererLib.RendererClass();
this.Renderer.Initialise(null);
DispatchRendererEvent("renderer-set-parentwindow",
(int)this.Panel.Handle, 0);
DispatchRendererEvent("renderer-set-windowstyle", 2, 0);
DispatchRendererEvent("renderer-set-position", 0, 0);
DispatchRendererEvent("renderer-set-dimensions",
this.Panel.ClientRectangle.Width,
this.Panel.ClientRectangle.Height);
this.Renderer.InitialiseWindow();
...
}
The Renderer object is now initialised and able to render XHTML documents. This, in itself, is a two stage process. First, the document must be loaded in one of three ways:
Regardless of the method that you use, the document must be well formed, otherwise the load will fail; malformed documents may only be rendered using the supplementary IRenderHTML interface. After the document has been loaded successfully, it can be rendered by the Render() method. You may also pass a fragment identifier and a base URI to this method if necessary.
So, based on the above, if your application were to contain a browser-style address bar, the button click handler might look something like the following:
private void Button_Click(object sender, System.EventArgs e)
{
int nFragmentIndex = this.Input.Text.IndexOf('#');
Uri uri;
String sFragId;
if(nFragmentIndex != -1)
{
uri = new Uri(this.Input.Text.Substring(0, nFragmentIndex));
sFragId = this.Input.Text.Substring(nFragmentIndex + 1);
}
else
{
uri = new Uri(this.Input.Text);
sFragId = "";
}
String sURL = uri.AbsoluteUri;
String sBase = sURL.Substring(0, sURL.LastIndexOf('/') + 1);
this.Renderer.LoadURI(sURL);
this.Renderer.Render(sFragId, sBase);
}
You can continue to load and render as many documents after this as you wish. All that remains is to ensure that you call the Destroy() method before your application terminates:
protected override void Dispose(bool disposing)
{
if(disposing)
{
this.Renderer.Destroy();
...
}
base.Dispose(disposing);
}
A sample C# form (see screenshot, below), containing code based on the principles outlined in this tutorial, is available from here.
The following meta properties may be used in the head of your web application. For an example that uses most of these tags click on the link at the bottom.
top, bottom, left and right. The application will begin in the centre of the specified edge unless a qualifer is present, separated by a hyphen. Possible qualifiers are middle, top, bottom, left and right. This means that top and top-middle are equivalent. However, although top-right and right-top have the same position, they will have different autohide behaviour.
position and anchor) this value indicates that the application should automatically slide off screen when mouse focus is lost. Returning the mouse pointer to that edge of the display slides the application back into view.100 renders the application completely opaque. As values decrease from there, the application becomes more and more faint, allowing obscured windows to become more clearly visible.


For scripts that are passed as command line arguments, Sidewinder provides a number of classes and functions as part of its JavaScript API.
The following classes are exposed via the Sidewinder JavaScript API.
Application class
The Event class implements the Event interface.
The EventListener class is a proxy by which JavaScript functions may be nominated to handle events. Additionally, it implements the EventListener interface.
The following methods are available on the EventListener class. Additionally, it implements the EventListener interface.
Constructs an instance of the EventListener class.
Parameters: Optional JavaScript function to be called from the proxy's implementation of handleEvent.
Return Value: none
Example Usage
function handleEvent(evt)
{
...
}
...
var l = new EventListener(handleEvent);
Destroy the instance and free its resources.
Parameters: none
Return Value: none
Example Usage
function handleEvent(evt)
{
...
}
...
var l = new EventListener(handleEvent);
...
l.Destroy();
Nominates the JavaScript method to be used as an event handler by this instance. Overrides any handler nominated by preceding calls to this method or in the constructor.
Parameters: JavaScript function to be called from the proxy's implementation of handleEvent.
Return Value: none
Example Usage
function handleEvent(evt)
{
...
}
...
var l = new EventListener();
l.SetHandler(handleEvent);
ObjectParcel class
The Renderer class models a window that may contain either XHTML markup or plain text. Additionally, it implements the EventTarget interface.
Either in the constructor, or the subsequent call to Create, a number of initial settings may be specified for a Renderer instance. These settings are passed as a single parameter, using JSON syntax.
The value of this parameter dictates whether the object will automatically hide when it loses mouse focus. If this parameter is unspecified or invalid, the default setting of false is used.
Values: true | false
The value of this parameter dictates the context in which the Edge, Position and Direction parameters are to be applied. If this parameter is unspecified or invalid, the default setting of "screen" is used.
Values: "screen" | [handle]
Where [handle] represents the value returned by an object's GetHandle() method.
The value of this parameter dictates in which direction, relative to its Context, an AutoHide object will slide open. If this parameter is unspecified or invalid, the default setting of "in" is used.
Values: "in" | "out"
The value of this parameter dictates the edge of the Context area that the object will be positioned against. If this parameter is unspecified or invalid, the default setting of "none" is used.
Values: "left" | "right" | "top" | "bottom" | "none"
The value of this parameter dictates the height, in pixels, of the client area of the Renderer window. The client area includes only the rendered content; window chrome should not be accounted for here.
Values: any positive integer
The value of this parameter dictates the relative opacity of the object. A value of 100 renders the the object completely opaque, whereas a value of 0 renders the object completely transparent. If this parameter is invalid or unspecified, the default value of 100 is used.
Values: any integer in the range 0 .. 100
The value of this parameter dictates the position along an Edge of a Context, at which the object will be placed. If this parameter is unspecified or invalid, the default setting of "centred" is used.
Values: "left" | "right" | "top" | "bottom" | "centred"
The value of this parameter dictates the precise position, measured in pixels, along the x-axis of a Context, at which the object will be placed.
Values: any positive integer
The value of this parameter dictates the precise position, measured in pixels, along the y-axis of a Context, at which the object will be placed.
Values: any positive integer
The value of this parameter dictates a number of different window styles, each one set by a different bit. These bits may be specified by performing a logical or operation with the appropriate values, described in the list below. Values that are not present in the list are reserved and should not be used. In the event that other values are used, behaviour is undefined.
0x00000002: Hides the taskbar button for this window.
0x00000200: Displays a maximise button in the title bar of the window.
0x00000400: Displays a minimise button in the title bar of the window.
0x00000800: Adds a system menu for this window.
0x00001000: Displays a close button in the title bar of the window.
0x00002000: Creates the window in its maximised state.
0x00004000: Creates the window in its minimised state.
0x00008000: Forces the window to always be displayed on top of other windows.
0x00200000: Displays a window with no border.
0x02000000: Displays a border around the window.
0x20000000: Displays a title bar on the window.
The value of this parameter dictates the title that is assigned to the object. If this parameter is unspecified or invalid, the default setting of the application name is used.
Values: any string
The value of this parameter nominates, in hexadecimal rrggbb format, a colour to be rendered as transparent within the object. This has the effect of making all regions that match the nominated colour completely hidden, with other windows and applications visible "underneath". If this parameter is unspecified or invalid, no colours are nominated as transparent.
Values: any string containing a 24 bit hexadecimal value, where the 8 highest-order bits denote the level of red in the nominated colour, the 8 middle-order bits denote the level of green in the nominated colour and the 8 lowest-order bits denote the level of blue in the nominated colour
The value of this parameter dictates whether an XHTML or a text Renderer is created. If this parameter is unspecified or invalid, the default setting of "xhtml" is used.
Values: "xhtml" | "text"
The value of this parameter dictates the width, in pixels, of the client area of the Renderer window. The client area includes only the rendered content; window chrome should not be accounted for here.
Values: any positive integer
The following methods are available on the Renderer class. Additionally, it implements the EventTarget interface.
Constructs an instance of the Renderer class.
Parameters: Optional creation parameters, used to set physical properties of the window.
Return Value: none
Example Usage
var r = new Renderer(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Create();
r.Show();
Create the Renderer window.
Parameters: Optional creation parameters, used if none were specified during instantiation
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Show();
Destroy the Renderer window and free its resources.
Parameters: none
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Show();
...
r.Destroy();
Show the Renderer window.
Parameters: none
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Show();
Hide the Renderer window.
Parameters: none
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Show();
...
r.Hide();
Load and render an XHTML document.
Parameters: an RFC3986-conformant URI string
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Show();
r.Load("http://www.formsplayer.com/");
Load and render in-memory data.
Parameters: a string containing either an XHTML document or plain text (dependent on the object's Type)
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Show();
r.Write("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>Title</title></head><body>Body</body></html>");
On text renderers only, insert in-memory data before existing rendered data.
Parameters: a string containing plain text
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "text",
Width: 800,
Height: 600
}
);
r.Show();
r.Write("This is line two.\n");
r.Insert("This is line one.\n");
On text renderers only, append in-memory data after existing rendered data.
Parameters: a string containing plain text
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "text",
Width: 800,
Height: 600
}
);
r.Show();
r.Write("This is line one.\n");
r.Append("This is line two.\n");
Clear the rendered data.
Parameters: none
Return Value: none
Example Usage
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.Show();
r.Write("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>Title</title></head><body>Body</body></html>");
...
r.Clear();
Retrieves the handle associated with this instance, which may be used as the value for the Context parameter.
Parameters: none
Return Value: String containing the instance handle
Example Usage
var r1 = new Renderer;
r1.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
var r2 = new Renderer;
r2.Create(
{
Type: "xhtml",
Width: 200,
Context: r1.GetHandle(),
Edge: "left",
Direction: "out"
}
);
r1.Show();
r2.Show();
Retrieves the platform-dependent implementation of this instance, which may be used when handling new window requests.
Parameters: none
Return Value: ObjectParcel containing the platform-dependent Renderer implementation.
Example Usage
function onNewWindow(evt)
{
var r = new Renderer;
r.Create( { Type:"xhtml" } );
r.Show();
evt.parameter.objectValue = r.GetRenderingImplementation();
}
function handleEvent(evt)
{
switch(evt.type)
{
case "renderer-request-newwindow":
onNewWindow(event);
break;
...
}
}
...
var l = new EventListener;
l.SetHandler(handleEvent);
var r = new Renderer;
r.Create(
{
Type: "xhtml",
Width: 800,
Height: 600
}
);
r.addEventListener("renderer-request-newwindow", l, true);
r.Show();
...
StdErr class
StdOut class
Variant class
The following functions are exposed via the Sidewinder JavaScript API.
Closes all windows and terminates the application.
Parameters: none
Return Value: none
Example Usage
Exit();