5    Creating Internationalized X, Xt, and Motif Applications

This chapter discusses some of the internationalization features that are available for creating a graphical user interface. More specifically, this chapter addresses the following components:

This chapter assumes that you are already familiar with these components. For more complete information on them, refer to the following documents:

In addition to these documents, you can refer to reference pages for individual functions.

This chapter does not discuss internationalization features specific to the Common Desktop Environment. Refer to the Common Desktop Environment: Internationalization Programmer's Guide for information about using these features.

5.1    Using Internationalization Features in the X Toolkit Intrinsics

The X Toolkit Intrinsics includes internationalization features related to the initialization process and resource management. The following sections describe these features. For complete information on using routines from the X Toolkit Intrinsics Library (libXt) in your applications, refer to the reference pages for individual components.

5.1.1    Establishing a Locale with Xt Functions

An internationalized X Toolkit application must parse resources in a locale-dependent manner. Therefore, an application must establish its locale before initializing the resource database. But it is also true that the application's locale can be specified by resources. To solve this paradox, Release 5 of the X Toolkit introduced the language procedure, which is registered before initializing X Toolkit and then called during initialization at the appropriate time to set locale. The XtSetLanguageProc( ) function registers the language procedure for setting the locale. By default, this function first calls the Standard C Library function setlocale( ) to set the locale and then calls the X Library functions XSupportsLocale( ) and XSetLocaleModifiers( ) to initialize the locale. An application that uses the X Toolkit routines must call XtSetLanguageProc( ), even if the application uses the system default language procedure; otherwise, the locale is not set and other Xt routines do not behave in a locale-dependent manner. One of the most common ways to set locale is for applications to make the following call before calling XtAppInitialize( ):

XtSetLanguageProc(NULL,NULL,NULL);

After calling XtSetLanguageProc( ), your application can then call one of the following Xt initialization functions:

These functions call XtDisplayInitialize( ), which obtains the value of the xnlLanguage resource by parsing the command line and the RESOURCE_MANAGER property. The XtDisplayInitialize( ) function then calls the language procedure registered by the call to XtSetLanguageProc(), passing it the xnlLanguage value as an argument. After that, XtDisplayInitialize() parses resources in the locale returned by the language procedure.

5.1.2    Using Font Set Resources with Xt Functions

The Xt routines support the XFontSet structure in place of the XFontStruct structure in any internationalized widgets that draw native-language text. The following resource attributes exist to support XFontSet:

The X Toolkit includes a converter that changes a preregistered string, such as -*-*-*-R-*-*-*-120-75-75-*-*-*-*, to a list of font sets in the structure (XFontSet). The converter should establish a default font set list so that, if the string cannot be converted to a valid font set list, there is a fallback to a valid font set.

5.1.3    Filtering Events During Text Input with Xt Functions

Starting with Release 5 of the X Toolkit Intrinsics, the XtDispatchEvent( ) function was changed to call XFilterEvent( ). This change allows an input method to intercept registered X events before being processed by an application that uses Xt routines.

5.1.4    Including the Codeset Component of Locales with Xt Functions

Starting with Release 5 of the X Toolkit Intrinsics, an integral locale entity supports the codeset component, in addition to the language and territory components supported by earlier releases.

5.2    Using Internationalization Features of the OSF/Motif and DECwindows Motif Toolkits

The chapter on internationalization features in the OSF/Motif Programmer's Guide discusses how you internationalize Motif applications. The following sections are a supplement to information in that chapter.

5.2.1    Setting Language in a Motif Application

Most of the internationalization features in the OSF/Motif Toolkit (libXm) and the DECwindows Extensions to the OSF/Motif Toolkit (libDXm) are supported through features first introduced in Release 5 of the X Library (libX) and the X Toolkit (libXt). Motif internationalization features are also supported the same way when Release 6 or Release 6.3 of the X Library and X Toolkit are installed. For example, to establish the locale of your Motif application, you use the same set of functions and guidelines as described for an Xt application. (See Section 5.1.1.) If your application fails to call XtSetLanguageProc() before initializing X Toolkit to register the language procedure, the Motif widgets do not support the internationalization features discussed in subsequent sections; in other words, the widgets revert to behavior expected in releases earlier than X Toolkit Release 5 and OSF/Motif Release 1.2.

The language for an application can be specified by:

Elements higher on the preceding list take precedence over lower elements. Note the following points:

5.2.2    Using Compound Strings and the XmText, XmTextField, and DXmCSText Widgets

The OSF/Motif XmText and XmTextField widgets provide internationalization features based on the X and X Toolkit Libraries. The widgets use the codeset of the current locale to encode text information that users enter and display. To display the data in the correct fonts, the widgets use the following search pattern to locate the fonts:

Items in the preceding list are in precedence order from highest to lowest; the widgets stop the search when an item higher on the list determines the font set.

The internationalization features available through the text widgets have changed from earlier OSF/Motif releases on the following two dimensions:

Note

When users select the off-the-spot input style, an application window is enlarged to make room for the input status and preedit area (usually at the bottom of the window). Therefore, the off-the-spot input style requires that auto-resizing be enabled for any application in which that input style is used.

If you are writing an X or Motif application that will be used in Asian countries, do not use toolkit functions to disable auto-resize for your application.

You can use the following functions to create a compound string for codesets that include multiple character sets:

Note

Right-to-left display of language text, which is appropriate for languages such as Hebrew, is supported through the DXmCSText widget. The XmText and XmTextField widgets support only left-to-right displays.

5.2.3    Internationalization Features of Widget Classes

The following widget classes support native-language input and display capabilities through the XmText and XmTextField widgets (see Section 5.2.2):

5.3    Using Internationalization Features in the X Library

Starting with Release 5 of the libX11 library, the X Consortium defined new specifications for developing X clients that handle data for different locales. The new specifications are based on the ANSI C locale model, which configures the Standard C Library to process data in different native languages. These specifications provide interfaces for:

The following sections, which describe how to write an internationalized application with the X Library, cover the following topics:

To illustrate programming techniques, particularly those pertaining to text input, sections that discuss the preceding topics include excerpts from an application named ximdemo. The complete source file and an Imakefile for this application are provided on line in the $I18NPATH/usr/examples/ximdemo directory. You can read the source file, and build and run the application to understand more fully how to apply the programming techniques being discussed.

5.3.1    Using the X Library to Manage Locales

An internationalized X client uses the same locale announcement mechanism, the setlocale function in the Standard C Library, as other kinds of applications use. The X Library includes two additional functions to determine the locale and configure locale modifiers: XSupportsLocale( ) and XSetLocaleModifiers( ). Table 5-1 briefly describes these functions. They are more fully described in XSupportsLocale(3X11) and XSetLocaleModifiers(3X11).

Table 5-1:  Locale Announcement Functions in the X Library

Function Description
XSupportsLocale( ) Determines if the X Library supports the current locale.
XSetLocaleModifiers( )

Specifies a list of X modifiers for the current locale setting.

This list is a null-terminated string where list elements use the format @category =value. The only standard category currently defined as a locale modifier is im, which identifies the input method. However, several im entries can appear on a modifier list when a locale supports more than one input method.

To provide default values on the local host system, the value defined for the XMODIFIERS environment variable is appended to the list of any modifiers supplied by the function call. For example, on Tru64 UNIX systems, the default value for the input method is DEC. The following command explicitly sets the XMODIFIERS variable to this value:

% setenv XMODIFIERS @im=DEC

In this example, the value @im=DEC would be appended to the modifier list specified on the call to XSetLocaleModifiers( ).

X Library functions operate according to current locale and locale-modifier settings or according to locale and locale modifier settings attached to objects that are supplied to the functions. There are five types of objects related to locale settings:

The locale and locale modifiers of these objects depend on the locale setting when the objects were created. Therefore, you can create objects for various languages and use them simultaneously to process data from different locales. This capability lets you develop multilingual X window applications. Adhere to the following rules when developing your application:

Example 5-1 shows how an X application sets or determines locale.

Example 5-1:  Setting Locale in an X Windows Application

#include <stdio.h>
#include <X11/Xlocale.h>
#include <X11/Xlib.h>

.
.
.
#define DEFAULT_LOCALE "zh_TW.dechanyu" [1]
.
.
.
main(argc, argv) int argc; char *argv[]; {
.
.
.
immodifier[0] = '\0'; for(i=1; i<argc; i++) { if(!strcmp(argv[i], "-Root")) { best_style = XIMPreeditNothing; }
.
.
.
else if (!strcmp(argv[i], "-locale")) [2] locale = argv[++i]; else if (!strcmp(argv[i], "-immodifier")) { strcpy(immodifier, "@im="); strcat(immodifier, argv[++i]); } }
.
.
.
if(locale == NULL) locale = DEFAULT_LOCALE; [3] if(setlocale(LC_CTYPE, locale) == NULL) { fprintf(stderr, "Error : setlocale() !\n"); exit(0); } if (!XSupportsLocale()) { fprintf(stderr, "X does not support this locale"); exit(1); } if (XSetLocaleModifiers(immodifier) == NULL) { (void) fprintf(stderr, "%s: Warning : cannot set locale \ modifiers. \n", argv[0]); }
.
.
.

  1. Defines a constant to contain the setting for the default locale

    In this example, the constant's value is explicitly set to zh_TW.dechanyu. [Return to example]

  2. Determines if a locale was specified on the application command line

    The user can override the default locale by using the -locale option on the command line that runs this application. [Return to example]

  3. Sets the locale to the value of the DEFAULT_LOCALE constant if the locale was not specified on the application command line

    If this constant were set to the NULL string ("") rather than zh_TW.dechanyu, the default locale would be determined by the setting of the LANG environment variable for the process in which the application is run. [Return to example]

5.3.2    Displaying Text for Different Locales

Codesets for some locales, particularly those for Asian languages, require more than one X window font to display all the characters defined. To handle these codesets, the X Library supports the concept of a font set, which allows you to use more than one font to draw and measure text. The font set concept is implemented by the XFontSet structure, which replaces the XFontStruct structure that was supported by X Library releases earlier than Release 5.

A font set is bound to the locale with which it was created. The functions that draw and measure text interpret the text according to the locale of the font set and therefore map characters to their font glyphs correctly.

The implementation of functions that draw and measure text allows you to use fonts with different encodings to display native-language text.

5.3.2.1    Creating and Manipulating Font Sets

Table 5-2 summarizes the functions that create and use font sets. For complete information on a function, refer to its reference page.

Table 5-2:  X Library Functions That Create and Manipulate Font Sets

Function Description
XCreateFontSet( ) Creates a font set for a specified display. This function determines the codesets required for the current locale and loads a set of fonts to support those codesets.
XFreeFontSet( ) Frees a specified font set and any associated components, such as the base font name list, the font name list, the XFontStruct list, and XFontSetExtents.
XFontsOfFontSet( ) Returns a list of XFontStruct structures and font names for the given font set.
XBaseFontNameListOfFontSet( ) Returns the original base font name list supplied by the client when the font set was created.
XLocaleOfFontSet( ) Returns the name of the locale bound to the specified font set.

Example 5-2 shows the functions that create and use font sets.

Example 5-2:  Creating and Using Font Sets in an X Windows Application


.
.
.
#define DEFAULT_FONT_NAME "-*-SCREEN-*-*-R-Normal--*-*, -*" [1]
.
.
.
char *base_font_name = NULL;
.
.
.
XFontSet font_set;
.
.
.
char **missing_list; int missing_count; char *def_string;
.
.
.
if (base_font_name == NULL) base_font_name = DEFAULT_FONT_NAME; [2] font_set = XCreateFontSet(display, base_font_name, &missing_list, &missing_count, &def_string);
.
.
.
/* * if there are charsets for which no fonts can be found, * print a warning message. */ if (missing_count > 0) { fprintf(stderr, "The following charsets are \ missing: \n"); for (i=0; i<missing_count; i++) fprintf(stderr, "%s \n", missing_list[i]); XFreeStringList(missing_list); }
.
.
.

  1. Defines the constant, DEFAULT_FONT_NAME, to contain the value of the the default base font name list

    In this example, the default base font name list is set to -*-SCREEN-*-*-R-Normal--*-*, -*. For a default base font name list, you should specify a generic name (using wildcard fields as shown in the example) rather than a fully specified list of fonts. A fully specified font list works only for a particular locale, whereas a generic name can be the default for multiple locales. [Return to example]

  2. Determines whether the default base font name list was supplied on the command line

    The user can override the default base font name list by using the -fs option on the application command line. [Return to example]

5.3.2.2    Obtaining Metrics for Font Sets

Table 5-3 summarizes the X Library functions that can query font set metrics and measure text.

Table 5-3:  X Library Functions That Measure Text

Function Description
XExtentsOfFontSet( ) Returns an XFontSetExtents structure, which contains information about the bounding box of the fonts in the specified font sets.
XmbTextEscapement( ), XwcTextEscapement( ) Calculate the escapement (in pixels) required to draw a given string by using the specified font set.
XmbTextExtents( ), XwcTextExtents( ) Calculate the overall bounding box of the string's image and a logical bounding box for spacing purposes. These functions also return the value returned by XmbTextEscapement( ) and XwcTextEscapement( ), respectively.
XmbTextPerCharExtents( ), XwcTextPerCharExtents( ) Return the text dimensions of each character of the specified text according to the fonts loaded for the specified font set.

5.3.2.3    Drawing Text with Font Sets

Table 5-4 summarizes functions provided specifically for drawing text in different native languages. Unlike other X Library functions that draw text, the internationalized functions do the following:

These functions free applications from handling text encoding directly.

Table 5-4:  X Library Functions That Draw Text

Function Description
XmbDrawText( ), XwcDrawText( )

Draw text, using multiple font sets, and allow complex spacing and font set shifts between text strings.

Use these functions in place of their single-font counterparts, XDrawText( ) and XDrawText16( ).

XmbDrawString( ), XwcDrawString( )

Using one font set, draw only the specified text with the foreground pixel.

Use these functions in place of their single-font counterparts, XDrawString and XDrawString16.

XmbDrawImageString( ), XwcDrawImageString( )

Fill a destination rectangle with the background pixel; then draw the specified image text, using one font set, and paint that text with the foreground pixel.

Use these functions in place of their single-font counterparts, XDrawImageString( ) and XDrawImageString16( ).

Example 5-3 shows how internationalized functions draw text.

Example 5-3:  Drawing Text in an X Windows Application

GC      Jxgc_on, Jxgc_off;
int     Jxcx, Jxcy;
int     Jxcx_offset=2, Jxcy_offset=2;
int     Jxsfont_w, Jxwfont_w, Jxfont_height;
XRectangle      *Jxfont_rect;
int     Jxw_width, Jxw_height;
#define Jxmax_line      10
int     Jxsize[Jxmax_line];
char    Jxbuff[Jxmax_line][128];
int     Jxline_no;
int     Jxline_height;

.
.
.
static int JxWriteText(display, client, font_set, len, string) Display *display; Window client; XFontSet font_set; int len; char *string; { int fy; XFillRectangle(display, client, Jxgc_off, Jxcx, Jxcy, Jxsfont_w, Jxfont_height); [1] if(len == 1 && (string[0] == LF || string[0] == TAB || string[0] == CR)) { _JxNextLine(); XFillRectangle(display, client, Jxgc_off, 0, Jxcy, Jxw_width, Jxfont_height); } else { if(Jxcx >= (Jxw_width - Jxwfont_w) || (Jxsize[Jxline_no] + len) >= 256) { _JxNextLine(); XFillRectangle(display, client, Jxgc_off, 0, Jxcy, Jxw_width, Jxfont_height); } strncpy(&Jxbuff[Jxline_no][Jxsize[Jxline_no]], string, len); Jxsize[Jxline_no] += len; fy = -Jxfont_rect->y + Jxcy; XmbDrawImageString(display, client, font_set, Jxgc_on, Jxcx, fy, string, len); [2] Jxcx += XmbTextEscapement(font_set, string, len); [3] if(Jxcx >= Jxw_width) { _JxNextLine(); XFillRectangle(display, client, Jxgc_off, 0, Jxcy, \ Jxw_width, Jxfont_height); } } XFillRectangle(display, client, Jxgc_on, Jxcx, Jxcy, \ Jxsfont_w, Jxfont_height); }

  1. Displays a block-type cursor by using XFillRectangle( ) [Return to example]

  2. Displays a native-language string by using XmbDrawImageString( )

    The string may contain both single-byte and multibyte characters. [Return to example]

  3. Calculates the position for drawing the next string with XmbTextEscapement( ) [Return to example]

5.3.2.4    Handling Text with the X Output Method

The concept of a font set, as described in the preceding sections, was introduced in Version 5 of the X library. Version 6 of the X library implements the more generalized concepts of output methods and output contexts. Output methods and output contexts handle multiple fonts and context dependencies to enable bidirectional text and context-sensitive text display.

To draw locale-dependent text, the application needs to know which fonts are required for that text, how the text can be separated into its components, and which font is required for each of those components. Version 6 of the X library therefore incorporates the following objects to address this problem:

The following table summarizes the X library functions related to XOM and XOC. For more information on these functions, refer to their reference pages.

Table 5-5:  X Library Functions for Output Method and Context

Function Description
XOpenOM( ) Opens an output method to match the specification of the current locale and modifiers. The function returns an XOM object to which the current locale and modifiers are bound.
XCloseOM( ) Closes the specified output method.
XSetOMValues( ) Sets an output method's attributes.
XGetOMValues( ) Gets the properties or features of the specified output method.
XDisplayOfOM( ) Returns the display associated with the specified output method.
XLocaleOfOM( ) Returns the locale associated with the specified output method.
XCreateOC( ) Creates an output context within the specified output method.
XOMOfOC( ) Returns the output method associated with the specified output context.
XSetOCValues( ) Sets the values of the XOC object.
XGetOCValues( ) Gets the values of the XOC object.
XDestroyOC( ) Destroys the specified output context.

5.3.2.5    Converting Between Different Font Set Encodings

X fonts may be available in different encodings for the following reasons:

Font-encoding divergence from one system to another causes problems for applications that you run on different kinds of systems. Therefore, the implementation of the functions for text drawing and measurement incorporates a mechanism to convert between different font encodings. For conversion to take place, you must design your application so that it can determine the base font name list appropriate for the run-time environment. The application can obtain the base font name list from a resource file or through an option the user specifies on the command line. For example, in the command line to run the ximdemo application, the user can include the -fs option to specify a base font name list.

The conversion mechanism for font encoding is available only when your application uses the internationalized text drawing functions in the X Library. The conversion mechanism is not available with the primitive text drawing functions, such as XDrawText( ) and XDrawString( ).

5.3.3    Handling Interclient Communication

When designing applications for use with different languages and in different countries, you cannot assume that only Latin-1 or ASCII text strings are used for interclient communication. The X Library therefore contains functions that can handle text strings from any language for interclient communication. Table 5-6 summarizes these functions.

Table 5-6:  X Library Functions for Interclient Communication

Function Description
XmbSetWMProperties( )

Provides a single programming interface for setting essential window properties.

Your application uses these properties to communicate with other clients, particularly window and session managers. For example, the functions have arguments for window and icon names and these names can contain multibyte characters in some locales.

XmbTextListToTextProperty( ), XwcTextListToTextProperty( ) Convert text encoded in the current locale to text properties of type STRING or COMPOUND_TEXT.
XmbTextPropertyToTextList( ), XwcTextPropertyToTextList( ) Convert text properties of type STRING or COMPOUND_TEXT to a list of multibyte-character or wide-character strings.
XwcFreeStringList( ) Frees the memory allocated by XwcTextPropertyToTextList( ).
XDefaultString( )

Queries the default string that is substituted when a character cannot be converted.

When conversion routines encounter a string with a character that cannot be converted, they substitute a locale-dependent default string. The XDefaultString( ) function queries that default string.

Example 5-4 shows interclient communication in an X application.

Example 5-4:  Communicating with Other Clients in an X Windows Application


.
.
.
if (!strcmp(locale,"zh_TW.dechanyu")) { strcpy(title, "XIM F|n/"); } else if (!strcmp(locale, "zh_CN.dechanzi")) { strcpy(title, "XIM J>76"); } else if (!strncmp(locale, "ja_JP", 5)) { strcpy(title, "XIM %G%b"); } else if (!strcmp(locale, "ko_KR.deckorean")) { strcpy(title, "XIM 5%8p"); } else if (!strcmp(locale, "th_TH.TACTIS")) { strcpy(title, "XIM !RCJR8T5"); } else { strcpy(title, "XIM Demo") [1] } XmbSetWMProperties(display, window, title, title, NULL, \ 0, NULL, NULL, NULL); [2]
.
.
.

  1. Inserts native-language text in quoted arguments to the strcmp( ) and strcpy( ) functions

    In this example, the text is for a window title. Text strings are explicitly specified in the function calls for the sake of simplicity. In practice, X or Motif applications extract such text strings from locale-specific resource or User-Interface Language (UIL) files. [Return to example]

  2. Passes the text to the XmbSetWMProperties( ) function to parse the title, using the locale, and to set the window manager's property accordingly [Return to example]

5.3.4    Handling Localized Resource Databases

As is also true for font sets, the locale of an X resource file depends on the locale setting when the file was created. Therefore, when a resource file or string is loaded to create a resource database, the file or string is parsed in the current locale. Table 5-7 summarizes the X Library functions that handle localized resource databases.

Table 5-7:  X Library Functions That Handle Localized Resource Databases

Function Description
XrmLocaleOfDatabase( ) Returns the name of the locale bound to the specified database.
XrmGetFileDatabase( )

Opens the specified file, creates a new resource database, and loads it with the specifications read from the file.

The file is parsed in the current locale.

XrmGetStringDatabase( )

Creates a new resource database and stores the resources that are specified in a null-terminated string.

The string is parsed in the current locale.

XrmPutLineResource( )

Adds a single resource entry to the specified database.

The entry string is parsed in the locale of the database.

XrmPutFileDatabase( )

Stores a copy of the specified database in the specified file.

The file is written in the locale of the database.

XResourceManagerString( )

Converts the RESOURCE_MANAGER property encoded in type STRING to the multibyte string encoded in the current locale.

This function converts encoding in the same way encoding is converted by the XmbTextPropertyToTextList( ) function.

5.3.5    Handling Text Input with the X Input Method

When developing internationalized X applications, programmers must be able to request data input in different locales from the same keyboard. The X Library incorporates two abstractions, or objects, that address this problem:

5.3.5.1    Opening and Closing an Input Method

To use an input method, an application must first call XOpenIM( ). This function establishes a connection to the input method for the current locale and locale modifiers. The function returns an XIM object to which the current locale and locale modifiers are bound. The binding of the locale and modifiers to the XIM object occurs when the call executes and cannot be changed dynamically.

When the input method is no longer required, the application closes the XIM object with a call to XCloseIM( ).

Two other functions are available to obtain information about an XIM object:

The input method opened by the XOpenIM( ) function is determined from the following (in order of highest to lowest priority):

If XOpenIM( ) cannot obtain the input method from the preceding sources, the fallback is to support only ISO Latin-1 input. The XOpenIM( ) call fails under the following conditions:

Example 5-5 shows how to open and close an input method.

Example 5-5:  Opening and Closing an Input Method in an X Windows Application

main(argc, argv)
int     argc;
char    *argv[];
        {
        Display                 *display;

.
.
.
XIM im;
.
.
.
char *res_file = NULL;
.
.
.
XrmDatabase rdb = NULL;
.
.
.
preedcb_cd.win = client; if(res_file) { printf("Set Database : file name = %s\n", res_file); rdb = XrmGetFileDatabase(res_file); [1] } if((im = XOpenIM(display, rdb, NULL, NULL)) == NULL) { printf("Error : XOpenIM() !\n"); [2] exit(0); }
.
.
.
XCloseIM(im); [3]
.
.
.

  1. Passes the resource database rdb to XOpenIM( ) for looking up resources that are private to an input method

    You can specify resource databases created in the application by the internationalized Xt functions. [Return to example]

  2. Checks if the input method has been opened successfully [Return to example]

  3. Closes the input method [Return to example]

5.3.5.2    Querying Input Method Values

Behavior of input methods in some areas is vendor-defined. For example, different implementations of an input method may support different combinations of user interaction styles. To help you develop portable applications, the X Library includes the XGetIMValues( ) function to determine the attributes of an input method. The XNQueryInputStyle attribute specifies the user interaction styles supported by an input method.

Example 5-6 shows how to use the XGetIMValues( ) function with the XNQueryInputStyle attribute to obtain information for an input method.

Example 5-6:  Obtaining the User Interaction Styles for an Input Method

main(argc, argv)
int     argc;
char    *argv[];
        {
        Display                 *display;

.
.
.
int i, n;
.
.
.
XIMStyles *im_styles; XIMStyle xim_mode=0; XIMStyle best_style = XIMPreeditCallbacks; XIM im;
.
.
.
XIMStyle app_supported_styles;
.
.
.
for(i=1; i<argc; i++) { if(!strcmp(argv[i], "-Root")) { best_style = XIMPreeditNothing; } else if (!strcmp(argv[i], "-Cb")) { best_style = XIMPreeditCallbacks; [1] }
.
.
.
/* set flags for the styles our application can support */ app_supported_styles = XIMPreeditNone | XIMPreeditNothing | XIMPreeditCallbacks; [2] app_supported_styles |= XIMStatusNone | XIMStatusNothing; XGetIMValues(im, XNQueryInputStyle, &im_styles, NULL); n = 1; [3] if(im_styles != (XIMStyles *)NULL) { for(i=0; i<im_styles->count_styles; i++) { xim_mode = im_styles->supported_styles[i]; if((xim_mode & app_supported_styles) == xim_mode) { /* if we can handle it */ n = 0; if (xim_mode & best_style) /* pick user selected style */ break; [4] } } } if(n) { printf("warning : Unsupport InputStyle. or No IMserver.\n"); exit (0); }
.
.
.

  1. Determines if the user specified a preferred interaction style on the application command line

    In the ximdemo application, users can use the -Root and -Cb options to specify the interaction styles. These options represent the only two styles supported by this particular application. The -Root option specifies the style to be Root Window; this style requires minimal interaction between the client and the input server. The -Cb option specifies a style where preediting is handled by callbacks. This style enables on-the-spot preediting. [Return to example]

  2. Defines the app_supported_styles bitmask to specify the two interaction styles that the application can support [Return to example]

  3. Calls XGetIMValues( ) to query interaction styles

    The call returns the interaction styles to the im_styles parameter. [Return to example]

  4. Selects the interaction style that the input method supports and the application can handle properly

    The interaction style specified by the user takes precedence; otherwise, the application selects the last interaction style in the returned style list. [Return to example]

Supported interaction styles for an input method can vary from one locale to another. Refer to the technical reference guides (available in HTML format only on the Tru64 UNIX documentation CD-ROM) to find out what interaction styles are supported for a particular input method.

5.3.5.3    Creating and Using Contexts for an Input Method

Just as the X Server can maintain multiple windows for a display, an application can create multiple contexts for an input method. The X Library contains the XCreateIC( ) function to create an object for input context (XIC). The XIC object maintains a number of attributes that you can set and obtain through other functions. Among these attributes are:

To destroy an XIC object, call the XDestroyIC( ) function.

Example 5-7 shows how to use the XCreateIC( ) and XDestroyIC( ) functions.

Example 5-7:  Creating and Destroying an Input Method Context in an X Windows Application


.
.
.
Display *display;
.
.
.
Window root, window, client;
.
.
.
XIMStyle xim_mode=0;
.
.
.
XIM im; XIC ic;
.
.
.
XVaNestedList preedit_attr, status_attr; XIMCallback ximapicb[10]; char immodifier[100]; preedcb_data preedcb_cd;
.
.
.
window = XCreateSimpleWindow(display, root, 0, 0, W_WIDTH, W_HEIGHT, 2, bpixel, fpixel);
.
.
.
client = JxCreateTextWindow(display, window, 0, 0, W_WIDTH-2, W_HEIGHT-2, 1, bpixel, fpixel, font_set, &font_height);
.
.
.
if (xim_mode & XIMPreeditCallbacks) { ximapicb[0].client_data = (XPointer)NULL; ximapicb[0].callback = (XIMProc)api_preedit_start_cb; ximapicb[1].client_data = (XPointer)(&preedcb_cd); ximapicb[1].callback = (XIMProc)api_preedit_done_cb; ximapicb[2].client_data = (XPointer)(&preedcb_cd); ximapicb[2].callback = (XIMProc)api_preedit_draw_cb; ximapicb[3].client_data = (XPointer)NULL; ximapicb[3].callback = (XIMProc)api_preedit_caret_cb; nestlist = XVaCreateNestedList(10, XNPreeditStartCallback, &ximapicb[0], XNPreeditDoneCallback, &ximapicb[1], XNPreeditDrawCallback, &ximapicb[2], XNPreeditCaretCallback, &ximapicb[3], NULL); [1] } if (xim_mode & XIMPreeditCallbacks) { [2] ic = XCreateIC(im, XNInputStyle, xim_mode, XNClientWindow, window, XNFocusWindow, client, XNPreeditAttributes, nestlist, NULL); [3] } else { /* preedit nothing */ ic = XCreateIC(im, XNInputStyle, xim_mode, XNClientWindow, window, XNFocusWindow, client, NULL ); [4] } if(ic == NULL) { [5] printf("Error : XCreateIC() !\n"); XCloseIM(im); exit(0); }
.
.
.
exit: XDestroyIC(ic); [6]

  1. Calls the XVaCreateNestedList( ) function to create a nested argument list for preediting and status attributes

    The XNPreeditAttributes and XNStatusAttributes attributes contain a list of subordinate attributes. Your application must create a nested list to contain the subordinate attributes before setting or querying them. [Return to example]

  2. Specifies XIC attributes

    Your application must always specify some XIC attributes when creating an XIC object. The XNInputStyle attribute is mandatory; requirements for other attributes depend on the interaction style. [Return to example]

  3. Registers callbacks for on-the-spot interaction style

    When the interaction style is on the spot, your application must register all callbacks when creating the XIC object.

    Your application does not have to set the XNClientWindow attribute when creating the XIC, but must set this attribute before using the XIC. If the XIC is used before XNClientWindow is set, results are unpredictable. [Return to example]

  4. Sets the interaction style, client window, and focus window attributes for the root-window style

    These are the only attributes your application needs to set at XIC creation time when the interaction style is root window. [Return to example]

  5. Specifies actions when XIC creation fails

    The call to XCreateIC( ) fails (returns NULL) under the following conditions:

    [Return to example]

  6. Closes the XIC [Return to example]

Table 5-8 lists and summarizes the functions available for managing an XIC object.

Table 5-8:  X Library Functions That Manage Input Context (XIC)

Function Description
XSetICFocus( )

Enables keyboard events to be directed to the input method.

You must call this function when the focus window of an XIC receives input focus; otherwise, keyboard events are not directed to the input method.

XUnsetICFocus( )

Prevents keyboard events from being directed to the input method.

Call this function when the focus window of an XIC loses focus.

XmbResetIC( ), XwcResetIC( )

Reset the XIC to its initial state.

Any input pending on that XIC is deleted. These functions return either the current preedit string or NULL, depending on the implementation of the input server.

XIMOfIC( ) Returns the XIM associated with the specified XIC.
XSetICValues( ) Sets attributes to a specified XIC.
XGetICValues( ) Queries attributes from a specified XIC.

5.3.5.4    Providing Preediting Callbacks for the On-the-Spot Input Style

If your application supports the on-the-spot interaction style, you have to provide a set of preediting callbacks. There are a number of callbacks associated with XIC. Example 5-8 shows these callbacks.

Example 5-8:  Using Preediting Callbacks in an X Windows Application


.
.
.
int Jxsize[Jxmax_line]; char Jxbuff[Jxmax_line][128]; int Jxline_no; int Jxline_height; int sav_cx, sav_cy; int sav_w_width, w_height; int sav_size[Jxmax_line]; int sav_line_no; char preedit_buffer[12]; void save_value() { int i; sav_cx = Jxcx; sav_cy = Jxcy; sav_line_no = Jxline_no; for (i=0; i< Jxmax_line; i++) sav_size[i] = Jxsize[i]; } void restore_value() { int i; Jxcx = sav_cx; Jxcy = sav_cy; Jxline_no = sav_line_no; for (i=0; i< Jxmax_line; i++) Jxsize[i] = sav_size[i]; } int api_preedit_start_cb(ic, clientdata, calldata) XIC ic; XPointer clientdata; XPointer calldata; { int len; len = 12; /* save up the values */ save_value(); [1] return(len); [2] } void api_preedit_done_cb(ic, clientdata, calldata) XIC ic; XPointer clientdata; XPointer calldata; { preedcb_data *cd = (preedcb_data *)clientdata; /* restore up the values */ restore_value(); [3] /* convenient handling */ JxRedisplayText(cd->dpy, cd->win, cd->fset); return; } void api_preedit_draw_cb( ic, clientdata, calldata) XIC ic; XPointer clientdata; XIMPreeditDrawCallbackStruct *calldata; { preedcb_data *cd = (preedcb_data *)clientdata; int count; char *reset_str; if (calldata->text) { if (calldata->text->encoding_is_wchar) [4] { } else { count = strlen(calldata->text->string.multi_byte); if (count > 12) { /* preedit string > max preedit buffer */ reset_str = XmbResetIC(ic); [5] XFillRectangle(cd->dpy, cd->win, Jxgc_off, Jxcx, Jxcy, Jxw_width*13, Jxfont_height); /* clear the preedit area */ restore_value(); if (reset_str) XFree(reset_str); return; } if (!calldata->chg_length) { /* insert character */ if (!calldata->chg_first) { /* insert in first character in preedit buffer */ strncpy(&preedit_buffer[0],calldata->text->string.multi_byte, count); restore_value(); } else { /* Not Yet Implemented */ } } else { /* replace character */ if (!calldata->chg_first) { /* replace from first character in pre-edit buffer */ strncpy(&preedit_buffer[0],calldata->text->string.multi_byte, count); restore_value(); } else { /* Not Yet Implemented */ } } XFillRectangle(cd->dpy, cd->win, Jxgc_off, Jxcx, Jxcy, Jxw_width*13, Jxfont_height); /* clear the preedit area */ JxWriteText(cd->dpy, cd->win, cd->fset, count, preedit_buffer); } } else { /* should delete preedit buffer */ /* Not yet implemented */ } return; } void api_preedit_caret_cb(ic, clientdata, calldata) XIC ic; XPointer clientdata; XIMPreeditCaretCallbackStruct *calldata; { /* Not yet implemented */ return; }
.
.
.

  1. Saves the current drawing position

    As part of the operation of drawing preediting strings, this application saves the current drawing position as the value of the PreeditStartCallback attribute. Once the preediting is complete, the application erases the preediting string and restores the original drawing position. [Return to example]

  2. Returns the length of the preediting string

    The value of 12 bytes is an arbitrary number to limit the length of the string. The value should match the size of the preediting buffer. This application declares the preediting buffer (preedit_buffer) to be a 12-byte character array. [Return to example]

  3. Restores the drawing position and redraws the text buffer [Return to example]

  4. Handles wide-character encoding

    This example assumes that the preediting string is in multibyte encoding. However, your application should handle both multibyte and wide-character encoding. Wide-character encoding is preferable because information, such as character position, is returned in the XIMPreeditDrawCallbackStruct structure as the number of characters rather than the number of bytes. [Return to example]

  5. Clears the preediting string when its size exceeds 12 bytes

    The size of the string is obtained from the PreeditDrawCallback attribute. Without processing the string returned on the call to XmbResetIC( ), the application frees the string with a call to Xfree( ). [Return to example]

5.3.5.5    Filtering Events for an Input Method

An input method has to receive events before the events are processed by the application. The application has to pass to the input method not only KeyPress/KeyRelease events but other events as well. The X Library contains the XfilterEvent( ) function to pass events to an input method. Use this function, along with related functions, as follows:

  1. Obtain a mask for the events to be passed to the input method by calling the XGetICValues( ) function with the XNFilterEvents argument.

  2. Register the event types with the XSelectInput( ) function.

  3. In the main loop of the program, usually right after the call to XNextEvent( ), call XFilterEvent( ) to pass the event to the input method.

    A return status of True indicates that the input method has filtered the event and it needs no further processing by the application.

Example 5-9 shows the preceding process.

Example 5-9:  Filtering Events for an Input Method in an X Windows Application


.
.
.
long im_event_mask;
.
.
.
XGetICValues(ic, XNFilterEvents, &im_event_mask, NULL); mask = StructureNotifyMask | FocusChangeMask | ExposureMask; XSelectInput(display, window, mask); mask = ExposureMask | KeyPressMask | FocusChangeMask | im_event_mask; XSelectInput(display, client, mask);
.
.
.
for(;;) { XNextEvent(display, &event); if(XFilterEvent(&event, NULL) == True) continue; [1] switch(event.type ) { /* dispatch event */
.
.
.
} }
.
.
.

  1. Filters the event

    Note that the XtDispatchEvent( ) function calls XFilterEvent( ). Therefore, you could replace the for loop as shown in this example with a call to XtAppMainLoop( ). [Return to example]

5.3.5.6    Obtaining Composed Strings from the Keyboard

You use the XmbLookupString( ) or XwcLookupString( ) function in your X application to obtain native-language characters and key symbols. Your application has to take into account the complexity of some input methods, which require several keystrokes to compose a single character. Therefore, expect that a composed character or string may not be returned on every call to one of these functions.

Example 5-10 shows how to get keyboard input in an X application.

Example 5-10:  Obtaining Keyboard Input in an X Windows Application


.
.
.
XEvent event;
.
.
.
int len = 128; char string[128]; KeySym keysym; int count;
.
.
.
for(;;) { XNextEvent(display, &event); if(XFilterEvent(&event, NULL) == True) continue; switch(event.type ) { case FocusIn : [1] if(event.xany.window == window) XSetInputFocus(display, client, RevertToParent, CurrentTime); else if(event.xany.window == client) { XSetICFocus(ic); } break; case FocusOut : [1] if(event.xany.window == client) { XUnsetICFocus(ic); } break; case Expose : if(event.xany.window == client) JxRedisplayText(display, client, font_set); break; case KeyPress : [2] count = XmbLookupString(ic, (XKeyPressedEvent *)&event, string, len, &keysym, NULL); if( count == 1 && string[0] == (0x1F&'c')) { /* exit */ goto exit; } if( count > 0 ) { [3] JxWriteText(display, client, font_set, count, string); } break; case MappingNotify : XRefreshKeyboardMapping( (XMappingEvent *)&event); break; case DestroyNotify : printf("Error : DestroyEvent !\n"); break; } }

  1. Handles FocusIn and FocusOut events

    In this example, one XIC is associated with a focus window. Some input servers require focus change information to update the status area. Therefore, each FocusIn event calls XSetICFocus( ) and each FocusOut event calls XUnsetICFocus( ).

    Your application can also use one XIC for several focus windows. In this case, you do not need to call XSetICFocus( ) for every focus change event, but you do have to set the XNFocusWindow attribute of the XIC. [Return to example]

  2. Handles KeyPress events

    Make sure that your application passes only KeyPress events to XmbLookupString( ) or XwcLookupString( ). Results are undefined if you pass KeyRelease events to these functions.

    For simplicity in this example, the status field in the call to XmbLookupString( ) is NULL. Your own application should check for the status return and respond appropriately. For example, if the status return is XBufferOverflow, your application might try to allocate more memory for the buffer. [Return to example]

  3. Processes the string when one is returned

    XmbLookupString( ) returns the size of the composed string (in bytes). [Return to example]

5.3.5.7    Handling Failure of the Input Method Server

The XNDestroyCallback resources for an input method and an input method context were introduced in X11R6. These resources, which are triggered by failure of the input method server, close the XIM and XIC objects for a client application. If a client application continues to run without detecting server failure and then closes the XIC and XIM objects, results are unpredictable.

Example 5-11 shows how to register the XNDestroyCallback resource for the XIM object and how to close the XIM in the event of server failure.

Example 5-11:  Handling Failure of the Input Method Server

static void     _imDestroyCallback();  [1]

.
.
.
Bool IMS_Connected = False; XIMCallback cb; [2]
.
.
.
if((im = XOpenIM(display, rdb, NULL, NULL)) == NULL) { printf("Error : XOpenIM() !\n"); exit(0); } else { IMS_Connected = True; cb.client_data = (XPointer) &IMS_Connected; cb.callback = (XIMProc) _imDestroyCallback; XSetIMValues(im, XNDestroyCallback, &cb, NULL); [3] }
.
.
.
case KeyPress : if (IMS_Connected) count = XmbLookupString(ic, (XKeyPressedEvent *)&event, string, len, &keysym, NULL); else count = XLookupString((XKeyPressedEvent *)&event, string, len, &keysym, NULL); [4]
.
.
.
static void _imDestroyCallback(im, client_data, call_data) XIM im; XPointer client_data; XPointer call_data; { Bool *Connected = (Bool *)client_data; *Connected =3D False; [5] }    

  1. Declares the function that closes the XIM if the input method server (IMS) fails for any reason [Return to example]

  2. Declares the IMS_Connected variable to specify whether the input method server is still connected and the cb structure to contain client information needed for resource registration [Return to example]

  3. If the call to open the XIM fails, prints an error message and exits

    Otherwise, sets the IMS_Connected variable to True, fills the cb structure with appropriate client data, and calls the XSetIMValues( ) function to register the XNDestroyCallback resource for the XIM [Return to example]

  4. If the input method server is running, uses the XmbLookupString( ) function to process user input

    Otherwise, uses the XLookupString( ) function [Return to example]

  5. Specifies the prototype for the function that closes the XIM in the event that the input method server fails [Return to example]

Note that the ximdemo program is very simple and uses only one input method context. In this case, there is no need to explicitly close the XIC when the input method server fails. The following example shows the prototype for a callback function that would close an XIC:

static void icDestroyCallback(ic, client_data, call_data)
XIC ic;
XPointer client_data;
XPointer call_data;

5.3.6    Using X Library Features: A Summary

The following list of steps for processing native-language input summarizes the information presented in preceding sections on the X Library. For your convenience, the step description also notes when programming with X Toolkit Intrinsics (Xt) functions differs from programming with X Library functions. Refer to Section 5.1 for discussion of internationalization features of the X Toolkit Intrinsics.

  1. Call setlocale( ) to bind to the current locale.

    You can accomplish the same result by registering an initialization callback function with XtSetLanguageProc( ).

  2. Call XSupportsLocale( ) to verify that X supports the current locale.

  3. Either call XSetLocaleModifiers( ) or set the XMODIFIERS environment variable to define the input method being used.

  4. Call XOpenIM( ) to connect to the selected input method.

    If you are writing a widget, you can skip this step and assume that a valid XIM will be passed to the widget as a resource.

  5. Call XGetIMValues( ) to query the interaction styles supported by the input method.

    When writing a widget, do this step in the initialization method.

  6. Create a window to associate with an XIC.

    When using Xt functions, create a widget.

  7. Call XCreateFontSet( ) to create a font set for this window. In X11R6, you can use XOpenOM() instead.

    If you are using Xt functions and have created a widget, use the value set for XtDefaultFontSet.

  8. Choose an interaction style from the supported values obtained by the application and pass this value as an argument to XCreateIC( ).

    If you are using XIMPreeditCallbacks, you must write the callback routines and register them on the call to XCreateIC( ).

  9. Call XGetICValues( ) to query the XNFilterEvents attribute and register the event that the input method needs from the focus window.

  10. Call XFilterEvent( ) in the main event loop before dispatching an event.

    If the call returns True, you can discard the event.

    If programming with routines from the X Intrinsics (Xt) Library, use XtDispatchEvent( ).

  11. In the main event loop, set and unset input focus when the focus window receives FocusIn and FocusOut events.

    If programming with routines from the X Intrinsics (Xt) Library, use an event handler or a translation/action table to track focus events.

  12. For unfiltered KeyPress events, call XmbLookupString( ) or XwcLookupString( ) to obtain key symbols and the composed string.

    You can draw the string with the internationalized functions for text drawing.