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 Indigo Magic Desktop and other applications. “Schemes for Colors and Fonts” in Chapter 3 in Indigo Magic User Interface Guidelines describes the guidelines for using schemes in the Indigo Magic 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.

“Testing Your Application with Schemes” 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. Silicon Graphics 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 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 “Colors” 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 Indigo Magic 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 don't 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 might 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.)

Using Schemes in Your Application

This section describes how to write your application for use with schemes.

Turning on Schemes for Your Application

Silicon Graphics incorporates schemes in its implementation of Xt, so you don't 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

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


Note: To ensure that users don't 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 can't be changed by users, call the function SgiUsesScheme():

void SgiUsesScheme(char *value)

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

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 doesn't have unique class names for menu bars, menu panes, and option menus. To allow schemes to be applied to these elements, your application must follow some simple naming conventions for these widgets. Schemes expect applications to 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”. Don't hard code colors or fonts in your application because they might 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 might not be correct if a user changes the scheme.

There are obviously some cases for which this recommendation doesn't 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 aren't derived from schemes.

Fonts are usually less critical than colors, although the best visual effects will be produced if you use only the fonts defined in the schemes. You should be aware that on low-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 shouldn't 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 might 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 might 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 could 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 could 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 could set a label widget to be “red” as follows:

YourApp*label*background: SGI_DYNAMIC RedColor

The exact shade of red will change from scheme to scheme, but will always be “reddish” and always fit with the other colors in the scheme.

If necessary, you can also use non-scheme colors and fonts, although Silicon Graphics strongly recommends that you don't do this. In particular, if you hard-code a color, the user might select a scheme in which that color doesn't provide the contrast you desire. The color could even be “lost” among the other scheme colors. Non-scheme fonts are less likely to cause problems, but your application will still 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 could 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 might need to access some of the scheme's colors or fonts directly from within a program. For example, you might 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 could 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'll use the color in.


Tip: There is a far simpler method for retrieving a resource value if you're using the IRIS ViewKit toolkit. Instead of writing the getColorResource() function listed in Example 3-1, you could simply call:


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

You must handle some resources programmatically. For example, the Indigo Magic 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 ReadOnlyColor, and can be retrieved by the resource readOnlyColor. Assuming that you've created the getColorResource() function listed in Example 3-1, the following code illustrates this process:

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


Tip: The equivalent IRIS ViewKit code would be:


Pixel ro = (Pixel) VkGetResource( textw, "readOnlyColor",
                                  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 “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

Indigo Magic toggle check mark color

radioColor

RadioColor

Indigo Magic radio pip color

indicatorBackground

IndicatorBackground

Indigo Magic 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 doesn't 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 will 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


Testing Your Application with Schemes

For best results, you should be sure to test your application against all available schemes, and watch for any anomalies. As an added precaution, you might try using the Scheme Browser, schemebr, (available from the “Colors” option of the Customize menu in Desktop toolchest) to create some variations on existing schemes and see how your program will react. 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 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, but there are several things to be aware of. First, 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, you should still make sure your program looks good with the existing schemes. Second, if you install your scheme on a user's system, the user might apply that scheme to other applications. If you attempt to design a new scheme, you should attempt to 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 “Colors” 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 Silicon Graphics. Making only minor changes will reduce the chances that the new scheme will not work with other programs. Once you have created and saved your new scheme, you can retrieve the files from your $HOME/.desktop-<hostname>/scheme 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 will appear 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 might want your application to use one particular scheme, not the one that the user selects. Silicon Graphics 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