This chapter assumes that you are already familiar with these components. For more complete information on them, refer to the following documents:
This guide includes a chapter that specifically addresses internationalization concerns of programmers writing Motif applications.
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.
These functions call XtDisplayInitialize(), which obtains the value of the xnlLanguage resource by
parsing the command line and the RESOURCE_MANAGER property. The
functions then pass this language value to the language procedure registered
by the call to XtSetLanguageProc().
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.
The language for an application can be specified by:
Elements higher on the preceding list take precedence over lower elements.
Note the following points:
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
a font set.
The internationalization
features available through the text widgets have changed on the following
two dimensions:
Note that you can specify interaction styles as a priority list for
the XmNpreeditType resource when creating locale-dependent resource
files for your application.
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:
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 directory $I18NPATH/usr/examples/ximdemo.
You can read the source file, build the application, and run it to understand
more fully how to apply the programming techniques being discussed.
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 X Window System Toolkit and
the reference pages for individual components.5.1.1 Establishing a Locale with Xt Functions
An internationalized
X application must parse resources in a locale-dependent manner. Therefore,
an application must establish its locale before initializing the resource
database. The
XtSetLanguageProc()
function registers a 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(); 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:
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:
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). For example, to set
locale and register a language procedure, you use the same set of functions
and guidelines in a Motif application as described for an Xt application in Section 5.1.1. As is true for the X Toolkit library, the OSF/Motif
and DECwindows Motif Toolkit libraries do not provide a default language procedure.
Therefore, if your application fails to register and create a language procedure,
the XmText and XmTextField widgets do not support the
internationalization features discussed in subsequent sections; in other words,
the widgets revert to behavior expected in releases earlier than the X Toolkit
Release 5 and OSF/Motif Release 1.2.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:
Note
Note
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:
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. In
addition, the X Library includes two additional functions to determine the
locale and configure locale modifiers: XSupportsLocale()
and XSetLocaleModifiers(). Table 5-1
provides brief descriptions of these functions. They are more fully described
in the XSupportsLocale
(3X11) and XSetLocaleModifiers
(3X11) reference pages.
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:
Results are unpredictable when the data's locale does not match the
object's locale.
Example 5-1 shows how an X application
sets or determines locale.
In this example, the constant's value is explicitly set to zh_TW.dechanyu.
The user can override the default locale by using the -locale
option on the command line that runs this application.
If this constant had been set to NULL 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.
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.
Digital's implementation of functions that draw and measure text allow
you to use fonts with different encodings to display native-language text.
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]);
}
.
.
.
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 structure XFontSet, which replaces the structure XFontStruct that was supported by X Library releases earlier than Release 5.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.
Example 5-2 shows the functions that create and
use font sets.
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.
The user can override the default base font name list by using the -fs option on the application command line.
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);
}
.
.
.
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.
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.
Example 5-3 shows how internationalized
functions draw text.
The string may contain both single-byte and multibyte characters.
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:
XOM is an opaque data structure that the application can use to communicate
with an output method.
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.
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);
}
5.3.2.4 Handling Text With the X Output Method
The concept of a font set that is described in 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 bi-directional text and context-sensitive text display.
For example, character sets for Japanese (JIS X0208), Chinese (GB 2312), and Korean (KS C 5601) are available in GL or GR encoding.
Font-encoding divergence from one system to another causes problems for applications that you run on different kinds of systems. Therefore, Digital's 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.
.
.
.
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)
.
.
.
In this example, the text is for a window title. Text strings are explictly specified in the function calls for the sake of simplicity. In practice, X applications extract such text strings from locale-specific resource or User-Interface Language (UIL) files.
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.
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.
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.
In Digital's implementation of input methods, the input
method opened by the XOpenIM() function is determined from
the following (in order of highest to lowest priority):
You can specify resource databases created in the application by the
internationalized Xt functions.
Example 5-6 shows how to use the XGetIMValues() function with the XNQueryInputStyle attribute to obtain
information for an input method.
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.
The call returns the interaction styles to the im_styles
parameter.
The interaction style specified by the user takes precedence; otherwise,
the application selects the last interaction style in the returned style list.
Supported interaction styles for an input method can vary from one
locale to another. Refer to the user guides provided with Digital UNIX
language variant subsets to find out what interaction styles are supported
for a particular input method.
To destroy an XIC object, call the XDestroyIC() function.
Example 5-7 shows how to use the XCreateIC() and XDestroyIC() functions.
The attributes XNPreeditAttributes and XNStatusAttributes contain a list of subordinate attributes.
Your application must create a nested list to contain the subordinate attributes
before setting or querying them.
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.
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.
These are the only attributes your application needs to set at XIC creation
time when the interaction style is root window.
The call
to XCreateIC() fails (returns NULL) under the following
conditions:
Table 5-8 lists and summarizes the functions
available for managing an XIC object.
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.
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)
.
.
.
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. Currently, only the
XNQueryInputStyle attribute
is defined, and this attribute specifies the user interaction styles supported
by 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);
}
.
.
.
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 function
XCreateIC() 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:
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)
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.
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.
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.
In
Digital's implementation of X windows, you can specify the encoding of preediting
and status strings in a resource database that is passed to the XOpenIM() function. The resources associated with these strings are:
Specifies the encoding of the preediting string.
Specifies the encoding of the status string.
Specify wchar as the encoding to indicate that wide-character
encoding is used.
The size of the string is obtained from the PreeditDrawCallback attribute. Without processing the string returned on the call to XmbResetIC(), the application simply frees the string with a
call to Xfree().
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.
Note that the function
XtDispatchEvent() calls XFilterEvent(). Therefore, you could replace the for loop as shown in this
example with a call to XtAppMainLoop().
Example 5-10 shows how to get keyboard input
in an X application.
In this example, one XIC is associated with a focus window. On Digital
systems, 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.
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.
XmbLookupString() returns the size of the composed
string (in bytes).
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.
You can accomplish the same result by registering an initialization
callback function with XtSetLanguageProc().
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.
When writing a widget, do this step in the initialization method.
When using Xt functions, create a widget.
If you are using Xt functions and have created a widget, use the value
set for XtDefaultFontSet.
If you are using XIMPreeditCallbacks, you must write the
callback routines and register them on the call to XCreateIC().
If the call returns True, you can discard the event.
If programming with routines from the X Intrinsics (Xt) Library, use XtDispatchEvent().
If programming with routines from the X Intrinsics (Xt) Library, use
an event handler or a translation/action table to track focus events.
You can draw the string with the internationalized functions for text
drawing.
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;
}
.
.
.
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:
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 */
.
.
.
}
}
.
.
.
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: 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;
}
}
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 closing the XIC
and XIM objects, results are unpredictable.
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)
}
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.