Movatterモバイル変換


[0]ホーム

URL:


ContentsPreviousNext

20 Compound Strings


This chapter describes Motif's technology for encoding font changes and character directions in the strings that are used by almost all of the Motif widgets.

Compound strings are designed to address two issues frequently encountered by application designers: the use of foreign character sets to display text in other languages and the use of multiple fonts to render text. With the addition of internationalized string rendering capabilities in X11R5, the use of compound strings for internationalization purposes is theoretically no longer necessary. However, the Motif widget set still uses compound strings extensively, so applications have no choice but to create them to display text.

20.1 Internationalized Text Output

The internationalization features in X11R5 are based on the ANSI-C locale model. Under this model, an application uses a library that reads a customization database at run-time to get information about the user's language environment. An Xt-based application can establish its language environment (or locale) by registering a language procedure withXtSetLanguageProc(), as described in Section #slangproc. The language procedure returns a language string that is used byXtResolvePathname() to find locale-specific resource files. See Volume Four, X Toolkit Intrinsics Programming Manual, for more information on the localization of the resource database.

One of the important characteristics of a language environment is the encoding that is used to represent the character set for the particular language. In X, character set simply refers to a set of characters, while an encoding is a numeric representation of these characters. Both of these terms are different from the definition of a font, which is a collection of glyphs used to represent the characters in an encoding. A charset (not the same as a character set) is an encoding in which all of the characters have the same number of bits. Charsets are often defined by standards bodies such as the International Standards Organization (ISO). For example, the ISO Latin-1 charset (ISO8859-1) defines an encoding for the characters used in all Western languages. The first half of Latin-1 is standard ASCII, while the second half (with the eighth bit set) contains accented characters needed for Western languages other than English. Character 65 in ISO Latin-1 is an uppercase "A", while 246 is a lowercase "o" with an umlaut (<OVERSTRIKE<o[[umlaut]]>OVERSTRIKE>).

However, not all languages can be represented by a single charset. Japanese text commonly contains words written using the Latin alphabet, as well as phonetic characters from the katakana and hirigana alphabets, and ideographic kanji characters. Each of these character sets has its own charset; the phonetic and Latin charsets are 8-bits wide, while the ideographic charset is 16-bits wide. The charsets must be combined into a single encoding for Japanese text, so the encoding uses shift sequences to specify the character set for each character in a string.

Strings in an encoding that contains shift sequences and characters with non-uniform width can be stored in a standardNULL-terminated array of characters; this representation is known as a multibyte string. Strings can also be stored using a wide-character type in which each character has a fixed size and occupies one array element in the string. The text output routines in X11R5 support both multibyte and wide-character strings. To support languages that use multiple charsets, X developed theXFontSet abstraction for its text output routines. AnXFontSet contains all of the fonts that are needed to display text in the current locale. The new text output routines work with font sets, so they can render text for languages that require multiple charsets. See Volume One, Xlib Programming Manual, for more information on internationalized text output.

With the addition of these features in X, a developer can write an internationalized application without using the internationalization features provided by compound strings. In an internationalized application, strings are interpreted using the encoding for the current locale. To support a number of locales, the application needs to store string data in separate files from the application code. The application must provide a separate file for each of the locales supported, so that the program can read the appropriate file during localization.

However, since most Motif widgets use compound strings for representing textual data, a Motif application has to use compound strings to display text. As we describe compound strings in this chapter, we'll discuss how to use them so as not to interfere with the lower-level X internationalization features.

20.2 Creating Compound Strings

Almost all of the Motif widgets use compound strings to specify textual data. Labels, PushButtons, and Lists, among others, all require their text to be given in compound string format, whether or not you require the additional flexibility compound strings provide. The only widgets that don't use compound strings are the Text and TextField widgets. As a result, you cannot use the compound string techniques for displaying text using multiple fonts. However, in Motif 1.2, these widgets do support internationalized text output, so they can display text using multiple character sets. For information on the internationalization capabilities of the Text and TextField widgets, see Section #stexti18n.

A compound string (XmString) is made of three components: a tag, a direction, and text. The tag is an arbitrary name that the programmer can use to associate a compound string with a particular font or font set. In Motif 1.1, the tag was referred to as a character set. Since the tag doesn't necessarily specify a character set, Motif 1.2 now refers to the entity as a font list tag; this change is strictly semantic. The tag-to-font mapping is done on a per-widget basis, so the same name can map to different fonts for different widgets.

An application can create a compound string that uses multiple fonts by concatenating separate compound strings with different tags to produce a single compound string. Concatenating compound strings with different fonts is a powerful way to create graphically interesting labels and captions. More importantly, because fonts are loosely bound to compound strings via resources, you can dynamically associate new fonts with a widget while an application is running and effectively change text styles on the fly.

20.2.1 The Simple Case

Many applications only need to use compound strings to specify various textual resources. In this case, all that is needed is a routine that converts a standard C-styleNULL-terminated text string into a compound string. The most basic form of conversion can be done using theXmStringCreateLocalized() function, as demonstrated in examples throughout this book. This routine takes the following form:

   XmString   XmStringCreateLocalized(text)       char *text;
Thetext parameter is a common Cchar string. The value returned is of typeXmString, which is an opaque type to the programmer.

XmStringCreateLocalized() is a new routine in Motif 1.2; it creates a compound string in the current locale, which is specified by the tagXmFONTLIST_DEFAULT_TAG. This routine interprets thetext string in the current locale when creating the compound string. If you are writing an internationalized application that needs to support multiple locales, you should useXmStringCreateLocalized() to create compound strings. The routine allows you to take advantage of the lower-level internationalization features of X.

Most applications specify compound string resources in resource files. This technique is appropriate for an internationalized application, as there can be a separate resource file for each language environment that is supported. Motif automatically converts all strings that are specified in resource files into compound strings usingXmStringCreateLocalized(), so the strings are handled correctly for the current locale. If an application needs to create a compound string programmatically, it should useXmStringCreateLocalized() to ensure that the string is interpreted in the current locale. All of the examples in this book useXmStringCreateLocalized() to demonstrate the appropriate technique, even though the examples are only designed to work in the C locale.

With Motif 1.1, you should use theXmStringCreateSimple() routine to create a compound string that uses the default character set and direction. This function is obsolete in Motif 1.2; it remains for backwards-compatibility purposes only. With bothXmStringCreateLocalized() andXmStringCreateSimple(), you cannot explicitly specify the tag or the string direction that is used for the compound string, and the string cannot have multiple lines.

BothXmStringCreateLocalized() andXmStringCreateSimple() allocate memory to store the compound string that is returned. Widgets that have compound string resources always allocate their own space and store copies of the compound string values you give them. When you are done using a compound string to set widget resources, you must free it usingXmStringFree(). The following code fragment demonstrates this usage:

   XmString str = XmStringCreateLocalized ("Push Me");   XtVaCreateManagedWidget ("widget_name",       xmPushButtonGadgetClass, parent,       XmNlabelString,  str,       NULL);   XmStringFree (str);
The process of creating a compound string, setting a widget resource, and then freeing the string is the most common use of compound strings. However, this process involves quite a bit of overhead, as memory operations are expensive. Memory is allocated by the string creation function and again by the internals of the widget for its own storage, and then your copy of the string must be deallocated.

The programmatic interface to the string creation process can be simplified by using theXtVaTypedArg feature in Xt. This special resource can be used in variable argument list specifications for functions such asXtVaCreateManagedWidget() andXtVaSetValues(). It allows you to specify a resource using a convenient type and have Xt do the conversion for you. In the case of compound strings, we can use this method to convert a C string to a compound string. The following code fragment has the same effect as the previous example:

   XtVaCreateManagedWidget ("widget_name",       xmPushButtonWidgetClass, parent,       XtVaTypedArg, XmNlabelString, XmRString,           "Push Me", 8, /* or strlen ("Push Me") + 1 */       NULL);
XtVaTypedArg takes four additional parameters: the name of the resource, the type of the value specified for the resource, the value itself, and the size of the value. We set theXmN­labelString resource. We want to avoid converting the character string to a compound string, so we specify achar* value andXmRString as its type. This terminology may be confusing to a new Motif programmer. Xt uses the typedefString forchar*. The representation type used by Xt resource converters for this type isXtRString (XmRString in Motif). A compound string, on the other hand, is of typeXmString; its representation type isXmRXmString. You just have to read the symbols carefully. Resource converters are described in detail in Volume Four, X Toolkit Intrinsics Programming Manual, Motif Edition. The string"Push Me" is the string value; the length of the string, including theNULL-terminating byte, is 8.

TheXtVaTypedArg method for specifying a compound string resource is only a programmatic convenience; it does not save time or improve performance. The three-step process of creating, setting, and freeing the compound string still takes place, but it happens within Motif's compound string resource converter. Using automatic conversion is actually slower than converting a string usingXmStringCreateLocalized(). However, unless you are creating hundreds of strings, the difference is negligible. The convenience and elegance of theXtVaTypedArg method may be worth the performance tradeoff.

The reason most of the examples in this book do not make use of the feature is that we are trying to demonstrate good programming techniques tuned to a large-scale, production-size, and quality application. Using theXtVaTypedArg method for compound strings is painfully slow when repeated over hundreds of Labels, PushButtons, Lists, and other widgets. TheXtVaTypedArg method is perfectly reasonable for converting other types of resources, however. If you are converting a lot of values from one type to another, it is in your own best interest to evaluate the conversion process yourself by testing the automatic versus the manual conversion methods.

20.2.2 Font List Tags

Motif provides two different compound string creation routines that allow you to specify a tag used to associate the compound string with a font or a font set. This tag is a programmer-specified identifier that enables a Motif widget to pick its font from a list of fonts at run-time. In Motif 1.1, the font list tag was referred to as a character set, but strictly speaking, it does not specify a character set.

TheXmStringCreate() andXmStringCreateLtoR() routines allow you to specify a font list tag. These routines take the following form:

   XmString   XmStringCreate(text,tag)       char *text;       char *tag;
   XmString   XmStringCreateLtoR(text,tag)       char *text;       char *tag;
Both of these routines create and allocate a new compound string and associate thetag parameter with that string. As with any compound string, be sure to free it withXmStringFree() when you are done using it.

XmStringCreate() creates a compound string that has no specified direction. The default direction of a string may be taken from theXmNstringDirection resource. This resource is defined by manager widgets; it specifies the string direction for all the children of the manager. If the default direction is not adequate,XmStringDirectionCreate() can be used to create a compound string with an explicit direction, as we'll discuss shortly.

XmStringCreateLtoR() creates a compound string in which the direction is hard-coded as left-to-right. Motif also defines theXmStringLtoRCreate() routine; its functionality is identical toXmStringCreateLtoR(). This function is also useful for converting newline-separated strings into compound strings, as we explain later in this section. Unfortunately, Motif does not provide a corresponding right-to-left compound string creation function. If you need such a routine, it is not that difficult to write one.

The actual font or font set that is associated with the compound string is dependent on the widget that renders the string. Every Motif widget that displays text has anXmNfontList resource. This resource specifies a list of fonts and/or font sets for the widget; each entry in the list may have an optional tag associated with it. For example, a resource file might specify a font list as follows:

   *fontList: -*-courier-*-r-*--*-120-*=TAG1,           -*-courier-*-r-*--*-140-*=TAG2,           -*-courier-*-r-*--*-180-*=TAG3
At run-time, the compound string is rendered using the first font or font set in the widget's font list that matches the font list tag specified in the compound string creation function. In Motif 1.2, the compound string rendering functions use the new X11R5 text output functions, so compound strings are displayed appropriately for the current locale. If Motif cannot find a match, the compound string is rendered using the first item in the widget's font list, regardless of its tag. This loose binding between the compound string and the font or font set used to render it is useful in a number of ways:

the source code demonstrates how a compound string can be rendered using different fonts in different PushButton widgets.XtSetLanguageProc() is only available in X11R5; there is no corresponding function in X11R4.XmStringCreateLocalized() is only available in Motif 1.2;XmStringCreateSimple() is the corresponding function in Motif 1.1.

   /* string.c  -- create a compound string with the "MY_TAG" tag.    * The tag defaults to the "9x15" font.  Create three pushbuttons:    * pb1, pb2, and pb3.  The user can specify resources so that each of the    * widgets has a different font associated with the "MY_TAG" tag    * specified in the compound string.    */   #include <Xm/RowColumn.h>   #include <Xm/PushBG.h>   String fallbacks[] = { "*fontList:9x15=MY_TAG", NULL };   main(argc, argv)   int argc;   char *argv[];   {       Widget        toplevel, rowcol;       XtAppContext  app;       XmString      text;       Display      *dpy;       XtSetLanguageProc (NULL, NULL, NULL);       toplevel = XtVaAppInitialize (&app, "String", NULL, 0,           &argc, argv, fallbacks, NULL);       text = XmStringCreate ("Testing, testing...", "MY_TAG");       rowcol = XtVaCreateWidget ("rowcol",           xmRowColumnWidgetClass, toplevel,           NULL);       XtVaCreateManagedWidget ("pb1",           xmPushButtonGadgetClass, rowcol,           XmNlabelString, text,           NULL);       XtVaCreateManagedWidget ("pb2",           xmPushButtonGadgetClass, rowcol,           XmNlabelString, text,           NULL);       XtVaCreateManagedWidget ("pb3",           xmPushButtonGadgetClass, rowcol,           XmNlabelString, text,           NULL);       XmStringFree (text);       XtManageChild (rowcol);       XtRealizeWidget (toplevel);       XtAppMainLoop (app);   }
This simple program creates three PushButton gadgets that all use the same compound string for their labels. The font list tagMY_TAG is associated with the9x15 font in the fallback resources. By default, all of the buttons look the same, as shown in the figure.

figs.eps/V6a.19.01.eps.png
Output of string.c

However, the figure shows what happens to the output when the following resources are specified:

   *pb1.fontList: -*-courier-*-r-*--*-120-*=MY_TAG   *pb2.fontList: -*-courier-*-r-*--*-140-*=MY_TAG   *pb3.fontList: -*-courier-*-r-*--*-180-*=MY_TAG

figs.eps/V6a.19.02.eps.png
Output of string.c with font list resources set

The font associated withMY_TAG for each of the PushButtons is different, so the compound string for each one is rendered in a different font. This case isn't really that exciting, however, because we could have achieved the same effect without specifying a font list tag for each font. Since each font list only contains one font, Motif has no choice but to display the compound string using that font. The following resource specification creates the output shown in the figure:

   *pb1.fontList: -*-courier-*-r-*--*-120-*   *pb2.fontList: fixed,-*-courier-*-r-*--*-140-*=ANOTHER_TAG   *pb3.fontList: fixed,-*-courier-*-r-*--*-180-*=MY_TAG

figs.eps/V6a.19.03.eps.png
Output of string.c with multiple font list resources set

In this case, the compound string in the first PushButton uses a 12-point Courier font, since that is the only font in the font list. The second PushButton uses thefixed font because it is first in the list and neither of the fonts hasMY_TAG associated with it. The third button uses the 18-point Courier font associated withMY_TAG. In Motif 1.2, the constantXmFONTLIST_DEFAULT_TAG is used to tag compound strings that are created in the encoding of the current locale. When a compound string is created usingXmStringCreateLocalized(), this tag is used. The equivalent compound string can also be created usingXmStringCreate() with the tag explicitly set toXmFONTLIST_DEFAULT_TAG. Just as with other font list tags, Motif looks for a font or font set with a matching tag when it renders the compound string. This font list tag is used to identify the font or font set that is correct for the encoding of the current locale. If a font list does not useXmFONTLIST_DEFAULT_TAG, the first item in the font list is automatically associated with this tag.

An internationalized application should only useXmFONTLIST_DEFAULT_TAG in font lists to ensure that compound strings are rendered correctly for the current locale. However, it is possible to use explicit font list tags for locale-specific text. Explicit tags are necessary when an application wants to display compound strings using different point sizes or type styles. In this case, the compound string and the font list associated with it need to use the same tag, and the tag should be mapped toXmFONTLIST_DEFAULT_TAG usingXmRegisterSegmentEncoding().

In Motif 1.1, the first font in widget's font list is the default character set for that widget. If the widget does not have a font list, it uses a default character set referred to by the constantXmSTRING_DEFAULT_CHARSET. If the user has set theLANG environment variable, its value is used for this character set. If this value is invalid or its associated font cannot be used, Motif uses the value ofXmFALLBACK_CHARSET, which is vendor-defined but typically set to "ISO8859-1".

For backwards compatibility, Motif 1.2 essentially equatesXmFONTLIST_DEFAULT_TAG withXmSTRING_DEFAULT_CHARSET when it cannot find an exact match between a compound string and a font list.XmFONTLIST_DEFAULT_TAG in a compound string or font list matches the tag used in creating a compound string or specifying a font list entry with the tagXmSTRING_DEFAULT_CHARSET. Some Motif widgets define font list resources that allow them to provide a consistent appearance for all of their children. In Motif 1.2, the VendorShell widget defines theXmNbuttonFontList,XmNlabelFontList, andXmNtextFontList resources, while the MenuShell definesXmNbuttonFontList andXmNlabelFontList. These resources apply to all of the buttons, Labels, and Text widgets that are descendents of the widget. In Motif 1.1, the VendorShell and MenuShell only defined theXmNdefaultFontList resource; this resource applied to all of the children of the widget. For backwards compatibility, if one of the more specific font list resources is not set, its value is taken fromXmNdefaultFontList.

The BulletinBoard widget defines theXmNbuttonFontList,XmNlabelFontList, andXmNtextFontList resources primarily for use in dialog boxes. These font lists apply to the buttons, Labels, and Text widgets that descend from a BulletinBoard. For more information on the use of the resources in dialog boxes, see Chapter 5, Introduction to Dialogs.

All of these font list resources are designed to help you maintain a consistent interface. However, you can always specify the font for a particular button, Label, or Text widget using the widget'sXmNfontList resource, as this resource overrides the more general ones.

20.2.3 Compound String Segments

A compound string is composed of segments, where each segment contains a continuous sequence of text with no change in font list tag or direction. A compound string segment can be terminated by a separator, which is the equivalent of a newline in a character string. Separators in compound strings should not be confused with the Separator widget and gadget class. Segments can be concatenated with other segments or compound strings to create longer strings; each segment can specify a different tag and direction to make a string that uses mutiple fonts and directions.

XmStringSegmentCreate() provides complete control over the creation of a compound string, as it allows you to specify the text, a font list tag, and a direction. This routine also lets you specify whether or not a separator is added to the compound string. The routine takes the following form:

   XmString   XmStringSegmentCreate(text,tag,direction,separator)       char              *text;       char              *tag;       XmStringDirectiondirection;       Booleanseparator;
Compound strings are rendered either from left-to-right or from right-to-left. If you are going to use left-to-right strings uniformly in your applications, you really don't need to read this section. There are several ways to build a compound string that is rendered from right-to-left; the best method is dependent on the nature of your application.

If your application uses right-to-left strings for all of its widgets, you may want to use the ManagerXmNstringDirection resource. This resource specifies the direction for compound strings used by widgets that are immediate children of a Manager widget, provided that the string direction is not hard-coded in the compound strings. If you use this resource, you can continue to useXmStringCreate() orXmStringCreateLocalized() to create compound strings.

Most right-to-left languages display certain things, like numbers, from left-to-right, so it is not always possible to use theXmNstringDirection resource. In this case, you have to create compound string segments that hard-code their directional information. You can create individual string segments with a specific by direction using eitherXmStringDirectionCreate() orXmStringSegmentCreate(). Both of these routines take an argument of typeXmStringDirection, which is defined as anunsignedchar. You can specify eitherXmSTRING_DIRECTION_R_TO_L orXmSTRING_DIRECTION_ L_TO_R for values of this type.

When usingXmStringSegmentCreate(), you specify the string direction using thedirection parameter. For example, we can change the call toXmStringCreate() in the source code to the following:

   text = XmStringSegmentCreate ("Testing, testing...", "MY_TAG",       XmSTRING_DIRECTION_R_TO_L, False);
Obviously, you would normally do this only if you were using a font that was meant to be read from right-to-left, such as Hebrew or Arabic. The output that results from this change is shown in the figure.

figs.eps/V6a.19.04.eps.png
Output of string.c using a right-to-left string direction


You can also use the functionXmStringDirectionCreate() to create a compound string segment that contains only directional information. This routine takes the following form:

   XmString   XmStringDirectionCreate(direction)       XmStringDirectiondirection;
The routine returns a compound string segment that can be concatenated with another compound string to cause a directional change. Separators are used to break compound strings into multiple lines, in much the same way that a newline character does in a character string. To demonstrate separators, we can change the string creation line in the source code to the following:
   text = XmStringCreateLtoR ("Testing,0esting...", "MY_TAG");
In this case, we useXmStringCreateLtoR() not because we need to specify the left-to-right direction explicitly, but because this function interprets embedded newline characters (\n) as separators. The effect of this change is shown in the figure, where the PushButtons display multiple lines of text.

figs.eps/V6a.19.05.eps.png
Output of string.c using separators to render multiple lines

XmStringCreate() andXmStringSegmentCreate() do not interpret newline characters as separators; they create a single compound string segment in which the'\n' is treated just like any other character value in the associated font or font set, as shown in the figure.XmStringSegmentCreate(), however, can be told to append a separator to the compound string it creates.

figs.eps/V6a.19.06.eps.png
Output of string.c with \n not interpreted as a separator

Most applications need newline characters to be interpreted as separators. For example, if you are usingfgets() orread() to read the contents of a file, and newlines are read into the buffer, you should useXmStringCreateLtoR() to convert the buffer into a compound string that contains separators. the source code shows a function that reads the contents of a file into a buffer and then converts that buffer into a compound string.XmFONTLIST_DEFAULT_TAG replacesXmSTRING_DEFAULT_CHARSET in Motif 1.2.

   XmString   ConvertFileToXmString(filename, &lines)   char *filename;   int *lines;   {       struct stat  statb;       int          fd, len, lines;       char        *text;       XmString     str;       *lines = 0;       if (!(fd = open (filename, O_RDONLY))) {           XtWarning ("Internal error -- can't open file");           return NULL;       }       if (fstat (fd, &statb) == -1 ||               !(text = XtMalloc ((len = statb.st_size) + 1))) {           XtWarning ("Internal error -- can't show text");           close (fd);           return NULL;       }       (void) read (fd, text, len);       text[len] = 0;       str = XmStringCreateLtoR (text, XmFONTLIST_DEFAULT_TAG);       XtFree (text);       close (fd);       *lines = XmStringLineCount (str);       return str;   }

Since separators are considered to be line breaks, we can count the number of lines in the compound string using the functionXmStringLineCount(). However, this does not imply that separators terminate compound strings or cause font changes. As we have shown, a separator can be inserted into the middle of a compound string without terminating it. The fact that separate segments are created has little significance unless you need to convert compound strings back into C strings, which we discuss in Section #sstringcvt.

20.2.4 Multiple-font Strings

Once multiple font list tags are specified in a font list, you can use the list to display more than one font or font set in a single compound string. You can create a multi-font string in one of two ways: create the compound text in segments or create separate compound strings. Either way, once the segments or strings have been created, they must be concatenated together to form a new compound string that has font-change information embedded in it. the source code demonstrates the creation of a compound string that uses three fonts.XtSetLanguageProc() is only available in X11R5; there is no corresponding function in X11R4.

   /* multi_font.c -- create three compound strings using 12, 14 and 18    * point fonts.  The user can specify resources so that each of the strings    * use different fonts by setting resources similar to that shown    * by the fallback resources.    */   #include <Xm/Label.h>   String fallbacks[] = {       "multi_font*fontList:-*-courier-*-r-*--12-*=TAG1,-*-courier-bold-o-*--14-*=TAG2,-*-courier-medium-r-*--18-*=TAG3",       NULL   };   main(argc, argv)   int argc;   char *argv[];   {       Widget        toplevel;       XtAppContext  app;       XmString      s1, s2, s3, text, tmp;       String        string1 = "This is a string ",                     string2 = "that contains three ",                     string3 = "separate fonts.";       XtSetLanguageProc (NULL, NULL, NULL);       toplevel = XtVaAppInitialize (&app, "String", NULL, 0,           &argc, argv, fallbacks, NULL);       s1 = XmStringCreate (string1, "TAG1");       s2 = XmStringCreate (string2, "TAG2");       s3 = XmStringCreate (string3, "TAG3");       /* concatenate the 3 strings on top of each other, but we can only        * do two at a time.  So do s1 and s2 onto tmp and then do s3.        */       tmp = XmStringConcat (s1, s2);       text = XmStringConcat (tmp, s3);       XtVaCreateManagedWidget ("widget_name",           xmLabelWidgetClass, toplevel,           XmNlabelString,     text,           NULL);       XmStringFree (s1);       XmStringFree (s2);       XmStringFree (s3);       XmStringFree (tmp);       XmStringFree (text);       XtRealizeWidget (toplevel);       XtAppMainLoop (app);   }
The output of this program is shown in the figure.

figs.eps/V6a.19.07.eps.png
Output of multi_font.c

TheXmNfontList resource is specified using three fonts, each with a distinct font list tag. We create each string usingXmStringCreate() with the appropriate text and tag. Then we concatenate the strings usingXmStringConcat(), two at a time until we have a single compound string that contains all the text.XmStringConcat() does not work likestrcat() in C. The Motif function creates a new compound string that is composed of the two existing strings, rather than appending one string to the other string. Details of this function and other related functions are discussed in Section #sstringfunc.

It is possible to specify compound string resource values, such as theXmNlabelString resource of the Label widget, in a resource file as normal C strings. Motif provides a resource converter that converts the character string into a compound string. However, this resource converter does not allow you to specify font list tags in the character string. If you need font changes within a compound string, you need to create the compound strings explicitly in your application as we have done in the source code

20.3 Manipulating Compound Strings

Most C programmers are used to dealing with functions such asstrcpy(),strcmp(), andstrcat() to copy, compare, and modify strings. However, these functions do not work with compound strings, as they are not based on a byte-per-character format, and they may haveNULL characters as well as other types of information embedded in them. In order to perform these common tasks, you can either convert the compound string into a character string, or you can use the compound string manipulation functions provided by Motif. The method you choose depends largely on the complexity of the compound strings you have and/or the complexity of the manipulation you need to do.

20.3.1 Compound String Functions

Motif provides a number of functions that allow you to treat compound strings in much the same way that you treat C-style character arrays. The toolkit provides the following routines:

   XmStringByteCompare()   XmStringCompare()   XmStringConcat()   XmStringCopy()   XmStringEmpty()   XmStringHasSubstring()   XmStringLength()   XmStringNConcat()   XmStringNCopy()
BothXmStringCompare() andXmStringByteCompare() compare two compound strings. These routines take the following form:
   Boolean   XmStringCompare(string1,string2)       XmStringstring1,string2;
   Boolean   XmStringByteCompare(string1,string2)       XmStringstring1,string2;
XmStringCompare() simply checks if the strings have the same text components, directions, and separators; it returnsTrue if they do. This routine is simpler and more frequently used thanXmStringByteCompare(), which performs a byte-by-byte comparison of the two compound strings. If each string uses the same font list tags, has the same direction, and contains the same embeddedchar string internally, the function returnsTrue. The mapping between font list tags and fonts does not happen until a compound string is rendered by a widget, so whether or not the same font list tag actually maps to two different fonts does not affect the results of this function.

XmStringConcat() andXmStringNConcat() can be used to concatenate compound strings. These functions take the following form:

   XmString   XmStringConcat(string1,string2)       XmStringstring1,string2;
   XmString   XmStringNConcat(string1,string2,n)       XmStringstring1,string2;       intn;
Both of these routines create a new compound string and copy the concatenation ofstring1 andstring2 into the newly allocated string.XmStringNConcat() copies all ofstring1, but onlyn bytes fromstring2, into the new string. The original strings are preserved, and you are responsible for freeing the string returned by the routines usingXmStringFree().

You can copy a compound string using eitherXmStringCopy() orXmStringNCopy(), which take the following forms:

   XmString   XmStringCopy(string)       XmStringstring;
   XmString   XmStringNCopy(string,n)       XmStringstring;       intn;
Both functions copystring into a newly-allocated compound string;XmStringNCopy() only copiesn bytes fromstring.

XmStringHasSubstring() determines whether or not a compound string contains a particular substring. The routine has the following form:

   Boolean   XmStringHasSubstring(string,substring)       XmStringstring,substring;
For this function,substring must be a single-segment compound string. If its text is completely contained within any single segment ofstring, the function returnsTrue. The two strings must use the same font list tags for the routine to returnTrue.

To get the length of a compound string, useXmStringLength(), which has the following form:

   int   XmStringLength(string)       XmStringstring;
This function returns the number of bytes in the compound string including all tags, direction indicators, and separators. If the structure ofstring is invalid, the routine returns zero. This function cannot be used to get the length of the text represented by the compound string; it is not the same asstrlen()).

You can determine whether or not a compound string contains any segments usingXmStringEmpty(), which takes the following form:

   Boolean   XmStringEmpty(string)       XmStringstring;
This function returnsTrue if there are no segments in the specifiedstring andFalse, otherwise. If the routine is passedNULL, it returnsTrue.

20.3.2 Compound String Retrieval

You can retrieve a compound string from a Motif widget usingXtVaGetValues(). However, the wayXtVaGetValues() is used for compound string resources is different than how it is used for most other resources. The value returned byXtVaGetValues() for a compound string resource is a copy of the internal data, so the compound string must be freed by the application, as shown in the following code fragment:

   XmString str;   extern Widget pushbutton;   char *text;   XtVaGetValues (pushbutton, XmNlabelString, &str, NULL);   ...   /* do whatever you want with the compound string */   ...   XmStringFree (str);  /* must free compound strings from GetValues */
To avoid memory leaks in your application, you must remember to free any compound strings that you retrieve from a widget usingXtVaGetValues().

20.3.3 Compound String Conversion

If the Motif routines described in the previous section are inadequate for your needs, you can convert compound strings back into C strings and manipulate them using the conventional C functions. This process can be simple or complicated depending on the complexity of the compound string to be converted. If the compound string only has one tag associated with it and has a left-to-right orientation, the process is quite simple. In this case, which is quite common, you can use the following function to make the conversion:

   Boolean   XmStringGetLtoR(string,tag,text)       XmStringstring;       XmStringCharSettag;       char              **text;
XmStringGetLtoR() takes a compound string and a tag and converts it back into a C character string. If successful, the function returnsTrue, and thetext parameter points to a newly-allocated string. Since the routine allocates storage for the character string, you must free this pointer when you are done using it, as shown in the following code fragment:
   XmString  string;   char     *text;   if (XmStringGetLtoR (string, "MY_TAG", &text)) {       printf ("Text = %s0, text);       XtFree (text);   }

As its name implies,XmStringGetLtoR() only gets left-to-right oriented text. Additionally, the function only gets the first text segment from the compound string that is associated with the specifiedtag. If the string contains multiple tags or has a right-to-left direction, you need to traverse the compound string and retrieve each segment individually in order to obtain the entire string. Motif defines a new type,XmStringContext, that is used to identify and maintain the position within the compound string being scanned. To cycle through a compound string, you need to use the following sequence of operations:

XmStringInitContext() initializes a string context that allows an application to read the contents of a compound string segment by segment. This routine takes the following form:

   Boolean   XmStringInitContext(context,string)       XmStringContext  *context;       XmStringstring;
The function allocates a newXmStringContext type and sets the pointer that is passed by the calling function in thecontext parameter to this data. If the allocation is successful and the compound string is valid, the function returnsTrue.

Once the string context has been initialized, the contents of the string can be scanned usingXmStringGetNextSegment():

   Boolean   XmStringGetNextSegment(context,text,tag,direction,separator)       XmStringContextcontext;       char               **text;       XmStringCharSet     *tag;       XmStringDirection   *direction;       Boolean             *separator;
The routine does not take anXmString parameter because thecontext parameter is used to keep track of the compound string. The function reads the next segment; it stops when it encounters a new tag or a directional change. The values fortext,tag, anddirection are filled in, and if a separator is found at the end of the segment,separator is set toTrue. Thetext parameter points to allocated data that should be freed by the caller usingXtFree().

When you are through scanning the compound string, you need to free the string context usingXmStringFreeContext(), which takes the following form:

   void   XmStringFreeContext(context)       XmStringContextcontext;
the source code shows a routine that uses these functions to print a compound string used as the label for a widget.
   void   PrintLabel(widget)   Widget widget;   {       XmString           str;       XmStringContext    context;       char              *text, *tag, buf[128], *p;       XmStringDirection  direction;       Boolean            separator;       XtVaGetValues (widget, XmNlabelString, &str, NULL);       if (!XmStringInitContext (&context, str)) {           /* compound strings from GetValues still need to be freed! */           XmStringFree (str);           XtWarning ("Can't convert compound string.");           return;       }       /* p keeps a running pointer thru buf as text is read */       p = buf;       while (XmStringGetNextSegment (context, &text, &tag,               &direction, &separator)) {           /* copy text into p and advance to the end of the string */           p += (strlen (strcpy (p, text)));           if (separator == True) { /* if there's a separator ... */               *p++ = '0;               *p = 0;  /* add newline and null-terminate */           }           XtFree (text);   /* we're done with the text; free it */       }       XmStringFreeContext (context);       XmStringFree (str);       printf ("Compound string:0s0, buf);   }

20.4 Working With Font Lists

As we have demonstrated, font lists can be set in a resource file. If your application is robust enough to handle any particular font that the user may specify, you are encouraged to use fallback resources and the application defaults files for all font list specifications. This technique simplifies maintenance for your application, as you do not have to open fonts, maintain handles to them, and free them. If you are writing an internationalized application, you should only specify font lists in resource files so that you can specify different fonts and/or font sets in the resource files for different locales.

However, if you specifically don't want the user to override your font specifications, you can hard-code fonts within the application using various Motif routines to create a font list. In this case, you are taking on the responsibility of creating, maintaining, and destroying fonts as necessary. Motif also provides routines that allow you to retrieve information about a font list.

20.4.1 Creating Font Lists

All of the font list creation functions deal with a font list object of typeXmFontList. This type is intended to be opaque, so you should not attempt to access the internal fields of the data structure. If you need information about the fonts in a font list, you can use the routines for querying a font list that we are going to describe.

The Motif API for font lists has changed significantly in Motif 1.2 to support the newXFontSet abstraction. The Motif 1.1 routines exist for backwards compatibility, but they are now obsolete. In Motif 1.2, each item in a font list specifies anXmFontListEntry and an associated tag, while in Motif 1.1 each item specifies a font and a character set tag. TheXmFontListEntry type is an opaque type that can specify either a font or a font set.

The process for creating a font list involves creating individual font list entries and then appending these entries to a font list. the source code shows a program that produces the same output as the source code but now the font list is hard-coded in the program.XtSetLanguageProc() is only available in X11R5; there is no corresponding function in X11R4.XmFontListEntryCreate() is only available in Motif 1.2; there is no corresponding function in Motif 1.1.XmFontListAppendEntry() is only available in Motif 1.2;XmFontListCreate() andXmFontListAdd() are the corresponding functions in Motif 1.1.

   /* fontlist.c -- demonstrate how to create, add to, and destroy    * font lists.  The fonts and text displayed are hardcoded in    * this program and cannot be overriden by user resources.    */   #include <Xm/Label.h>   main(argc, argv)   int argc;   char *argv[];   {       Widget         toplevel;       XtAppContext   app;       XmString       s1, s2, s3, text, tmp;       XmFontListEntry   entry1, entry2, entry3;       XmFontList     fontlist;       String         string1 = "This is a string ",                      string2 = "that contains three ",                      string3 = "separate fonts.";       XtSetLanguageProc (NULL, NULL, NULL);       toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,           &argc, argv, NULL, NULL);       entry1 = XmFontListEntryLoad (XtDisplay (toplevel),           "-*-courier-*-r-*--*-120-*", XmFONT_IS_FONT, "TAG1");       entry2 = XmFontListEntryLoad (XtDisplay (toplevel),           "-*-courier-bold-o-*--*-140-*", XmFONT_IS_FONT, "TAG2");       entry3 = XmFontListEntryLoad (XtDisplay (toplevel),           "-*-courier-medium-r-*--*-180-*", XmFONT_IS_FONT, "TAG3");       fontlist = XmFontListAppendEntry (NULL, entry1);       fontlist = XmFontListAppendEntry (fontlist, entry2);       fontlist = XmFontListAppendEntry (fontlist, entry3);       XmFontListEntryFree (&entry1);       XmFontListEntryFree (&entry2);       XmFontListEntryFree (&entry3);       s1 = XmStringCreate (string1, "TAG1");       s2 = XmStringCreate (string2, "TAG2");       s3 = XmStringCreate (string3, "TAG3");       /* concatenate the 3 strings on top of each other, but we can only        * do two at a time.  So do s1 and s2 onto tmp and then do s3.        */       tmp = XmStringConcat (s1, s2);       text = XmStringConcat (tmp, s3);       XtVaCreateManagedWidget ("label", xmLabelWidgetClass, toplevel,           XmNlabelString,     text,           XmNfontList,        fontlist,           NULL);       XmStringFree (s1);       XmStringFree (s2);       XmStringFree (s3);       XmStringFree (tmp);       XmStringFree (text);       XmFontListFree (fontlist);       XtRealizeWidget (toplevel);       XtAppMainLoop (app);   }
This program creates font list entries for three fonts, appends the entries to a font list, and uses the resulting font list to specify theXmNfontList resource of a Label widget. The compound strings are created using the same tags as the font list entries, so they are displayed in the appropriate fonts.

In the source code we create the font list entries usingXmFontListEntryLoad(), which takes the following form:

   XmFontListEntry   XmFontListEntryLoad(display,font_name,type,tag)       Display    *display;       char       *font_name;       XmFontTypetype;       char       *tag;
This routine loads the font or creates the font set specified byfont_name. The function uses Xt resource converters to convert the string name of the font to the appropriate type. Thetype parameter specifies whether the font name is a font or a font set; it can have the valueXmFONT_IS_FONT orXmFONT_IS_FONT_SET. Thetag is associated with the font list entry. If the routine can load or create the specified font, it allocates and returns anXmFontListEntry, which the application must free usingXmFontListEntryFree(). If the routine cannot find the specified font, it returnsNULL.

Once we have created the font list entries, we can use them to make a font list.XmFontListAppendEntry() appends a font list entry to a font list. We call this routine three times to add the three entries.XmFontListAppendEntry() takes the following form:

   XmFontList   XmFontListAppendEntry(oldlist,entry)       XmFontListoldlist;       XmFontListEntryentry;
The routine adds the specifiedentry to the old font list and returns a new font list. Ifoldlist isNULL, the routine simply creates a font list using the font list entry. Motif caches font lists, so when we add a font list entry to a font list, the routine searches the cache for a font list that matches the new font list. If the routine finds a matching font list, it returns that font list and increments its reference count. Otherwise,XmFontListAppendEntry() allocates space for the new font list and caches it. The routine deallocates the storage for the old font list, but the application is responsible for freeing the storage for the new font list usingXmFontListFree().

After we add the font list entries to the font list, we don't need the individual entries, so we free them usingXmFontListEntryFree(). Notice that this routine takes an address of a font list entry, not the actual font list entry. When Motif creates a font list entry, it does not copy theXFontStruct orXFontSet, so these items must not be freed. If you pass a font list entry, instead of its address, toXmFontListEntryFree(), you end up freeing the font or font set, which results in an X protocol error.

The fontlist.c program creates compound strings just like our previous examples. The strings are associated with the same tags as the font list entries, so the strings are rendered using the appropriate fonts. The program sets theXmNfontList resource of the Label widget, so the fonts are hard-coded in the application and cannot be modified using a resource file. When a font list is assigned to a widget, the widget copies the list usingXmFontListCopy(). After the resource has been specified, the program no longer needs the font list, so it frees it usingXmFontListFree().

We usedXmFontListEntryLoad() to both load the font and create a font list entry. Alternatively, we could have loaded the fonts using a routine likeXLoadQueryFont() and then calledXmFontListEntryCreate() to create the font list entries. This routine takes the following form:

   XmFontListEntry   XmFontListEntryCreate(tag,type,font)       char       *tag       XmFontTypetype;       XtPointerfont;
Thetype parameter specifies whether the specifiedfont is anXFontStruct or anXFontSet. You can load a font usingXLoadQueryFont(). UseXCreateFontSet() to create a font set. (See Volume One, Xlib Programming Manual, for more information on these routines.)XmFontListEntryCreate() allocates and returns a font list entry; the application is responsible for freeing this entry usingXmFontListEntryFree().

It is purely a matter of preference whether you useXmFontListEntryCreate() orXmFontListEntryLoad(). In the source code we could replace our calls toXmFontListEntryLoad() with the following code:

   XFontStruct         *font1, *font2, *font3;   XmFontListEntry     entry1, entry2, entry3;   font1 = XLoadQueryFont (XtDisplay (toplevel),       "-*-courier-*-r-*--*-120-*");   font2 = XLoadQueryFont (XtDisplay (toplevel),       "-*-courier-bold-o-*--*-140-*");   font3 = XLoadQueryFont (XtDisplay (toplevel),       "-*-courier-medium-r-*--*-180-*");   entry1 = XmFontListEntryCreate ("TAG1", XmFONT_IS_FONT, font1);   entry2 = XmFontListEntryCreate ("TAG2", XmFONT_IS_FONT, font2);   entry3 = XmFontListEntryCreate ("TAG3", XmFONT_IS_FONT, font3);
The functionality of the program is the same in either case, so which method you use really depends on whether you want to load the fonts yourself or let the routine handle it for you.

In Motif 1.1, there are two routines for dealing with font lists.XmFontListCreate() creates a new font list with one entry, whileXmFontListAdd() adds a font to an existing font list. These routines take the following form:

   XmFontList   XmFontListCreate(font,charset)       XFontStruct      *font;       XmStringCharSetcharset;
   XmFontList   XmFontListAdd(oldlist,font,charset);       XmFontListoldlist;       XFontStruct      *font;       XmStringCharSetcharset;
The routines both take anXFontStruct, so you have to load the font yourself usingXLoadQueryFont(). The functions both allocate and return a font list that the application must free when it is done using it. These routines exist for backwards compatibility purposes only, so you should not use them with Motif 1.2.

20.4.2 Retrieving Font Lists

You can retrieve a font list directly from a widget usingXtVaGetValues() no matter whether the font list is specified in a resource file or created programatically. The following code fragment demonstrates this technique:

   XmFontList fontlist;   XtVaGetValues (widget, XmNfontList, &fontlist, NULL);
The font list returned byXtVaGetValues() is a pointer to internal data, so it should be considered read-only. You should not alter this font list or free it. This is in direct contrast to how Motif usesXtVaGetValues() for compound strings, where a copy of the string is returned. If you need to manipulate the font list, you can make a copy of it usingXmFontListCopy().

Once you have obtained a font list from a widget, you can use it to specify the font list for another widget, as shown in the following code:

   XtVaSetValues (another_widget, XmNfontList, fontlist, NULL);
Since the font list was obtained through a call toXtVaGetValues(), we do not free it after setting theXmNfontList resource.

20.4.3 Querying Font Lists

TheXmFontList type is opaque to the programmer, so if you need to get information about a font list, you have to use Motif-specific functions that access font list information. This internal information can be useful if you need the font handles or tags for any reason. Motif provides a number of routines to cycle through the font list. TheXmFontContext type is used to identify and maintain the position within the font list being queried. To query a font list, you need to use the following sequence of operations:

XmFontListInitContext() initializes a font context that lets an application get the individual font list entries from the font list. This routine takes the following form:
   Boolean   XmFontListInitFontContext(context,fontlist)       XmFontContext  *context;       XmFontListfontlist;
The routine is passed the address of anXmFontContext variable and a font list. It allocates a new font context structure based on the font list and returnsTrue. If the font list is not valid or there is not enough memory available to allocate a new context,False is returned.

Once the font context has been initialized, the entries in the font list can be retrieved usingXmFontListNextEntry():

   XmFontListEntry   XmFontListNextEntry(context)       XmFontContextcontext;
This routine cycles through all of the font list entries in the font list. The first call returns the first entry in the font list; repeated calls using the same font context access successive entries. Since theXmFontListEntry type is also opaque, you have to useXmFontListEntryGetFont() andXmFontListEntryGetTag() to retrieve the actual font or font set and tag for the font list entry. These routines take the following form:
   XtPointer   XmFontListEntryGetFont(entry,type_return)       XmFontListEntryentry;       XmFontType      *type_return;
   char *   XmFontListEntryGetTag(entry)       XmFontListEntryentry;
XmFontListEntryGetFont() returns anXFontStruct or anXFontSet depending on the value oftype_return. The routine does not copy the data structure, so the application must not free it.XmFontListEntryGetTag() retrieves the tag for the font list entry. This routine allocates storage for the tag, so the application must free it.

In Motif 1.1, you callXmFontListGetNextFont() to cycle through the fonts in a font list. This routine has the following form:

   Boolean   XmFontListGetNextFont(context,charset,font)       XmFontContextcontext;       XmStringCharSet *charset;       XFontStruct     **font;
If the function returnsTrue, the character set and font pointers are set to the appropriate values. Thecharset returned is a pointer to allocated data that must be freed when no longer needed. The value forfont points to the actualXFontStruct data used in the font list, so it must not be freed. If the end of the list has been reached, the function returnsFalse. This routine exists for backwards compatibility and should not be used with Motif 1.2.

When you are done querying the font list, you need to free the font context usingXmFontListFreeFontContext(), which takes the following form:

   void   XmFontListFreeFontContext(context)       XmFontListFontContextcontext;
If you are searching through a font list and need to back up, you must restart the entire process by freeing the current font context and creating a new one.

20.5 Rendering Compound Strings

Motif always renders compound strings automatically within its widgets, so you should never find yourself in a situation where you need to render a compound string manually. However, if you are writing your own widget, you may need to incorporate the same type of functionality. Motif provides three functions that render compound strings:

   XmStringDraw()   XmStringDrawImage()   XmStringDrawUnderline()
In Motif 1.2, all of these routines use the X11R5 text output routines when necessary, to ensure that the text is rendered correctly for the current locale.

The most basic rendering function isXmStringDraw(), which takes the following form:

   XmStringDraw(display,window,fontlist,string,gc,x,y,width,alignment,layout_direction,clip);       Display       *display;       Windowwindow;       XmFontListfontlist;       XmStringstring;       GCgc;       Positionx,y;       Dimensionwidth;       unsigned charalignment;       unsigned charlayout_direction;       XRectangle    *clip;
As you can see, the function requires a great deal of information to actually render the string. If you are rendering into a widget, you can specify thedisplay andwindow usingXtWindow() andXtDisplay(). Since a gadget does not have a window, you must useXtWindowOfObject() with a gadget. Thefontlist parameter can be constructed using any of the functions described in Section #sfontlist, or you can retrieve a font list from a widget usingXtVaGetValues().

The function also requires a graphics context (GC) so that certain rendering attributes such as color can be applied. A graphics context is generally not available through a widget, so you have to get one at the Xlib level. If you are writing your own widget, you can probably use aGC that is cached by Xt and returned byXtGetGC() (see Volume Four, X Toolkit Intrinsics Programming Manual). Also, if you are writing your own widget, you may want to consider exposing theGC to the programmer in the form of a resource.

Thex,y, andwidth parameters specify the coordinates and width of the rectangle that contains the compound string. Thewidth parameter is used only for alignment purposes. There is no height parameter because the font list may specify fonts that are unknown in size and whose heights are too variable. Theclip parameter defines the drawing boundary; you can passNULL to indicate that the rendering should not be clipped.

Thealignment parameter can be set to one of the following values:

   XmALIGNMENT_BEGINNING   XmALIGNMENT_CENTER   XmALIGNMENT_END
The value identifies the justification for the text. The effect of the value is modified by the value of thelayout_direction parameter, which can be set toXmSTRING_DIRECTION_L_TO_R orXmSTRING_DIRECTION_R_TO_L.

The functionXmStringDrawImage() is toXmStringDraw() asXDrawString() is toXDrawImageString(). The difference is that the image routines overwrite the background even in places where the font does not set bits in the character image, while the other routines only render foreground pixels.

TheXmStringDrawUnderline() routine takes the same parameters asXmStringDraw() with one addition. The last parameter specifies the portion of the compound string that should be underlined. A compound string can be wholly or partially underlined depending on whether the last parameter specifies the entire compound string or only a substring of thestring parameter.

It may be necessary to get dimensional information about a compound string in order to know where to place it within the window when it is drawn. You may also want this data to determine the optimal or desired width and height of a widget in case you have to provide a geometry callback method. When a call toXtQueryGeometry is made, a widget that contains compound strings may need to tell the calling function the dimensions it needs to render its compound strings adequately. Motif provides the following routines to help you determine compound string dimensions:

   XmStringBaseLine()   XmStringExtent()   XmStringHeight()   XmStringWidth()

Each of these functions takesfontlist (XmFontList) andstring (XmString) parameters. The font list is dependent on the widget associated with the string, but there is no requirement that you must use a string that is associated with a widget. If you just want to get the dimensions of a particular compound string rendered using an arbitrary font or font set, you can create a font list manually, as described in Section #sfontlist.

XmStringBaseline() returns the number of pixels between the top of the character box and the baseline of the first line of text in the compound string.XmStringWidth() andXmStringHeight() return the width and height, respectively, for the specified compound string.XmStringExtent() takes two additional parameters,width andheight. These arguments return the width and height in pixels of the smallest rectangle that encloses the compound string specified instring.

20.6 Summary

Compound strings can be useful for creating multi-line or multi-font text for widgets such as Labels, PushButtons, and ToggleButtons. Compound strings were also designed to help in making internationalized applications, but this functionality has basically been made obsolete by the addition of internationalization features in X11R5. Since Motif applications have to use compound strings to display most textual data, the trick to developing an internationalized application is to use compound strings without interfering with lower-level X internationalization functionality.

The best practice is to specify compound string and font list resources in resource files, so that you can have a separate file for each language that is supported by your application. If you have to create compound strings in an application, you should useXmStringCreateLocalized() or specify theXmFONTLIST_DEFAULT_TAG font list tag to ensure that the strings are interpreted and rendered in the current locale.


ContentsPreviousNext

[8]ページ先頭

©2009-2025 Movatter.jp