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.
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.
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 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.
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.
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()).
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.
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.
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,
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:
| ||
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.
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 |
These are the kind of transparencies that a visual supports. |
The following are the constructors and destructors for the VkCutPaste class:
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&)
This section describes the VkVisual's public 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:
| |||||
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() | 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() |
| |||||
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. |
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:
| |
statusString() | virtual const char *statusString(status status) const Prints, to stderr, the string equivalent to the passed enum value. | |
transparencyString() |
Prints, to stderr, the string equivalent to the passed enum value. | |
visualClassString() |
Prints, to stderr, the string equivalent to the passed value (“Pseudocolor”, and so on). |
visualParent() |
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() |
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. |
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.