Every Motif widget has a number of resources that control or modify its behaviour and appearance. Depending on the widget's class, resources control aspects such as the size of the widget, the colour of the widget, whether scroll bars should be displayed and many other properties.
When a widget is created it inherits resources from a higher widget class and also creates its own (Section 5.5). All these resources have default values. It would be tedious to specify 30 plus resource values each time we create a widget.
However the application programmer or user may want to customise one or two resources in order to control a widget's size in a GUI or its dimensions on the screen, for example.
Throughout this Chapter we will use the PushButton program, push.c, developed in Chapter 4 as a case study and we shall see how we alter the size (width and height) of the button. The resource variables XmNwidth and XmNheight hold these values.
There are a few ways in which we can alter a particular resource's value.
Broadly, there are two methods of altering resources in Motif:
The advantage of using external files is that it allows the user to customise Motif applications without having to recompile the program. The user may never need to access the source code. Applications may also be customised each time they are run. Due to the wide variety of possible systems running X and a vast range of user needs this can be a useful feature. For example, screen resolutions vary a great deal from device to device and what may be a visually adequate size for a widget on one display may be totally inadequate on another. Also certain resources, particularly colour displays, may vary substantially across different platforms.
There are four basic ways to externally customise an application:
One problem with the external setting of resource values occurs if it has already been hard-coded, since hard-coded resource values have a higher precedence than all externally set resources.
There are some advantages to hard-coding resource values :
A trade-off is sometimes required between applying hard-coding and allowing user freedom.
There is one other internal coding method for changing resources, by using what are called fallback resources . As their name implies fallback resources are set only if a resource has not been set by any of the above means. Fallbacks are therefore useful for setting alternatives to the default Motif resource settings.
The remaining sections in this Chapter detail how each individual resource setting method may be used.
When Motif initialises the application it looks for the .Xdefaults file in your HOME directory. The .Xdefaults file is a standard text file, where each line may contain a resource value setting, a blank line or a comment denoted by an exclamation mark (!). This file contains directives that can reset any resource for any application, using the following method:
application_class_name.widget_name.resource_name.
Note that when referring to resource names outside a program, the XmN part of the resource is dropped from the resource name. So, the width and height of the PushButton widget in the push.c application are referred to by:
Push.Push_me.width or Push.Push_me.height
! Comment: Set push application, PushButton dimensions Push.Push_me.width: 200 Push.Push_me.height: 300
where 200 and 300 are the widget's new dimensions. Note that there is a colon separating the resource name and its new value.
Wild card (*) settings are also allowed. Therefore to set all widgets called ``Push_me'' width and height you could write:
! Comment: wildcard setting of widget Push_me dimensions *Push_me.width: 200 *Push_me.height: 300
Motif widget class names may also be used. This will set all widgets of a given class and application to the same values so care should be taken. An alternative method to set the width and height of the PushButton of push.c is to use the Motif XmPushButton class name to set its resources via:
! Comment: Set push application, ! XmPushButton widget class dimensions Push*XmPushButton.width: 200 Push*XmPushButton.height: 300
The class resource file relates to a particular application, or class of applications. The application class name created with XtVaAppInitialize() is used to associate a class resource file with an application. Thus, the push.c program has an application class ``Push'' and therefore the application would have a class file named Push. The class resource files are normally stored in the user's home directory.
It is possible, and quite practical, to associate several applications with a single class name (by setting the appropriate XtVaAppInitialize() argument) and therefore with a single class resource file. This would allow for one class file to control the resource setting for many usually similar applications. Individual applications can again be referred to by their (compiled) program name, but this is not common.
The setting of individual resource values is as described for the .Xdefaults file, except that the wild card matching may not have such far reaching consequences. Therefore, to set the dimension of the PushButton in push.c we could write:
! Class Resource File for push.c called "Push" ! Store in HOME directory *Push_me.width: 200 *Push_me.height: 300
Resource values can be set with X window command line parameters. Some common resources can be easily referred to and a general command exists to set any resource value. The advantage of using the command line is that resource values can be altered each time the program is run. This is ideal if you only change a resource infrequently, or you are experimenting to find suitable resource values. However, setting resource values in this fashion regularly involves a lot of typing, so alternative methods should be considered.
Common resource values have special abbreviations for command line operation. These
are listed in Table.
The foreground and background colours are referred to by the common colour name database which is detailed in the reference manuals (Section 17.4). So to set the background to red for the push.c program. We would run the program from the command line as follows:
push -bg red
The -geometry option sets the windows dimension and position. It has 4 parameters:
WidthxHeight+Xorigin+Yorigin
where Width, Height, Xorigin and Yorigin are integer values separated by x or +.
Therefore to set the window size to 300 by 300 with the origin at top left corner run the program from the command line with the following arguments:
push -geometry 300x300+0+0
You can omit either the size, WidthxHeight, or position, +Xorigin+Yorigin parameters in order to either size or position a window.
Therefore to set the window size to 500 by 500 and to allow the window manager to place it somewhere type:
push -geometry 500x500
and to explicitly position a window and use the default dimension type:
push -geometry +100+100
The -xrm option allows the user to set resources that are not otherwise facilitated from the command line. Following the -xrm option you supply a string that contains a resource setting similar to a single line resource value setting in a user or class resource file (including wildcards).
Therefore to change the highlight colour of the PushButton in push.c we could type:
push -xrm "Push*highlightColor: red"
where Push is the application class name and (XmN)highlightColor is the resource being set to red.
Multiple settings of resource values require -xrm calls for each resource value setting. Therefore to set the highlight and foreground colours for the above PushButton we could type:
push -xrm "Push*highlightColor: red" \ -xrm "Push*foreground: blue"
The X system provides a program, xrdb, that allow you to set up and edit resources stored on the root window of a display. The data is stored in RESOURCE_MANAGER property and, also, in SCREEN_RESOURCES property if multiple screens are supported. For the sake of simplicity we will assume that we are only working with a single screen and therefore do not need to consider the SCREEN_RESOURCES property further.
When xrdb is run it reads a .Xresources file from which it creates the RESOURCE_MANAGER property. The .Xresources file is usually stored in the users home directory. The .Xresources file can contain similar resource value settings as described for the .Xdefaults file and class resource file. However, xrdb can actually run the .Xresources or an other input file through the C preprocessor, so C preprocessor syntax is allowed in the .Xresources file. Several macros are defined so that constructs like #ifdef and #include may be used. One common example of their use is to set separate colour and monochrome resources for different screen settings. The macro COLOR is defined if a colour screen is present for a given display. Therefore, an .Xresources file could look for this and take appropriate actions:
#ifdef COLOR ! Colour screen detected set colour resources Push*foreground: RoyalBlue Push*background: LightSalmon #else ! must be a monochrome screen Push*foreground: black Push*background: white #endif
For further information on xrdb readers should consult the X Window system user reference manuals, or online manual documentation.
One advantage of this method of setting resources is that it allows for dynamic changing of defaults without editing files. In fact, the setting of resources via files may not work on X terminals with limited computing power, or when programs are run on multiple machines (since other machines may not have the appropriate .Xdefaults or class resource files). Having all the resource information in the server means that the information is available to all clients.
There are two basic methods for setting resource values from within a C program. The first method described below is dynamic, meaning that resources can be set and altered at any occasion from within the program. Another method allows resources to be set when a widget is created. Both these methods would override other methods of resource setting.
Using this method we can change the values of a resource at any time from within a program. Typically two functions are employed to do this:
Therefore, to set the size of the button resources in push.c we would use XtSetArg() to set width and height values in the arg list and then set the arg values for the button widget as follows:
Arg args[2]; /* Arg array */ int n = 0; /* number arguments */ XtSetArg(args[n], XmNwidth, 500); n++; XtSetArg(args[n], XmNwidth, 750); n++; XtSetValues(button, args, n);
A related function XtGetValues() exists to find out resource values (Chapters 11 and 13 contain some examples of XtGetValues() in use).
A convenience function XtVaSetValues() actually combines the above two operations and make programming a little less tedious. XtVaSetValues sets the resource value pair for a given widget using a NULL terminated list much like XtVaCreateManagedWidget() (see below).
Therefore, we can achieve the same result as above for setting the button in push.c via:
XtSetValues(button, XmNwidth, 500, XmNwidth, 750, NULL);
We can set resource values at creation. This is common if we wish to permanently override a default resource value. There are a couple of methods we can adopt to achieve this.
We can set an Arg argument list using XtSetArg() as in the previous section and then specify the arg list and the number of arguments in the XmCreate...() function. Therefore, we could amend the push.c program to set the resources at initialisation of the button widget by inserting the following code:
Arg args[2]; /* Arg array */ int n = 0; /* number arguments */ ...... XtSetArg(args[n], XmNwidth, 400); n++; XtSetArg(args[n], XmNwidth, 600); n++; button = XmCreatePushButton(top_wid, "Push_me", args, n);
There is an alternative method which lets us set resource values and create a managed widget in one function call. The function is XtVaCreateManagedWidget() and is a convenient way to program such tasks. Note that this is a general function that can create many different classes of widget. This function is preferred for the creation of widgets due to its uniformity of syntax/structure and its brevity in performing more than one task. Where appropriate all widgets will subsequently be created using this function.
Let us look a the syntax of this function:
Widget XtVaCreateManagedWidget(String name, WidgetClass widget_class, Widget parent, ... resource name/value pairs ..., NULL)
where:
The function returns a widget of the class specified.
Therefore, to create a managed PushButton widget with dimensions 400 by 300 we would type:
button = XtVaCreateManagedWidget("Push_me", XmPushButtonWidgetClass, top_wid, XmNwidth, 400, XmNheight, 200, NULL);
Here, XmPushButtonWidgetClass is the class identifier of a PushButton. Other widget types should be fairly obvious.
Fallback resources are used as a mechanism where the specified resource value settings only take effect if all other resource setting methods have failed. Fallback resources are passed as arguments to the XtVaAppInitialize() function (Section 4.6.1). The fallback resources are passed as a NULL terminated list of Strings to this function. Each String specifies a resource value setting similar to those developed for the user and class resource files. Therefore, to set fallback resources for the push.c program we could include the following code:
#include <Xm/Xm.h> #include <Xm/PushB.h> /* Define fallback\_resources */ static String fallback\_resources[] = { "*width: 300", "*heigth: 400", NULL /* NULL termination} }; main(int argc, char **argv) { Widget top_wid, button; XtAppContext app; top_wid = XtVaAppInitialize(&app, "Push", /* class name */ NULL, 0, /* NO command line options table */ &argc, argv, /* command line arguments */ fallback\_resources, /* fallback\_resources list */ NULL); .........