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:
The Toolkit Intrinsics Library available with Release 6 of
the X Window System (libXt
)
The libraries available with Version 1.2 of OSF/Motif (libXm
)
The features provided as DECwindows Extensions to the OSF/Motif
Toolkit (libDXm
)
The X Library available with Release 6 of the X Window System
(libX11
)
This chapter assumes that you are already familiar with these components. For more complete information on them, refer to the following documents:
OSF/Motif Programmer's Guide
DECwindows Motif Guide to Application Programming
DECwindows Extensions to Motif
Programmer's Supplement for Release 5 of the X Window System, Version 11
This book is published by O'Reilly and Associates, Inc.
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:
XtInitialize( )
XtAppInitialize( )
XtOpenDisplay( )
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
:
XtNFontSet
(the resource name)
XtCFontSet
(the resource class)
XtRFontSet
(the resource representation
type)
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:
The value of the
argv
argument on the call
to
XtAppInitialize( )
,
XtOpenDisplay( )
,
XtDisplayInitialize( )
, or
XtOpenApplication()
The setting of the language resource in the
RESOURCE_MANAGER
property of the root window for the specified display
The setting of the
xnlLanguage
resource
in the user's
.Xdefaults
file
The setting of the
LANG
environment variable
Elements higher on the preceding list take precedence over lower elements. Note the following points:
After an application opens its first display, Motif routines use the established language setting until the application terminates.
If the
RESOURCE_MANAGER
property exists
in the root window, Motif routines do not use the
.Xdefaults
file, even if the language resource is not defined in the
RESOURCE_MANAGER
property.
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:
Search the font list for an entry that is a font set and has
the font list element tag
XmFONTLIST_DEFAULT_TAG
Search the font list for an entry that specifies a font set and use the first one found
Use the first font in the font list
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:
The segments of a compound string can contain data from multiple character sets. This ability is enabled through the font set construct and support for a locale's codeset rather than a single character set per language. (Codesets other than Latin ones usually support multiple character sets.) To take advantage of this change, your application must ensure that:
The font list structure defines the appropriate font set as the list element used to display segments of the compound string.
The compound string includes a tag that will match the correct font set rather than a single font.
For input methods,
the
XmText
,
XmTextField
, and
DXmCSText
widgets support the on-the-spot interaction style, as
well as off-the-spot, over-the-spot, and root-window styles supported through
Release 1.2 of OSF/Motif.
You can specify interaction styles as a priority list for the
XmNpreeditType
resource when creating locale-dependent resource
files for your application.
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:
XmStringCreate( )
, which creates a compound string composed
of text and a font list element tag
XmStringCreateLocalized( )
, which creates
a compound string that uses the encoding of the current locale
Note
Right-to-left display of language text, which is appropriate for languages such as Hebrew, is supported through the
DXmCSText
widget. TheXmText
andXmTextField
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):
Command
FileSelectionBox
Label
List
MessageBox
SelectionBox
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:
Requesting user input in different native languages
Drawing fonts used for native-language text
Obtaining language-specific resource values
Interclient communication that supports native-language text through codeset conversion
The following sections, which describe how to write an internationalized application with the X Library, cover the following topics:
Managing locales
Drawing and measuring native-language text
Handling interclient communication
Localizing X resource databases
Handling text input and output
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
To provide default values on the local host system, the value defined for
the
In this example,
the value
|
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:
XOM
and
XOC
, which are related to text output
These
objects were introduced in the Version 6 implementation of
XrmDatabase
, which is associated with application resource files.
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:
Identify the locale that applies to data and handle that data with the appropriate locale-specific object.
Results are unpredictable when the data's locale does not match the object's locale.
When passing text to WPI interfaces (such as
printf( )
) in the Standard C Library, ensure that the current locale setting
for the process matches the locale of the data being passed.
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]); }
.
.
.
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]
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]
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]
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); }
.
.
.
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]
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]
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:
Work with font sets rather than single fonts
Handle text drawing according to the locale of the font set
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,
|
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,
|
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,
|
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); }
Displays a block-type cursor by using
XFillRectangle( )
[Return to example]
Displays a native-language string by using
XmbDrawImageString( )
The string may contain both single-byte and multibyte characters. [Return to example]
Calculates the position for drawing the next string with
XmbTextEscapement( )
[Return to example]
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:
X Output Method (XOM)
XOM is an opaque data structure that the application can use to communicate with an output method.
X Output Context (XOC)
XOC is compatible with
XFontSet
in terms of its program
interface but is a more generalized abstraction.
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:
More than one encoding for a character set may be in common use.
For example, character sets for Japanese (JIS X0208), Chinese (GB 2312), and Korean (KS C 5601) are available in GL or GR encoding.
More than one character set may be supported in a particular country.
Different vendors have adopted different font encoding schemes in their products.
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
|
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]
.
.
.
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]
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]
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
This function converts
encoding in the same way encoding is converted by the
|
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:
XIM is an opaque data structure that an application can use to communicate with an input method.
XIC represents the state of a text entry field in the context of a multithreaded
approach to user input.
An application can provide multiple text entry fields
for users to input text data and allow users to switch between fields.
To
obtain data input, the application calls
XmbLookupString( )
or
XwcLookupString( )
with an input context.
The strings returned are always encoded in the locale associated with the
XIM/XIC objects.
The following sections provide more information about using
input-method objects.
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:
This function returns the display associated with the specified XIM object.
This function returns the locale associated with the specified XIM object.
The
input method opened by the
XOpenIM( )
function is
determined from the following (in order of highest to lowest priority):
The value for the
im
modifier specified
in the call to
XSetLocaleModifiers( )
The input method specified for the
XMODIFIERS
environment variable
The default input method, whose name is
DEC
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:
The server for the specified input method is not running.
The
im
modifier is specified incorrectly.
The specified input method does not support the current locale.
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]
.
.
.
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]
Checks if the input method has been opened successfully [Return to example]
Closes the input method [Return to example]
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); }
.
.
.
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]
Defines the
app_supported_styles
bitmask
to specify the two interaction styles that the application can support
[Return to example]
Calls
XGetIMValues( )
to query
interaction styles
The call returns the interaction styles to the
im_styles
parameter. [Return to example]
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:
The interaction style for the input context
The font set with which preediting and status text is drawn
The callbacks for handling on-the-spot preediting
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]
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]
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]
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]
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]
Specifies actions when XIC creation fails
The call to
XCreateIC( )
fails (returns NULL) under the following conditions:
A required attribute is not set
A read-only attribute (for example,
XNFilterEvents
) is set
An attribute name is not recognized
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; }
.
.
.
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]
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]
Restores the drawing position and redraws the text buffer [Return to example]
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]
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]
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:
Obtain a mask for the events to be passed to the input method
by calling the
XGetICValues( )
function with the
XNFilterEvents
argument.
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 */
.
.
.
} }
.
.
.
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]
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; } }
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]
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]
Processes the string when one is returned
XmbLookupString( )
returns the size of the
composed string (in bytes). [Return to example]
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] }
Declares the function that closes the XIM if the input method server (IMS) fails for any reason [Return to example]
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]
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]
If the input method server is running, uses the
XmbLookupString( )
function to process user input
Otherwise, uses the
XLookupString( )
function
[Return to example]
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.
Call
setlocale( )
to bind to the
current locale.
You can accomplish the same result by registering an initialization
callback function with
XtSetLanguageProc( )
.
Call
XSupportsLocale( )
to verify
that X supports the current locale.
Either call
XSetLocaleModifiers( )
or set the
XMODIFIERS
environment variable to define the
input method being used.
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.
Call
XGetIMValues( )
to query the
interaction styles supported by the input method.
When writing a widget, do this step in the initialization method.
Create a window to associate with an XIC.
When using Xt functions, create a widget.
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
.
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( )
.
Call
XGetICValues( )
to query the
XNFilterEvents
attribute and register the event that the input method
needs from the focus window.
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( )
.
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.
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.