Chapter 3. Using Schemes
Prev | Part I. Getting the Right Look and Feel | Next

## Chapter 3. Using Schemes

Schemes provide an easy way to apply a collection of resources to your application. The scheme mechanism allows your users to select from pre-packaged collections of colors and fonts that are designed to integrate visually with the IRIX Interactive Desktop and other applications. “Schemes for Colors and Fonts” in Chapter 3 in IRIX Interactive User Interface Guidelines describes the guidelines for using schemes in the IRIX Interactive Desktop environment.

This chapter contains the following sections:

- “Schemes Overview” provides an overview to schemes.

- “Using Schemes in Your Application” describes what you need to do to use schemes in your application.

- “Extending a Scheme to Support New Colors” provides tips for testing how your application responds to different schemes.

- “Creating New Schemes” describes how to create new schemes.

- “Hard-Coding a Scheme for an Application” describes how to force your application to use one specific scheme.

## Schemes Overview

Schemes allow you to provide default colors and fonts for your application, while also ensuring that users can easily select other color and font collections according to their individual needs and preferences. SGI includes some standard system schemes with the X execution environment, but end users can modify existing schemes or create new ones, and you can create new schemes or extend existing ones for use with your application.

This section provides an overview of schemes and explains why you should use schemes in your application.

### Why You Should Use Schemes

As a developer, it is impossible for you to choose colors and fonts for your application that satisfy all users. Aside from the consideration of individual taste, display characteristics vary and some users have various degrees of colorblindness. Schemes allow users to select colors and fonts according to their preferences and needs.

Although users can already use the X resource mechanism to customize colors and fonts, it is very difficult and time-consuming for most end users to do so, because the task requires knowledge of the internal structure of the program. On the other hand, if your application supports schemes, users can use the graphical Schemes Browser, `schemebr` (available from the “Color Schemes” option of the Customize menu in Desktop toolchest), to change colors and fonts.

Using schemes also reduces the time and effort required to develop your application. Instead of choosing your own colors and fonts and coding them into your application, you can simply set a resource value to activate schemes and get the distinctive IRIX Interactive Desktop appearance.

### Basic Scheme Concepts

A scheme simply maps specific colors and fonts to abstract resource names according to the functions they serve in an application. So instead of using specific colors like “blue” or “#123456” and specific fonts like “-*-screen-medium-r-normal--13-*-*-*-*-*-iso8859-1,” your application can use symbolic values like TextForeground, TextSelectedColor, and FixedWidthFont. The exact definition of these symbolic values depends on the scheme the user chooses to apply to your application. As long as your application uses the symbolic color and font names for the purposes for which they were intended, users or graphic designers can design a new palette (a binding of the symbolic values to specific colors) and the result should look good with your application.

Often, you do not even need to deal with the symbolic colors and fonts yourself. The schemes mechanism includes a map file that automatically binds the symbolic values to the various IRIS IM widgets and widget resources. One case where you may need to set a color or font explicitly is if you need to highlight a component (for example, in a chart). The schemes mechanism defines special symbolic values such as HighlightColor1 through HighlightColor8 for these purposes. (See “Directly Accessing Colors and Fonts” for more information on the symbolic values.) Another case where you need to be aware of the symbolic values is if you need to extend a scheme for your application. (See “Extending a Scheme to Support New Colors” for more information on extending a scheme.)

## Using Schemes in Your Application

This section describes how to write your application for use with schemes and includes:

- “Turning on Schemes for Your Application”

- “Special Considerations for Programming with Schemes”

- “Assigning Non-Default Colors and Fonts to Widgets”

- “Directly Accessing Colors and Fonts”

### Turning on Schemes for Your Application

SGI incorporates schemes in its implementation of Xt, so you do not need to link to a separate schemes library or call a special function to use schemes. All you need to do to enable schemes is to include in your application's `app-defaults` file (in the `/usr/lib/X11/app-defaults` directory) the line:

    AppClass*useSchemes:     all

AppClass is your application's class name. This activates all aspects of schemes.

| Note: To ensure that users do not accidently override your settings, be sure to prefix the useSchemes resource with your application's class name.

To deactivate schemes, you can set:

    AppClass*useSchemes: none

If you wish to activate schemes without using an `app-defaults` file, or if you want to guarantee that the schemes setting cannot be changed by users, call the function `SgiUseScheme()`:

    void SgiUseScheme(char *value)

value can be either “all” or “none.” This function requires that you include the header file `<X11/SGIScheme.h>`.

For example:

    /* schemes.c                           */
    /* cc -o schemes schemes.c -lXm -lXt    */

    #include <Xm/Label.h>
    #include <X11/SGIScheme.h>

    void main(int argc, char** argv)
    {
       Widget toplevel, label;
       XtAppContext app_context;

       SgiUseSchemes(“all”);

       toplevel = XtAppInitialize(&app_context, “Hello”,
                             NULL, 0, &argc, argv, NULL, NULL, 0);

       label = XmCreateLabel(toplevel, “hello”, NULL, 0);
       XtManageChild(label);

       XtRealizeWidget(toplevel);
       XtAppMainLoop(app_context);
    }

### Special Considerations for Programming with Schemes

The schemes map file automatically handles applying colors and fonts to most IRIS IM widgets based on the widgets' class names. Unfortunately, IRIS IM does not have unique class names for menu bars, menu panes, and option menus. To allow schemes to be applied to these elements, your application should use some simple naming conventions for these widgets. Name all menu bars “menuBar,” all option menus “optionMenu,” and the pane of all option menus “optionPane.” Schemes also recognize some other variations of these names, including “menu_bar,” “menubar,” “menu_Bar,” and so on.

If you need to set a color or a font in your application, use the procedures described in “Assigning Non-Default Colors and Fonts to Widgets” and “Directly Accessing Colors and Fonts”. Do not hard code colors or fonts in your application because they may not work with the scheme that a user selects. For example, if you programmatically set a text color to black and a user chooses a scheme that has a very dark background, your text is unreadable. Also avoid setting colors that IRIS IM normally computes. For example, if you hard code the top or bottom shadow colors used by IRIS IM controls, these colors may not be correct if a user changes the scheme.

There are obviously some cases for which this recommendation does not apply. The most common are windows in which you are rendering images. For example, if your application uses OpenGL or some other library to render an image in a window, the colors used in this window are not derived from schemes.

Fonts are usually less critical than colors, although the best visual effects are produced if you use only the fonts defined in the schemes. You should be aware that on high-resolution screens, the sizes of the fonts defined by schemes can change. Therefore, you should design the layout of your application to handle variable-sized fonts. This means you should not hard-code x, y locations or fixed widths or heights for widgets in your application. Instead use IRIS IM manager widgets such as the Form to achieve a flexible layout that can respond to changes in font sizes.

### Assigning Non-Default Colors and Fonts to Widgets

Sometimes, you may want to override the default color or font assigned to a widget by a scheme. For example, all labels are set by default to use a bold font (BoldLabelFont); however you may decide that a regular font (PlainLabelFont) is more appropriate for some of your application's labels.

To assign a non-default font or color to a widget, include a line in your application's `app-defaults` file mapping a different symbolic scheme resource to that widget. For example, the following line assigns a regular label font (rather than the default bold font) to a label in your application named “simpleLabel”:

    YourApp*simpleLabel*fontList: SGI_DYNAMIC PlainLabelFont

The symbol SGI_DYNAMIC identifies this resource as a dynamically changeable scheme resource. The actual font assigned to PlainLabelFont can potentially be different in each scheme. As the user changes schemes, the correct resource is applied to your program.

| Note: Remember to prefix the widget hierarchy with your application's class name to prevent users from accidentally overriding your setting.

You can use the same technique with colors. For example, suppose you have two types of label widgets positioned on an IRIS IM XmDrawingArea widget and you want to use color to give some significance to different labels. Perhaps the application is some type of a flowchart and some of the labels represent tasks in progress, while other represent tasks that have been completed. The schemes map file already maps the symbolic scheme resource DrawingAreaColor to the XmDrawingArea widget. The scheme palette also provides colors that both provide a nice contrast against the DrawingAreaColor and allow the current TextForeground color to be readable. These colors are DrawingAreaContrast1, DrawingAreaContrast2, DrawingAreaContrast3, and DrawingAreaContrast4. To specify the colors of each label widget in your application, you can set the following resources:

    YourApp*label1*background: SGI_DYNAMIC DrawingAreaContrast1
    YourApp*label2*background: SGI_DYNAMIC DrawingAreaContrast1
    YourApp*label3*background: SGI_DYNAMIC DrawingAreaContrast2
    ...

Each scheme also contains a set of basic colors that you can use for simple graphics, icons, and so on. These colors maintain their basic characteristics, but change slightly from scheme to scheme to blend with the general flavor of the scheme. For example, you can set a label widget to be “red” as follows:

    YourApp*label*background: SGI_DYNAMIC RedColor

The exact shade of red changes from scheme to scheme, but always is “reddish” and always fits with the other colors in the scheme.

If necessary, you can also use non-scheme colors and fonts, although SGI strongly recommends that you do not do this. If you hard-code a color, the user may select a scheme in which that color does not provide the contrast you desire. The color can even be “lost” among the other scheme colors. Non-scheme fonts are less likely to cause problems, but your application will have an inconsistent appearance if it uses them.

You use the same methods to assign a non-scheme color or font that you normally would in an X program. For example, you can set a font for a label named “simpleLabel” in your `app-defaults` file as follows:

    YourApp*simpleLabel*fontList: 6x12

### Directly Accessing Colors and Fonts

When your application uses widgets only, the schemes map file automatically retrieves all colors and fonts from the current scheme and assigns them to your application's widgets. However, you may need to access some of the scheme's colors or fonts directly from within a program. For example, you may want to draw a bar chart or other display using colors that look good no matter what scheme the user has selected.

Example 3-1 shows an example of a function that retrieves a color value given a widget, the color resource name, and the color resource class.

Example 3-1. Retrieving a Scheme Color Value

    Pixel getColorResource(Widget w, char *name, char *classname)
    {

        XtResource request_resources;
        Display *dpy  = XtDisplay ( w );
        int      scr  = DefaultScreen ( dpy );
        Colormap cmap = DefaultColormap ( dpy, scr );
        XColor   color, ignore;
        char    *colorname;

        request_resources.resource_name   = (char *) name;
        request_resources.resource_class  = (char *) className;
        request_resources.resource_type   = XmRString;
        request_resources.resource_size   = sizeof (char *);
        request_resources.default_type    = XmRImmediate;
        request_resources.resource_offset = 0;
        request_resources.default_addr    = (XtPointer) NULL;

        XtGetSubresources(w,
                          (XtPointer) &colorname,
                          NULL, NULL,
                          &requested_resources,
                          1, NULL, 0);

        if ( colorname &&
             XAllocNamedColor ( dpy, cmap, colorname, &color,
                                &ignore ) )
            return ( color.pixel );
        else
            return ( BlackPixel ( dpy, scr ) );
    }

You can then retrieve the color defined by the scheme resource drawingAreaContrastColor1 using `getColorResource()` as follows:

    color1 = getColorResource(barChartWidget,
                              "drawingAreaContrastColor1",
                              XmCForeground);

where barChartWidget is the widget that you will use the color in.

| Tip: There is a simple method for retrieving a resource value if you are using the IRIS ViewKit toolkit. Instead of writing the `getColorResource()` function listed in Example 3-1, you can call:

    Pixel color1 = (Pixel) VkGetResource( barChartWidget,
                                "drawingAreaContrastColor1",
                                 XmCForeground, XmRPixel,
                                "Black" );

You must handle some resources programmatically. For example, the IRIX Interactive User Interface Guidelines suggests that your application use a different color for text fields that are not editable than it uses for editable text fields. The IRIS IM text widget currently does not change colors automatically when set to read only mode; so your application must handle this itself. The correct color is provided by schemes as the symbolic name ReadOnlyBackground, and can be retrieved by the resource readOnlyBackground. Assuming that you've created the `getColorResource()` function listed in Example 3-1, the following code illustrates this process:

    ro = getColorResource( textw,  "readOnlyBackground",
                           XmCForeground);
    XtVaSetValues( textw, XmNeditable, FALSE,
                   XmNbackgroundColor, ro,
                   NULL);

| Tip: The equivalent IRIS ViewKit code would be:

    Pixel ro = (Pixel) VkGetResource( textw, "readOnlyBackground",
                                      XmCForeground, XmRPixel,
                                      "White" );
    XtVaSetValues( textw, XmNeditable, FALSE,
                   XmNbackgroundColor, ro,
                   NULL);

### Pre-Defined Scheme Resources and Symbolic Values

Table 3-1 lists the pre-defined scheme resources and symbolic values. You can use the resources to retrieve color and font values from within your application as described in “Directly Accessing Colors and Fonts”. You can use the symbolic values to assign colors and fonts to widgets in resource files as explained in “Assigning Non-Default Colors and Fonts to Widgets”.

Table 3-1. Pre-Defined Scheme Resources and Symbolic Values

Resource | Symbolic Value | Intended Use
--- | --- | ---
basicBackground | BasicBackground | Background of application
textForeground | TextForeground | Color of text characters
textBackground | TextBackground | Background of multi-line text widgets
textFieldBackground | TextFieldBackground | Background of single-line text field widgets
readOnlyBackground | ReadOnlyBackground | Background of read-only text and text field widgets
textSelectedBackground | TextSelectedBackground | Background when text is selected with the mouse
textSelectedForeground | TextSelectedForeground | Color of text characters when text is selected with the mouse
disabledTextForeground | DisabledTextForeground | For future use, this color will indicate disabled text instead of stippling.
scrolledListBackground | ScrolledListBackground | Background of scrolled list widgets
scrollBarTroughColor | ScrollBarTroughColor | Trough of scrollbar
scrollBarControlBackground | ScrollBarControlBackground | Scrollbar controls (thumb, searchbutton)
buttonBackground | ButtonBackground | Background of push buttons
selectFillColor | SelectFillColor | Fill color for standard IRIS IM radio and toggle buttons
selectColor | SelectFillColor | IRIS IM toggle and check fill color
checkColor | CheckColor | IRIX Interactive Desktop toggle check mark color
radioColor | RadioColor | IRIX Interactive Desktop radio pip color
indicatorBackground | IndicatorBackground | IRIX Interactive Desktop background color for toggles and radios
warningColor | WarningColor | Background color for icons in warning dialogs
errorColor | ErrorColor | Background color for icons in error dialogs
informationColor | InformationColor | Background color for icons in information dialogs
wMBackground | WMBackground | Window manager colors. Note that `4Dwm` currently does not pick up foreground. “Active” colors are used for window manager borders with mouse focus.
wMActiveBackground | WMActiveBackground |
wMForeground | WMForeground |
wMActiveForeground | WMActiveForeground |
alternateBackground1 | AlternateBackground1 | Can be used as background color for widgets or text areas. Guaranteed to be different from one another, contrast with basic background and text background, and can have text drawn on them.
alternateBackground2 | AlternateBackground2 |
alternateBackground3 | AlternateBackground3 |
alternateBackground4 | AlternateBackground4 |
alternateBackground5 | AlternateBackground5 |
alternateBackground6 | AlternateBackground6 |
drawingAreaBackground | DrawingAreaBackground | Background of drawing area widgets (typically used for graphs)
drawingAreaContrastColor1 | DrawingAreaContrastColor1 | Contrast colors for drawing areas (typically used for graphs and trees). These colors are guaranteed to be different from one another, different from the drawing area background, and can have text drawn on them
drawingAreaContrastColor2 | DrawingAreaContrastColor2 |
drawingAreaContrastColor3 | DrawingAreaContrastColor3 |
drawingAreaContrastColor4 | DrawingAreaContrastColor4 |
highlightColor1 | HighlightColor1 | Bright highlights suitable for small color spots. The first four are supposed to be in the same hue family as the corresponding DrawingAreaContrast colors so that the pair may be used for doing highlights in an annotated scrollbar. These colors are typically used for outlining and drawing graphs, wherever a small amount of color needs to be highly visible.
highlightColor2 | HighlightColor2 |
highlightColor3 | HighlightColor3 |
highlightColor4 | HighlightColor4 |
highlightColor5 | HighlightColor5 |
highlightColor6 | HighlightColor6 |
highlightColor7 | HighlightColor7 |
highlightColor8 | HighlightColor8 |
redColor | RedColor | Colors that can be used for various graphics purposes. These colors always approximate their names, but may be slightly adjusted to blend with each scheme. Typically used in graphs and charts.
orangeColor | OrangeColor |
yellowColor | YellowColor |
greenColor | GreenColor |
blueColor | BlueColor |
brownColor | BrownColor |
purpleColor | PurpleColor |
boldLabelFont | BoldLabelFont | Bold labels, such as column headings
smallBoldLabelFont | SmallBoldLabelFont | Labels for tight packing situations
tinyBoldLabelFont | TinyBoldLabelFont | Labels where space is at a premium
plainLabelFont | PlainLabelFont | Button labels, also can be used for values in “Name: Value” pairs
smallPlainLabelFont | SmallPlainLabelFont | Small buttons
obliqueLabelFont | ObliqueLabelFont | Menus
smallObliqueLabelFont | SmallObliqueLabelFont | Small menus
fixedWidthFont | FixedWidthFont | Text areas where fixed width is mandatory, for example where it's important that columns line up
smallFixedWidthFont | SmallFixedWidthFont | Text where a fixed-width font is appropriate but space is at a premium

## Extending a Scheme to Support New Colors

SGI strongly recommends that you use existing scheme colors for your application. Using the existing scheme colors ensures that your application will work with all schemes. However, you may need to add colors in some basic cases.This section explains how to extend Schemes to support new colors when necessary.

To extend a scheme, you create new symbolic values for the resources you need and then define bindings between these values and resources that your application can retrieve. This section describes the internal organization of scheme files and then describes how to define these symbolic values and mappings.

### Scheme File Organization

All system scheme files are kept in the directory `/usr/lib/X11/schemes` by default. This directory contains several subdirectories, one for each scheme. The directory `Base` serves as the basis of all schemes, although it is not a user-identifiable scheme itself. `Base` contains at least three files: `Base`, `BaseColorPalette`, and `FontPalette`. You may see other files as well.

Each of the palette files (`BaseColorPalette` and `FontPalette`) contain `cpp`-style definitions of symbolic names that represent colors and fonts. The `Base` file (referred to as a map file) contains the default mappings between these symbolic names and specific resources, using the same format as all X resource files.

For example, the `Base` file contains a line like:

    *XmText*foreground: TextForeground

This says that all Text widgets should use the color represented by TextForeground as their foreground color. By default, all schemes share the mappings specified in this `Base` file. However, the value assigned to each symbolic name can vary from scheme to scheme. For example the Mendocino scheme defines TextForeground to be #fffffe (white) whereas the Milan scheme defines TextForeground to be #000000 (black). The scheme mechanism evaluates these specifications at run time, based on the scheme specified by the user.

By default, all applications pick up the definitions in the `Base` file and the palette files from the selected scheme. However, applications can load additional scheme files as well.

### How to Extend a Scheme

There are two methods for extending a scheme. The first is to add additional mappings between existing colors and widgets in your application. This may be necessary if you want to bind colors of fonts to your widgets in a different way, or if you are using custom widgets that are not handled by the basic scheme mappings. You should do this by adding resources to your application's `app-defaults` file, using the SGI_DYNAMIC mechanism described earlier.

The second situation occurs when you would like to use colors or fonts that are not provided as a part of the existing schemes. Your should try to avoid this situation when at all possible, because users can use the scheme editor to create new schemes, and there is no current mechanism for using the scheme editor to adjust any additional colors your application may define. The standard scheme palettes contain over 40 colors, which should be enough for most situations.

To add new colors to the existing schemes, you need to create a new palette file that contains `cpp`-style definitions of those colors. To get your application to load this new palette, you then need to set a resource, paletteFileList, in your application's `app-defaults` files that specifies as a comma-separated list all custom palette files to be loaded.

For example, assume you have an application whose class name is Calendar and that you need two colors that you refer to in your program symbolically as brightColor and darkColor. If no color in the exiting schemes satisfies your requirements for this color, you will need to extend a scheme. Here are the steps you'd follow:

1. Define the colors in a palette file. By convention, you should name this file `<AppClass>Palette`, where `<AppClass>` is the application class of your application. In this case, you would name the palette `CalendarPalette`. It would contain the lines:

       #define BrightColor red
       #define DarkColor MidnightBlue

   You can use any color names available on your target systems, as well as RGB specifications. If the resources you are using are dependent on the gamma setting, you should account for this in the palette file. You can handle the commonly used gamma settings like this:

       #ifdef GAMMA_1_0
       #define BrightColor <color that looks right on 1.0 gamma>
       #define DarkColor <color that looks right on 1.0 gamma>
       #endif
       #ifdef GAMMA_1_7
       #define BrightColor <color that looks right on 1.7 gamma>
       #define DarkColor <color that looks right on 1.7 gamma>
       #endif
       #ifdef GAMMA_2_4
       #define BrightColor <color that looks right on 2.4 gamma>
       #define DarkColor <color that looks right on 2.4 gamma>
       #endif

   The scheme mechanism handles gamma other than those listed here by finding the closest match.

2. Create additional palette files as needed. If your new resources need to change values when a scheme changes, create a file named `CalendarPalette` for each scheme you want to support. For each scheme, choose the colors that look right for that scheme. Note that if you do not support all existing schemes, the values of your new scheme resources defaults to the values in Base; so your application may not look right when a user selects that scheme.

3. Set your application's paletteFileList resource to load the new palettes. In this example, you would add the following line to your `app-defaults` file:

       Calendar*schemeFilePaletteList: CalendarPalette

4. When you install your software on a user's machine, you need to install the executable, the `app-defaults` file, and any other files specific to your application. You must also install your palette files into the directory of each scheme you support. You should, at a minimum, support the schemes found in `/usr/lib/X11/schemes`. You may also want to support schemes you find installed in `/usr/local/schemes`.

## Testing Your Application with Schemes

For best results, be sure to test your application against all available schemes, and watch for any anomalies. As an added precaution, you can try using the Scheme Browser, `schemebr` (available from the “Color Schemes” option of the Customize menu in Desktop toolchest), to create some variations on existing schemes and see how your program reacts. If you have not added any resources and are not setting any colors or fonts in your program or `app-defaults` files, any scheme should be reasonable. If you have extended the schemes or set colors directly in your application, you should watch carefully to see how your application reacts as colors change. It is always possible to use the scheme editor to create a very bad scheme, but if your program seems more sensitive than others to changes, you should think more carefully about your use of color.

## Creating New Schemes

You can also include your own new schemes in your software distribution; however, be aware of the following concerns:

- The largest benefit of schemes is the users' ability to change to schemes of their choice; so even if you create a scheme that you prefer for your application, make sure your program looks good with the existing schemes.

- If you install your scheme on a user's system, the user may apply that scheme to other applications. If you attempt to design a new scheme, make sure the scheme works reasonably with other applications on the desktop.

The easiest way to design a new scheme is to use the Scheme Browser, `schemebr`, available from the “Color Schemes” option of the Customize menu in Desktop toolchest. For best results, you should base your scheme on an existing scheme, preferably one of the standard ones supported by SGI. If you make only minor changes, your new scheme should work with other programs. Once you have created and saved your new scheme, you can retrieve the files from your `$HOME/.desktop-<hostname>/schemes` directory, where <hostname> is the name of your system. You can install your scheme in `/usr/local/schemes/<SchemeName>`, where <SchemeName> is the name you have chosen for your scheme. Once installed, this scheme appears in the Scheme Browser as a local scheme. You can also include this scheme with your software distribution.

## Hard-Coding a Scheme for an Application

In some rare situations, you may want your application to use one particular scheme, not the one that the user selects. SGI strongly recommends that you not use this approach, but if your application has special needs, the process is simple to do. Specify the value of the scheme resource in your application's `app-defaults` file using a complete path name. For example:

    YourApp*scheme: /usr/lib/X11/schemes/Milan

When using this approach, the location of the scheme directory is unimportant. For example, if you've designed a custom scheme for your application, you can place the scheme directory in special configuration directory for your application. For example:

    YourApp*scheme: /usr/lib/YourApp.config/YourAppScheme

This setting implies that `/usr/lib/YourApp.config/YourAppScheme` is a scheme directory. This means that the directory `YourAppScheme` would need to contain the files `BaseColorPalette` (containing the color palette you have defined), a file whose name is the same as the scheme that contains mappings, and a file named `FontPalette`. Normally, the `FontPalette` file would be a copy of the file in `/usr/lib/X11/schemes/Base`, and the map file would be the same as `/usr/lib/X11/schemes/Base/Base`, but renamed to have the same name as your scheme.

Prev | Table of Contents | Next
Chapter 2. Getting the IRIX Interactive Desktop Look |  | Chapter 4. Using the SGI Enhanced Widgets