Chapter 5 - Clients - the Application Programs

Introduction

So far we have covered the server and the communications channel between server and clients, and in the last chapter we saw how clients respond to and process events sent to them, to handle user input and other functions. Now we are going to look at the other functions which a client program has to provide, how it is constructed, and some representative examples of applications. The emphasis here is on a single client working more or less in isolation; later on, in Chapter 9, we'll consider multiple applications and how they interact.

5.1 An overview of the client and its role

X clients are application programs. They contain the application code - for example, to process the payroll, send electronic mail messages, or handle queries and updates to a database. They also include code for X support.

The function of the client is to give you the application functionality that you need to do your job as a user, and so the main part of the client is the application code. For example, typical clients include spreadsheet programs, accounts packages, electronic mail programs, database systems, network management packages, program debugging tools, medical imaging systems, etc.

However, because the client is an X program, it also needs to contain all the code to handle the various aspects of X operation, many of which we have already seen:

So the client (in fact, each client) has to include a large amount of code to make use of X and, when running, it will contain all the data structures describing the user interface of the program, how it interfaces with the application code, and so on (Figure A). This contrasts with other window systems, where most of these functions are provided either directly by the operating system, or by the base window system itself. In X mueh of this functionality is provided by the Xlib library, and in most cases the user int.erface components are provided by a toolkit. Even so, these libraries and toolkits are actually built into the client at compile-time (as we'll see in more detail in the next chapter).

Very little is contained in the server - only the very basic data structures it needs to maintain its windows on screen, use the fonts it has loaded, etc.

In many ways the situation is similar to an application written for an ordinary, character-based terminal. The application doesn't run on the terminal itself, but on the remote host. Everything to do with the application and all its data structures - even those relating to the layout of windows and graphics on the screen - are contained in the application itself. The only information in the terminal is the low-level data relating to the display on the screen, such as the bitmaps of the characters, their colour, and style (underline, bold, etc.). (Recall the comparison we made of X-terminals and character-based terminals, in Module 3.2.1.)

Minimizing what's held in the server is a deliberate design feature. The server needs to be small and stable, whereas applications (and the llbraries and toolkits they are built on) are more easily changed. Moreover, functions provided by the server are limited by the speed of the server's CPU, whereas if a client function isn't fast enough, it ean be speeded up (for everybody on the network) by running it on a faster machine. (If the function were in the server it would involve changing the machines on all the users' desks.)

The rest of this chapter covers in detail many of these aspects of the client.

Figure A. In X most application functions are not part of the base X systems.

5.2 What X clients consist of, and how they are built

Clients are usually built with libraries, to simplify coding and encourage good programming practice and `playing by the rules'. The program structure of X clients is `event-driven'.

As we saw in the previous module, applications include a lot of code to handle X. The most basic way to build an application is to use the Xlib library, whieh provides the fundamental interface to X; it contains elementary functions for issuing requests to the server, and receiving and processing events.

However, the interface provided by the standard X function library, Xlib, is very low level. It is more suited to systems programmers than applications programmers. So, most applications are built with a toolkit. Simply, a toolkit is a library of higher-level functions which is layered on top of Xlib, as shown in Figure A. As well as hiding some of the detailed internals of X, a toolkit typically provides a consistent user interface, with standard functions to create and use user interface components such as menus, scrollbars, pushbuttons, etc. However, this layered structure is not like the ISO sevenlayer reference model for networks, in which a layer can only talk to its immediate neighbours above and below. Instead, in X a layer can communicate with any other as necessary, as show in Figure A. The application code needs to access the operating system directly for services such as file handling, time-of-day, etc., for surely such facilities are none of X's business. For detailed graphics the application will probably need the low-level but powerful graphics primitives provided by Xlib and will bypass the toolkit, while the toolkit layer may require access to the operating system, for example to write temporary data to a work file. (Xlib is described in detail in Module 5.2.2, and toolkits in Module 5.2.4 and Chapter 6.)

Applications also contain other libraries. For example, a typical large graphical application might contain libraries of functions related to the user-problem it addresses (for example, chemical, financial, or statistical functions), functions which encapsulate organization- or project-defined standards, or facilities, third-party libraries for standard graphics functions (for example, GKS-to-X conversion), and so on, as already shown schematically in Figure A.

In the next module we look at how an X application must be structured to be able to handle all the different events that the server may generate for it; in the three modules after that we look at the Xlib and toolkit libraries for building X programs.

Figure A. X applications have a layered structure

5.2.1 X programs are event-driven

Because the user can interact with any component of the graphical user interface presented by an X application, the program does not know which actions it will have to perform next. Instead it is driven by events - caused by user input or other external factors. This largely determines the internal structure of an X program.

X programs, in common with those for most other window systems, are event-driven, whereas most programs for character-based terminals are data-driven. Let us see what these terms mean, by taking as an example a hypothetical program to let the user enter contact details for a customer. The data-driven program asks (prompts you) for the data it requires, and will not allow you to proceed until it gets what it wants. You have no choice about which field may be entered; the program has complete control and therefore knows exactly in what order information will be entered.

On the other hand, the event-driven program has no control over what you are going to enter. You can start not only by entering the phone number first, but by entering half of the address, then skipping to the name, then modifying the phone number, not to mention being able to access the pull-down menus. In other words, the application must be prepared to handle whatever you choose to do - it must base its processing on external events. (To some extent, applications which make use of forms-based input on character-based non-X terminals, have a similar event-driven structure.)

The structure of data-driven programs is straightforward, as illustrated in Figure A. However, event-driven programming requires a very different style. The program must be always ready to receive an event (typically user input), and once an event is received work out what sort of event it is, what it means, and how to process it. This structure is shown schematically in Figure B.

Event-driven programming constrains how you write your programs. In particular, you have to ensure there are no long computations - processing must be done in small pieces so that the program is always ready to respond to an event very soon after it has arrived. This can be difficult enough when you are writing a new program from scratch, but may be almost impossible if you are trying to change an old program to use X. The best approach may be to write a separate X event-driven front end which runs as a separate process, communicating with a more or less unchanged old program. Indeed there are a number of development tools available precisely for this type of work (see Module 14.3).

Figure A. Structure of a data-driven program.

Figure B. Loop structure of an event-driven program.

5.2.2 Basic X client functions are provided by the Xlib library

The Xlib library provides the client with a set of subroutines for issuing requests to the server and receiving and processing events. It is the lowest level interface to the X system, and most applications use it as their low-level foundation.

The standard X library, Xlib, is just a library of subroutines, providing the following functions:

In a way you can think of Xlib as the X `operating system'; calls to the subroutines it contains are analogous to system calls. Now let us look in turn at each of the facilities it provides.

Xlib makes the X protocol requests available to the applications programmer as a series of C-language functions. (`Xlib is a C-language binding of the protocol.') Originally Xlib provided functions that were little more than wrappers around the requests. However, with time Xlib has been improved and now it offers a lot more, as we see below.

Xlib handles the client side of the communications between the applicabon and the server. When the application calls a function to issue a request, X passes the reduest to the necessary transport software so it can be sent to the server. This will be network software if the client is running remotely, or inter-process communication (IPC) software if client and server are on the same machine. Xlib also provides all the functions necessary for the application to select for particular event types and to inform the server of this selection. When events are sent by the server over the network or IPC software, Xlib receives the events and queues them until the application is ready to retrieve and process them using other Xlib functions.

Xlib provides many utility or convenience functions for X-related tasks, including reading in default values for various components of the program, parsing default values to see what they mean (for example, for geometry specifications of window size and position), handling regions (arbitrary sets of pixel locations), interpreting colour specifications, manipulating bitmaps and images, and translating keyboard events to ASCII strings. In other words, Xlib gives you a wide range of facilities for managing those data structures within your application which are related to X, but which need to be processed by the client and not just by the server. For instance, reading a bitmap from a file must be done on the client machine and using the client machine's file system, before the bitmap can be sent to the server for drawing.

Xlib has grown to include many performance-enhancing features. Xlib buffers requests, collecting several together before it passes them to the network software for transporting to the server, so that network traffic is reduced. Multiple requests for drawing single items into the same window are merged into a single `poly' request. For example, multiple successive calls to draw lines in a particular window are merged into a single poly-line draw reyuest which draws multiple line segments in a single operation. Not only does this batching reduce the network traffic, it also reduces the number of requests the server has to handle, and the amount of processing it has to perform.

Using Xlib in a program

The next module shows a listing of a very simple X program using only the basic functions provided by Xlib. The program displays the string `Hello, world' in a window, and correctly handles events when the window is exposed or resized, re-displaying and re-centring the string in the window (Figure A). The program is compiled and linked with the commands shown in Figure B.

In the program listing, all the functions with names beginning with an uppercase `X', such as XOpenDisplay() and XDrawString(), are provided by Xlib. You can see from this example that programming using Xlib is long-winded and excessively detailed. The toolkits described in Module 5.2.4 help overcome this problem.

Figure A. The X `Hello, World' program

Figure B. Compile and link commands for a simple X program.

5.2.3 Listing of a program based on Xlib

The program listed here is a simple X program to display a string in a window. It handles events when the window is exposed or resized, re-displaying and recentring the string in the window. It also allows customization using the standard X defaults or resources mechanism (described in Module 12.2).

#include
#include
#include
#define STRING "Hello, world"
#define BORDER 1
#define FONT "fixed"
#define ARG_FONT "font"
#define ARG_BORDER_COLOR "bordercolor"
#define ARG_FOREGROUND "foreground"
#define ARG_BACKGROUND "background"
#define ARG_BORDER "border"
#define ARG_GEOMETRY "geometry"
#define DEFAULT_GEOMETRY ""

XWMHints xwnsh = {
(InputHint|StateHint), /* flags */
False, /* input */
Normal State, /* initial state */
0, /* icon pixmap */
0, /* icon window */
0, 0, /* icon location */
0, /* icon mask */
0, /* Window group */
};
main(argc,argv)
int argc ;
char **argv;
{
Display *dpy; /* X server connection */
Window win; /* Window ID */
GC gc; /* GC to draw with */
char *fontName; /* Name of font for string */
XFontStruct *fontstruct; /* Font descriptor */
unsigned long ftw, fth, pad; /* Font size parameters */
unsigned long fg, bg, bd; /* Pixel values */
unsigned long bw; /* Border width */
char *tempstr; /* Temporary string */
XColor color; /* Temporary color */
Colormap cmap; /* Color map to use */
XGCValues gcv; /* Struct for creating GC */
XEvent event; /* Event received */
XSizeHints xsh; /* Size hints for window manager */
char *geomSpec; /* Window geometry string */
XSetWindowAttributes xswa; /* Temporary Set Window Attribute struct */

if ((dpy = X OpenDisplay(NULL)) == NULL) {
fprintf(stderr, "%s: can't open %s\n", argv[0], XDisplayName(NULL));
exit(1);}
if ((fontName = XGetDefault(dpy, argv [0], ARG_FONT)) == NULL) {
fontName = FONT;}
if ((fontstruct = XLoadQueryFont(dpy, fontName)) == NULL) {
fprintf(stderr, "%s: display %s doesn't know font %s\n",
argv [0], DisplayString(dpy), fontName);
exit(1);}
fth = fontstruct->max bounds.ascent + fontstruct->max bounds.descent;
ftw = fontstruct->max bounds.width;
cmap = DefaultColormap(dpy, DefaultScreen(dpy));

if ((tempstr = XGetDefault(dpy, argv [0], ARG_BORDER_COLOR)) == NULL ||
XParseColor(dpy, cmap, tempstr, &color) == 0 ||
XAllocColor(dpy, cmap, &color) == 0) {
bd = WhitePixel(dpy, DefaultScreen(dpy)); }
else {
bd = color.pixel;}
if ((tempstr = XGetDefault(dpy, argv[0], ARG_BACKGROUND)) == NULL ||
XParseColor(dpy, cmap, tempstr, &color) == 0 ||
XAllocColor(dpy, cmap, &color) == 0) {
bg = BlackPixel(dpy, DefaultScreen(dpy));}
else {
bg = color.pixel;}
if ((tempstr = XGetDefault(dpy, argv[0], ARG_FOREGROUND)) == NULL ||
XParseColor(dpy, cmap, tempstr, &color) == 0 ||
XAllocColor(dpy, cmap, &color) == 0) {
fg = WhitePixel(dpy, DefaultScreen(dpy)); }
else {
fg = color.pixel;}
pad = BORDER;
if ((tempstr = XGetDefault(dpy, argv[0], ARG_BORDER)) == NULL)
bw = 1;
else
bw = atoi(tempstr);
geomSpec = XGetDefault(dpy, argv[0], ARG_GEOMETRY);
if (geomSpec == NULL) {
xsh.flags = (PPosition | PSize);
xsh.height = fth + pad * 2;
xsh.width = XTextWidth(fontstruct, STRING, strlen(STRING)) + pad * 2;
xsh.x = (DisplayWidth(dpy, DefaultScreen(dpy)) - xsh.width) / 2;
xsh.y = (DisplayHeight(dpy, DefaultScreen(dpy)) - xsh.height) / 2; }
else {
int bitmask;

bzero(&xsh, sizeof(xsh));
bitmask = XGeometry(dpy, DefaultScreen(dpy), geomSpec, DEFAULT_GEOMETRY,
bw, ftw, fth, pad, pad, &(xsh.x), &(xsh.y), &(xsh.width), &(xsh.height));
if (bitmask & (XValue | YValue)) {
xsh.flags != USPosition;}
if (bitmask & (WidthValue | HeightValue)) {
xsh.flags != USSize;}}
win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
xsh.x, xsh.y, xsh.width, xsh.height, bw, bd, bg);
XSetStandardProperties(dpy, win, STRING, STRING, None, argv, argc, &xsh);
XSetWMHints(dpy, win, &xwmh);
xswa.colormap = DefaultColormap(dpy, DefaultScreen(dpy));
xswa.bit_gravity = CenterGravity;
XChangeWindowAttributes(dpy, win, (CWColormap | CWBitGravity), &xswa);
gcv.font = fontstruct->fid;
gcv.foreground = fg;
gcv.background = bg;
gc = XCreateGC(dpy, win, (GCFont | GCForeground | GCBackground), &gcv);
XSelectInput(dpy, win, ExposureMask);
XMapWindow ( dpy, win ) ;
while (1) {
XNextEvent(dpy, &event);
if (event.type == Expose && event.xexpose.count == 0) {
XWindowAttributes xwa; /* Temp Get Yiindow Attribute struct */
int x, y;
while (XCheckTypedEvent(dpy, Expose, &event));
if (XGetWindowAttributes(dpy, win, &xwa) == 0)
break;
x = (xwa.width - XTextWidth(fontstruct, STRING, strlen(STRING))) / 2;
y = (xwa.height + fontstruct->max bounds.ascent
- fontstruct->max bounds.descent) / 2;
XClearWindow(dpy, win);
XDrawString(dpy, win, gc, x, y, STRING, strlen(STRING));}}
exit(1);
}
Figure A. Listing of `simple' Xlib program

5.2.4 Most X applications use a high-level toolkit

Because the Xlib library is low-level, most applications also use higher-level libraries or toolkits to simplify coding by handling many of the complex details, and to ensure consistency in tha user interface.

It is obvious from the sample program in the previous module that applications written using Xlib are complex and long-winded (and therefore will be error-prone, and difficult to maintain.) The X developers realized this, and have always intended that applications programmers should use a higher-level interface to the system - they should use a toolkit - layered on top of Xlib as illustrated in Figure A. Most of the lower-level Xlib facilities need to be used only by developers of toolkits or specialist window system programmers. This approach has many benefits for the end-user of the application as well as the programmer:

You can think of an X toolkit as analogous to the `standard libraties' provided by an operating system, for example the C-language Stdio for input/output, or CurSeS for handling character-based screens. They are provided to simplify, to standardize, and to optimize performance for the machine they are running on; it is possible to write programs without them and just use the lowest-level interface, but it is much more difficult. In other words, Xlib is the equivalent of the raw operating system interface (Figure B).

There are now many different X toollcits available, and we'll deal with them in detail in Chapter 6.

Figure C shows a listing of a program written using the standard X Toolkit. Like the program in the previous module, it displays the string `Hello, world' in a window, and in fact has much greater functionality that the earlier (Xlib) program as now we have a whole range of customization facilities and other options provided by the Toolkit. Even so, the Toolkit version is very much shorter, and this degree of improvement is typical.

Figure A. A toolkit layered on top of the basic Xlib library

Figure B. Analogies of X and operating system layers.

Figure C. Listing of a simple X Toolkit program.

5.3 Internationalizing and localizing applications - Xi18n

It is important for both vendors and users of software that the same application is usable in many different countries. It must be able to handle different natural (human) languages, both for input and for output, and address other country-dependent aspects such as the format of dates and times and numbers. Release 5 of X has introduced many internationalization features which let you write programs that are not specific to any country or natural language, but will operate correctly in each country and obey the local conventions. X internationalization (Xi18n) is based on the ANSI C concept of the `locale', which defines what the localized behaviour of the program is to be.

Being able to use a piece of software in more than one country is becoming more and more important to users. Organizations increasingly have to work in an international context, with offices or personnel or at least associates in other countries, and they also tend to standardize on third-party software for their whole operation worldwide. For example, the same spreadsheet and word processor will be used in an organization's London, Chicago, Frankfurt, and Tokyo offices, and it must work correctly according to each country's local conventions. Moreover, users in Tokyo will probably have to process documents in English, as well as Japanese. For software vendors too, it is important that their product be usable across the world, so that the product has as wide a market as possible.

What are the requirements of a program which has to operate in many different countries?

We want the application to be able to handle these country-specific customs and language. But we don't want to have to write (and maintain) a different version of the program for each country. First, that would be very expensive. Second, different languages may be required simultaneously; for example, a person translating from French to Japanese would want two versions of a word processor on-screen at the same time, one in Japanese and one in French. What we really want is for the program itself to be adaptable so it uses different languages without recompiling or relinking. We want to be able to write generic code, and let the user (or system administrator) use environment variables or other configuration controls to select the paracular language and country conventions required; then when the program is run, a specific database is loaded which gives the required behaviour for the specified environment. Internationalization is the process of enabling the program to do this. It involves removing hard-coded logic and information specific to one language, and replacing them with mechanisms that allow the program to be tailored, at run-time, to one particular language.

Localization is the process of tailoring an already internationalized program for use in a particular country. It must ensure that the user can input the characters in that language, and that all messages and labels are displayed in that language also.

Internationalization is often called il8n (because there are 18 letters between the initial `i' and the final `n' of `internationalization'). The specific X implementation of internationalization is referred to as Xi18n.

Locales

ANSI C defines the concept of locale. A locale is a name to describe how an application is to behave dealing with a particular language or other country-specific conventions. The locale to be used is specified at the start of the program (usually by means of an environment variable so it is not hard-coded into the program). It causes locale-specific messages to be loaded from a database, and it specifies how various input and output functions behave, to match the specified local requirements. This ANSI locale model really only allows single-language programs: it lets your program work with any natural Ianguage, but only with one at a time - it is internationalization but not a `multilingual' facility.

X internationalization is based on this ANSI locale model.

In the next two modules we look at the mechanisms X provides for internationalization and localization.

5.3.1 Internationalized text input, and input methods

X supports localized text input using `input methods'. Internally characters can be stored in `multibyte' or `wide-character' storage.

(If technical details aren't so relevant to you, you can skip over this module. )

As we outlined in Module 4.2.3, an input method is a mechanism to let you enter from your keyboard characters which are not directly available on that keyboard. The simplest example of this is the compose input method for entering special symbols and characters specific to some European languages; this facility is available on many non-X systems. It is suitable where the written language is based on an alphabet of a small number of symbols (letters) which are used in different combinations to form words; examples are the English (Latin) and Cyrillic alphabets.

However, many oriental languages are ideographic - instead of building up words from a small, fixed, set of letters, each word is represented by its own special symbol which is often a semi-graphical representation of the idea it relates to. As a result, these languages have very large numbers of symbols - many tens of thousands - so some special methods are needed for inputting them, that is, for specifying from the keyboard which symbol is to appear on the screen or in a file. This is what input methods allow you to do, and because of the size of the problem, they can be quite complex. Let's consider Japanese as an example.

Japanese has both ideographic symbols (Figure A) and a phonetic writing system using an alphabet. The phonetic characters are shown on the keyboard, and the user types particular sequences of these to generate a single ideograph. However, the same seyuence of phonetic symbols corresponds to several different ideographs (in the same way that in English many words that sound the same have completely different meanings, for example `right', `write', `rite' - and even `right' has several distinct meanings of its own). So, the input method must let the user resolve the ambiguities, for example by presenting a menu of the ideographs, and letting the user choose the required one; this is called pre-editing. Pre-editing may be done `on the spot', in the window where the text is being input, or `over the spot', in a special window on top of where the text is being input, or in a window elsewhere specially reserved for pre-editing (`off the spot' ). The input method may also require other status and auxiliary windows, to show the user what is happening, and for any other special dialogs the method requires.

Coding all this into an application is a lot of work. Even worse, to build an application to work with all different natural languages would require many different input methods, and further, there are several different input methods available for some languages. So X allows the input method to be run as a separate process, called an input server, and the application communicates with this process, passing to it the input events from the server, and getting back the composed (converted) text. However, setting up and using this communication is handled within the Xlib functions for using input methods and is transparent to the applications programmer. So, while this architecture does mean there is a communication overhead for handling input, it also allows the application to use other input methods (and therefore natural languages) without recompiling or relinking. Unfortunately, different vendors' implementations of Xlib use their own different X-based protocols to communicate with the input server, so users don't have the freedom to choose from all available input methods. The MIT X Consortium is working on ways to overcome this, with the goal of providing a portable way to add support for new locales not already provided the Xlib vendor, so the user can select locale dynamically.

Storing characters internally

Traditionally, programs have internally stored characters one per byte, as ASCII (or EBCDIC). For internationalized programs this is no longer adequate as one character may require several bytes. There are two ways of handling this:
  1. Multibyte characters are stored in a variable number of bytes, each character occupying only the minimum storage required. While this gives optimal use of storage, it complicates string processing. For example, to access the nth character in a string, you cannot index to it directly because you don't know what size the preceding n-1 characters are; so you always have to start at the beginning of the string, and read from there. This character type is supported by ANSI C.
  2. Wide characters are each stored in a fixed number of bytes, the number being that required by the biggest character. This uses more storage, but allows strings to be handled in much the same way as single-byte characters. (For example, programming constructs such as S++ still work.)

In the next module we look at X's mechanisms for internationalized output.

Figure A. Oriental languages contain large numbers of ideographic characters.

5.3.2 Internationalized X text output

Localized text output is supported with `font sets' and context-dependent text drawing. Localized messages and menu labels are loaded from a locale-dependent database.

(If teehnical details aren 't so relevant to you, you can skip over this module.)

X version 11 has always supported both 8-bit and 16-bit fonts. That is, a character or symbol is represented by either an 8- or 16-bit number, depending on the font. In Figure A a string of 8-bit bytes is shown interpreted as characters in an 8-bit ASCII font. This also illustrates that the encoding of the string - how a numeric value on the string is translated to a printed character - is determined by the font and is specific to a font. The last component of a font's XLFD name specifies what the encoding for the font is; for example `-iso8859-1' specifies `Latin-1' encoding, which includes the printable ASCII characters as well as almost all the accented characters needed for European languages.

16-bit encoding allows fonts to contain large numbers of characters, and this is almost adequate for drawing the text characters of most languages. However, there are still problems. First, some languages contain more than the 65536 symbols which can be accommodated in a 16-bit font. Second, multiple fonts are needed to cover the requirements of some languages. For example, for Japanese you might have one font for ASCII characters (for computer-related work), another R-bit font for the phonetic `kana' characters, and a 16-bit font for the ideographic characters.

In Release 5, the concept of a fontset was introduced. A fontset is a list of the fonts which the X text-drawing functions may use when drawing a particular string in the language, taking different symbols from the different fonts as required. A fontset is specified by a list of XLFD font-names. Allowing multiple fonts to be used solves both the problems above.

A third problem with text output is context-dependence, that is, where the appearance of a symbol to be drawn depends on what symbols are beside it. The simplest example is ligatures in certain fonts in English: if the letter `i' is preceded by an `f', the two characters are not drawn individually and separately but as a single composite symbol. Two `f's followed by an `i' are treated similarly. For other languages, the symbol used for a character can depend on the surrounding ones, even when it is not drawn as a composite symbol with them. The text-drawing routines in Release 5 can now handle these cases.

Note that all these changes, both for text input and output, are exclusively within the client and don't affect the server, even though they appear to be an intrinsic part of the system. The code necessary to support these facilities is within the application code or in Xlib or another library. The fontset list is used exclusively on the client side, by Xlib. Xlib decides which font should be used for each character to be drawn; then it sends to the server a standard text drawing request, which includes (via a graphics context) which single font is to be used for this piece of text. Thus the server sees no change, and thus the X Protocol is unchanged. This is a good example of how putting as little functionality as possible in the server allows X to grow organically while still maintaining upward compatibility.

Localized messages, labels, and other text

Being able within the program to draw the charact.ers of the user's language is only a partial solution. As part of localizing the program you must also provide translated versions of messages, menu labels, and all other text.

Therefore, internationalized programs must not hard-code any text that will appear in the user interface. Instead, all strings must be stored in a local-dependent configuration file or database; when the program is run, it loads the appropriate database for the given locale, retrieves the individual messages and labels from the database, and uses them when drawing the user interface components.

Supporting locale-related databases is not part of X, but is a standard facility which is provided by the operating system (or ought to be), which X then just uses.

Figure A. Encoding of an eight-bit font (here, as ASCII characters).

5.4 Examples of X application programs

X applications cover a very broad spectrum. The simplest are small `desk accessories', such as clocks and calculators. At the other extreme of complexity are programs such as industrial control applications, CAD systems, etc., which merely use X as the interface to the application code that is the main part of the program. There are also specific tools for developing with, and administering, X systems.

In X, everything apart from the fundamental mechanisms of the base system is handled by client programs. As a result we have clients offering a very wide range of functionality. In this module and the next, we describe a few applications, just to give you an idea of what is available.

Desk accessories

Most X systems give you several little convenience tools to help you with small day to day tasks. Typical examples are clocks, calculators, calendars, etc.

Tools for the user to control the X system, and utility programs

These are the X applications that provide much of the basic functionality included as part of the base system with other window systems. The most important of these are the window manager, terminal emulators, and desktops and file managers.

Utility programs provide facilities for killing off X applications, capturing and printing screen images, and creating and editing icons.

Office automation

Window systems are especially good for office automation applications because of their good graphics and sophisticated font handling. Functions such as word processors, desktop publishing (DTP) systems, spreadsheets, electronic mail, and text editors are provided either as standalone applications or as integrated program suites.

Vertical end-user applications

The real purpose of computer systems is to provide tools and applications to help the end-users do theu job more effectively. X is a fundamental technology, in the same way that database systems are applied to almost every application area, so there are now X clients for medical, scientific, commorcial and financial areas, etc.

However, because of X's graphical facilities, it is particularly popular for systems such as CAD and CAE, imaging, mapping, and any other application where input or output is largely graphical in nature.

Program development and migration tools

Standard program development using Xlib and X toolkits requires no special facilities. However, special systems to allow programs to be developed graphically, and which provide very high-level programming facilities are becoming common. These UIMSs (user interface management systems) not only generate programs that use X, but they are themselves X applications in their own right as well.

Most existing programs were not developed to use X, so special facilities are needed to run these programs on X systems. Special functionality may be ineluded in servers, for example to run applications developed for other window systems running on the same processor type. However, other special emulation systems, for emulating a PC on a RISC workstation, for instance, are usually written as X clients.

X-specific tools for system administration

Managing a complex system like X with its many different capabilities such as font servers, server options, and customization facilities requires special tools, especially where the environment is on a large multi-vendor network. Most X systems include system administration tools for simplifying the management of these aspects of the system, primarily for the system manager rather than the end user.

5.4.1 Some common X applications

This module illustrates the wide range of functionality provided by X clients, from simple convenience tools to complex applications.

Desk accessories

Office automation

Graphics applications

The contrib release contains xloadimage which understands a wide range of standard picture formats.

Tools for the user to control the X system, and utility programs

Program development and migration tools

X-specific tools for system administration

  • xdm: the X display manager, which makes an X terminal behave similarly to a character-based oned, by presenting you with a login window to begin with. When you login, you start your X `session' and do your work. When you finish and logout, xdm resets the server, and presents the login window again, ready for the next user. As we'll see in Module 11.1.3, xdm combined with the XDMCP facility is essential for administering large networks of X stations.
  • xmodmap: allows you to print and modify your keyboard and mouse mappings.
  • xfd: is the X font display program, which we illustrated in Module 3.7.2. xset: lets you configure options of your server, such as whether keyboard autorepeat is enabled, how loud the bell should sound, where the server should look for its fonts, etc.
  • xlsfonts: lists the names of the fonts available the server, optionally showing only those matching a wild-carded font name specification.


    Summary

    In this chapter we have looked at the third major component of X - the client application program - and what its overall role is, having seen in the previous chapter how it processes events. We looked in detail at what the client's principal components are and how it is constructed using the standard Xlib library, toolkits, and other function libraries. We looked at how internationalized applications can be built, allowing them to work with different locales specifying the language and other local conventions the program is to work with, and how an internationalized program is localized, to work in a particular locale. Finally we looked at a wide range of example applications, to give an indication of the breadth of function provided by X clients.

    In the next chapter we continue with the client, and explain in detail what an application's `look and feel' is, how the user interface is built into the application, and how a standard user interface or look and feel is provided using toolkits.

    Many other important aspects of clients are covered later. Chapter 9 (Inter-Client Communications) explains how clients ean communicate and interact with each other, Chapter 10 (Writing X Programs) includes more information on programming a client, and client performance is covered in Chapter 13 (Performance Factors).