Chapter 12. Interclient Communication

As a multi-window environment, X must support a mechanism for communication between applications. There are three: properties, selections, and cut buffers, all of which are described in this chapter. The special case of communication between an application and the window manager is also covered here. Internationalized interclient communication is described in “Internationalized Interclient Communication” in Chapter 10 Standard conventions for additional aspects of interclient communication are covered in Appendix L of Volume Zero, X Protocol Reference Manual.

Communication is necessary to make sure that all applications running under X cooperate properly with the window manager and share the system resources politely. Communication also allows applications to interchange data. Most applications in an integrated computing environment should have the ability to transfer data to and accept data from other applications.

Communication between clients takes place through properties.Sometimes properties are set directly by one application and read by another. This is the case with most communication between the window manager and the clients.

There is also a simple but limited means of communication throughproperties called cut buffers. But the preferred and most powerful method of general communication between clients is called selections. Selections actually establish a dialog between the two applications, not just a one-way communication. Both cut buffers and selections are ways of using properties for communication.

Successful communication depends on conventions for the meanings of the data communicated through properties and selections. Theconventions in this area were established initially in Release 4, with the adoption as an X Consortium standard of the Inter-Client Communication Conventions Manual (ICCCM), which isreprinted in Appendix L, Interclient Communcation Conventions, of Volume Zero (as of the second printing). The current version of the ICCCM is version 1.

Several R3 routines are now obsolete because of new routines added to Xlib in R4. This edition describes only the currently valid interfaces. The outdated routines formerly used by applications are XSetStandardProperties(), XSetWMHints(), XSetZoomHints(), XSetNormalHints(), XStoreName() and XSetIconName().

Properties and Atoms

Properties allow you to associate arbitrary information with windows, usually to make that data available to the window manager or other applications. Properties are stored in the server.

Each property has a unique integer ID, called an atom. An atom is just a nickname for a property, so that arbitrary length property name strings do not have to be transferred back and forth between Xlib and the server. The atom is assigned by the server and will remain defined in the server even after the client that defined it terminates. The atoms for the predefined properties are constants defined in <X11/Xatom.h>; all of them begin with the prefix XA_. This naming convention avoids name clashes with user-defined symbols.

A property is uniquely identified by an atom and a window. Therefore, there may be one property on each window identified by a given atom. In other words, there can be a XA_WM_NAME property on each and every window, even though by convention this property is only set or read on the top-level windows of each application. A property on a window takes up space only once it is set.

Each property also has a name, which is an ASCII string. For the predefined properties, the name is never used in code. That is why we have chosen for this manual to refer to all predefined properties by their atoms. But for properties defined by convention between related clients (not predefined), the property name string is used so that the applications can determine the correct atom for the property. The first client to call XInternAtom() with the property name string as an argument gets a new atom. Subsequent clients that call XInternAtom() with the same string will get the same atom. After each client has called XInternAtom(), they use the atom rather than the string to refer to the property. They use this process because for properties defined by clients, the actual number used for an atom may differ between invocations of the server.

Once created, an atom remains defined in the server even after the client that created it has exited. A server remembers all atoms that were ever defined since the server started up. This means that one client can refer to an atom first interned by another client even if that other client has already exited.

Each property has a type, which itself is a property. There are several predefined properties for use as some of the more often needed types.

The data associated with a property can be stored as an array of 8-bit quantities, 16-bit quantities, or 32-bit quantities only. Properties can contain structures or raw data, but if one is to contain a structure of complex type, it must be encoded into one of the three byte formats by the program before being sent to the server and decoded when read from the server. The predefined property types have been carefully designed to match one of the data formats so that encoding and decoding are not necessary.

Properties remain set until the window to which they are attached is destroyed, which happens automatically when the client that created the window exits. However, properties set on the root window remain defined even after the client that set them has exited, since the root window is never destroyed.

There are 68 predefined properties for window manager communication, selections, standard colormaps, and font specifications. The properties used for window manager communication and selections are described in this chapter. The standard colormap properties are described in Chapter 7, “Color” and the font properties are described in Chapter 6, “Drawing Graphics and Text”

Properties are set with XChangeProperty() and read with XGetWindowProperty(). Whenever XChangeProperty() is called, a PropertyNotify event is generated.

The Compound Text Encoding

An X Consortium standard defines a format for text properties that support multiple character sets, such as multi-lingual text. It is called the Compound Text Encoding. As of late 1992, the Compound Text Encoding specification is printed in Volume Zero, X Protocol Reference Manual.

The format is based on ISO standards for encoding and combining character sets. Compound Text is intended to be used in three main contexts: inter-client communication using selections; window properties (e.g., window manager hints); and resources (e.g., as defined in Xlib and the Xt Intrinsics). All of the standard routines for setting window manager hints that set text properties support the compound text encoding. If you are only concerned with your program operating in English on a system where the window manager also uses English, these routines are easy to use.

The target type for selections in the Compound Text encoding is COMPOUND_TEXT.

Communicating with the Window Manager

To permit window managers to perform their role of mediating the competing demands for screen space and colormaps, the clients being managed must adhere to certain conventions. These conventions specify things that clients must do, things they should or can do if desired, and things that they must not do. The most basic thing clients are expected to do is to set certain properties so that the window manager has information on which to base its decisions.

It is a fundamental principle of client-window manager communication that a general client should not care which window manager is running or, indeed, if one is running at all. The choice of window manager is up to the user or perhaps the system administrator, not the client.

The fact that window managers need information about the clients they are managing and yet that window managers vary and might not be running lead to the concept of the hint. A hint is a suggestion to the window manager about a preference of the application made by setting a property. Xlib makes this easy by providing routines that conveniently set the right properties. The window manager is encouraged to honor as many of the hints as possible, but it is not required to honor any of them. Therefore, the application must not depend on its hints being honored; it must be capable of operating when any of its hints are ignored or denied.[49]

In general, the object of the X11 design is that clients should, as far as possible, do exactly what they would do in the absence of a window manager, except for:

  • Hinting to the window manager about the screen space and colormaps they would like to use.

  • Cooperating with the window manager by accepting the resources they are allocated, even if not those requested.

  • Being prepared for hardware-limited resource allocations to change at any time. The client can select events that will announce these changes.

Note that these procedures are not required for the virtually unlimited X resources such as windows or cursors.

Clients create one or more windows that are children of the root window. All these windows are known as top-level windows. It is these windows that the window manager controls, and it is also these windows on which the application sets window manager hint properties.

Standard Properties for Window Manager

Once the client has created one or more top-level windows but before it maps them, it must place properties on those windows to help the window manager manage them effectively. The following sections describe each property that must or should be set and how to set it.

It is important to remember that the version 1 conventions are the accepted X Consortium standard and will continue to be valid in R5 and later; there will be additions but not incompatible changes.

Some of the properties that a client sets for the window manager are mandatory (the standard properties), and some are optional. XSetWMProperties() which was introduced and used in basicwin in Chapter 3, “Basic Window Program” sets all the required properties. The purpose of XSetWMProperties() is to provide a simple interface for the programmer who wants to code an application quickly. Other functions are provided to communicate more optional information to the window manager.

In order to work well with most window managers, every program should call XSetWMProperties() for each top-level window. These provide the window manager with the following information:

  • Name of the application for titlebar.

  • Name string for the icon.

  • Command and arguments used to invoke the program.

  • Icon pixmap and mask or window.

  • Preferred initial icon position.

  • Size hints for window in normal state.

  • Startup state (normal or iconified).

  • Keyboard focus model used by the application.

  • Window group; for applications with multiple top-level windows, this describes which window is the main window for iconifying.

The window manager, not Xlib, chooses its own default response when any of these properties are not set. Also, they are only hints. A window manager determines what to do with this information and is allowed to ignore it. They will, of course, be ignored if no window manager is running.

The following sections describe the properties set by the client that indicate its preferences to the window manager. Table 12-1 shows all the predefined properties that clients can set and the section in this chapter where they are described.

Table 12-1. The Window Manager Hints Property Atoms

Property

Property Type

C Type

Description

See

For window manager:

XA_WM_CLASS

XA_STRING

XClassHint

Application class and name for resource database lookup.

Section 12.3.1.5

XA_WM_HINTS

XA_WM_HINTS

XWMHints

Additional hints set by client for use by window manager.

Section 12.3.1

XA_WM_ICON_NAME

"TEXT"

XTextProper ty

Name to be used in icon.

Section 12.3.1.2

XA_WM_NAME

"TEXT"

XTextProper ty

Application name.

Section12.3.1.1

XA_WM_NORMAL_HINTS

XA_WM_SIZE_ HINTS

XSizeHints

Size hints for window in normal state (not iconified or zoomed).

Section12.3.1.3

XA_WM_TRANSIENT_FO R_HINT

XA_STRING

char *

Tells window manager which window is the real main window with which a temporary window is associated.

Section 12.3.1.4.6

XA_WM_ZOOM_HINTS

XA_WM_SIZE_ HINTS

XSizeHints

Size hints for zoomed window.

Section 12.3.1.3

For session manager:

WM_CLIENT_MACHINE

"TEXT"

XTextProper ty

The name of machine running the client, as seen from the machine running the server.

Section12.3.1

XA_WM_COMMAND

"TEXT"

XTextProper ty

Command and arguments, separated by ASCII 0's, used to invoke application.

Section 12.3.2.1

In addition to the functions mentioned above that set all of the standard properties, Xlib also provides separate functions for setting and getting each property. These are referenced in the sections below describing each property. See the relevant pages in Volume Two, for full details on each function. Applications set these properties and never read them, and the window manager gets them but never sets them. Therefore, if you are writing an application, you will only use the routines that set these properties.

Application Name - XA_WM_NAME

The XA_WM_NAME property is a string that the client wishes displayed in association with the window (for example, in a window titlebar).

Window managers are expected to make an effort to display this information; simply ignoring XA_WM_NAME is not acceptable window manager behavior. Clients can assume that at least the first part of this string is visible to the user, unless the user has made an explicit decision to make it invisible by placing the headline off-screen or covering it by other windows. But XA_WM_NAME should not be used for application-critical information nor to announce changes of application state that require timely user response. The expected uses are:

  • To permit the user to identify one of a number of instances of the same client.

  • To provide the user with noncritical state information.

Even window managers that support headline bars will place some limit on the length of string that can be visible; brevity here is important.

XSetWMName() and XGetWMName() set and get the XA_WM_NAME property. These interfaces support the use of the Compound Text Encoding.

Icon Name - XA_WM_ICON_NAME

The XA_WM_ICON_NAME property is a string that the client wishes displayed in association with its icon window when the client is iconified (for example, an icon label). In other respects, it is similar to XA_WM_NAME. Fewer characters will normally be visible in XA_WM_ICON_NAME than XA_WM_NAME, for obvious geometric reasons.

If an icon pixmap has been specified in the standard properties or XA_WM_HINTS, it may be displayed in the icon in addition to or instead of the icon name. XSetWMIconName() and XGetWMIconName() set the XA_WM_NAME property.

Window Size Hints - XA_WM_NORMAL_HINTS

An application must tell the window manager its geometry preferences for each of its top-level windows before mapping them. [50] These hints specify not only the preferred initial size (and sometimes position) of the window but also the preferred increments of sizes and aspect ratios the window manager should respect when allowing the user to resize the application. (The aspect ratio is the ratio of the width of the application to its height.)

XSetWMProperties() normally sets the XA_WM_NORMAL_HINTS property for a window in normal state. XSetWMNormalHints() is also available if for some reason XSetWMProperties() is not suitable.

The XA_WM_NORMAL_HINTS property is an XSizeHints structure, shown in Example 12-1.

Example 12-1. The XSizeHints structure

typedef struct {
   long flags;                  /* Marks defined members in
                                 * structure */
   int x, y;                    /* Obsolete */
   int width, height;           /* Obsolete */
   int min_width, min_height;
   int max_width, max_height;
   int width_inc, height_inc;
   struct {
          int x;                /* Numerator */
          int y;                /* Denominator */
   } min_aspect, max_aspect;
   int base_width, base_height;
   int win_gravity;
} XSizeHints;


  • The x, y, width, and height members describe a desired position and size for the window. The coordinate system for x and y is the root window, irrespective of any reparenting that may have occurred. These fields are obsolete, because the window manager will use the initial size and position of the window when mapped to get this information. (The window manager redirects the application's mapping request to itself, so that the window manager can inspect the position and size of the window set by the application, and perhaps change them, before mapping the window.)

  • The min_width and min_height members specify the minimum size that the window can be for the application to be useful. Most window managers will not allow the user to resize the application smaller than this size. The base_width and base_height fields if set are used instead of min_width and min_height. If they are not set, min_width and min_height are used.

  • The max_width and max_height members specify the maximum useful size.

  • The width_inc and height_inc members define an arithmetic progression of sizes, from the minimum size to the maximum size, into which the window prefers to be resized. For example, xterm prefers size increments matching the dimensions of the font being used.

    The following algorithm should be used by the window manager to calculate the displayed size of the top-level window. i and j are nonnegative integer loop variables within the window manager that would be incremented until a size that matches the window manager's window management policy is reached.

    width = base_width + (i * width_inc)
    height = base_height + (j * height_inc)
    

    (When base_width and base_height are not set, min_width and min_height are used instead of base_width and base_height.) Window managers will use i and j instead of width and height in reporting window sizes to users. Similarly, applications should interpret the command line or user default geometry using width_inc and height_inc pixels instead of single pixels as the unit. xterm, for example, interprets size specifications in terms of multiples of the font dimensions, not in pixels. A default xterm window has 80 columns and 24 rows of characters. To create an xterm window with more rows, you can use the command:

    spike% xterm -geometry 80x40  
    
  • The min_aspect and max_aspect members specify the desired range of ratios of width to height for the window and are each expressed as a ratio of the x and y members of min_aspect and max_aspect. (The ratio x / y in min_aspect or max_aspect is the minimum or maximum value for width / height.)

  • The base_width and base_height fields if set are used instead of min_width and min_height. If they are not set, min_width and min_height are used.

  • The win_gravity field controls how the window's initial position will be interpreted by the window manager. By default, this hint is NorthWestGravity, which means that the position of the window when mapped by the application is used by the window manager as the position of the northwest corner (top-left) of the window. The other values for this field are CenterGravity, EastGravity, NorthEastGravity, NorthGravity, SouthEastGravity, SouthGravity, SouthWestGravity, and WestGravity. If the hint is set to CenterGravity, the window manager will place the center of the window where the origin of the window was when the application mapped it.

  • The flags member of XSizeHints indicates which members in the structure contain important information. The constants in Table 12-2 can be combined with bitwise OR to set flags. The USPosition and USSize flags indicate that the user specified the desired values, while PPosition and PSize indicate that the program determined the values. This distinction is important since it supports the power structure--the user overrides the window manager, and the window manager overrides the program in decisions about window layout. The window manager can override the program's choice of window location or geometry when PPosition or PSize, respectively, are set, but the user's choices should override the window manager's choice when USPosition or USSize are set.

Table 12-2. The XSizeHints Flags

Flag

Description

USPosition

User-specified x, y

USSize

User-specified width, height

PPosition

Program-specified position

PSize

Program-specified size

PMinSize

Program-specified minimum size

PMaxSize

Program-specified maximum size

PResizeInc

Program-specified resize increments

PAspect

Program-specified min and max aspect ratios

PBaseSize

Program-specified base size

PWinGravity

Program-specified window gravity

PAllHints

Program-specified all hints

XSetWMSizeHints() is only useful if an application and a window manager agree on a private protocol that defines a new type of size hint atom beyond the one defined by the version 1 conventions or if a new type of size hint is added in later conventions.

XAllocSizeHints() allocates an XSizeHints structure and zeros all the fields. This function should be used so that new fields can be added in later releases while maintaining binary compatibility of applications written with earlier releases. In other words, using this function avoids compiling in the size of this structure, which may change. You declare only a pointer to this structure and then set it by calling XAllocSizeHints(). XAllocSizeHints() is used in the example program in Chapter 3.

XGetWMNormalHints() is normally used by the window manager to read the hints.

Additional Window Manager Hints - XA_WM_HINTS

The hints stored in the XA_WM_HINTS property provide an assortment of information to the window manager. Setting this property is required according to the ICCCM. Normally this is done by calling XSetWMProperties(). The XA_WM_HINTS property includes:

  • Whether the program sets the keyboard focus window independently or only when assigned by the window manager.

  • Whether the program desires to begin life as a window or as an icon.

  • A window to be used by the window manager as an icon, or a pixmap and mask to be used by the window manager to draw on an icon window it creates.

  • The initial position of the icon.

This property is normally set by the client with XSetWMProperties(). You should use the new XAllocWMHints() function to allocate an XWMHints structure, then set its fields, and then call XSetWMProperties(). An example doing this is shown in Chapter 3. The XWMHints structure is shown in Example 12-2.

Example 12-2. The XWMHints structure

typedef struct {
   long flags;             /* Marks defined members in structure */
   Bool input;             /* Does application need window
                            * manager for keyboard input */
   int initial_state;      /* See below */
   Pixmap icon_pixmap;     /* Pixmap to be used as icon */
   Window icon_window;     /* Window to be used as icon */
   int icon_x, icon_y;     /* Initial position of icon */
   Pixmap icon_mask;       /* Pixmap to be used as mask
                            * for icon_pixmap */
   XID window_group;       /* ID of related window group */
   /* This structure may be extended in the future */
} XWMHints;

The following sections describe each member of XWMHints and how it should be set.

Flags Field

The client must set the flags field to indicate which members of the XWMHints structure are to be read by the window manager. This is done by combining the symbols shown in Table 12-3 using bitwise OR (|).

Table 12-3. Flags for Window Manager Hints

Member

Flag

Bit

input

InputHint

0

initial_state

StateHint

1

icon_pixmap

IconPixmapHint

2

icon_window

IconWindowHint

3

icon_x, icon_y

IconPositionHint

4

icon_mask

IconMaskHint

5

window_group

WindowGroupHint

6

All of the above

AllHints

0-6


Input Field and the Keyboard Focus

The input member of XWMHints is used to communicate to the window manager the keyboard focus model used by the application. [51] For the input hint to be read by the window manager, the InputHint constant must be specified in the flags field of XWMHints.

There are four input models:

  • No Input. The client never expects keyboard input. An example would be xload or another output-only client.

  • Passive Input. The client expects keyboard input but never explicitly sets the keyboard focus. An example would be a simple client with no subwindows, which will accept input in PointerRoot mode, or when the window manager sets the keyboard focus to its top-level window (in click-to-type mode).

  • Locally Active Input. The client expects keyboard input and explicitly sets the keyboard focus but only does so when one of its windows already has the focus.

    An example of a Locally Active style client would be a client with subwindows defining various data entry members. Such an application might use Next and Prev keys to move the keyboard focus between the members, once its top-level window has acquired the focus in pointer-following mode or when the window manager sets the keyboard focus to its top-level window (in click-to-type mode).

  • Globally Active Input. The client expects keyboard input and explicitly sets the keyboard focus even when the focus is set to a window the client does not own. An example would be a client with a scrollbar that wants to allow users to scroll the window without disturbing the keyboard focus even if it is in some other window. The client wants to acquire the keyboard focus when the user clicks in the scrolled region, but not when the user clicks in the scrollbar itself, and then set the focus back to its original window. Thus, the client wants to prevent the window manager setting the keyboard focus to any of its windows.

Clients using the Globally Active and No Input models should set the input flag to False. Clients using the Passive and Locally Active models must set the input flag to True.


Note: If your application requires keyboard input and you neglect to set the input flag to True, you application will not get keyboard events under some window managers, such as olwm.

Under version 1 conventions, clients that use the Locally Active or Globally Active focus models must participate in one of the WM_PROTOCOLS called WM_TAKE_FOCUS, as described in “Window Manager Protocols - WM_PROTOCOLS”

Initial State Field

The initial_state member of XWMHints indicates to the window manager whether the application prefers to start off in iconified or normal state. initial_state specifies the state the client prefers to be in at the time the top-level window is mapped. The window manager does not reread this property so it is not useful for changing state after a window has been mapped. How to request a change of state is described in “Changing Application State” The initial_state flags are shown in Table 12-4.

Table 12-4. Initial State Hint Flags

Flag

Description

IconicState

Client wants to be iconified.

NormalState

Client wants top-level normal window visible.

When setting the initial_state member of XWMHints, you must OR the StateHint constant set into the flags member of XWMHints to indicate that the field is to be set.

Even though there is have no flag for an inactive state, a window manager might implement a concept of inactive state in which an infrequently used client's window would be represented as a string in a menu. But this state is invisible to the client, which would see itself merely as being in IconicState.

Icon Hints Fields

Under X, icons are by convention managed by the window manager, except that the client is allowed to provide a variety of pixmap patterns, names, and an icon window among which the window manager may pick and choose. The four members of XWMHints shown in Example 12-3 provide this information to the window manager.

Example 12-3. The icon hints elements of the XWMHints structure

typedef struct {
     .
     .
   Pixmap icon_pixmap;   /* Pixmap for icon */
   Pixmap icon_mask;     /* Pixmap to be used as mask for
                          * icon_pixmap */
   Window icon_window;   /* Window to be used as icon */
   int icon_x, icon_y;   /* Initial position of icon */
     .
     .
} XWMHints;

icon_pixmap is the pattern to be used to distinguish the icon from other clients. This pixmap should be:

  • One of the sizes specified in the XA_WM_ICON_SIZE property on the root, as described in “XA_WM_ICON_SIZE”

  • One bit deep. The window manager will select, through the resource database, suitable background (for the 0 bits) and foreground (for the 1 bits) colors. These resources can, of course, specify different colors for the icons of different clients.

The icon_mask is a one-bit-deep pixmap that determines which pixels in icon_pixmap are drawn on the icon window. This allows for icons that appear to be nonrectangular. Some window managers (including uwm) use the icon pixmap as a background tile for the icon window, a method which does not allow for the use of a mask.

icon_window is a window created but not mapped by the client. Clients that need to know their icon's ID or want to draw more than a simple two-color bitmap on the icon should set this hint. For example, xbiff and xmh change their icon pixmap when mail arrives, and they need to know their icon's ID to do this. Therefore, they must supply an icon window.

The icon_window hint should not be used unless needed. When it is not specified, the window manager creates the icon window itself.

You do not know which of the hints the window manager will honor. With current window managers, you can be confident that if icon_window is set, the window it names will be visible. If not, if icon_pixmap is set, the pixmap it names is visible. Otherwise, the window's XA_WM_ICON_NAME string is visible.

The conventions specify that the window manager must use the specified icon window. Therefore the application can read events from that icon window if desired.

An application that sets an icon_window is responsible for redrawing the window in case of Expose events. One way to set the icon design to be displayed is to set the background pixmap attribute of the icon window. The advantage of this approach is that there is no need to handle Expose events for the icon, because the background is automatically redrawn by the server. The disadvantage is that there is no way to apply a mask to generate a nonrectangular icon.

The icon window:

  • Must be an InputOutput child of the root window.

  • Should be one of the sizes specified in the XA_WM_ICON_SIZE property on the root (described in “XA_WM_ICON_SIZE”).

  • Must use the default visual and default colormap for the screen in question.

  • Should not be mapped, unmapped, or configured by the client.

  • Should not have the override_redirect window attribute set to True (should be left as the default).

The client must not:

  • Select ResizeRedirectMask on the icon.

  • Depend on being able to receive input events via their icon windows, although most window managers will allow some subset of key and button events through.

  • Manipulate the borders of their icon windows.

To summarize the client procedures regarding icons:

  • Use XSetWMIconName() to set a string in XA_WM_ICON_NAME. All clients should do this, since it provides a fallback for window managers whose ideas about icons differ widely from those of the client.

  • Set a pixmap into the icon_pixmap member of the XA_WM_HINTS property and possibly another into the icon_mask member. The window manager is expected to display the pixmap masked by the mask. The pixmap should be one of the sizes found in the XA_WM_ICON_SIZE property on the root. Window managers will normally clip or tile pixmaps which do not match XA_WM_ICON_SIZE.

Or:

  • Set a window into the icon_window member of the XA_WM_HINTS property. The window manager is expected to use that window instead of creating its own and to map that window whenever the client is in IconicState. In general, the size of the icon window should be one of those specified in XA_WM_ICON_SIZE on the root, if that property exists. Window managers may resize icon windows. If the client supplies an icon window, it is responsible for redrawing it when necessary.

Window Group Field

The window_group member of XWMHints lets the client specify that it has multiple top-level windows which should be iconified together or managed by the window manager as a group. For example, group leaders may have the full set of decorations and other group members a restricted set.

Applications with only one top-level window need not set this hint.

One of the top-level windows is known as the group leader. The window_group member of the hints for each of the other top-level windows should be set to the window ID of the group leader.

The group leader may be a window which exists only for that purpose and may never be mapped. Its window_group member should contain its own ID. The properties of the window group leader are those for the group as a whole (for example, the icon to be shown when the entire group is iconified). Every other top-level window may also have its own hints applicable only to itself.

Transient Window Field

All temporary subwindows of the root, such as pop-up menus and dialog boxes, should use XSetTransientForHint() to set the XA_WM_TRANSIENT_FOR property to the ID of the top-level window of the application that is creating the temporary window. This allows the window manager to process the temporary window accordingly (perhaps by decorating it differently than if it were a separate application). In particular, window managers will present newly mapped transient windows without requiring any user interaction, even if mapping top-level windows normally does require interaction.

It is important not to confuse XA_WM_TRANSIENT_FOR with the override_redirect window attribute. The override_redirect attribute specifies that the window manager does not get the chance to intercept the mapping request and thus no chance at all to decorate the window. This should be done only on the most temporary of windows, such as menus, or on windows that the programmer wants to be mapped without window manager intervention, such as automated demonstration programs. XA_WM_TRANSIENT_FOR should be used when other windows are allowed to be active while the transient window is visible, such as when the pointer is not grabbed while the window is popped up. If other windows must be frozen, use override_redirect and grab the pointer while the window is mapped.

Temporary windows that are popped up frequently should also set the save_under window attribute so that windows beneath the window may not need to redraw themselves quite so often.

To summarize, clients wishing to pop up a window should do one of three things:

  • They can create and map another normal top-level window, which will get decorated and managed as a separate client by the window manager. See the discussion of window groups in “Window Group Field”

  • If the window will be visible for a relatively short time and deserves a somewhat lighter treatment, they can set the XA_WM_TRANSIENT_FOR property. They can expect less decoration but should set all the normal window manager properties on the window. An example of an appropriate case would be a dialog box.

  • If the window will be visible for a very short time and should not be decorated at all, the client can set the override_redirect window attribute. In general, this should be done only if the pointer is grabbed while the window is mapped. The window manager will never interfere with these windows, which should be used with caution. An example of an appropriate use is a pop-up menu.

Application Class Name and Instance Name - XA_WM_CLASS

The XA_WM_CLASS property is a string containing two null-separated fields, res_class and res_name. res_class is meant to be used by the window manager to look up resources applicable to this application in the resource database. The window manager uses res_name for the titlebar of the window.

The application should normally specify res_class as the application name with an initial capital.

If the res_name field is NULL, then the following is used:

  1. If “-name NAME” is given on the command line, NAME is used as the instance name.

  2. Otherwise, if the environment variable RESOURCE_NAME is set, its value will be used as the instance name.

  3. Otherwise, argv[0] stripped of any directory names is used as the instance name.

Note that WM_CLASS strings, being null-terminated, differ from the general conventions that text properties are null-separated. This inconsistency is necessary for backwards compatibility.

An application should look up its own resources in the resource database using XGetDefault() or with the resource manager routines described in Chapter 13, “Managing User Preferences” If the user defaults are not found under res_name, the application should use res_class.

The XA_WM_CLASS property should only be written once and must be present when the window is mapped; window managers will ignore changes to it while the window is mapped.

The XA_WM_CLASS property contains a structure of type XClassHint. Example 12-4 shows the XClassHint structure.

Example 12-4. The XClassHint structure

typedef struct {
   char *res_name;
   char *res_class;
} XClassHint;


The XAllocClassHint() function should be used to allocate and zero the XClassHint structure. An example of doing this is presented in Chapter 3.

XA_WM_CLASS can be set by the client with XSetClassHint() and read by the window manager with XGetClassHint().

Standard Properties for Session Manager

A session manager is in charge of starting and stopping applications in a controlled manner, so that a session made up of several running applications can be halted and restarted in its original state. This is useful, for example, when the user wants to log out without having to start from scratch when logging back in.

Note that session managers are rare or nonexistent at the present time. Nonetheless, these conventions should be honored because it is only a matter of time before session managers become available. And the session manager does not necessarily need to be a separate client from the window manager. A window manager may have session-management capabilities.

There are two properties that need setting for the benefit of session managers, WM_COMMAND and WM_CLIENT_MACHINE. These supply the command and arguments needed to invoke an application in its current state and the machine on which it should be run. Together they supply enough information to restart the application. These are described in the following sections.

Application Command and Arguments

The XA_WM_COMMAND property stores the shell command and arguments used to invoke the application, separated by NULL characters.

Applications use XSetCommand() function to set the command property. Window managers use XGetCommand() to read it.

Clients should ensure, by resetting this property as often as necessary, that it always reflects a command that will restart them in their current state.

Client Machine

To restart a client, the session manager needs to know not only the command and arguments but also the machine on which the client was running. The application sets the WM_CLIENT_MACHINE property to contain this information, using XSetWMClientMachine().

This property should be set to a string forming the name of the machine running the client as seen from the machine running the server.

Optional Properties for Window and Session Manager

The client will need to set one or more of the following properties if it uses multiple colormaps, if it takes the keyboard focus, if it has data that must be saved before the session manager kills it, or if it has multiple top-level windows and it would like to survive when the user deletes one of them.

Using Created Colormaps - WM_COLORMAP_WINDOWS

An application should never install its own colormap. The window manager needs certain information from the application to be able to install colormaps at the appropriate times. An application that uses colormaps other than the default must do two things to make sure that the window manager knows which colormaps to install for each window:

  • Set the colormap window attribute of each window that is to use a colormap other than the default.

  • Set the WM_COLORMAP_WINDOWS property on the application's top-level window to tell the window manager which windows use colormaps different from the top-level window's colormap. In other words, you do not need to set WM_COLORMAP_WINDOWS unless your application uses more than one colormap.

The top-level window is always assumed to need its colormap installed. Applications set the WM_COLORMAP_WINDOWS property with XSetWMColormapWindows(), and the window manager reads it with XGetWMColormapWindows().

Window Manager Protocols - WM_PROTOCOLS

Setting the WM_PROTOCOLS property is optional. It is for applications that can benefit from being notified by the window manager or session manager of certain conditions.

The WM_PROTOCOLS property contains a list of atoms, each identifying a communication protocol between the application and the window manager in which the application wants to participate. Atoms can identify both standard protocols and private protocols specific to individual window managers. All the protocols in which a client can volunteer to take part involve the window manager sending the client a ClientMessage event. The message_type field of the event will be the atom for WM_PROTOCOLS, and the data field will contain the atom for one of the protocols listed in Table 12-5.

Table 12-5. Current Standard WM_PROTOCOLS

Protocol

Purpose

WM_TAKE_FOCUS

Assignment of keyboard focus.

WM_SAVE_YOURSELF

Save client state warning.

WM_DELETE_WINDOW

Request to delete top-level window.

More to come...

Note that none of the above properties are represented by predefined atoms. Therefore, you will need to call XInternAtom() once for each one that you intend to use.

An application sets the WM_PROTOCOLS property using XSetWMProtocols(), and the window or session manager reads it with XGetWMProtocols().

WM_TAKE_FOCUS

Applications that use the Locally Active and Globally Active focus models should specify that they want to participate in this protocol. Under both these focus models, the application explicitly sets the keyboard focus to one of its windows. Any application that does not set the keyboard focus to any of its windows does not need to participate in this protocol.

To applications that specify WM_TAKE_FOCUS, the window manager may send a ClientMessage event with the atom corresponding to WM_TAKE_FOCUS in their data[0] field. If the application wants the keyboard focus, it should respond by calling XSetInputFocus() with its window argument set to the window of theirs that last had the keyboard focus or to their default input window and with the time argument set to the timestamp in the message. The revert_to argument should be set to RevertToParent.

A client could receive WM_TAKE_FOCUS when opening from an icon or when the user has clicked outside the top-level window in an area that indicates to the window manager that it should assign the focus (for example, clicking in the headline bar can be used to assign the focus).

The goal of WM_TAKE_FOCUS is to support window managers that want to assign the keyboard focus to a top-level window in such a way that the top-level window can either assign it to one of its subwindows or decline the offer of the focus. A clock, for example, or a text editor with no currently open frames might not want to take focus even though the window manager generally believes that clients should take the keyboard focus after being deiconified or raised.

Clients that call XSetInputFocus() must set the time argument to the timestamp of the event that caused them to make the attempt. Note that this cannot be a FocusIn event, since they do not have timestamps, and that clients may acquire the focus without a corresponding EnterNotify. Clients must not use CurrentTime in the time field.

Clients using the Globally Active model can only use XSetInputFocus() to acquire the input focus when they do not already have it on receipt of one of the following events: ButtonPress, ButtonRelease, passive-grabbed KeyPress, and passive-grabbed KeyRelease.

In general, clients should avoid using passive-grabbed key events for this purpose except when they are unavoidable (as, for example, a selection tool that establishes a passive grab on the keys that cut, copy, or paste).

Clients that set the input focus should set the revert_to argument of the XSetInputFocus() request to the parent of the window that is to be the new focus window. This determines the behavior of the input focus if the window the focus has been set to becomes not viewable. All other settings lead to problems, as described in Appendix L, Interclient Communcation Conventions, of Volume Zero (as of the second printing).

Clients should not give up the input focus of their own volition. They should ignore input that they receive instead.

WM_SAVE_YOURSELF

This protocol is for applications that would like to be notified before the window or session manager terminates them, so that they can save their state and place themselves in a state from which they can be restarted. Such termination, from the application's perspective, would otherwise bypass all the application's internal safety measures (such as when an editor reminds you to save before exiting).

Applications that express interest in this protocol may receive a ClientMessage event the atom for WM_SAVE_YOURSELF in its data[0] field.

Clients receiving WM_SAVE_YOURSELF should place themselves in a state from which they can be restarted and should update XA_WM_COMMAND (by calling XSetCommand()) to be a command that will restart them in this state. The session manager will be waiting for a PropertyNotify event on XA_WM_COMMAND as a confirmation that the client has saved its state, so that XA_WM_COMMAND should be updated (perhaps with a zero-length append) even if its contents are correct. No interactions with the user are permitted during this process.

After receiving the WM_SAVE_YOURSELF message through the event, saving its state, and updating XA_WM_COMMAND, the client should not change its state (in the sense of doing anything that would require a change to XA_WM_COMMAND) until it receives a mouse or keyboard event. Once it does so, it can assume that the danger is over. The session manager will ensure that these events do not reach clients until the danger is over or until the clients have been killed.

Clients with multiple top-level windows should ensure that only one of their top-level windows has a nonzero-length XA_WM_COMMAND property. They should also respond to a WM_SAVE_YOURSELF message by (in this order):

  1. Updating the nonzero length XA_WM_COMMAND property if necessary.

  2. Updating the XA_WM_COMMAND property on the window for which they received the WM_SAVE_YOURSELF message if it was not updated in step 1.

WM_DELETE_WINDOW

This protocol prevents the possibility of an application with multiple top-level windows being terminated unexpectedly by the session manager. It should be selected by applications whose server connection must survive the deletion of some of their top-level windows. Clients which choose not to include WM_DELETE_WINDOW in the WM_PROTOCOLS property will be disconnected from the server if the user asks for one of the client's top-level windows to be deleted.

Once an application has expressed interest in this protocol, if one of the top-level windows is deleted, the application will receive a ClientMessage event whose data[0] field is the atom for WM_DELETE_WINDOW.

Clients receiving a WM_DELETE_WINDOW message should behave as if the user selected “delete window” from a (hypothetical) menu. They should perform any confirmation dialogue with the user, and if they decide to complete the deletion, either:

  • Change the window's state to Withdrawn (as described in “Changing Application State”) and release all associated state (backing store, for example), or

  • Destroy the window.

If the user aborts the deletion during the confirmation dialogue, the client should continue as if it never received the ClientMessage event that began the dialogue.

If the client aborts a destroy and the user then attempts to delete the window again, the window manager should start the WM_DELETE_WINDOW protocol again. Window managers should not use XDestroyWindow() on a window that has WM_DELETE_WINDOW in its WM_PROTOCOLS property.

Note that the WM_SAVE_YOURSELF and WM_DELETE_WINDOW protocols are orthogonal to each other and may be selected independently.

Properties Set by the Window Manager

The properties described above are those which the client is responsible for maintaining on its top-level windows. This section describes what the client can do with the properties that the window manager sets to give information to the client. There are currently two such properties. XA_WM_ICON_SIZE stores information about the sizes of icons that the window manager prefers. The application should use this information to create an icon pixmap or window of one of the right sizes.

The other property, WM_STATE, stores the current state (normal, iconic, or withdrawn) of the application. This is mostly for communication between the window manager and session manager but may also be used by some applications.

XA_WM_ICON_SIZE

The window manager may set the XA_WM_ICON_SIZE property on the root window to specify the icon sizes it allows. Clients should read this property using XGetIconSizes() and provide an icon window or pixmap of an appropriate size as part of the XWMHints described in “Icon Hints Fields” This property is an XIconSize structure shown in Example 12-5.

Example 12-5. The XIconSize structure

typedef struct {
   int min_width, min_height;
   int max_width, max_height;
   int width_inc, height_inc;
} XIconSize;

The width_inc and height_inc members define an arithmetic progression of sizes, from the minimum size to the maximum size, representing the supported icon sizes. XGetIconSizes() actually returns a list of these structures, in case the window manager needs more than one to specify all of its accepted icon sizes.

Some commercial window managers set this property. Clients should be prepared to create an icon pixmap to fit the hint of each of the standard window managers and can even use the hint to determine which window manager is in operation.

Window managers use XSetIconSize to set this property for clients.

XAllocIconSize() function should be used to allocate and zero the XIconSize structure.

WM_STATE

According to the ICCCM adopted as of Release 4, the window manager sets this property on top-level windows. The contents of this property is for communication between window managers and session managers. However, the existence of the property set on a window may be used to identify the top-level windows of other applications, for applications that need this information.

Xlib currently provides no routines for reading or writing this property, but of course, you can use XChangeProperty() or XGetWindowProperty().

This property does not have a predefined atom--to read or write this property you will need to call XInternAtom() to get the atom for this property.

Text Properties

There are functions to set and read text properties that support encodings suitable for non-Western languages.

You will need to convert strings into XTextProperty structures before you can call XSetWMProperties(), XGetWMClientMachine(), XGetWMIconName(), XGetWMName(), XSetWMClientMachine(), XSetWMIconName(), or XSetWMName().

These routines use the XTextProperty structure, which contains enough information to read and write the property in any format (8-bit, 16-bit, or 32-bit). The XTextProperty structure is shown in Example 12-6.

Example 12-6. The XTextProperty structure

typedef struct {
    unsigned char *value;   /* Property data */
    Atom encoding;          /* Type of property */
    int format;             /* 8, 16, or 32 */
    unsigned long nitems;   /* Number of items in value */
} XTextProperty;

You need to set the fields in two copies of this structure before calling XSetWMProperties(), in order to set the window name and icon name properties, as was done in basicwin in Chapter 3, “Basic Window Program” There are two ways to do this: one is to set the fields directly one at a time, and the other is to use XStringListToTextProperty(). The latter is easier and better, because it does not require hardcoding the format or encoding. See Example 3-9 for a demonstration of how to do this.

Four more routines are provided to manipulate the XTextProperty structure:

XTextPropertyToStringList() 

Creates a list of strings from an XTextProperty structure. This is used internally by XGetCommand()--it is useful for reading properties composed of multiple strings. This is rarely used in normal application code.

XFreeStringList() 

Frees memory allocated by XTextPropertyToStringList().

XSetTextProperty() 

Convenience routine for XChangeProperty() that sets a property according to the information in an XTextProperty structure.

XGetTextProperty() 

Convenience routine for XGetWindowProperty() that reads a property into an XTextProperty structure. This helps because XGetWindowProperty() is complicated.

Constraints on Client Actions

The window manager is allowed to change the border width, color, or pattern of an application's top-level window's border (usually to indicate which window has the keyboard focus), so this window must be an InputOutput window. This also means that the application should not try to use the border to indicate any application state.

The client may receive notification that its window has been reparented, moved, resized, raised, or lowered or that its border width has been changed by selecting StructureNotifyMask on its top-level window. It should not respond to these events by trying to change any of these characteristics, however.

Changing Application State

Some applications may need to tell the window manager that they wish to be iconified, deiconified, or taken completely off the screen. There are right and wrong ways to do this.

An application can call XIconifyWindow() to have one of its top-level windows iconified. This function sends a ClientMessage event to the window manager, telling it to iconify this application. There is no equivalent routine to have the window manager return the application to normal state.

It is also possible to tell the window manager to unmap both the top-level window and its icon. This is done by calling XWithdrawWindow(). This is useful because the window manager rereads all the standard properties when the window returns from withdrawn to normal state.[52]

There is no routine to tell the window manager to change a withdrawn application back into normal state. The technique under version 1 conventions is for client to set the initial_state field of the XWMHints structure to NormalState, then call XSetWMHints() to reset this property, and then map the top-level window.

To change from withdrawn state to iconic state, the application should follow the same procedure but set the initial_state field to IconicState.

To change from iconic state to normal state, the client needs only to map the window--it need not reset the property.

If a client selects StructureNotifyMask on the top-level window, it will receive an UnmapNotify event when it moves to iconic state and a MapNotify when it moves to normal state.

Clients can also select VisibilityChangeMask on their top-level or icon windows. They will then receive a VisibilityNotify event (with the state field set to VisibilityFullyObscured) when the window concerned becomes completely obscured even though mapped (and thus perhaps a waste of time to update) and a VisibilityNotify event (with state field not set to VisibilityFullyObscured) when it becomes even partly viewable.

Reconfiguring the Top-level Window

Clients can resize, reposition, and restack their top-level windows using XReconfigureWMWindow(). This routine is the same as XConfigureWindow(), except that it takes care of an error condition possible when running under a reparenting window manager. XReconfigureWMWindow() lets you specify a sibling window relative to which your top-level window should be stacked, and this will work even if the window manager has reparented your top-level window so that what once was a sibling is no longer a sibling.

Even when the client is not attempting to change the stacking order, the entire reconfigure request is sent by the server to the window manager for approval, and the window manager has the opportunity to honor, modify, or deny the request. The client finds out the window manager's decision through ConfigureNotify events.

Most applications do not need to specify or even suggest the position of their top-level windows. However, when doing so, the position the client specifies should be relative to the root window regardless of reparenting.

Client requests to reconfigure the top-level window are interpreted by the window manager in the same manner as the initial window geometry mapped from withdrawn state. There is no guarantee that the window manager will allocate the requested size or location, and clients must be prepared to deal with any size and location.

The window manager has several options in deciding how to respond to a request by the application to reconfigure a top-level window:

  • Not changing the size or location of the window at all, a client will receive a synthetic ConfigureNotify event describing the (unchanged) state of the window. The (x,y) coordinates will be in the root coordinate system, adjusted for the border width the client requested, irrespective of any reparenting that has taken place. The border_width will be the border width the client requested. The client will not receive a real ConfigureNotify, since no change has actually taken place.

  • Moving the window without resizing it, a client will receive a synthetic ConfigureNotify event following the move describing the new state of the window, whose (x,y) coordinates will be in the root coordinate system adjusted for the border width the client requested. The border_width will be the border width the client requested. The client may not receive a real ConfigureNotify event describing this change, since the window manager may have reparented the top-level window. If it does receive a real event, the synthetic event will follow the real one.

  • Resizing the window (whether or not it is moved), a client which has selected StructureNotifyMask will receive a ConfigureNotify event. Note that the coordinates in this event are relative to the parent, which may not be the root if the window has been reparented, and will reflect the actual border width of the window, which the window manager may have changed. XTranslateCoordinates() can be used to convert the coordinates if required.

The general rule is that coordinates in real ConfigureNotify events are in the parent's space, whereas in synthetic events, they are in the root space.

Clients should be aware that their borders may not be visible. Most window managers use reparenting techniques to decorate client's top-level windows with titles, controls, and other details. Ones that do are likely to override the client's attempts to set the border width and set it to zero. Clients should, therefore, not depend on the top-level window's border being visible nor use it to display any critical information. Other window managers will allow the top-level windows' borders to be visible.

Clients should ignore the above field of all ConfigureNotify events that they receive on their top-level windows, since they cannot be guaranteed to contain useful information.

Selections

Selections are the primary mechanism X11 defines for clients that want to exchange information with other clients. A selection transfers arbitrary information between two clients. You can think of a selection as a piece of text or graphics that is highlighted in one application and can be pasted into another, though the information transferred can be almost anything. Clients are strongly encouraged to use this mechanism so that there is a uniform procedure in use by all applications.

The user may want to transfer information from an application and, at other times, to the application. Many applications need to be able to assume either role. In particular, clients should not display text in a permanent window without allowing the user to select it and convert it into a string, and any application that requires the user to type extensively should allow the user to paste in text from other applications.

Selections communicate between an owner client and a requestor client. The owner has the data representing the value of a selection, and the requestor wants it. The selection mechanism provides a way to notify other clients when useful data is placed in a property and to allow the owner of the data to convert it to a type asked for by the requestor.

Note that in the X11 environment, all data transferred between clients must go via the server (unless they are running on the same host, but that is a special case). An X11 client can neither assume that another client can open the same files nor communicate directly through IPC channels. The other client may be talking to the server via a completely different networking mechanism (for example, one client might be DECnet and the other TCP/IP). Thus, passing indirect references to data such as file names, hostnames, port numbers, and so on is permitted only if both clients specifically agree.

The Selection Mechanism

Let's look how a typical selection transaction occurs and then go into all the details of how to make it happen. From the user's point of view, it works like this:

  1. The user highlights a selection of text or graphics in one application. For example, in xterm, selections are highlighted with the foreground and background colors reversed.

  2. The user moves the pointer into another application and presses the key or button that indicates that the selection should be pasted. The keys or buttons used for this purpose in all applications probably should be the ones used by xterm, since most users use the cutting and pasting feature of xterm frequently.

The desired result is that the text or graphics should appear in the application in which it was pasted. Now how do two applications actually make this happen?

The application in which the text or graphics is being selected must first of all figure out what information is being selected and be able to convert it into a format that can be transferred to other applications. If the selection is text (usually the selection is a string) and the selected area is highlighted, by having the user drag the pointer over the area, then this application has to become the owner of a selection atom.

There are two built-in selection atoms: XA_PRIMARY and XA_SECONDARY. Unless the client foresees needing two simultaneous selections, it should use XA_PRIMARY. It calls XSetSelectionOwner(), specifying the selection atom, any window that it created (this window is used by other applications to identify the owner), and the time. The time used should be from the event that triggered the bid to own the selection (not CurrentTime) because of race conditions that can otherwise occur. If the client does not already own the selection atom, then this call will generate a SelectionClear event for the old owner, telling it to unhighlight the old selection.

Each client that wants to be able to have a selection pasted into it must set aside a key or button combination to indicate that the user wishes to paste in the current selection. In response to the event that occurs when that key or button combination is pressed, the client calls XConvertSelection(). This call specifies which selection the application wants (XA_PRIMARY until other conventions are established), the property to place the data in, the window on which to set this property, and the time. These arguments are quite clear. But the XConvertSelection() call also specifies a target type that the application wants the data in. You need to understand what happens after the XConvertSelection() call to understand the purpose of the target type property.

The server places all the arguments of the XConvertSelection() call into an XSelectionRequestEvent and sends the event to the selection owner. The owner then tries to convert the selection data into the format specified in the target type property. If the selection owner knows how to convert the data into the requested type, it puts the data in the property specified in the event and returns the atom of this property in the property member of a SelectionNotify event. If the selection owner cannot convert the selection into the requested type, it returns None as the property member in the SelectionNotify event. The owner sends this SelectionNotify event using XSendEvent().

When the requestor receives the SelectionNotify event, it either reads the property if it is set, repeats the request with a different target type if the owner returned None, or gives up on pasting data from that selection owner. It could be that the user is trying to do something like paste graphics into a text-only application.

Now you should understand the selection mechanism in general, so let's look at a more tangible example of how it takes place.

An Example of Selection

Let's say a text editor is the owner of the selection XA_PRIMARY. The user is editing a C program and debugging the same C program in another window. The user would like to select a line in the source code and instruct the debugger to stop at that same line without having to type in the line number. Perhaps the debugger would have a button labeled “stop at,” which, when pressed, would tell the debugger to request a value for the primary selection. The text editor would allow the user to select text on a line and would be able to convert that selection into a string if it were pasted into another text editor or into a line number if it were pasted into the debugger. Which type the text editor would choose would depend on the target type of the selection request.

Assuming the text editor already uses the selection mechanism to transfer text to other applications, adding the line number capability should be easy. It would simply need to look for a new target type that indicated to it to figure out what line number the selected text is on. It might choose the first line, if more than one line were selected, or simply display an error message telling the user to select a single line.

The debugger application would then make the call shown in Example 12-7.

Example 12-7. Setting the primary selection to a line number

Display display;
Atom target;
Window debugger_window;
Time time;
Bool only_if_exists;
Atom data_prop;
/* We create atom for data to be put into */
data_prop = XInternAtom(display, "STOP_LINE_NUM",
      only_if_exists = False);
/* Target type atom must have been created by owner */
target_type = XInternAtom(display, "LINE_NUMBER",
      only_if_exists = True);
if (target_type == None) {
   fprintf(stderr, "%s: selection owner did not create \
         LINE_NUMBER atom", argv[0]);
   return(False);
}
XConvertSelection(display, XA_PRIMARY, target_type,
      data_prop, debugger_window, time = triggering_event_time)
/* Wait for a SelectionNotify event and, if the property
 * member is the same as data_prop, the conversion went fine;
 * if the property member is None, the conversion failed */


The server sends all of the above information in a SelectionRequest event to the text editor client (which had previously made itself the owner of the selection with XSetSelectionOwner()).

The text editor stores the data in the property specified in the SelectionRequest event on debugger_window, then sends a SelectionNotify event (using XSendEvent()) to the requesting application. Upon receiving this event, the debugger reads this property and uses its value to place a break point in the C program.

Now that you have seen a more practical application of selections, we'll move on to a more precise description of each step in the selection transfer process.

Acquiring Selection Ownership

When the user decides to select something in an application, the application needs to become the selection owner. Being the selection owner means that when any other application requests the value of the selection with XConvertSelection(), the owner gets the resulting XSelectionRequest event. The transfer of selection ownership also makes sure that only one application at a time is attempting to set the properties. The previous application to call XSetSelectionOwner(), if it was another application, receives a SelectionClear event, which indicates to it that it should clear any area it has highlighted.

Note that if the time in the XSetSelectionOwner() request is in the future relative to the server's current time or if it is in the past relative to the last time the selection concerned changed hands, the XSetSelectionOwner() request appears to the client to succeed, but ownership is not actually transferred. To ensure that ownership has been transferred, a client must perform the sequence shown in Example 12-8.

Example 12-8. Code to ensure transfer of selection ownership

XSetSelectionOwner(display, selection_atom, owner, time);
if (XGetSelectionOwner(display, selection_atom) != owner) {
    /* We didn't get the selection */
}

If XGetSelectionOwner() returns a window ID rather than None, then the selection ownership was successfully transferred.

Responsibilities of the Selection Owner

When a requestor wants the value of a selection, the owner receives a SelectionRequest event. Example 12-9 shows the XSelectionRequestEvent structure.

Example 12-9. The XSelectionRequestEvent structure

typedef struct {
   int type;
   unsigned long serial;   /* # of last request processed by
                            * server */
   Bool send_event;        /* True if this came from SendEvent
                            * request */
   Display *display;       /* Display the event was read from */
   Window owner;
   Window requestor;
   Atom selection;
   Atom target;
   Atom property;
   Time time;
} XSelectionRequestEvent;


The owner and the selection members will be the values specified in the XSetSelectionOwner() request, and therefore, the selection owner is interested in them only if it owns more than one selection.

The owner should convert the selection into the type specified by the target member and set the property specified by the property member of the SelectionRequest event. Current conventions hold that all properties used to reply to SelectionRequest events should be placed on the requestor window. If the data comprising the selection cannot be stored on the requestor window (for example, because the server cannot provide sufficient memory), the owner must refuse the selection request as above.

The owner should also send the requestor a SelectionNotify event using XSendEvent() with an event_mask of 0. The members of the SelectionNotify event should be set to the same values received in the SelectionRequest event, except that if the selection could not be converted to the requested type, the property member should be set to None. Example 12-10 shows the XSelectionEvent structure which is used for SelectionNotify events.

Example 12-10. The XSelectionEvent structure

typedef struct {
   int type;
   unsigned long serial;   /* # of last request processed by
                            * server */
   Bool send_event;        /* True if this came from SendEvent
                            * request */
   Display *display;       /* Display the event was read from */
   Window requestor;
   Atom selection;
   Atom target;
   Atom property;          /* Atom or None */
   Time time;
} XSelectionEvent;


The selection, target, and property members should be set to the values received in the SelectionRequest event. Setting the property member to None indicates that the conversion requested could not be made.

The data stored in the property must eventually be deleted. According to the current conventions, selection requestors are responsible for deleting the converted properties whose names they receive in SelectionNotify events. Owners are responsible for deleting all other properties involved in communicating selections.

A selection owner may need confirmation that the data comprising the selection has actually been transferred. They should express interest in PropertyNotify events for the requestor window and wait until the property in the SelectionNotify event has been deleted before assuming that the selection data has been transferred.

Giving Up Selection Ownership

When some other client becomes the owner of a particular selection, the previous owner receives a SelectionClear event. The XSelectionClearEvent structure is shown in Example 12-11.

Example 12-11. The XSelectionClearEvent structure

typedef struct {
   int type;
   unsigned long serial;   /* # of last request processed by
                            * server */
   Bool send_event;        /* True if from a SendEvent request */
   Display *display;       /* Display the event was read from */
   Window window;
   Atom selection;
   Time time;
} XSelectionClearEvent;


The time member is the time at which the ownership changed hands, and the owner member is the window the new owner specified in its XSetSelectionOwner() request.

If an owner loses ownership while it has a transfer in progress, that is to say before it receives notification that the requestor has received all the data, it must continue to service the ongoing transfer to completion.

To relinquish ownership of a selection voluntarily, a client should execute a XSetSelectionOwner() call for that selection atom, with owner specified as None and time specified as CurrentTime. Alternatively, the client may destroy the window used as the owner argument of the XSetSelectionOwner() call, or it may exit. In both cases, the ownership of the selection involved will revert to None.

Requesting a Selection

A client wishing to obtain the value of a selection in a particular form issues an XConvertSelection() call. The arguments of the call are three atoms, a window, and the time. The first atom is the selection, usually XA_PRIMARY. The second atom is the target type, the type in which the requestor wants the data. The conventions will specify a standard list of target type atoms. The third atom specifies the property that the owner should set to the converted data. The window argument is the window on which the property containing the data is to be set. The time member should be set to the timestamp on the event triggering the request for the selection value. Note that the requestor of a selection does not need to know the owner of the selection or the window it specified in the XSetSelectionOwner() call.

The client that calls XConvertSelection() call will get a SelectionNotify event sent to it from the selection owner. The requestor, selection, time, and target arguments of this event will be the same as those on the XConvertSelection() request.

If the property member is None, the conversion has been refused. This can mean that there is no owner for the selection, that the owner does not support the conversion implied by target, or that the server did not have sufficient space to accommodate the data.

If the property member is not None, then that property will exist on the requestor window. The value of the selection can be retrieved from this property using XGetWindowProperty(). When using XGetWindowProperty() to retrieve the value of a selection, the property argument should be set to the property member in the SelectionNotify event. The type member should be set to AnyPropertyType, because the requestor has no way of knowing beforehand what type the selection owner will use.

The property in the SelectionNotify should be deleted by invoking XGetWindowProperty() with the delete argument set to True. As discussed above, the owner has no way of knowing when the data has been transferred to the requestor unless the property is removed.

Large Data Transfers

Selections can get large, and this poses two problems:

  • Transferring large amounts of data to the server is expensive, and it would be beneficial to be able to reuse the data once it has been sent to answer further XConvertSelection() requests.

  • All servers will have limits on the amount of data that can be stored in a single property. Exceeding this limit will result in a BadAlloc error on the XChangeProperty() call that the selection owner uses to store the data.

The proposed conventions for dealing with these problems are given in Appendix L, Interclient Communcation Conventions, of Volume Zero (as of the second printing).

More on Selection Properties and Types

A given selection has a type associated with it. Built-in property types that might apply to selections are XA_BITMAP, XA_CARDINAL, XA_INTEGER, XA_PIXMAP, XA_POINT, XA_RECTANGLE, and XA_STRING. Other types that clients could define might be XA_FILE_NAME or XA_PICTURE (a sequence of graphics primitives to reproduce a picture--the Macintosh uses this type of selection to cut and paste graphics into text applications and vice versa).

It is important to observe that defining a new atom consumes resources in the server, and they are not released until the server reinitializes. Thus, it must be a goal to reduce the need for newly minted atoms.

The selection named by XA_PRIMARY is used for all commands which take only a single argument. It is the principal means of communication between clients which use the selection mechanism.

It is suggested that the selection named by XA_SECONDARY be used:

  • As the second argument to commands taking two arguments. For example, it might be used when exchanging the primary and secondary selections.

  • As a means of obtaining data when there is a primary selection, and the user does not wish to disturb it.

The CLIPBOARD selection can be used to hold deleted data (it has no predefined atom). There is a client called xclipboard that will display the contents of the CLIPBOARD, even if the client where the data was selected has already been killed.

Target Atoms

The atom that a requestor supplies as the target argument of XConvertSelection() determines the form of the data supplied. The set of such atoms is extensible, but a generally accepted base set of target atoms is needed. The set specified in the conventions is shown in Appendix L, Interclient Communcation Conventions, of Volume Zero (as of the second printing). However, some types are already predefined properties, and these can safely be used.

Target properties describe types of data. They contain the C language types of the structures that are used for many of the Xlib functions. The predefined target atoms are shown in Table 12-6.

Table 12-6. Predefined Target Type Atoms

Type Atom

C Language Type

XA_ARC

XArc

XA_POINT

XPoint

XA_ATOM

Atom

XA_RGB_COLOR_MAP

Atom (standard colormap)

XA_BITMAP

Pixmap (of depth 1)

XA_RECTANGLE

XRectangle

XA_CARDINAL

int (dimensionless)

XA_STRING

char *

XA_COLORMAP

Colormap

XA_VISUALID

VisualID

XA_CURSOR

Cursor

XA_WINDOW

Window

XA_DRAWABLE

Drawable

XA_WM_HINTS

XWMHints

XA_FONT

Font

XA_INTEGER

int

XA_WM_SIZE_HINTS

XSizeHints

XA_PIXMAP

Pixmap

The owner should not translate the selection into some arbitrary fallback target type (such as XA_STRING) and return the fallback target to the requestor in the SelectionNotify event, because this might confuse the requestor. The conversion should simply fail. The requestor then has the option of requesting another type. The requestor can supply the target TARGETS to get a list of target types the owner supports.

Cut Buffers

Cut buffers are provided as a simple but limited method of communication between applications. Cut buffers are particularly good for editors, because they can act like a stack of buffers, recording the history of deletions.

The selection mechanism is superior for many applications, since it allows communication regarding the type of the data transferred. Selections are described in “Selections” It is also possible for an application to use both cut buffers and selections.

The cut buffers are eight properties on the root window of screen 0 of a server. The buffers are numbered 0 to 7. Cut buffers rely on a prior agreement between the two clients regarding the format of the data to be placed in the cut buffers. The data that can be placed in a single cut buffer is limited to the maximum size of a single property, which is server-dependent.

Because the cut buffers are properties, it is possible to be notified when they have been written into. PropertyNotify events can assist applications in timing their communication. These are selected with PropertyChangeMask.

The functions that are used to read and write to cut buffers are XFetchBuffer(), XFetchBytes(), XStoreBuffer(), and XStoreBytes(). The routines with Bytes in the name use cut buffer 0 only, while the others may use any of the eight. XRotateBuffers() moves the contents of the eight buffers any number of positions.

The cut buffer properties are named by the predefined atoms XA_CUT_BUFFER0 to XA_CUT_BUFFER7.

The cut buffers can let applications implement a first-in, last-out stack of data. A client using this cut buffer mechanism must initially ensure that all eight buffer properties exist, using XChangeProperty() to append zero-length data to each. A client storing data in the cut buffers (an owner) must first rotate the ring of buffers by +1, using XRotateWindowProperties to rename XA_CUT_BUFFER0 to XA_CUT_BUFFER1 to .... to XA_CUT_BUFFER7 to XA_CUT_BUFFER0. It must then store the data into XA_CUT_BUFFER0, using XStoreBytes().

A client obtaining data from the cut buffers should use XFetchBytes() to retrieve the contents of XA_CUT_BUFFER0.

A client may, in response to a specific user request, rotate the cut buffers by -1, using XRotateWindowProperties to rename XA_CUT_BUFFER7 to XA_CUT_BUFFER6 .... and so on and XA_CUT_BUFFER0 to XA_CUT_BUFFER7.

Data should be stored to the cut buffers and the ring rotated only when requested by explicit user action. Users depend on their mental model of cut buffer operation and need to be able to identify operations that transfer data to and from the buffers.

Note that there is nothing magic about the properties used by Xlib's cut buffer routines or those routines themselves. If an application needs more buffers, it can intern additional atoms for CUT_BUFFER8 and so on and write its own equivalent of XStoreBuffer() and XFetchBuffer() that can write and read these properties.



[49] Applications that create their own colormap are the only ones that will not be able to run without a window manager if they honor the conventions, because the window manager is responsible for installing the colormap.

[50] The pop-up menu is the only type of top-level window that does not need to have XA_WM_NORMAL_HINTS set for it. Instead, the override_redirect window attribute should be set to True.

[51] To remind you, the keyboard focus is the window to which keyboard events go, sometimes ignoring the pointer position. When the pointer is outside the keyboard focus window, all keyboard events are delivered to that window. When the pointer is inside the keyboard focus window or any of its descendants, keyboard events are delivered to the window containing the pointer.

[52] Remember that resetting a property with a complex structure such as XA_WM_HINTS or XA_WM_NORMAL_HINTS redefines all members in that property. You must reset all fields, even those which you are not changing since the last time you set the property.