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.
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 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.
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. Note
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:
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. Note
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.
XSupportsLocale
(3X11) and XSetLocaleModifiers
(3X11) reference pages.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 Digital 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 is the string that 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:
These objects were introduced in the Version 6 implementation of XrmDatabase, which is associated with application resource files.
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.
#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]); }
.
.
.
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.
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.
.
.
.
#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); }
.
.
.
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.
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. |
These functions free applications from handling text encoding directly.
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.
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); }
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.
Function | Description |
---|---|
XOpenOM() | Opens an output method to match the current locale and modifiers specification. 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. |
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().
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.
|
.
.
.
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.
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 from encoding of type STRING to the encoding of
the current locale. This function converts encoding in the same way encoding is converted by the XmbTextPropertyToTextList() function.
|
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):
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)
.
.
.
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.
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); }
.
.
.
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.
.
.
.
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)
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.
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. |
.
.
.
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; }
.
.
.
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.
.
.
.
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 */
.
.
.
} }
.
.
.
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.
.
.
.
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; } }
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().
Make sure that your application passes only KeyPress events to XmbLookupString() or XwcLookupString(). Results are undefined if you pass KeyRelease events to these functions.
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.
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) }
static void icDestroyCallback(ic, client_data, call_data) XIC ic; XPointer client_data; XPointer call_data;
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.