XmHTML Programmers Guide
Author: Koen D'Hondt

Chapter 2
XmHTML Widgets

Have you ever wanted to write an application capable of displaying HTML documents, went out to find a Widget which offered HTML display capabilities and finally give up on your wonderfull idea when no such widget seemed to be available? Maybe you did find a HTML widget but were not satisfied with its capabilities? With the XmHTML Widget described in this chapter you no longer have to despair.

With the XmHTML Widget one can create applications that range from simple HTML viewers to full-blown WWW browsers. The XmHTML Widget offers a widget capable of displaying HTML documents and, as one would expect, allows full interactive use of HTML documents thru various callback resources and convenience functions. Besides of being able to display HTML documents, displaying of plain text and images is also supported.

XmHTML widgets provide the following mechanisms for program control:

- Resources that access the widget's content and can alter it's appearance.
- Callback resources that allow navigation through and between HTML documents when hyperlinks are activated.
- Callback resources that provide both visual and content information about the widget's text.
- Keyboard management methods that control output (paging style).
- Convenience routines allowing quick and easy ways to load images, scroll through the widget's text and access document information.

XmHTML widgets implement the full HTML 3.2 standard as well as a few extensions. The chapter on HTML Extensions lists the supported extensions. One supported extension that is worthwhile to mention is the <FRAMESET> extension.

The current implementation of the XmHTML widget does have its limitations though. The most important features lacking in the current release (1.0.22 Alpha) are support for HTML tables and progressive document loading. All these features will be added in due time.

As you will notice in this chapter, the behaviour and name of a number of XmHTML's resources and convenience functions closely resemble those of Motif's Text widget. The first reason for this similarity is that both widget's display text. The second reason is that, if you are already familiar with Motif's Text widget, the interface to a XmHTML widget will also look familiar and thus learning how to use a XmHTML widget will be a bit easier.

# 2.1 The Basics of a XmHTML Widget

To understand and appreciate most of the material described in this chapter, it is important to address some of the basic resources and functions provided by the XmHTML widget. The widget's text and HTML verification process, document fonts, dimensions of the widget and hyperlink resources are among the most important. We begin with how to create a standard XmHTML widget.

## 2.1.1 Creating a XmHTML Widget

Applications that wish to use XmHTML widgets need to include the file <XmHTML.h>. You can create a standard XmHTML widget using the `XtVaCreateManagedWidget()` function:

    	Widget html_w;

    	html_w = XtVaCreateManagedWidget("name", xmHTMLWidgetClass, parent,
    		resource-value pairs,
    		NULL);

The resource-value pairs can be any number of resources specific to the XmHTML widget or its superclasses. Please note that the XmHTML widget is subclassed from the Manager widget class.

Another way of creating a standard XmHTML widget is by using the `XmCreateHTML()` convenience function:

    	Widget html_w;

    	html_w = XmCreateHTML(parent, "name", args, nargs);

The args argument can be any number of resource-value pairs specified using the `XtSetArg` function. nargs specifies how many resource-value pairs are contained in the args argument.

## 2.1.2 The XmHTML Widget's Text

The first thing to learn about the XmHTML widget is how to access its internal text storage. The most simple method to do this is by using the `XmNvalue` resource. Unlike most widgets in the Motif toolkit that use text, the XmHTML widget does not use compound strings for its value. Instead, the value is specified as a regular C string as shown in example 2-1.

Example 2-1. The simple_html.c program

    /* simple_html.c -- Create a minimally configured XmHTML widget */
    #include <XmHTML.h>

    main(int argc, char **argv)
    {
    	Widget toplevel;
    	XtAppContext app;

    	toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
    		&argc, argv, NULL, NULL);

    	XtVaCreateManagedWidget("html", xmHTMLWidgetClass, toplevel,
    		XmNvalue, "<html><body>A minimally configured XmHTML widget."
    			"</body></html>",
    		NULL);

    	XtRealizeWidget(toplevel);
    	XtAppMainLoop(app);
    }

This short program simply creates a XmHTML widget whose initial value is set to "A minimally configured XmHTML widget." (See Figure 2-1).

Figure 2-1. simple_html.c: a minimally configured XmHTML widget

### HTML Verification

As one can see in the above example, the value of the `XmNvalue` resource contains five HTML elements: four markup and one text element. This brings us to one of the most important aspects of the XmHTML widget: it is a widget for displaying HTML documents. HTML documents are text documents written in the HyperText Markup Language, which is a language composed of a set of elements that define a document and guide its display.

In order for XmHTML to display such a document properly, it is necessary that the widget verifies the correctness of these markup elements. It does this by comparing the contents of the document that is to be displayed against the now official W3C HTML 3.2 recommendation (referred to as the HTML 3.2 standard). This standard defines both appearance and content of each markup element. During this verification process (which is performed before anything is displayed), the widget goes thru great lengths as to ensure that the document adheres to this standard. As such, the widget is capable of modifying the specified markup elements substantially (it will never modify text elements). The disadvantage of this document verification is that a document might not look as expected, but the main advantage is that even the most horrid HTML document will be displayed.

A detailed description of this document verification and repair process is given in the next chapter, so we will only mention that the more a document adheres to the HTML 3.2 standard, the less the widget will modify the markup elements.

### Setting a XmHTML Widget's Text

The initial value of the `XmNvalue` resource may be set either at initialization time (as in example 2-1) or by using `XtVaSetValues`:

    	XtVaSetValues(html_w, XmNvalue, text, NULL);

This resource always represents the entire text of the widget.

Another method for setting the text in a XmHTML widget is by using the convenience routine `XmHTMLTextSetString`:

    	void
    	XmHTMLTextSetString(html_w, value)
    		Widget  html_w;
    		char   *value;

Although the two methods produce the same results, the convenience routine may be more efficient since it accesses the internals of the widget directly (The `XtVaSetValues()` method involves going through the X Toolkit Intrinsics). On the other hand, if you are also setting many other resources at the same time, the `XtVaSetValues` method is better since it saves the overhead of multiple function calls (All resources can be set in a single call).

Whichever function you use, the value (however it is provided) is copied into the internals of the widget. This is important to known if you have provided the value via an allocated memory buffer: once the text is set in the widget, you can safely free this memory buffer.

A XmHTML widget's may contain large amounts of text provided there is enough memory available on the computer running the client application. The upper limit on the number of bytes a XmHTML widget may have is given by the maximum value of an unsigned int (4 gigabyte on 32 bit systems), so it is more likely that the user's computer will run out of memory before the XmHTML widget's maximum capacity is reached.

### Getting a XmHTML Widget's Text

XmHTML widget's provide several methods for obtaining text. Before learning how to get the widget's text however, it is important to make a distinction between the source text and the displayed text. The source text is the text you have set into a XmHTML widget by using the `XmNvalue` resource (or by using the `XmHTMLTextSetString()` convenience function), while the displayed text is the source text after HTML verification has taken place. This distinction is important since XmHTML widget's will never modify the source text but instead create a new HTML document while the HTML verification process is taking place.

[Note: A new HTML document is not actually created: when text is set in a XmHTML widget, the HTML parser translates the source text to a list of internal objects. The new HTML document that is mentioned in the above paragraph only exists in theory but can be created upon request as we will soon see.]

You might ask yourself why this distinction is important. The answer is that it depends on the type of application you are using a XmHTML widget for. Lets assume you are using a XmHTML widget in an application that displays HTML documents you have retrieved via a network layer (a WWW browser for example). When the user of your application wishes to save the document he has been viewing, it is most likely he wishes to save the original document and not the verified document. On the other hand, when you are using a XmHTML widget in an application intended for writing and/or verifying HTML documents, the most obvious thing a user would want to save is his verified document.

#### Getting the Source Text

So how does one go about getting a XmHTML widget's text? To get the widget's source text, you can use either `XtVaGetValues()` or the `XmHTMLTextGetSource()` convenience function. Both methods return the value of the `XmNvalue` resource. The value returned is a pointer to the internal text storage, which may never be freed nor modified. The code fragment below demonstrates how to use the convenience function:

    	String text_p;

    	if((text_p = XmHTMLTextGetSource(html_w)) != NULL)
    	{
    		/* Save, display the text, but never modify or free it */
    	}

Or, by using the Xt function `XtVaGetValues()`:

    	String text;

    	XtVaGetValues(html_w, XmNvalue, &text_p, NULL);

Similar to using the `XmHTMLTextSetString()` convenience function to set a XmHTML widget's text, using the `XmHTMLTextGetSource()` to get a XmHTML widget's text may be more efficient since it accesses the internals of the widget directly instead of going through the X Toolkit Intrinsics.

[Note: It is also worthwhile to mention that all of the `XmHTML...` convenience functions access the internals of the XmHTML widget directly. None of them involves going through the X Toolkit Intrinsics.]

If you want to modify the source text, or you just want a copy of the text that you can modify for other reasons, then you must copy the text into your own local dataspace:

    	char *text_p, buf[1024];

    	text_p = XmHTMLTextGetSource(html_w);

    	(void)strncpy(buf, text_p, 1024);
    	/* modify "buf" all you want */

Here, we don't know how much text `text_p` points to, but for purposes of this demonstration, we assume it's not more than 1024 bytes. Just to be sure that we don't cause an overflow of `buf`, we use `strncpy()`. Let me stress that, unless you are intimately familiar with the nature of the XmHTML widget your are using, it is unwise to make general assumptions about the amount of text you are getting.

#### Getting the Displayed Text

The method to get the displayed text is very similar to the Motif Text `XmTextGetString()` convenience function: `XmHTMLTextGetString()`. Both functions allocate enough space (using `XtMalloc()`) to contain all the text and return a pointer to this newly allocated area. While the pointer can be modified any way you like, you must free it using `XtFree()` when you are through using it. The code fragment below demonstrates how this function may be used:

    	String text_p;

    	if((text_p = XmHTMLTextGetString(html_w)) != NULL)
    	{
    		/*
    		* Allocated memory returned.
    		* do anything with "text_p" you want.
    		*/
    		XtFree(text_p);
    		/* we *must* free "text" or there will be a memory leak */
    	}

This convenience function returns a HTML document created from the XmHTML widget's internal representation of the original source document after HTML verification has taken place. Depending on the adherance to the HTML 3.2 standard of the original source document, the newly created HTML document may or may not differ from the original source document. If there is a difference, it will only be found in the markup elements; XmHTML widget's never modify text elements.

Getting the displayed text of a XmHTML widget is potentially an expensive operation if the widget contains large amounts of text. A XmHTML widget needs to create a HTML document from the internal representation every time `XmHTMLTextGetString()` is called.

## 2.1.3 XmHTML Widget's Dimensions

Let's return to Example 2-1 and examine more closely what is exposed to the user. As you can notice from the output of the program (shown in Figure 2-1), a vertical scrollbar is displayed and the text is not entirely visible: the user has to drag the vertical scrollbar to see all the text contained in the XmHTML widget. When no size has been specified, the width of a XmHTML widget defaults to 20 ex (a TEX measure for average character width) and the height of a single line in the default font.

You specify the size of a XmHTML widget by using the `XmNwidth` and `XmNheight` resources (which a XmHTML widget inherits from the `Core` widget), as shown in Example 2-2:

Example 2-2. The simple_html2.c program

    /* simple_html2.c -- Create another minimally configured XmHTML widget */
    #include <XmHTML.h>

    main(int argc, char **argv)
    {
    	Widget toplevel;
    	XtAppContext app;

    	toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
    		&argc, argv, NULL, NULL);

    	/* create a XmHTML widget but this time we specify a size */
    	XtVaCreateManagedWidget("html", xmHTMLWidgetClass, toplevel,
    		XmNvalue, "<html><body>Another minimally configured XmHTML "
    			"widget.</body></html>",
    		XmNwidth, 200,
    		XmNheight, 75,
    	NULL);

    	XtRealizeWidget(toplevel);
    	XtAppMainLoop(app);
    }

The output of this program is shown in Figure 2-2.

Figure 2-2. simple_html2.c: another minimally configured XmHTML widget

The specified width and height are only used at initialization. Once the application is up and running, the user can resize windows and effectively change those dimensions.

### 2.1.3.1 Autosizing a XmHTML Widget

As you can see in Figure 2-2, the widget's text is now entirely visible but a vertical scrollbar is still present. We could remove this vertical scrollbar by obtaining a handle to it and then unmanaging it, but another and more subtle way to remove the vertical scrollbar is to use the autosizing feature of a XmHTML widget as shown in Example 2-3.

Example 2-3. The autosize_html.c program

    /* autosize_html.c -- Demonstrate the autosizing feature of a XmHTML widget */
    #include <XmHTML.h>

    main(int argc, char **argv)
    {
    	Widget toplevel;
    	XtAppContext app;

    	toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
    		&argc, argv, NULL, NULL);

    	/* make sure we may resize ourselves */
    	XtVaSetValues(toplevel, XmNallowShellResize, True, NULL);

    	/* create a XmHTML widget but this time enable autosizing */
    	XtVaCreateManagedWidget("html", xmHTMLWidgetClass, toplevel,
    		XmNvalue, "<html><body>An AutoSizing XmHTML widget.</body></html>",
    		XmNresizeWidth, True,
    		XmNresizeHeight, True,
    	NULL);

    	XtRealizeWidget(toplevel);
    	XtAppMainLoop(app);
    }

The output of this program is shown in Figure 2-3.

Figure 2-3. autosize_html.c: an autosizing XmHTML widget

When looking at Example 2-3, we notice a few things that are of interest. First of all, there is the `XmNallowShellResize` resource. The value of this resource determines whether a `Shell` widget (or any of its subclasses, in this case a `topLevelShellWidget`) will honor geometry requests from its children. Since we want the XmHTML widget to compute its own size, we must set this resource to `True` (it is `False` by default).

The second and most interesting thing to notice are the `XmNresizeWidth` and `XmNresizeHeight` resources. These resources control the autosizing feature of XmHTML widgets. The first enables autosizing in horizontal direction and the latter in vertical direction. When the `XmNresizeWidth` resource is set to `True`, XmHTML widget's base their initial width on the width of the longest text element in the source document, with a maximum of 80 characters. XmHTML widget's with autosizing enabled will never cover the entire screen: the maximum dimensions a XmHTML widget take will never exceed 80% of the available screen dimensions.

In strong contrast with specifying the dimensions of XmHTML widget's using the `XmNwidth` and `XmNheight` resources, autosizing is persistent: When the user resizes a window, the dimensions of a XmHTML widget are not affected. Autosizing remains effective as long as the autosizing resources are set.

You should use the autosizing feature of XmHTML widget's sparingly. Dynamic resizing of widgets is generally considered as poor design. This is especially true of widgets in a Shell or Dialog with other elements in it.

An example of acceptable use of dynamic resizing would be when a XmHTML widget is used in a popup dialog used for displaying small amounts of text (such as explanation of terminology in a Hypertext Help system).

### 2.1.3.2 XmHTML Widget's Dimensions and Resources

As we will see in section 2.1.5, XmHTML Children, a XmHTML widget creates three subwidgets: a DrawingArea and two scrollbars.

When a XmHTML widget is created, the size of the DrawingArea is set explicitly by the widget itself, but it uses the Motif default values when it creates the scrollbars. It is important that you realize this when you set the dimensions of a XmHTML widget by means of application-wide fallback resources or when specifying them in a resource file: if you specify the dimensions of a XmHTML widget using resource wildcarding you can be sure to expect unwanted behaviour whenever text is set into the widget.

The correct way to specify the widget dimensions is as follows:

    static String fallbackResources[] = {
    	"*XmHTML.width:       575",
    	"*XmHTML.height:      600",
    };

This will only set the width of the DrawingArea subwidget to 575 pixels and the height to 600 pixels, leading to the expected behaviour.

If on the other hand you incorrectly specify the dimensions as follows:

    static String fallbackResources[] = {
    	"*XmHTML*width:       575",
    	"*XmHTML*height:      600",
    };

you are not only setting the dimensions of the DrawingArea subwidget but also the dimensions for every subwidget created by a XmHTML widget. Needless to say that this kind of behaviour is unwanted. The correct way to specify the dimensions of both a XmHTML widget and its ScrollBar subwidgets is as follows:

    static String fallbackResources[] = {
    	"*XmHTML.width:       575",
    	"*XmHTML.height:      600",
    	"*XmHTML*verticalScrollBar.width:       25",
    	"*XmHTML*horizontalScrollBar.height:    25",
    };

[Note: although it is possible to use resource wildcarding to set the dimensions of a XmHTML widget when the width and height of a ScrollBar are explicitly set, it is advisable that this is never done. The problem is not limited to the dimensions of the ScrollBars subwidgets but extends to any subwidgets a XmHTML widget creates when it encounters a HTML document with a <FORM></FORM> declaration in it.]

## 2.1.4 Document Scrolling

Adding document scrolling to XmHTML widget's is easy: you don't. If you look at the output of Example 2-1 (Figure 2-1), you will notice that a vertical scrollbar is present while we didn't instruct the XmHTML widget to add one. When the XmHTML widget was created it noticed that it wasn't high enough to display all of the text and thus it added a vertical scrollbar to allow the user to view all of the text by dragging the scrollbar. If you resize the window vertically, the vertical scrollbar will disappear when the widget is high enough to contain all text (including the horizontal and vertical margins).

The behaviour you have observed in Example 2-1 is the default behaviour for the XmHTML widget: when not all of the text can be fitted in the available dimensions, a horizontal and/or vertical scrollbar is added, and when all text can be fitted in the available dimensions, the horizontal and/or vertical scrollbar is removed.

As there might be cases where you want the presence of a vertical scrollbar while one is not required, you can force the presence of a vertical scrollbar by using the `XmNscrollBarDisplayPolicy` resource as shown in the following example:

Example 2-4. The forced_html.c program

    /* forced_html.c -- Force the display of the vertical scrollbar */
    #include <XmHTML.h>

    main(int argc, char **argv)
    {
    	Widget toplevel;
    	XtAppContext app;

    	toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
    		&argc, argv, NULL, NULL);

    	/* create a XmHTML widget but this time we specify a size */
    	XtVaCreateManagedWidget("html", xmHTMLWidgetClass, toplevel,
    		XmNvalue, "<html><body>A minimally configured "
    			"XmHTML widget.</body><html>",
    		XmNwidth, 200,
    		XmNheight, 75,
    		XmNscrollBarDisplayPolicy, XmSTATIC,
    		XmNscrollBarPlacement, XmTOP_LEFT,
    		XmNmarginWidth, 5,
    		XmNmarginHeight, 5,
            NULL);

    	XtRealizeWidget(toplevel);
    	XtAppMainLoop(app);
    }

The `XmNmarginWidth` and `XmNmarginHeight` resources determine the spacing between the outer borders of a XmHTML widget and the displayed text. For demonstration purposes they have been set to a smaller value than the default value of 20. If you compile and run this program you will see that a vertical scrollbar is present and stays present when the widget is resized, even when the widget is high enough to contain all text.

Example 2-4 also shows the `XmNscrollBarPlacement` resource. This resource controls the placement of both horizontal and vertical scrollbar. In this case the vertical scrollbar is placed on the left side of the window and the horizontal scrollbar is placed on top of the window (making the window smaller will show the horizontal scrollbar). Possible values for this resource are:

- `XmTOP_LEFT:` vertical ScrollBar on left; horizontal on top;
- `XmBOTTOM_LEFT:` vertical ScrollBar on left; horizontal on bottom;
- `XmTOP_RIGHT:` vertical ScrollBar on right; horizontal on top;
- `XmBOTTOM_RIGHT:` vertical ScrollBar on right; horizontal on bottom;

XmHTML widget's do not provide any way to force the display of a horizontal scrollbar, you can only control it's placement.

#### Keyboard Scrolling

XmHTML widget's implement a full keyboard navigation interface by installing a number of translations. On most keyboards, the arrows provide the same behaviour as dragging the scrollbars while the PageUp and PageDown keys scroll through a document a page at a time. Additional keys are also available, see the XmHTML Reference Manual for the complete set of translations that XmHTML widget's install.

## 2.1.5 XmHTML Children

A XmHTML widget is made up of a number of subwidgets: a DrawingArea widget in which the document is displayed, and two ScrollBars. You can get the handles to these children using the Xt `XtVaGetValues()` method, as demonstrated in the following code fragment:

    	Widget work_window, hsb, vsb;

    	XtVaGetValues(html_w,
    		XmNworkWindow, &work_window,
    		XmNhorizontalScrollBar, &hsb,
    		XmNverticalScrollBar, &vsb,
    		NULL);

Getting XmHTML widget children can be usefull when you want to install your own event handlers or set additional resources on these children.

Let us now demonstrate a case where it is usefull to get a handle to one of XmHTML's children: the workWindow. Amongst the many convenience routines offered by the XmHTML widget's is the `XmHTMLXYToInfo()` function. This function takes a XmHTML widget and a pointer position as it's arguments and returns a structure containing information about the contents of the currently displayed document at the requested pointer position. The structure returned is of type `XmHTMLInfoStructure`, which is defined as follows:

    typedef struct
    {
    	int line_no;		/* line number at selected position */
    	Boolean is_map;		/* true when clicked image is an imagemap */
    	int x,y;		/* position relative to image corner */
    	XmImageInfo *image;	/* image data */
    	XmHTMLAnchorPtr anchor;	/* possible anchor data */
    }XmHTMLInfoStructure, *XmHTMLInfoPtr;

The `XmImageInfo` and `XmHTMLAnchorPtr` members of this structure will be explained in the following sections, so we will now only say that the first structure contains information about an image over which the pointer is located, while the latter contains information about a hyperlink over which the anchor is currently located.

A perfect way to display this information to the user would be to display a popup menu when the user clicks on the currently displayed document. In order for this to work, we need to attach an event handler to the workWindow of a XmHTML widget. The following example demonstrates how to attach the event handler to the workWindow and how to use the `XmHTMLXYToInfo()` function:

Example 2-5. The work_window.c program

    /*
    * work_window.c: attaching an event handler to the work_window of a XmHTML
    * widget.
    */
    #include <XmHTML.h>

    void
    attachInfoHandler(Widget html, Widget popup)
    {
    	Widget work_window;

    	XtVaGetValues(html, XmNworkWindow, &work_window, NULL);

    	/*
    	* Add an event handler which responds to mouse clicks. "popup" is the
    	* popup menu which is to be displayed, it is stored as client_data
    	* for the event handler.
    	*/
    	XtAddEventHandler(work_window, ButtonPressMark, 0,
    		(XtEventHandler)infoHandler, popup);
    }

    void
    infoHandler(Widget work_window, Widget popup, XButtonPressedEvent *event)
    {
    	XmHTMLInfoPtr info;
    	Widget html_w;
    	WidgetList children;

    	/* we only take events generated by button 3 */
    	if(event->button != 3)
    		return;

    	/*
    	* The work_window is a child of a XmHTML widget, so we can get a handle
    	* to the XmHTML widget itself by using Xt's XtParent routine.
    	*/
    	html_w = XtParent(work_window);

    	/* get the info for the selected position.  */
    	info = XmHTMLXYToInfo(html_w, event->x, event->y);

    	/*
    	* Check the returned info structure. There will be nothing to display
    	* if the pointer wasn't over an image or anchor when the user
    	* clicked his mouse.
    	*/
    	if(info == NULL || (info->image == NULL && info->anchor == NULL))
    		return;

    	/*
    	* For this example we assume that the popup menu has two buttons:
    	* a hyperlink button and an image button. We retrieve these children
    	* of the popup menu using the XmNchildren resource of Motif's
    	* rowColumn widget.
    	*/
    	XtVaGetValues(popup, XmNchildren, &children, NULL);

    	/* check if the info structure has an anchor */
    	if(info->anchor)
    	{
    		XmString label;
    		label = XmStringCreateLocalized(info->anchor->href);
    		XtVaSetValues(children[0], XmNlabelString, label, NULL);
    		XmStringFree(label);
    		XtManageChild(children[0]);
    	}
    	else
    		XtUnmanageChild(children[0]);

    	/* check if the info structure has an image */
    	if(info->image)
    	{
    		XmString label;
    		label = XmStringCreateLocalized(info->image->url);
    		XtVaSetValues(children[1], XmNlabelString, label, NULL);
    		XmStringFree(label);
    		XtManageChild(children[1]);
    	}
    	else
    		XtUnmanageChild(children[1]);

    	/* the "popup" menu has now been configured, pop it up */
    	XmMenuPosition(popup, event);
    	XtManageChild(popup);
    }

Note that the above example does not use any global variables; we can obtain all handles to the widgets we need. The handle to the popup menu is stored as client_data for the event handler, while the handles to the menu buttons of the popup menu can be easily obtained using one of Motif's `RowColumn` widget resources. It is also important to notice that it is very easy to obtain the widget id of the XmHTML widget. The event handler was attached to the workWindow of a XmHTML widget, and therefore this workWindow is the same widget as the work_window argument to the infoHandler routine. This is the reason why the `XtParent(work_window)` call returns the handle of the XmHTML widget.

Also notice that we do not have to free any of the members of the returned `XmHTMLInfoStructure` structure. In fact, we are not permitted to do this since the `image` and `anchor` members of this structure contain pointers to data owned by a XmHTML widget. Unless it is explicitly mentioned, all structures returned by any of XmHTML widget's resources, callback resources or convenience routines should be considered as read only.

Example 2-5 is a simple demonstration which does not use any callbacks on the popup menu buttons. In a real implementation however, callback resources could be attached to each of the popup menu buttons which would allow the user to jump to the selected hyperlink or display information about the selected image.

[Note: if you want to specify resource values for the subwidgets mentioned in this chapter by means of application fallback resources or in a resource file, the following names should be used: workWindow for the DrawingArea child, verticalScrollBar for the vertical ScrollBar child and horizontalScrollBar for the horizontal ScrollBar child.]

# 2.2 Modifying the Document Appearance

A HTML document typically contains a number of hyperlinks. Hyperlinks (also referred to as anchors) are often used in HTML documents to allow the reader to navigate the currently displayed document or between different documents. In order for the reader to recognize these anchors they should appear different from the main content of a HTML document. XmHTML widget's provide a number of resources that control the appearance of these anchors.

Another set of resources allow you to control the fonts that are used to render the displayed text.

## 2.2.1 Changing the Anchor Appearance

XmHTML widget's identify three different types of anchors: a regular anchor, a visited anchor and an anchor which has the `target` attribute set. The latter is a special type of anchor and is one of the extensions to the HTML 3.2 standard that are implemented by XmHTML. Typical use of this attribute can be found in HTML documents that utilize the HTML `<FRAMESET>` extension, where this attribute indicates a destination to which the contents of the activated anchor should be sent. This destination can target (amongst others) another XmHTML widget or a new dialog. Other use of this attribute can be found in Hypertext help systems where it might be used to indicate that the contents of the activated anchor should be displayed in a popup window.

A visited anchor is an anchor that the reader of the document has selected in the past.

Each anchor has three states: passive, armed and activated. An anchor is considered armed when a user has located the mouse pointer over an anchor. It is active when the user presses the first or second mouse button on an armed anchor. It is considered passive otherwise.

XmHTML widget's provide four ways to let an anchor stand out:

- by changing the cursor when an anchor is armed;
- by actively changing the look of an anchor when it is armed;
- by rendering the anchor as a pushbutton;
- by underlining the anchor;

The first and second item in this list are always selectable, while the third and fourth item are mutually exclusive: you choose either to display the anchors as pushbuttons or to underline them. The latter offers the most control on anchor appearance, while some users may find pushbutton anchors aesthetically more pleasing (although it can be slightly more difficult to identify anchors). Both types allow you to control the color in which the anchor is displayed in both it's passive and activated state.

XmHTML widget's will display anchors as pushbuttons by default: the default value of the `XmNanchorButtons` resource is `True`. By setting this resource to False, anchors will be underlined instead of being displayed as a pushbutton.

### 2.2.1.1 Anchor Cursor Resources

To indicate that an anchor can be activated by the user, it is often convenient to not only render the anchor differently than the remainder of the document but also to change the cursor when the pointer is moved over an anchor.

XmHTML widget's will change the cursor to a hand with a pointing finger when the user moves the pointer over an anchor. The default cursor is a built-in cursor, but it can be changed to a different cursor by using the `XmNanchorCursor` resource. Although it will seldomly be needed, the `XmNanchorDisplayCursor` resource allows you to control whether or not XmHTML widget's should change the cursor when the pointer is moved over an anchor (it is `True` by default).

The following code fragment demonstrates how to create, set and destroy a cursor:

    #include <X11/cursorfont.h>	/* standard X cursors */
    #include <XmHTML.h>

    void
    setCursor(Widget html_w, Boolean destroy_cursor)
    {
    	static Cursor cursor;

    	/* create a standard X cursor when it is not yet created */
    	if(cursor == None)
    		cursor = XCreateFontCursor(XtDisplay(html_w), XC_hand2);

    	if(destroy_cursor)
    	{
    		/* only free the cursor when we have created one */
    		if(cursor != None)
    			XFreeCursor(XtDisplay(html_w), cursor);
    		cursor = None;
    	}
    	else	/* set this cursor as the anchor cursor for this XmHTML widget */
    		XtVaSetValues(html_w,
    			XmNanchorCursor, cursor,
    			XmNanchorDisplayCursor, True,
    			NULL);
    }

The `cursor` is created using `XCreateFontCursor()`, but this is not required; you may use other functions like `XCreateGlyphCursor()` or `XCreatePixmapCursor()`, if you like. See O'Reilly's X Window System Programming guides Volume One, Xlib Programmer's Manual, for more information.

It is also considered nice programming to use X resources sparingly (although in the case of cursor's it is not really required, they are a virtually unlimited resource under X). This is why the above fragment declares the allocated cursor as a static variable: once allocated the cursor id is always available and we can use it for every XmHTML widget that is provided as an argument to the above routine. When this routine is called with the `destroy_cursor` argument set to True the cursor is destroyed and reset.

### 2.2.1.2 Anchor Display Resources

Whether or not you select to display anchors as pushbuttons or to underline them, you can always specify the foreground color in which an anchor is rendered. You can specify a different foreground color for the passive state of each of the anchor types mentioned in the introduction to this section:

- `XmNanchorForeground`:
  specifies the foreground color that is to be used to render a regular anchor;
- `XmNanchorVisitedForeground`:
  specifies the foreground color that is to be used to render a visited anchor;
- `XmNanchorTargetForeground`:
  specifies the foreground color that is to be used to render an anchor that has the target attribute set;

The `XmNanchorActivatedForeground` resource identifies the foreground color to be used when an anchor is activated. This resource is the same for all three anchor types.

When you opt to underline the anchors, you can also use the `XmNanchorActivatedBackground` resource to specify the background color to use when an anchor is activated.

[Note: When a HTML document contains a background image and displaying of background images is enabled (which is true by default), the XmNanchorActivatedBackground resource is also ignored when anchors are to be underlined, making the anchors appear as being transparent.]

You need to specify a Pixel for all three resources. You can specify a Pixel value by pre-allocating a pixel (by using any of Xlib's `XAllocColor()` routines) or by using Xt's `XtVaTypedArg` method. Both methods have their pro's and con's, but in either case you must free the allocated color values when your application exits.

When you have set the `XmNanchorButtons` resource to `False`, you can also specify the type of underlining for each of the three anchor types. XmHTML widget's support the following types of underlining:

- `XmNO_LINE:`
  no lines are drawn;
- `XmSINGLE_LINE:`
  a single solid line. This is the default for regular and visited anchors;
- `XmDOUBLE_LINE:`
  a double solid line. This is the default for anchors that have the `target` attribute set;
- `XmSINGLE_DASHED_LINE:`
  a single dashed line;
- `XmDOUBLE_DASHED_LINE:`
  a double dashed line;

The resource names are as follows:

- `XmNanchorUnderlineType`:
  specifies the type of underlining to use for regular anchors;
- `XmNanchorVisitedUnderlineType`:
  specifies the type of underlining to use for visited anchors;
- `XmNanchorTargetUnderlineType`:
  specifies the type of underlining to use for anchors that have the `target` attribute set;

Finally, there is the `XmNhighlightOnEnter` resource. When set to `True` (which is the default), a XmHTML widget will actively modify the look of an anchor whenever it becomes armed by highlighting the anchor. The actual color and type of highlighting used heavily depends on the content of the document that is currently displayed. When a background image is present, a XmHTML widget will base the highlight color on the value of the `XmNanchorActivatedForeground` resource and render the anchor's text in the computed color. When no background image is present, the highlight color will be based on the current document background and the anchor's text will be rendered in a rectangle filled with the computed color. If you decide to enable this resource, it is adviced that you offer a possibility to the user to toggle the value of this resource: a XmHTML widget attempts to do it's best when computing the highlight color, but might fail to find a suitable color. This can happen, for instance, on documents where the colors used by the background (fixed color or background image), text and anchors are poorly balanced.

## 2.2.2 Marking a Visited Anchor

You now know that XmHTML widget's contain the concept of visited anchors, which are anchors that the reader of the document has selected in the past (e.g, have already been visited). But when the user of your application is switching between documents the following question arises: how do you inform a XmHTML widget that an anchor was previously visited by the user?

The answer is fairly simple: you use the `XmNanchorVisitedProc` resource. When a procedure has been installed for this resource, a XmHTML widget will call this procedure to test if an anchor has already been visited. There are two arguments to this procedure: the widget id of a XmHTML widget and the name of the anchor. It should return `True` when the anchor should be rendered using the `XmNanchorVisitedForeground` resource and `False` when it should be rendered as a regular anchor.

Please note that a XmHTML widget only calls any installed procedure when a document is set into a XmHTML widget, and that it will be called for every anchor that is found in this document.

The following example shows how easy it can be to use this resource:

    #include <XmHTML.h>

    static int num_visited_anchors;
    String visited_anchors[100];

    static Boolean
    visitedTestProc(Widget html_w, String anchor)
    {
    	int i;

    	for(i = 0; i < num_visited_anchors; i++)
    		if(!strcasecmp(visited_anchors[i], anchor))
    			return(True);
    	return(False);
    }

    int
    main(int argc, char **argv)
    {
    	Widget toplevel;
    	XtAppContext app;

    	toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
    		&argc, argv, NULL, NULL);

    	XtVaCreateManagedWidget("html", xmHTMLWidgetClass, toplevel,
    		XmNanchorVisitedProc, visitedTestProc,
    		NULL);

    	XtRealizeWidget(toplevel);
    	XtAppMainLoop(app);
    }

In this example we assume that text can be set in the XmHTML widget, `visited_anchors` contains a list of already visited anchors and that `num_visited_anchors` contains the number of items in the visited anchor list. In section 2.5 we will demonstrate how to maintain this list.

## 2.2.3 Specifying the Document Fonts

One of the most important (if not the most important) aspect that will determine the way a document will look to the user concerns the fonts used to render the text in a document. Selecting an appropriate default font (and its size) is a very important decision when using a XmHTML widget, and it is more difficult than it might seem, especially if you want to internationalize your application.

Font specification for a XmHTML widget does not follow the standard Motif font specification rules (the `XmFontList` type). Due to the nature of the HTML language this would be rather impossible; it does not only contain font markup elements that allow the writer of a HTML document to change the style of a font, but also to change the typeface and size of a font. To make things even more complicated, all of these font markup elements can be used in arbitrary sequence.

In order to cope efficiently with this virtually unlimited number of font combinations in HTML documents, XmHTML widget's allocate their fonts directly and employ a smart font caching scheme that will keep the number of required font allocations to an absolute minimum. The font cache is shared by all XmHTML widget's on a per display basis (which effectively means that you can use a XmHTML widget for a multi-display application).

Another reason why XmHTML widget's do not use the Motif font specification rules is that the XmHTML font allocation routines go thru great lengths to ensure that a requested font is matched. When a requested font can not be exactly matched, the font allocation routines attempt to find a close match by following a number of different paths instead of giving up immediatly and using a default font. XmHTML widget's produce much better looking text than some of the most well known HTML browsers as a result of this.

Because XmHTML widget's allocate their fonts themselves instead of relying on Motif, a number of resources are offered that allow you, the programmer, to select a character set, foundry, typeface, spacing and size of the fonts that are to be used for displaying a document.

[Note: In order to fully appreciate the font resources of XmHTML widget's you are encouraged to read Appendix A of O'Reilly's X Window System Programming guides, Volume One, Xlib Programmer's Manual.]

Before explaining the various font resources I will mention that a XmHTML widget uses the contents of the font resources to compose a X Logical Font Description (XLFD) which is used to query your X server. Knowing this, it is obvious that you are allowed to use wildcards for all font resources (except size of course). This can be potentially dangerous: depending on the configuration of your font path and directories, the font returned by the X server may or may not be what is intended.

As a final note in this fairly long introduction, the default values for each of the various font resources have been choosen in such a way that every combination represents a font that is present in the default font path of the standard R5 X distribution.

### 2.2.3.1 Specifying the Character Set

The character set resource, `XmNcharset`, is a string representing the ISO character set encoding to be used. The default character set used by XmHTML widget's, `ISO8859-1`, represents the ISO Latin-1 character set (which is used by all of the fonts in the 75dpi and 100dpi directories of X's default font path). This character set is a superset of the standard ASCII character set, which includes various special characters used in European languages other than English.

The `XmNcharset` resource makes it relatively easy to select a font for non-European (non-English) languages. For example, `"XmNcharset: koi8-*"` specifies the koi8 Cyrillic font, while `"XmNcharset: UJIS-*"` identifies a Japanese font.

It is also important to notice that this resource is very important, if not the most important font resource. If a charset is specified which is unknown to the X server (or the charset is given as a wildcard), a XmHTML widget has almost no control about the fonts to use: the actual charset that is used will then only depend on the fontpath configuration of the X server and the specified font family. Therefore it is considered wise to first verify if the requested character set is available on the system your application is running on before changing it. See also section 2.2.3.2, Specifying the Font Family.

The font allocation scheme used by XmHTML will first try to load a font for a given character set and font family. When that fails it will wildcard the charset. This causes a XmHTML Widget to honor the following sequence of HTML tags with the default charset:

`<FONT FACE="symbol">alpha</FONT>`

which is rendered as:

`` alpha

[Note: this will render the word alpha in the symbol font if it is installed on your X server, and in english if you are viewing this document with almost any other browser or haven't got the symbol font installed.]

### 2.2.3.2 Specifying the Font Family

XmHTML widget's use two different types of font: a proportional font and a fixed-width font. Proportional fonts are fonts in which each character in a character set has a different width (an example of a proportional font is Times Roman), while fonts in which each character has the same width are called fixed-width fonts. Proportional fonts are more easy for the human eye to read than fixed-width fonts and therefore the main portion of the text in a HTML document is rendered in a proportional font. Fixed-width fonts are used to display preformatted text in a HTML document.

You specify the proportional font family by using the `XmNfontFamily` resource, and the fixed-width font family by using the `XmNfontFamilyFixed` resource. The value for both these resources is a sequence of four dash-seperated strings that define a font family. These four fields are:

1. foundry: the type foundry that digitized and supplied the font, i.e. Adobe;
2. family: the font family name (also known as typeface), i.e. roman;
3. set width: a value describing a font's proportionate width according to the selected foundry, i.e. normal;
4. spacing: type of character spacing for a font. m (for monospace, i.e. fixed width) or p (proportional, i.e., variable-width) are two well known font spacings.

The default value for the `XmNfontFamily` resource is `adobe-times-normal-*`, and the default value for the `XmNfontFamilyFixed` resource is `adobe-courier-normal-*`. Both font families represent a standard, scalable font, present on each X server.

You should always try to specify a scalable font whenever possible: HTML documents intend to use a lot of differently sized fonts (the header markup elements for example all require a different font size), and the displayed text will generally look much better if a scalable font is used instead of a bitmapped font.

A note of caution: before changing any of the `fontFamily` resources, the existence of this font (within the context of the current or new value of the `XmNcharset` resource) should be verified before actually changing it. An unsuccesfull attempt to change the default font settings can cause a XmHTML widget to exit your application: if it can not find a default font it simply can not display anything.

### 2.2.3.3 Specifying the Font Sizes

The last step in specifying the document fonts is to specify the font sizes for both the proportional and fixed-width font families. Font sizes are always specified in points and not in pixels: specifying a font size in pixels would require you to know in advance the x- and y-resolution of the screen your application is running on. The XmHTML widget determines the screen resolution and selects an appropriate pixel size automatically.

You can specify the text font size, the sup- and superscript font size and the font size for each of the header markup elements for the proportional font family. For the fixed-width font family you can specify the text font size and sup- and superscript size.

The sizes for the proportional font family are given by the `XmNfontSizeList` resource. The value for this resource is a comma seperated list of eight strings. The list below describes the fields in this resource.

1. normal text size;
2. sub and superscript font size;
3. font size for the <H1> markup element;
4. font size for the <H2> markup element;
5. font size for the <H3> markup element;
6. font size for the <H4> markup element;
7. font size for the <H5> markup element;
8. font size for the <H6> markup element;

The default value for this resource is `"14,8,24,18,14,12,10,8"`.

You do not have to specify all values; when an element in this list has the value 0 (zero), the appropriate default font size is used.

The sizes for the fixed-width font family are given by the `XmNfontSizeFixedList` resource. The value for this resource is a comma seperated list of two strings, where the first value describes the normal text size and the second value the size for sup- and superscript text. The default value for this resource is `"12,8"`.

# 2.3 XmHTML and Images

One of the strong and much admired features of the XmHTML Widget is it's built in image support. A XmHTML widget can support a wide range of different image types (from simple X11 bitmaps through complex GIF animations to full 32bit RGB PNG images with an alpha channel). For simple applications one does not need to know anything about this image support as a XmHTML widget can handle almost everything by itself. In fact, you only need to read this section if you want to exploit XmHTML's image support to it's fullest.

## 2.3.1 The XmImageInfo Structure

The basis of XmHTML's image API is formed by the XmImageInfo structure. XmHTML uses this structure to compose the actual image.

    typedef struct _XmImageInfo
    {
        /* regular image fields */
        String url;                    /* original location of image */
        unsigned char *data;           /* raw image data. ZPixmap format */
        unsigned char *clip;           /* raw clipmask data. XYBitmap format */
        Dimension width;               /* used image width, in pixels */
        Dimension height;              /* used image height, in pixels */
        int *reds;                     /* red image pixels */
        int *greens;                   /* green image pixels */
        int *blues;                    /* blue image pixels */
        unsigned int ncolors;          /* Number of colors in the image */
        int bg;                        /* transparent pixel index */
        unsigned char *rgba;           /* image data in rgba format */
        float fg_gamma;                /* image gamma */
        unsigned int options;          /* image option bits */

        /* Additional animation data */
        int x;                         /* logical screen x-position for a frame */
        int y;                         /* logical screen y-position for a frame */
        int loop_count;                /* animation loop count */
        unsigned char dispose;         /* image disposal method */
        int timeout;                   /* frame refreshment in milliseconds */
        int nframes;                   /* no of animation frames remaining */
        struct _XmImageInfo *frame;    /* ptr to next animation frame */

        /* image classification fields and original data */
        unsigned char type;            /* image type, see below */
        int depth;                     /* bits per pixel for this image */
        unsigned char colorspace;      /* colorspace for this image */
        unsigned char transparency;    /* transparency type for this image */
        Dimension swidth;              /* image width as read from image */
        Dimension sheight;             /* image height as read from image */
        unsigned int scolors;          /* Original number of colors in the image */

        XtPointer user_data;           /* any data to be stored with this image */
    }XmImageInfo, *XmImageInfoStruct;

The first part of this structure contains the raw image data XmHTML requires to create an image. The second part is used for creating animations while the third part provides additional information about the image represented by this structure.

As will be shown in the following sections of this chapter, all of the convenience functions of a XmHTML widget that deal with images work with this structure, either as an argument or as a return value.

### 2.3.1.1 The XmImageInfo Structure Explained

Although this section is mostly intended for those that want to add support for an image type that is unknown to XmHTML, it also contains important information for those that want to enable what is known as delayed image loading or want to exploit XmHTML's built-in image support to its fullest extent. It explains every field in the XmImageInfo structure, what each field should contain and the default values assumed when an image is loaded using the XmHTMLImageDefaultProc.

`url`
  This field represents the original location from where the image in question should be or has been obtained. It is actually the contents of the `SRC` attribute of the `<IMG>` tag. It is important that this field always contains a value, especially if you want to switch on delayed image loading.

`data`
  This field represents the actual image data in ZPixmap format. It is a continuous stream of bytes in which each byte represents an index in the colormap for this image (as defined by the reds, greens and blues fields).

`clip`
  This field represents a bitmap (a pixmap with depth 1) which a XmHTML widget will use to create a clipmask. It is a continuous stream of bits, where each bit defines if the underlying pixel should be rendered (bit set to 1) or should be left as it is (bit set to 0). It is only valid for transparent images, although it is very well possible to use this field for defining non-rectangular pixmaps. The dimensions of this bitmap should equal the actual image dimensions.

`width` and `height`
  These fields contain the absolute dimensions of the final pixmap as given by the `data` field. They are specified in pixel units, and their product must match the size of the `data` field.

`reds, greens, blues` and `ncolors`
  Each of these fields is an array of color component values which together form the RGB colormap of the image. Each array must have the same size, and this size is given by the value of `ncolors`. This number must be equal the the number of colors used by the image. A XmHTML widget uses these arrays to allocate the actual image colors and then maps the image data onto these colors.

`bg`
  The index of the transparent pixel, or `-1` when the image is fully opaque.

`rgba`
  This field is only used for images containing an alpha channel. An alpha channel is a series of pixel values in an image used to compute partial pixel transparency. With partial pixel transparency fade in/out or anti-aliasing effects can be achieved regardless of the current background setting. The XmHTMLImageDefaultProc supports alpha channelled PNG images. The format of the data stored in this field is a continuous stream of bytes where each pixel is represented by its red, green, blue and alpha channel component.

`fg_gamma`
  This field contains the gamma value of the display on which the image was created. It is only used in combination with alpha channelled images.

`options`
  This field contains a combination of OR'd constants which tell a XmHTML Widget what it can and can't do with an `XmImageInfo` structure. A number of these constants define how and when a XmHTML should free a structure (or members of it), while others determine what type of operations are allowed and how the actual image should be processed.

  "Set by default" indicates a bit set when the XmHTMLImageDefaultProc was used to read an image.

  `XmIMAGE_DELAYED`
    When set, XmHTML will ignore all fields except `url` and use a default image instead. This default image can be updated at a later stage using either the XmHTMLImageReplace or XmHTMLImageUpdate convenience function; See the section on Delayed Image Loading for more information.

  `XmIMAGE_DEFERRED_FREE`
    When set, XmHTML will take care of destroying this structure when a new document is loaded. Set by default;

  `XmIMAGE_IMMEDIATE_FREE`
    When set, this structure will be destroyed as soon as XmHTML no longer needs it;

  `XmIMAGE_RGB_SINGLE`
    set this bit when the `reds, greens` and `blues` fields have been allocated with one single malloc instead of three separate. Set by default;

  `XmIMAGE_ALLOW_SCALE`
    set this bit when scaling an image is allowed. Set by default;

  `XmIMAGE_FRAME_IGNORE`
    use with animations: set this bit when a frame falls outside the logical screen area. No pixmap is created but the timeout for the frame is kept.

  `XmIMAGE_CLIPMASK`
    This bit is set when the returned `XmImageInfo` structure contains clipmask data. XmHTML uses this info to create a clipping bitmap. Changing this bit from set to unset will lead to a memory leak while changing it from unset to set without providing a clipmask yourself will cause an error to happen. You can however set this bit when you are providing your own clipmask (to provide non-rectangular images for example), provided you fill the "clip" field with valid bitmap data.

  `XmIMAGE_SHARED_DATA`
    This bit is set when images share data. XmHTML sets this bit when the image in question is an internal image, e.i., one for which the image data may never be freed. Be carefull setting this bit yourself, since it prevents XmHTML from freeing the image data present in the XmImageInfo structure. It can easily lead to memory leaks when an image is not an internal image.

  `XmIMAGE_PROGRESSIVE`
    Setting this bit will enable progressive image loading. A function must have been installed on the `XmNprogressiveReadProc` resource prior to setting this bit. Installing a function on the `XmNprogressiveEndProc` is optional but strongly advised. When this bit is set all other bits and all members except the `url` field of the `XmImageInfo` structure will be ignored.

  `XmIMAGE_DELAYED_CREATION`
    This bit is read-only. It is used internally by XmHTML for images with an alpha channel. Alpha channel processing merges the current background with the original RGBA data (see above) from the image and uses the result to compose the actual on-screen image (the merged data is stored in the "data" field of the `XmImageInfo` structure). XmHTML needs to store the original data somewhere, and when this bit is set it is stored in the "rgba" field of the `XmImageInfo` structure. When this bit is set, the returned structure may not be freed as long as the current document is alive. You can discard it as soon as a new document is loaded.

`type`
  This field contains a value which describes the type of image that is represented by this structure. This field is unused internally and is provided for your convenience only. You should consider this value read-only though as it might well be used in the future. Table 2-1 lists all possible values for this field.

  Table 2-1. Supported Image Types
  Type | Image description
  --- | ---
  IMAGE_ERROR | error on image loading
  IMAGE_UNKNOWN | unknown image
  IMAGE_XPM | X11 pixmap
  IMAGE_XBM | X11 bitmap
  IMAGE_GIF | CompuServe(C) Gif87a or Gif89a
  IMAGE_GIFANIM | animated gif
  IMAGE_GIFANIMLOOP | animated gif with NETSCAPE2.0 loop extension
  IMAGE_GZF | compatible Gif87a or Gif89a
  IMAGE_GZFANIM | compatible animated gif
  IMAGE_GZFANIMLOOP | compatible animated gif with NETSCAPE2.0 loop extension
  IMAGE_JPEG | JPEG image
  IMAGE_PNG | PNG image

## 2.3.2 The XmHTMLDefaultImageProc

## 2.3.3 Animations

## 2.3.4 XmHTML's Imagemap Support

# 2.4 XmHTML Widget Callback Functions

## 2.4.1 Anchor Activation Callback

## 2.4.2 Anchor Tracking Callback

## 2.4.3 Frame Notification Callback

## 2.4.4 Form Activation Callback

## 2.4.5 Imagemap Activation Callback

## 2.4.6 Document Verification Callback

## 2.4.7 Document Link Callback

## 2.4.8 Document Motion Callback

## 2.4.9 Document Arm Callback

## 2.4.10 Document Input Callback

# 2.5 Collective Example

# 2.6 Advanced XmHTML Programming Techniques

## 2.6.1 Adding Support for HTML Frames

## 2.6.2 Delayed Image Loading

When a document is loaded into a XmHTML widget, it might not always be possible to provide an image when the XmHTML widget encounters one in the document: a net connection might be slow or the image requested can be that large that loading it can take quite a long time. It can be quite annoying if XmHTML should block until the image is available. Therefore, XmHTML offers Delayed Image Loading. Delayed Image Loading fools XmHTML into thinking that it has the image it wants, so it will happily continue without a noticable slowdown, and display the document once it has been parsed and formatted.

Now, how does it work? Basically it is quite simple: when a XmHTML widget finds a <IMG> tag, it will call the function that has been installed for the XmNimageProc resource function (say, imageProc).

The XmNimageProc function should then initialise a blank XmImageInfo structure, fill in the url field and set the XmIMAGE_DELAYED bit (this last step is imperative). It should then call a function which requests an image from a remote server and return the new XmImageInfo to XmHTML. The image is retrieved asynchronously.

At some point in the future, the image has been retrieved by the network layer, and the application calls a routine (say replaceImage) which will replace the blank image in the XmImageInfo structure with the newly loaded one.

XmHTML widget's provide two functions for replacing or updating a delayed image: XmHTMLImageReplace and XmHTMLImageUpdate. The difference between these two functions is that the former will actually replace the given XmImageInfo structure with a new one while the latter will only update the given image.

The above will probably make more sense in an example, so here is one.

Example 2-?: Delayed Image Loading

    #include <XmHTML.h>

    XmImageInfo *imageProc(Widget w, String url)
    {
    	String filename;
    	static XmImageInfo *image;

    	image = NULL;

    	/* test delayed image loading */
    	if((filename = resolveFile(url)) != NULL)
    	{
    		image = XmHTMLImageDefaultProc(html, filename, NULL, 0);
    		image_cache[current_image].image = image;
    		image_cache[current_image++].name = strdup(filename);
    	}
    	else
    	{
    		image = (XmImageInfo*)malloc(sizeof(XmImageInfo));
    		memset(image, 0, sizeof(XmImageInfo));
    		image->options = XmIMAGE_DELAYED; /* Tell XmHTML this image is delayed */
    		image->url = strdup(url);
    		/* associate the new XmImageInfo with this url */
    		image_cache[current_image].image = image;
    		image_cache[current_image++].name = strdup(url);
    		fetchFileFromServer(url);
    	}
    	return(image);
    }

In the above example, it is first tested if the requested image is already available. When it is, XmHTMLImageDefaultProc is called to load the image, and it's return value is stored in an image cache.

When the requested image is not available on the other hand, a blank XmImageInfo structure is initialized and stored, the delayed bit is set and a function is called which will fetch the image asynchronously from a server. The blank XmImageInfo structure is then returned and XmHTML will continue where it left off. When the image has been received, the application calls the replaceImage function.

Example 2-?: Updating delayed images

    #include <XmHTML.h>

    void replaceImage(String url, unsigned char *buf, int len)
    {
    	int i;
    	XmImageInfo *image;

    	for(i = 0; i < image_cache_size; i++)
    	{
    		if(!(strcmp(image_cache[i].name, url)))
    		{
    			image = XmHTMLImageDefaultProc(html, url, buf, len);
    			XmHTMLImageReplace(html, image_cache[i].image, image);
    			image_cache[i].image = image;
    		}
    	}
    }

As already explained in this section, the replaceImage function is called when an image has been retrieved from a server. Contents of the image from location url have been placed in the buffer buf with size len.

Remember that we have already associated a XmImageInfo structure with a url in the imageProc function, so the first thing we do is get the correct XmImageInfo. When we have found the correct entry, we simply call XmHTMLImageDefaultProc to actually load the image, replace the image represented by our old XmImageInfo structure and update the image cache.

In a real world implementation the previous XmImageInfo structure would also be freed. It would also call the XmHTMLRedisplay function after all images have been loaded to force XmHTML to do a recalculation of it's screen layout.

## 2.6.3 Adding Support for Other Imagetypes

## 2.6.4 Using XmHTML's Image Support for Other Purposes

One of the many nice features in a XmHTML widget is the built-in image support. What is even nicer is that this image support is also available for purposes other than use with a XmHTML widget: the XmHTML widget set contains a number of routines that allow you to read an image of any of the supported image types. You can then use the returned XmImage to your own likings. This section explains the XmImage image datatype and describes how to create, destroy and use such images.

### 2.6.4.1 The XmImage Structure

The basis of the external image support of the XmHTML widget set is formed by the XmImage structure. This structure is defined as follows:

    typedef struct{
    	/* regular image data */
    	String file;		/* originating file */
    	unsigned char type;	/* image type */
    	Pixmap pixmap;		/* actual image	*/
    	Pixmap clip;		/* for transparant pixmaps */
    	int width;		/* image width */
    	int height;		/* image height */

    	/* animation data */
    	XmImageFrame *frames;	/* array of animation frames */
    	int nframes;		/* no of frames following */
    	int current_frame;	/* current frame count */
    	int current_loop;	/* current loop count */
    	int loop_count;		/* maximum loop count */
    	XtIntervalId proc_id;	/* timer id for animations */
    	Widget w;		/* image owner */
    	XtAppContext context;	/* Application context for animations */

    	/* Private data */
    	unsigned long *pixels;
    	int npixels;
      	struct _XColorContext *xcc;
    }XmImage;

The pixmap field contains the actual image. It is this pixmap that you should use in a call to XCopyArea to put it directly in a window or in combination with Motif's XmNlabelPixmap resource to put the pixmap in a label widget.

If the value of the clip field is other than None, it means the original image is a transparent image. You can then use this field as a clipmask of a GC so your image will also be transparent.

[Note: the clipmask is a pixmap of depth 1, so it is actually a X11 bitmap.]

One important reminder before explaining how to create and use a XmImage: you should never touch any of the fields in the XmImage structure which are mentioned as private data. This private data is used when the XmImage is destroyed, so modifying any of these fields is a potential danger and leads at least to a memory leak. If you really want to know what these fields represent, here's a very short explanation of what they represent:

- pixels: an array of allocated pixels values;
- npixels: the number of elements in pixels;
- xcc: a structure containing a lot of information about the current visual, colormap, maximum number of colors, color shifts and masks, etc... This structure is used when allocating colors. If you really want to know more about this structure, you should examine the following source files of the XmHTML Widget Set source code: `XCC.c, XCC.h` and `XCCP.h`

### 2.6.4.2 Creating a XmImage

You can create an XmImage by using the XmImageCreate convenience function. This function is defined as follows:

    XmImage *XmImageCreate(Widget w, String file, Dimension width,
    	Dimension height);

w must contain the id of a Widget (and not a Gadget) which will be the owner of this image, file is the name of a file representing the image that is to be loaded. The width and height arguments allow you to scale the image. If both have the value 0 (zero), the dimensions of the loaded image will be the dimensions as found in the image. Otherwise, XmImageCreate will scale to image to fit the given dimensions. Scaling is only done in the directions for which a value is given: if you only want to scale the image horizontally, you should only specify a value for width and set height to zero (or a value for height and 0 for width to only scale the image vertically).

Although the external image support is independent of a XmHTML widget, you can also use the XmImageInfo structure to create a XmImage. An example where this can be usefull is in conjuction with the XmHTMLXYToInfo() convenience function. As you may know by now, the return value of this function can contain a pointer to a XmImageInfo structure. Supposing this is the case and you would want to display a dialog box to the user with a thumbnail of the image, it is much more convenient to create a XmImage directly from the XmImageInfo structure instead of creating it from a file.

The syntax of the XmImageCreateFromInfo() convenience function is as follows:

    XmImage *XmImageCreateFromInfo(Widget w, XmImageInfo *info, Dimension width,
    	Dimension height);

The only difference with the XmImageCreate() function is that instead of a filename you now supply a XmImageInfo structure.

### 2.6.4.3 Destroying a XmImage

When you are done using a XmImage, you should destroy it using the XmImageDestroy convenience function. The syntax to this function is as follows:

    void XmImageDestroy(XmImage *image);

This function will take care of destroying all pixmaps, possible animation data and will free the colors allocated to this image. When this function returns the given XmImage will no longer be valid.

One thing that this function will not do is release any XtIntervalId that might be present in the given XmImage structure. It is your responsibility to do this.

### 2.6.4.4 How to use a XmImage

#### Normal Images

#### Running Animations

For the sake of clarity, we will repeat the animation data of the XmImage structure here:

    	/* animation data */
    	XmImageFrame *frames;	/* array of animation frames */
    	int nframes;		/* no of frames following */
    	int current_frame;	/* current frame count */
    	int current_loop;	/* current loop count */
    	int loop_count;		/* maximum loop count */
    	XtIntervalId proc_id;	/* timer id for animations */
    	Widget w;		/* image owner */
    	XtAppContext context;	/* Application context for animations */

The *frames field points to an array of structures of the following type:

    typedef struct
    {
    	int x;			/* x position in logical screen */
    	int y;			/* y position in logical screen */
    	int w;			/* width of this particular frame */
    	int h;			/* height of this particular frame */
    	int timeout;		/* timeout for the next frame */
    	unsigned char dispose;	/* previous frame disposal method */
    	Pixmap pixmap;		/* actual image */
    	Pixmap clip;		/* image clipmask */
    	Pixmap prev_state;	/* previous screen state */

    	/* private data */
    	unsigned long *pixels;
    	int npixels;
    }XmImageFrame;

The total number of frames is given by the nframes field in the XmImage structure. Each member of this array of structures represents a single frame in an animation, so displaying all frames in sequence will result in an animation being shown to the user.

Before embarking on how to display animations, it is necessary that you understand the what the fields of the XmImageFrame structure represent.

x, y, w and h

The first frame in an animation determines the screen size of the animation. This is what is called the logical screen. Every following frame can have a size equal to or less than the logical screen size. The x and y fields of the XmImageFrame structure determine the place of a frame on the logical screen, while the w and h fields determine the size of a frame.

[Note: Frames crossing logical screen boundaries are automatically clipped by the XmImageCreate routines.]

timeout

This field field indicates the number of milliseconds that should expire before the next frame in an animation is displayed.

loop_count

This field indicates how many times an animation should be run. A loop_count of zero indicates forever. Any self-respecting application should run animations with a non-zero loop_count only for the specified number of loops.

dispose

This indicates how the previous frame should be removed before a new frame is displayed. This field can have the following values:

XmIMAGE_DISPOSE_NONE (value = 1)
  do nothing, overlay the previous frame with the current frame;
XmIMAGE_DISPOSE_BY_BACKGROUND (value = 2)
  Restore to background color. The area used by the previous frame should be restored to the background color/image;

XmIMAGE_DISPOSE_BY_PREVIOUS (value = 3)
  Restore to previous. The area used by the previous frame should be restored to what was there prior to rendering the previous frame.

Handling disposal methods 2 and 3 are one of the most difficult items to deal with when running an animation. This is the reason why the prev_state field is present in the XmImageFrame structure.

The use of the remaining fields of the XmImageFrame structure will become clear in the following example which demonstrates how to run an animation and how to deal with the different disposal methods.

Example 2-?: Running an animation

    [Put in a copy of the src/paint.c, routine DrawFrame]

©Copyright 1996-1997 by Ripley Software Development
Last update: September 19, 1997 by Koen