LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1004|回复: 0

END-USER CUSTOMIZATION OF XT APPLICATIONS

[复制链接]
发表于 2006-8-19 05:42:49 | 显示全部楼层 |阅读模式
END-USER CUSTOMIZATION OF XT APPLICATIONS
Jean-Michel Léon
Table of Contents
ABSTRACT
RESOURCES WITH XLIB

      RESOURCE SPECIFICATION
      PRECEDENCE RULES

XT RESOURCES

      NAMING
      CONVENTIONS
      LOCATION
            HARD-CODED RESOURCES
            COMMAND LINE RESOURCES
            HOST SPECIFIC RESOURCES
            SERVER SPECIFIC RESOURCES
            APPLICATION SPECIFIC RESOURCES
            APPLICATION DEFAULT RESOURCES
            FALLBACK RESOURCES

APPLICATION CUSTOMIZATION

      WHAT IS CUSTOMIZABLE ?
            APPLICATION RESOURCES
            WIDGET SPECIFIC RESOURCES CUSTOMIZATION PROCESS
            CHOSE RESOURCES LOCATION
            FIND THE WIDGET TREE
            CUSTOMIZE !!!
            ADVICES RELATED TOOLS

ABSTRACT
I have noticed that only a few people use Xt resources in a very good way. Everybody knows how to define some resources in his .Xdefaults file, but Xt users seem to have always the same problems when they try to customize their applications: What is exactly a resource; why my resource is not taken in account; where must I write it; how must I write it? This article will describe the general resources management mechanism provided with the X Library (Xlib) and then it will detail how the X Toolkit (Xt) uses these mechanisms to provide a powerful customization protocol.
RESOURCES WITH XLIB
The main purpose of the X resources is to provide an easier way to define application options than modifying the source code or using hundreds of command line parameters or shell variables. Any variable of a program that has an initial value may be considered as "resourceable", which means that we could define an X resource for this variable whose value could be retrieved from a resource database. All the X functions needed for a complete resource management are part of the X Resource Manager (Xrm).

Resource values are given in files in a human-readable format. The simplest way to use the X resource manager is to define a set of key-value associations such as:

font: helvetica

Then, when our application starts, we can tell Xrm to load our resource file into an X Resource Data Base (Xrdb) and then we can ask to Xrm "What is the value of the resource `font' ?" and it will reply `helvetica'.

Xrm is a kind of data base manager, but usually, a data base contains precise keys and queries are performed by giving an imprecise key specification. At the opposite, with Xrm, we can define associations with imprecise key specifications and we must query them with precise keys. This is due to the fact that Xrm is intended to store associations for objects and that we want to be able to say something like "All my buttons in my application will be blue".

RESOURCE SPECIFICATION
A resource is defined with both a name and a class. The name is the key identifier, the class is a way to make some resources part of the same group. For example, if we have two color resources `foreground' and `background', we can make them part of the same class `Color'. This allows to declare:

foreground: red
background: blue

or simply if we want all the colors blue:

Color: blue

Obviously, this is possible only because the X resource manager knows how to handle the relationship between resource names and classes.

Xrm resource specifications have been designed with an object oriented goal: An application contains objects and each of these objects may use resources. For example, if we want to define the foreground of a window that we name win1: we want to say something like:

foregroundOfWin1: red

And for another window (win2), we could say:

foregroundOfWin2: red

This implies that we should find a name for each resource of our application, and it could quickly become difficult. That's why Xrm introduces a hierarchical resource naming that offers two main advantages:

    * it is easier to name objects using a hierarchical path than a unique symbolic name.
    * it allows to use imprecise resource specification

The hierarchy used to specify resources is natural when you define your application in an object-oriented way. Each object may contain other objects. Starting from our (possibly virtual) application object, we can build the complete objects hierarchy of our application. Consider the example of Figure 1:

The application (app) is defined as an object of class `Application', contains two objects and has a resource named `title'. Each object belongs to the class `Window' and has a resource named `foreground' which is of class `Color'. We can define theses resources:

FIGURE 1: APPLICATION 1
-----
  
      
-----

app.title: My Application
app.win1.foreground: red
app.win2.foreground: green

But we might as well want all the foregrounds of our the windows to be of the same color:

app.Window.foreground: red

This last specification means that every object contained by "app" which is of class Window must have a red foreground. Now we can add some objects to our application (see Figure 2).

We can give precise resource specification for each object:

FIGURE 2: APPLICATION 2
-----

      
-----

app.win1.win3.foreground: red

A precise specification implies that we must write the complete path of the object's resource that we define.

app.win1.foreground: red
app.win2.win1.foreground: blue

These two specifications are fully precise and define the foreground resource for two different objects. There is no ambiguity because there is only one object named "win1" which is child of "app" and there is only one object named win1 which is child of a child of "app" named "win2".

Defining resources for each object with precise specification could become boring and sometimes, we don't know the complete path defining an object and we cannot give the precise specification. Therefore it is interesting to use imprecise resource specifications. It allows to elide some levels of the resource path:

app*win1.foreground: red

Thus every object named win1 which is a descendant of "app" must have a red foreground, so `app.win1' and `app.win2.win1' will share the same resource.

Using both imprecise resource specification and objects class shows the whole power of this mechanism:

app*Window.foreground: red

means that all the application's objects of class Window will have the foreground resource to red. But this would not be really usable if we could not say that we want all of our the windows to be red except one which we want to be blue. This can be done by adding a more precise resource:

app*Window.foreground: red
app.win2.win1.foreground: blue

We can then define more than one resource that can be used for a precise object resource. It appears that it can become difficult to understand which resource will be used for which object. Xrm uses a set of precedence rules to determine which resource specification will match to a precise object's resource.

PRECEDENCE RULES
A resource specification can be described as levels, each level containing a component. Levels may be elided using an asterisk (*). A component may be a name, a class or a question mark (?) which matches any component. A component preceded with a dot (.) is said to have a tight binding. A component preceded with an asterisk (*) is said to have a loose binding.

The base principle is that the most precise specification has the highest priority. The algorithm scans specifications from left to right and apply for each level the 3 following rules:

   1. For a given level, an entry that contains a component takes precedence on an entry that elide this level.
   2. For a given level, a entry whose component is a name takes precedence on both an entry whose component is a class or a question mark (?); an entry whose component is a class takes precedence on an entry whose component is a question mark.
   3. For a given level, an entry whose component is preceded by a tight binding takes precedence on an entry whose component is preceded by a loose binding.

Examples:

a - app.win1.foreground: red
b - *win1.foreground: blue
c - app*foreground: red

rule 1 eliminates entries b and c.

a - app.win1.foreground: red
b - app.Window.foreground: blue
c - app.?.foreground: blue

rule 2 eliminates entries b and c.

a - app.Window.foreground: blue
b - app.?.foreground: blue

rule 2 eliminates entry b.

a - app.win1.foreground: blue
b - app.win1*foreground: blue

rule3 eliminates entry b.

XT RESOURCES
NAMING
The X Toolkit has an object oriented architecture where each object (called widget) is an instance of a class. Each class exports a set of fields which are associated with resources. Some resources may be read and written (they are get-able and set-able); others may only be read (they are only get-able). Each resource is named and belong to a class.

An Xt application is defined by building a widget tree. First we need a widget representing the application which contains widgets, which contain other widgets, and so on... An Xt application has consequently a natural hierarchical structure and any widget of the tree may be fully identified by the path built with widget names from the root (the application widget) to this widget.

The full name of a resource is given by the concatenation of the widget's names path and the resource name. The full class of a resource is given by the concatenation of the widget's classes path and the resource class.

Consider the xterm application, that is built with only two widgets (See Figure 3). The application widget (called a shell), that is the root of the widget hierarchy. This widget is named "xterm", its class is "XTerm" (See figure 4). The class of the root widget is defined by the application programmer and is so called application class.

The terminal widget named "vt100" whose class is "VT100". This widget has a resource named "background" of class "Background".

FIGURE 3: XTERM'S WIDGET TREE (NAMES)
-----

      
-----

FIGURE 4: XTERM'S WIDGET TREE (CLASSES)
-----

      
-----

The name and class of the resource "background" of the label widget are:

xterm.vt100.background
XTerm.VT100.Background

Each widget retrieves its resources by querying the resource database loaded by the toolkit, with the full resource name and class. The resource manager replies by searching the resource value through the database, applying its precedence algorithm on duplicate entries.

CONVENTIONS
By convention, Xt component's names begin with a lower case, and each contained word is capitalized; for example:

app.appMainWindow.backgroundPixmap: ...

Xt component's classes begin with an upper case, and each contained word is capitalized; for example:

TopLevelShell.MainWindow.Pixmap: ...

LOCATION
In order to allow several customizations, depending of the application class, the desired language of the interface, local preferences and user preferences, the X toolkit reads application resources from several sources. The resource loading algorithm is designed to load resource from the more general to the more precise, thus, each user in the world may use the same application with a totally different graphical appearance.

There are seven resource sources for an Xt application that are given below in priority order, which means that a resource found in the first level will override the same resource (i.e. a resource with exactly the same specification, if specification are different, loading order doesn't mind and priority depends only on the Xrm precedence algorithm) found in the other six levels. Levels 2 to 7 are loaded by priority order, so that a resource defined in level 2, for example, may be used to retrieve resources from another level. For each level, we say who is responsible for setting resources.

   1. Hard coded resource programmer
   2. Command line resources end-user
   3. Host-specific resources end-user
   4. Server-specific resources end-user
   5. Application-specific resources end-user
   6. Application-default resources programmer
   7. Fallback resources programmer

The application programmer is responsible of the levels 6-7 which are used to ensure a correct and minimum functionality set. He is in charge of the first level too, because he may need to set resources that must not be overridden by a user. A good interface programmer should choose the location of each resource to assume that the application will always work properly, but letting the most customization's flexibility to the end-user.

HARD-CODED RESOURCES
Defined by the programmer when the widget is created. There is no way to bypass or override these resources.

COMMAND LINE RESOURCES
The X toolkit provides a way to define resources when an application starts: by giving some options (like -bg red) we can dynamically add resources to the database. These resources have the highest end-user priority level and override all the end-user levels.

Each option that can be given on the command line will add a specific resource specification to the database. These resources are listed in Table 1, where each specification must be preceded by the application name.

TABLE 1: COMMAND LINE OPTIONS
-----------------------------------------------
OPTION             RESOURCE           VALUE      
                   SPECIFICATION                 
-----------------------------------------------
-background        *background        next arg   
-bd                *borderColor       next arg   
-bg                *background        next arg   
-borderwidth       .borderWidth       next arg   
-bordercolor       *borderColor       next arg   
-bw                .borderWidth       next arg   
-display           .display           next arg   
-fg                *foreground        next arg   
-fn                *font              next arg   
-font              *font              next arg   
-foreground        *foreground        next arg   
-geometry          .geometry          next arg   
-iconic            .iconic            next arg   
-name              .name              next arg   
-reverse           *reverseVideo      on         
-rv                *reverseVideo      on         
+rv                *reverseVideo      off        
-selectionTimeout  .selectionTimeout  next arg   
-synchronous       *synchronous       on         
+synchronous       *synchronous       off        
-title             .title             next arg   
-xnllanguage       .xnllanguage       next arg   
-xrm               other resources    next args  
                                                
-----------------------------------------------

The complete definition of each option may be found in the X manual (man X).

HOST SPECIFIC RESOURCES
These resources are retrieved from a file. The name of this file may be given in the environment variable XENVIRONMENT. If this variable is not set, the X toolkit searches for a file named $HOME/.Xdefaults-host, where host is the name of the machine where you start the application. This level may be used when an application does not require the same resources for each host.

SERVER SPECIFIC RESOURCES
This level is useful to set display-specific resources. For example, when you work on different screens, you can have a color screen or a monochrome screen. So it is interesting to be able to set different resources for different screens.

Resources of this level are those given to xrdb (see the xrdb manual), at init time. If you do not use xrdb, you might put these resources in a file named $HOME/.Xdefaults. Note that if you run xrdb (for example from ".xinitrc" file) the $HOME/.Xdefaults will no longer be loaded. So, It is a good idea to load your ".Xdefaults" with xrdb, because it avoids file duplication.

An advantage to use xrdb is that the file loaded by xrdb is processed first by the C-preprocessor, so that it allows to define conditional resource specifications:

#ifdef COLOR
XTerm*background: blue
#else
XTerm*background: white
#endif

An inconvenient is that as the resources are loaded in a window property, it uses memory in the X server and it adds an overhead to the starting time of all applications. Therefore the file loaded with xrdb should be as tiny as possible and for maximum efficiency, all resources should be set in an application-specific file, which is at the opposite of the current practice.

All the preprocessor's symbols defined by xrdb are listed and explained in the xrdb manual.

APPLICATION SPECIFIC RESOURCES
This is the level of per-application resources. As it is "per-application", resources are given in file whose name has a relation with the application: the application class. This file may be found by 3 different ways:

   1. if the global variable XUSERFILESEARCHPATH is set, Xt uses this path to find the resource file. This variable must give a list of file name substitutions, separated by a `:' and describing how to build the complete file name (see below). The first substitution that allows to find the file will be used. Even if no substitution is correct, steps 2 and 3 will not be performed (steps 2 and 3 will be performed only if this variable is undefined).
   2. if XUSERFILESEARCHPATH is not defined, Xt searches in the $XAPPLRESDIR directory, using a set of predefined substitutions.
   3. if the file has not been found after step 2, Xt searches it in $HOME, using once again predefined substitutions.

Any substitution given is a pattern that define how Xt must build the complete (path + name + extension) resource file name. It can contain the following rules that will be replaced with the matching string (note that the matching strings will be different for the application defaults level).

rule  matching string
%L  <language>
%N  <app-class>
%C  <custom-string>

For example, if your XUSERFILESEARCHPATH contains: /users/u2/%N%C, and if you run an application whose class is `XApp', it will be expanded into /users/u2/XApp<custom-string>.

The <custom-string> value is an application dependent resource that can be set in any previous resource specification level. A "standard" setting is to set in your ".Xdefaults" (when loaded with xrdb):

#ifdef COLOR
*customization: -color
#else
*customization: -mono
#endif

So, if you work on a color screen, Xt will load a resource file named <app-class>-color or if you are on a monochrome screen, it will load <app-class>-mono. With a customization resource set to `-color', the previous example is expanded into /users/u2/XApp-color.

The <language> value is an application dependant resource that can be set in any previous resource specification level. Resource name is "xnlLanguage", its class is "XnlLanguage". If the language cannot be retrieved from this resource, Xt tries to get the value of the LANG shell variable. Language string should describe both language and character encoding (see `locales' in the X documentation).

APPLICATION DEFAULT RESOURCES
This is a programmer's defined level, but it is important to understand it in order to be able to override its resources easily.

This level looks like the precedent level, but there are more rules defined:

%L  <language>
%N  <app-class>
%T  app-defaults
%C  <custom-string>
%S  <nothing>

The substitution string used is the content of the XFILESEARCHPATH variable; if it is not defined, a predefined set of substitutions will be used.

For this level, each resource should begin with `*', so that, according to the Xrm precedence rules, you can override it, simply by preceding it with <app-class> or <app-name>.

FALLBACK RESOURCES
This level should contain resources that MUST be defined and should be defined in the application defaults level too. Fallback resources will be used only if one of theses resources has not been loaded in previous level (because the application defaults file is not installed or not reachable through XFILESEARCHPATH).

APPLICATION CUSTOMIZATION
WHAT IS CUSTOMIZABLE ?
APPLICATION RESOURCES
These resources are defined by the application programmer and are application dependent. they are used to define a general behavior of the application. For example, the xmh application defines a resource named initialFolder which gives the name of the initial folder. You may find the complete description of these resources in the application documentation (the UNIX on-line manual for xmh). Application-specific resources are defined on the toplevel widget of the application so that their complete specification is always:

application-name-or-class.resource-name-or-class

WIDGET SPECIFIC RESOURCES
These are resources defined on each widget of the application. The complete specification for these resources requires the knowledge of the application's widget tree, that may be found either in the application documentation or using some tools. These resources depend on the widget set that is used to build the application; MOTIF widgets have not the same resources than Athena widgets. Resource names and classes are defined in the widget set documentation. Widget specific resources are intended to define geometry, appearance and behavior of widgets.

Here is a non exhaustive list (see Table 2) of the most common widget specific resources. Most of them are defined inside the X toolkit and are consequently available with any Xt based widget set. You must refer to your application's widgets set documentation to find real names and classes.

TABLE 2: COMMON RESOURCES
-------------------------------------------------------------
APPEARANCE                        GEOMETRY       BEHAVIOUR     
-------------------------------------------------------------
foreground and background colors  position       translations  
highlight color and thickness     width, height  accelerators  
shadow colors and thickness       margins        mnemonics     
border color and thickness                                    
icons                                                         
fonts                                                         
cursors                                                        
                                                               
-------------------------------------------------------------

CUSTOMIZATION PROCESS
CHOSE RESOURCES LOCATION
Reading 'LOCATION' on page 7, you must choose a location for your resources. I think the better way is to create a directory named `app-defaults' in your home directory and to set XAPPLRESDIR to $HOME/app-defaults. Then you will write resources in a file named with the application class in this directory.

FIND THE WIDGET TREE
You can find it in the application's documentation or using some tools, like editres that allows you to click on an application and to display its widget tree (See figure 5). If you can't get the widget tree of an application, that means that it is not editres-compliant and you have so to read the doc.

FIGURE 5: XFB'S WIDGET TREE (WIDGET NAMES)
-----

      
-----

CUSTOMIZE !!!
If you are not familiar with Xt, you will have to be patient. A good way to learn customization is to copy and modify the application-defaults resource file. Don't forget that resources are only read at init time, so to test a resources, you have to:

modify the resource file; save the resource file; run the application; modify the resource file;...

ADVICES
In a user's resource file, always start a resource specification with an application name or class (unless if it is really a resource usable by all application).

White spaces are sometimes significant. For example, a color name ended with a white space may generate a warning message from the toolkit.

Resource names and classes contain upper and lower cases (See "CONVENTIONS" on page 7.). Beware of capitalizing.

If you make a mistake in a resource specification it will be ignored without warning. Beware of misspelling.

Give specifications as precise as you can (See "RECEDENCE RULES" on page 5.). You will avoid it to be overridden by an application specific resource.

RELATED TOOLS
Here are few names of tools that can give some help during the customization process, see the manuals for more explanations.

   1. xprop (X(1)) is a tool that gives all the property defined on the top-level window of an application. The Inter Client Communication Convention Manual says that any application top-level window must have a property named WM_CLASS that contains both the application name and class. This is useful to get an application class.
   2. listres (X) is a tool that allows to list all resources defined on Xt and the Athena widgets. With no argument, it prints the list of defined widgets. With a widget name given as argument, it lists the resources name, class and type.

  $ listres Text
lists all the widget's resources for widget class `Text'.

   1. viewres (X) is a graphical interface that has the same functionality as listres. Widget classes are displayed as a tree, and you can ask for each of them to see the defined resources.
   2. appres (X) is a tool that prints the resource database that will be used for an application name or class:

$ appres XTerm -name myterm
lists the resource database for application named `myterm' of class 'XTerm'.

   1. editres (X) lets you change interactively a resource value for a running application. It is useful to test a resource modification without restarting the application. editres first displays the widget tree of the selected running application. You can choose a widget and ask to see its resource table. Then you can choose a resource and give it a new value. The application will automatically update the widget, according to the new resource value.
   2. xrdb (X) allows to load a file of screen dependent resources, that is given first to the C preprocessor. xrdb is intended to use conditional resource specifications based on some symbol defined, depending of the screen capabilities. Another interest is that xrdb points out all the duplicate entries of the file it is loading. Used in conjunction with appres it allows to "debug" the complete set of resources loaded by an application.
   3. xrp (available on avahi.inria.fr:/pub/xrp.tar.Z) is a small utility that prints, for an application class, the location of application-default and application-specific resource files:

$ xrp Editres
system app-defaults: /usr/lib/X11R5/app-defaults/Editres-color
user app-defaults: /u/babar/1/koala/leon/app-defaults/Editres-color

Footnotes

(1)
    Available with the standard X distribution



Jean-Michel Léon
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表