Chapter 9. Handling Visuals With ViewKit

This chapter describes the VkVisual class, a convenience class for dealing with X11 visuals. For ideas on how to use this class, see the examples in the usr/share/src/ViewKit/Basic/Visual directory.

Overview of the VkVisual Class

Dealing with the interaction between widgets and X11 visuals can be complicated (see “Overview of X Visuals” for more information). Programmers often decide to stick with the default visual when another visual would be more appropriate. Code, even library code, that assumes default visual attributes is commonplace.

The VkVisual class is designed to handle many of the confusing details so you can use the most appropriate visual for your needs. Of course, since VkVisual simplifies the model, applications that have more complex needs must still use direct Xlib or OpenGL calls. For most situations, however, VkVisual will be sufficient.

With VkVisual, it is easy to do such things as

  • obtain an existing widget's full visual information

  • obtain information about the default visual

  • pick the best visual for a Shell or for an entire application by describing its semantic characteristics (for instance, getting the “deepest overlay visual”)

  • deal with actual visuals, default or non-default, in a consistent and robust way that works across different kinds of hardware

  • obtain a suitable window for use when creating a graphics context (GC) or a pixmap

The VkVisual class itself deals with global issues, such as

  • associating a single colormap with a single visual

  • coordinating X11 visual information with that provided by the root window's SERVER_OVERLAY_VISUALS property

Each VkVisual instance deals with all of the information pertinent to a single visual. You can set up a visual as any of the following:

  • a caller-defined visual

  • the same visual a specific widget is using

  • the same visual a specific ViewKit component is using

  • the default visual

The visual information can also be reset to a new visual (using setVisual()), but all old visual information is then lost. If an application still needs both sets of visual information, it should create a second VkVisual object instead of resetting the first one.

Information such as the colormap or the read-only ArgList are created as needed. Any such information is cached, and reused as appropriate.

Overview of X Visuals

This section explains some basic points about X, Xt, and X11 visuals. It is important to understand this information if you are going to put all or part of your application's graphical user interface in a non-default visual.

X11 Visual Attributes

X11 does not attach any semantic meaning to a visual. For example, there is no concept of an overlay visual. There is, however, a semi-standard convention that has been adopted by workstation vendors:

  • A visual's level is the framebuffer level with which the visual is associated. This is a hardware-related term having nothing to do with X Window stacking order.

  • Levels less than zero refer to underlays.

  • Level zero refers to the normal planes. The default visual is generally, but not necessarily, in the normal planes.

  • Levels greater than zero refer to overlay planes.

  • Each X11 visual is associated with exactly one level.

  • Each level can be associated with more than one visual.

  • SERVER_OVERLAY_VISUALS is a property on the root window, relating each X11 visual to its level.

An X11 window has several attributes that need to be consistent when the window is created. If an application sets these values inconsistently, or if it allows an inconsistent value to be inherited, the X server will return a fatal BadMatch error.

  • XCreateWindow(3X) must be passed a consistent visual and depth.

  • The following fields in the XSetWindowAttributes structure passed to XCreateWindow(3X) must be consistent with the visual and depth:

    • Background pixmap— must be NULL or of the stated depth.

    • Background pixel—used if the background pixmap is NULL. The pixel value must not exceed the colormap size.

    • Border pixmap—must be NULL or of the stated depth.

    • Border pixel— used if the border pixmap is NULL. The pixel value must not exceed the colormap size.

    • Colormap—must match the visual.

You cannot change the depth and visual after the window is created, but you can change the XSetWindowAttributes values.

Xt Visual Handling

In order to achieve the required consistency in visual attributes when dealing with widgets in non-default visuals, there are several factors you have to keep in mind:

  • Widget access to the popup or overlay bitplanes is by means of non-default X11 visuals on a Silicon Graphics workstation.

  • A gadget does not have any visual resources of its own, because it draws into its parent's window.

  • Each widget class, because it is derived from the Core class, has borderPixmap, borderColor, colormap, and depth attributes. Each widget instance inherits the values of these attributes from its parent widget.

  • Shell and its subclasses are the only standard widgets that have an XmNvisual resource (and hence an X11 visual) directly associated with them. (However, there can be special widgets, such as the SgVisualDrawingArea widget [<Sgm/VisualDrawingA.h>], that have an associated X11 visual. Such special widgets are not common.)

  • Most widgets do not have a visual resource, so they must inherit their visual. If a widget does not have an XmNvisual resource, you cannot explicitly set its visual at creation time. To put these widgets into a non-default visual, their widget parent must be in a non-default visual.

  • Any widget that does not have a visual resource explicitly set at creation time inherits its visual from its parent window.

  • For all widgets other than Shell widgets, the parent window is the parent widget's window. This results in inheriting a consistent set of values.

  • For Shell widgets, the parent window is the root window. Thus, if the parent widget uses a visual different from the root window's visual, you must explicitly set at least some of the Shell's visual resources. If you do not, an X server BadMatch fatal error will occur.

Visual Inheritance in ViewKit

To avoid mismatches, ViewKit explicitly sets the visual information for all new Shell widgets it creates. This includes all menus and dialogs. Shell visual attributes are set in the following ways:

  • If visual information is passed in by the application, that information is used.

  • If the widget is a menu, and useOverlayMenus is set, an appropriate visual is chosen.

  • If the widget is a dialog, and useOverlayDialogs is set, an appropriate visual is chosen.

  • If none of the above apply, ViewKit sets the Shell (that is, menu or dialog) to the widget parent's visual.

The net effect is that you will not need to worry about visual inheritance in most of your ViewKit applications.

It is possible to place the top shell (VkApp's unrealized shell) in a non-default visual. Because of the inheritance described above, this effectively resets the visual for the rest of the application (see VkApp(3x), useOverlayApps() and preRealizeFunction()).

Maintaining Consistency

In order to maintain consistency when using visuals, there are several points you should keep in mind:

  • Visual consistency issues are especially important when creating Shell widgets, but they are also important at other times. For example, you cannot use a pixmap or a GC at a depth other than the one for which it was created.

  • Colormaps and pixel values need to be kept consistent. In general, the same pixel will not be the same color in the various colormaps. Be sure you use the correct pixel value for the current colormap.

  • Avoid the BlackPixel and WhitePixel macros, because they return pixel values suitable for use only with the normal planes colormap. For example, BlackPixel returns a pixel that is black in the colormap for the normal planes, but is generally transparent in the overlay colormaps.

  • Pixel values determined using the default colormap should not be used with another colormap. If the pixel exists at all, you are likely to get the wrong color. If the pixel does not exist (such as when you try to apply a pixel greater than 3 to a 2-bit overlay colormap), an X protocol error will occur.

  • Colormaps belonging to widgets in one of the overlay visuals may well be smaller than the default colormap, and pixel 0 may well be transparent.

  • Some hardware has a 2-bit level 1 visual, a 2-bit level 2 visual, and a 4-bit level 1 visual that are not entirely independent. The two-bit colormaps are independent, but they may overlap with the 4-bit colormap. The framebuffer pixels of the 4-bit visual may overlap with those of the 2- bit visuals. On such hardware, using the 4-bit visual is discouraged.

Colormap Coordination

There is no such thing as a system default colormap for any visual other than the default visual. If a VkVisual instance refers to the default visual, it automatically uses the default colormap. The first VkVisual instance that refers to each non-default visual creates a suitable colormap for that visual. Subsequent VkVisual instances that refer to the same visual re-use the colormap that the first instance created. This effectively establishes default colormaps for a single application. There is currently no supported way for multiple independent applications to cooperate on using a common colormap.

An application is guaranteed to have its colormaps installed only when it has colormap focus. Consequently, there may be colormap flashing. When an application gets colormap focus, all of the colormaps the application has declared are installed (whether or not it actually needs them). Each of these colormaps remains until another application needs to have it replaced. Any of your application's windows that use a conflicting colormap will not return to correct colors until your application next gets colormap focus.

Override widgets (menus and dialogs) are responsible for installing their own colormaps. Such widgets do not have their colormaps installed unless the application gets colormap focus and specifically installs the colormaps. ViewKit arranges automatic installation of any needed colormaps for the menu and dialog widgets it creates. If you create any directly, you must call XSetWMColormapWindows() yourself.

Failure to destroy colormaps that VkVisual creates causes colormap leakage in the X server. Fortunately, from a practical point of view, most applications do not need to be concerned with this, for the following reasons:

  • All created colormaps are deleted when the application terminates. Unless a lot of colormaps are being created, this should be adequate.

  • VkVisual reuses colormaps. Unless the application sets forceNewColormap or uses setColormap(), there will be at most one colormap for each visual used. This is normally few enough that they can be ignored until they are destroyed when the application terminates.

  • Any VkVisual that is constructed by passing it a widget uses the colormap from that widget. Such a colormap should not be explicitly destroyed.

Useful Enums

The VkVisual class provides some useful enums:

enum colors 

enum colors {MAX_AVAILABLE_COLORS}

Using this for the number of colors in the constructor, or in a setVisual() call, means that the deepest visual that otherwise satisfies the request criteria is considered a match.

enum index 

enum index {RESET, FIRST, NEXT, LAST}

You can pass this to VkVisualInfo(int) when using it to iterate over the visuals list.

enum planes 

enum planes {NORMAL_LEVEL, OVERLAY_LEVEL, UNDERLAY_LEVEL,

             MAX_OVERLAY_LEVEL, MIN_OVERLAY_LEVEL,
             MAX_UNDERLAY_LEVEL, MIN_UNDERLAY_LEVEL,
             ANY_LEVEL}
 

This specifies which level bit planes are being requested. These constants do not conflict with any legitimate specific level. Calls to the constructor, or to setVisual(), can specify either the explicit level required or one of these enum values:

  • NORMAL_LEVEL—The normal planes.

  • OVERLAY_LEVEL—Any overlay planes.

  • UNDERLAY_LEVEL—Any underlay planes.

  • MAX_OVERLAY_LEVEL—Highest available overlay level.

  • MIN_OVERLAY_LEVEL—Lowest available overlay level.

  • MAX_UNDERLAY_LEVEL—Underlay level closest to zero.

  • MIN_UNDERLAY_LEVEL—Underlay level furthest from zero.

  • ANY_LEVEL—Does not matter which level.

enum status 

enum status {FAILURE, SUCCESS, ALMOST}

These are the values that setVisual() can return. It is up to an application to notice that it did not receive SUCCESS, and make appropriate adjustments, if necessary.

  • SUCCESS —The visual found is exactly what was requested.

  • ALMOST—The visual found is likely to be close enough. It is up to the application to query the attributes to see whether they are acceptable.

  • FAILURE—There was a serious problem, such as setVisual() could not get the right visual class. This generally means that the default visual had to be assigned.

setVisual() returns the lowest status found in processing any of the parameters. If anything failed, setVisual() returns FAILURE. If nothing failed, but something was ALMOST, then setVisual() returns ALMOST. setVisual() returns SUCCESS only if everything succeeded.

enum transparency 


enum transparency {TRANSPARENT_NONE,

                   TRANSPARENT_PIXEL,
                   TRANSPARENT_MASK,
                   TRANSPARENT_DONT_CARE}
 

These are the kind of transparencies that a visual supports.

VkVisual Constructors and Destructor

The following are the constructors and destructors for the VkCutPaste class:

  • VkVisual (Widget w = NULL,

              Boolean forceNewCmap = FALSE) 
     
    

  • VkVisual (const VkComponent *component,

              Boolean forceNewCmap = FALSE) 
    

  • VkVisual (int visualClass,

              int level = NORMAL_LEVEL, 
              int colors = MAX_AVAILABLE_COLORS, 
              CARD32 xparentRequested = TRANSPARENT_DONT_CARE, 
              Boolean forceNewCmap = FALSE) 
    

  • VkVisual (const VkVisual&)

     
    

  • VkVisual &operator = (const VkVisual&)

     
    

  • virtual ~VkVisual()

Member Functions

This section describes the VkVisual's public functions.

Setting the Class's Visual Information

setColormap()  


virtual Colormap setColormap (Colormap cmap = NULL,

                             Boolean setDefault = FALSE)
 

Makes any colormap you pass in the object's current colormap. If you do not pass in a colormap, setColormap() creates a new, empty one that matches the current visual.

If setDefault is TRUE, setColormap() sets the new colormap as the default one for the visual associated with this VkVisual instance.

setColormap() returns the now-current colormap.


Note: setColormap() never frees a colormap because it has no way of knowing whether that colormap is still needed. Each time you call setColormap(), it overwrites the address of the previous map. It is up to your application to free any previous colormap before you call setColormap(). If you still need the previous colormap, you should make sure you have the address recorded. You can obtain the address by calling colormap().


setVisual() 

This function is overloaded to allow you to set visuals several different ways:

  • virtual void setVisual (Widget w = NULL,

                            Boolean forceNewCmap = FALSE)
     
    

    Resets the VkVisual to the visual of the widget or gadget w. If no widget or gadget is passed in, then setVisual() sets the VkVisual to the default visual.

    If forceNewCmap is TRUE, setVisual() creates a new, empty colormap. Otherwise, setVisual() reuses an existing colormap for this visual, if one is available. Unless you know you need a new colormap, you should leave forceNewCmap FALSE.

  • virtual void setVisual (const VkComponent *component,

                            Boolean forceNewCmap = FALSE)
     
    

    Resets the current instance of VkVisual to the visual used by component->baseWidget().

    If forceNewCmap is TRUE, setVisual() creates a new, empty colormap. Otherwise, setVisual() reuses an existing colormap for this visual, if one is available. Unless you know you need a new colormap, you should leave forceNewCmap FALSE.

  • virtual VkVisual::status setVisual (int visualClass,

                               int level,
                               int colors,
                               CARD32 transparent,
                               Boolean forceNewCmap = FALSE)
     
    

    Resets the instance's visual to be as close to the specified calling parameters as possible. This version always sets some visual; if there is no better match, it sets the default visual.

    visualClass must be one of the constants from <X11/X.h>, StaticGray, GrayScale, StaticColor, PseudoColor, TrueColor, or DirectColor. If the application asks for a class not supported by the current screen, setVisual() returns FAILURE and provides the default visual.

    level specifies the type of plane you want. setVisual() always tries to give you the type of visual you request (for instance, a specific level, overlay planes, underlay planes, or normal planes). setVisual() goes by the following rules:

    If level is one of the enum constants, that level is used.

    If level is a legal explicit level, it is used directly.

    If level is greater than the maximum level, then the maximum level is used.

    If level is less than the minimum level, then the minimum level is used.

    If the requested plane or planes exist for the specified visual class, setVisual() returns SUCCESS.

    If the requested plane has no visual of the requested class, but there is a normal planes visual of the requested class, then the normal planes visual is used and setVisual() returns ALMOST.

    If none of the above apply, setVisual() sets the instance's default visual, and returns FAILURE.

Data Access Functions

argCnt() 

virtual int argCnt() const

Returns the number of visual arguments in the ArgList returned by argList().

argList() 

The overloaded versions of this function are as follows:

  • virtual ArgList argList() const

    Returns the pointer to a read-only ArgList suitable for using in Xt calls such as these:

         VkVisual vis(parent);
         XtSetValues(w, vis.argList(), vis.argCnt());
    

  • virtual void argList(Arg *args, Cardinal *offset) const

    Appends the visual arguments to the ArgList, args, and increments the count, offset, by the number of arguments it appended.

  • inline void argList(Arg *args, int *offset) const

    Works the same as the previous version, except that it takes an int* for offset instead of a Cardinal*.

className() 

const char *className(void) const

Returns the class name of VkVisual, which is “VkVisual”.

colormap() 

virtual Colormap colormap() const

Returns the colormap associated with this instance of the VkVisual class. If there is no colormap, an empty, sharable one is created.

colormapCreated() 


virtual Boolean colormapCreated() const

Returns TRUE if the current colormap was created by VkVisual. This can be used by the application to tell whether or not the colormap should be destroyed when no longer needed.

depth() 

virtual int depth() const

Returns the depth associated with this instance's visual.

maxLevel() 

virtual int maxLevel() const

Returns the maximum framebuffer level for the current screen.

minLevel() 

virtual int minLevel() const

Returns the minimum framebuffer level for the current screen.

numColors() 

virtual int numColors() const

Returns the number of colors in the colormap associated with this instance's visual.

visual() 

virtual Visual *visual() const

Returns this instance's visual.

visualID() 

virtual VisualID visualID() const

Returns the visual ID of this instance's visual.

vkVisualInfo() 


The overloaded versions of this function are as follows:

  • virtual const
    VkVisualInfo *vkVisualInfo(VisualID vid) const

     
    

    Returns a pointer to the VkVisualInfo structure associated with the specified visual.

  • virtual const
    VkVisualInfo *vkVisualInfo(Visual *
    vis = NULL) const

     
    

    Returns a pointer to the VkVisualInfo structure associated with the specified visual. If vis is NULL, the current visual is used.

  • virtual const
    VkVisualInfo *vkVisualInfo(const Widget
    w) const

     
    

    Returns a pointer to the VkVisualInfo structure associated with the widget's visual.

  • virtual const
    VkVisualInfo *vkVisualInfo(int
    index) const

     
    

    Returns a pointer to one of the VkVisualInfo structures from the global list maintained by VkVisual. Possible arguments are:

    An integer from 0 to the number of available visuals.

    RESET—Resets the global record so that a call to VkVisualInfo(NEXT) will return a pointer to the first structure. Returns NULL.

    FIRST—Returns a pointer to the first structure.

    NEXT—Returns a pointer to the first structure beyond the previously retrieved one, regardless of how it was retrieved. If the previously retrieved structure was the last structure, a RESET is done and a NULL pointer is returned. The next VkVisualInfo(NEXT) call will then return a pointer to the first structure.

window() 

virtual Window window() const

Returns some window associated with this instance's visual. There is no guarantee as to which window you will get back, even if you used the VkVisual(widget) constructor. Typical use of this window is as a parameter to create a GC or to call the Xpm pixmaps routines (which derive visual information from the window they are passed).

        

If VkApp's window is associated with this instance's visual, VkApp's window are returned, regardless of what other windows are also associated with the visual. If the root window is associated with this instance's visual, the root window is returned. For any other X11 visual, a matching new InputOutput unmapped window is created the first time a window is needed for that particular visual. Windows are reused later as necessary. Separate VkVisual instances return the same window if the instances are for the same X11 visual.

        

Because a window may be re-used, it is important that the application not delete it.

Debugging Functions

indexString() 

virtual const char *indexString(index index) const

Prints, to stderr, the string equivalent to the passed enum value.

planesString() 

virtual const char *planesString(planes plane) const

Prints, to stderr, the string equivalent to the passed enum value.

printAll() 

virtual void printAll() const

Prints, to stderr, a variety of details about the visuals of the current display.

print() 

These are the overloaded versions of this function:

  • virtual void print() const

    Prints, to stderr, the visual information from the VkVisual instance.

  • virtual void print(const Widget w) const

    Prints, to stderr, the visual information matching the widget w.

  • virtual void print(const VkVisualInfo *vis) const

    Prints, to stderr, the visual information from vis.

  • virtual void print (VisualID vid) const

    Prints, to stderr, the visual information from the specified visual.

  • virtual void print (const Visual *vis) const

    Prints, to stderr, the visual information from the specified visual.

  • virtual void print (int index) const

    Prints, to stderr, the visual information from VkVisualInfo(index).

statusString() 

virtual const char *statusString(status status) const

Prints, to stderr, the string equivalent to the passed enum value.

transparencyString() 


virtual const
char *transparencyString(transparency
trans) const

Prints, to stderr, the string equivalent to the passed enum value.

visualClassString() 


virtual const char *visualClassString(int visClass) const

Prints, to stderr, the string equivalent to the passed value (“Pseudocolor”, and so on).

Static Functions

visualParent()  


static Widget visualParent(Widget w, Visual **v)

Returns the first widget in the widget tree (w or an ancestor of w), that has a visual attribute. Normally, this widget is a subclass of Shell, but it could be an SgVisualDrawingArea or any other widget that has a XmNvisual resource.

visualParentArgs() 


static void visualParentArgs(Widget parent, Arg *args, int *cnt)

Retrieves a set of visual resources consistent with the parent widget. The resources are copied into args and cnt is updated. All visual resources except XmNvisual are copied from the parent. XmNvisual is copied from the visual parent of parent.

VkVisual Examples

Example 9-1 and Example 9-2 illustrate how easy it is to deal with visuals using the VkVisual class:

Example 9-1. Putting a Single Widget in a Non-default Visual Using VkVisual

Widget p;                       // Parent widget
char *c = “Questions”;          // Widget's name
...
VkVisual vis(p);                // Get the visual info
XmCreateQuestionDialog(p, c, vis.argList(), vis.argCnt());
...

 

Example 9-2. Creating a GC of the Right Depth

Display *dpy;
VkVisual vis(widget);
...
XCreateGC(dpy, vis.window(),...);

Putting your entire application into a non-default visual is only a little more complicated. See “Putting Applications in the Overlay Planes” for more details.