5    国際化対応の X,Xt,および Motif アプリケーションの作成

この章では,グラフィカル・ユーザ・インタフェースを作成するときに利用できる国際化機能について説明します。 具体的には,次の各コンポーネントについて解説します。

この章では,読者が X ウィンドウ・システムや OSF/Motif ツールキットをすでに理解していることを前提としています。 これらのコンポーネントの詳細については,次のドキュメントを参照してください。

詳細については,これらのドキュメントの他に,各関数のリファレンス・ページも参照してください。

この章では,共通デスクトップ環境 (CDE) に特有の国際化機能については説明しません。 これらの機能の使用方法については,『Common Desktop Environment: プログラマーズ・ガイド(国際化対応編)』(オペレーティング・システムのオンライン・ドキュメント・セットとして入手可能) を参照してください。 (オペレーティング・システムのドキュメントは,Web サイト http://h50146.www5.hp.com/products/software/oe/tru64unix/manual/ で参照できます。)

アプリケーションを地域化する際に便利なように,CDE 環境でロケールを直接サポートできるようにするためのファイルを,以下のリストに示します。

メッセージ・カタログ

/usr/lib/nls/msg/locale_name/filename.cat...

リファレンス・ページ

/usr/share/locale_name/man/mann/refpage.n...

リソース・ファイル

/usr/lib/X11/locale_name/app-defaults/file_name

/usr/dt/app-defaults/locale_name/file_name

UID ファイル

/usr/lib/X11/locale_name/uid/file_name

CDE アクション/データタイプ・ファイル

/usr/dt/appconfig/types/locale_name/file_name

CDE ヘルプ・ファイル

/usr/dt/appconfig/help/locale_name/file_name

CDE スタイルマネージャのバックドロップ・ファイル

/usr/dt/backdrops/desc.locale_name

CDE スタイルマネージャのパレット・ファイル

/usr/dt/palettes/desc.locale_name

オペレーティング・システムがサポートしているロケールには,直接サポートしているものと,間接的に (自動コードセット変換を通して) サポートしているものがあります。 たとえば,オペレーティング・システムは,コードセット変換を通して ja_JP.UTF-8 ロケールをサポートしているので,オペレーティング・システム・ソフトウェアをインストールした後に,locale-name ディレクトリまたは locale-name 拡張子として ja_JP.UTF-8 を含むパスを見つけることはできません。

ただし,適切にローカライズしてエンコードしたファイルを作成し,上記のリストで指定された位置にそのファイルをインストールすると,ja_JP.UTF-8 を直接サポートできるようになります。 新しいロケールを最初から作成する方法については,第 6 章 を参照してください。

5.1    Xt イントリンシクス・ライブラリの国際化機能の使用

X ツールキット (Xt) イントリンシクス・ライブラリは,初期化処理とリソース管理に関連する国際化機能を提供します。 以降の項では,これらの機能について説明します。 アプリケーションで Xt イントリンシクス・ライブラリ (libXt) のルーチンを使用する方法については, 各コンポーネントのリファレンス・ページを参照してください。

5.1.1    Xt 関数によるロケールの設定

国際化 Xt を使用するアプリケーションでは,ロケールに応じてリソースを解析しなければなりません。 そのため,アプリケーションはリソース・データベースを初期化する前に,ロケールを設定しなければなりません。 ところがリソースでもアプリケーションのロケールを設定することができます。 この矛盾を解決するために,X ツールキットのリリース 5 では言語プロシージャが取り入れられました。 言語プロシージャは,X ツールキットを初期化する前に登録され,ロケールを設定するのに都合のよい時点で初期化中に呼び出されます。

XtSetLanguageProc() 関数は,ロケールを設定するための言語プロシージャを登録します。 省略時の動作では,この関数はまず,標準 C ライブラリの setlocale() 関数を呼び出してロケールを設定し,次に X ライブラリ関数の XSupportsLocale()XSetLocaleModifiers() を呼び出してロケールを初期化します。

Xt のルーチンを使用するアプリケーションでは,システムの省略時の言語プロシージャを使用している場合でも,XtSetLanguageProc() を呼び出さなければなりません。 この関数を呼び出さないと,ロケールは設定されず,他の Xt ルーチンはロケールに従った動作を行いません。

アプリケーションでロケールを設定する最も一般的な方法は,XtAppInitialize() を呼び出す前に,次の関数を呼び出すことです。

XtSetLanguageProc(NULL,NULL,NULL);

XtSetLanguageProc() を呼び出した後,アプリケーションは次の Xt 初期化関数のいずれかを呼び出せます。

これらの関数は,コマンド行と RESOURCE_MANAGER プロパティを解析することにより xnlLanguage リソースの値を取得する,XtDisplayInitialize() 関数を呼び出します。 次に XtDisplayInitialize() は,xnlLanguage 値を引数として,XtSetLanguageProc() の呼び出しで登録されている言語プロシージャを呼び出します。 この後,XtDisplayInitialize() は,言語プロシージャから返されたロケールのリソースを解析します。

5.1.2    Xt 関数におけるフォントセット・リソースの使用

Xt ルーチンは,母国語のテキストを表示するすべての国際化ウィジェットで,XFontStruct 構造体の代わりに XFontSet 構造体をサポートします。 XFontSet をサポートするために,次のリソース属性が用意されています。

X ツールキットには,-*-*-*-R-*-*-*-120-75-75-*-*-*-* のようなあらかじめ登録されている文字列を,構造体 (XFontSet) 内のフォントセットのリストに変換するコンバータが含まれています。 このような文字列を適切なフォントセットに変換できなかった場合でも,このコンバータは省略時のフォントセット・リストを設定し,適切なフォントセットの代替えとして使用できるようにします。

5.1.3    Xt ライブラリ関数におけるテキスト入力イベントのフィルタリング

X ツールキット・イントリンシクス・ライブラリのリリース 5 以降,XtDispatchEvent() 関数は XFilterEvent() の呼び出しに置き換えられました。 この変更により,入力サーバは,Xt ルーチンを使用するアプリケーションが登録された X イベントを処理する前に,それらのイベントを横取りできます。

5.1.4    Xt ライブラリ関数におけるロケールのコードセット・コンポーネントの取り込み

X ツールキット・イントリンシクス・ライブラリのリリース 5 以降,ロケール・エンティティは,以前のリリースでサポートされていた言語コンポーネントと地域コンポーネントに加え,コードセット・コンポーネントもサポートします。

5.2    OSF/Motif および DECwindows Motif ツールキットの国際化機能の使用

Common Desktop Environment: プログラマーズ・ガイド(国際化対応編)』では,国際化 Motif アプリケーションを開発するためのガイドラインを説明しています。 このマニュアルは,オペレーティング・システムのドキュメント・セットの一部で,Web サイト http://h50146.www5.hp.com/products/software/oe/tru64unix/manual/ で参照できます。

以降の項は,『Common Desktop Environment: プログラマーズ・ガイド(国際化対応編)』の内容を補足するためのものです。

5.2.1    Motif アプリケーションにおける言語の設定

OSF/Motif ツールキット (libXm),および OSF/Motif ツールキットに対する DECwindows 拡張 (libDXm) の大半の国際化機能は,X ライブラリ (libX) と X ツールキット (libXt) のリリース 5 以降で取り入れられた機能を通じてサポートされます。

Motif の国際化機能は X ライブラリと X ツールキットのリリース 6 またはリリース 6.3 をインストールした場合でも,同じようにサポートされます。 たとえば,Motif アプリケーションのロケールを設定するには,Xt アプリケーションで説明したのと同じ関数セットとガイドラインを使用します (5.1.1 項を参照)。 アプリケーションが,X ツールキットを初期化する前に言語プロシージャを登録するための XtSetLanguageProc() 呼び出しに失敗した場合,Motif ウィジェットは以降の項で説明する国際化機能をサポートしません。 つまり,ウィジェットは X ツールキットのリリース 5 および OSF/Motif リリース 1.2 より前のリリースと同じ動作をします。

アプリケーションの言語は,次のいずれかの方法で指定できます。 このリストは,優先度の高い順に並んでいます。 たとえば,argv 引数による言語設定は,RESOURCE_MANAGER での言語設定よりも優先されます。

  1. XtAppInitialize()XtOpenDisplay()XtDisplayInitialize(),または XtOpenApplication() の呼び出しの argv 引数の値

  2. 指定されたディスプレイのルート・ウィンドウの RESOURCE_MANAGER プロパティ中の言語リソース設定

  3. ユーザの .Xdefaults ファイル内の xnlLanguage リソース設定

  4. LANG 環境変数の設定

次の点に注意してください。

5.2.2    コンパウンド・ストリングと,XmText および XmTextField ウィジェットの使用

OSF/Motif の XmText ウィジェットと XmTextField ウィジェットには,X と X ツールキットのライブラリをベースとした国際化機能が備わっています。 これらのウィジェットは,ユーザが入力したり,表示するテキスト情報をエンコードするために,現在のロケールのコードセットを使用します。 ウィジェットは,正しいフォントでデータを表示するために,次のいずれかの検索パターンを使用してフォントを見つけます。 ウィジェットは優先度の高い順に検索パターンを使用し,フォントセットが決まったところで検索をやめます。

  1. フォント・リスト・エレメント・タグ XmFONTLIST_DEFAULT_TAG を持つフォントセットのエントリを,フォント・リスト中で検索する。

  2. フォントセットを指定するエントリをフォント・リスト中で検索し,最初に見つかったエントリを使用する。

  3. フォント・リスト中の最初のフォントを使用する。

テキスト・ウィジェットを通じて利用できる国際化機能は,初期の OSF/Mofif リリースと比較すると, 次の 2 点が変更されています。

注意

Off-the-Spot 前編集スタイルを選択した場合,入力ステータスと前編集のための領域 (通常はウィンドウの下部) を確保するために,アプリケーション・ウィンドウが拡大されます。 このため,Off-the-Spot 入力スタイルを使用するすべてのアプリケーションでは,自動サイズ変更が有効になっていなければなりません。

アジアの国々で使用される X アプリケーションや Motif アプリケーションを作成し,入力ステータスおよび前編集の領域を頻繁に使用する場合,ツールキットの機能を使用してアプリケーションの自動サイズ変更機能を無効にしないでください。

次の関数を使用して,複数の文字セットを含むコードセット用のコンパウンド・ストリングを作成できます。

注意

ヘブライ語などの言語における,右から左方向への言語テキストの表示は,DXmCSText ウィジェットを通じてサポートされます。 XmText ウィジェットと XmTextField ウィジェットは,左から右方向への表示だけをサポートします。

5.2.3    ウィジェット・クラスの国際化機能

次のウィジェット・クラスは,XmText ウィジェットと XmTextField ウィジェット (5.2.2 項を参照) を通じて,母国語の入力機能と表示機能をサポートします。

5.3    X ライブラリの国際化機能の使用

libX11 ライブラリのリリース 5 以降,X コンソーシアムは,異なるロケールのデータを扱える X クライアントを開発するための新しい仕様を規定しました。 新しい仕様は,さまざまな母国語でのデータ処理を可能にする標準 C ライブラリからなる,ANSI C のロケールモデルに基づいています。 この仕様は,次のインタフェースを提供します。

以降の項では,X ライブラリを使用して国際化プログラムを作成するさまざまな方法について説明します。

プログラミング手法 (特にテキスト入力に関連する手法) の例として,この章では,ximdemo というアプリケーションからの抜粋を示します。 完全なソース・ファイルと,このアプリケーションの Imakefile が,ディレクトリ $I18NPATH/usr/examples/ximdemo にあります。 このソース・ファイルを熟読して,アプリケーションを構築し実行してみることにより,この章で説明されているプログラミング手法の応用について理解をさらに深めることができます。

5.3.1    ロケールの管理

国際化対応の X クライアントは,他の種類のアプリケーションが使用するのと同じロケール宣言メカニズム,つまり,標準 C ライブラリの setlocale 関数を使用します。 また,X ライブラリにはロケールを判定し,ロケール修飾子を構成するための 2 つの関数,XSupportsLocale()XSetLocaleModifiers() が含まれています。 表 5-1 に,これらの関数とその要約を示します。 これらの関数の詳細については, XSetLocaleModifiers(3X11) のリファレンス・ページを参照してください。

表 5-1:  X ライブラリのロケール宣言関数

関数 説明
XSupportsLocale() X ライブラリが現在のロケールをサポートしているかどうかを判定します。
XSetLocaleModifiers()

現在のロケール設定での X 修飾子のリストを指定します。

XSetLocaleModifiers() リストは,次の形式の要素を持つ,ヌルで終了する文字列です。

@category =value

ロケール修飾子として現在定義されている標準 category は,入力サーバを識別するための im だけです。 ただし,ロケールで複数の入力サーバがサポートされている場合は,複数の im エントリが修飾子リストに表示されることがあります。

ローカル・ホスト・システムでの省略値を設定するために,XMODIFIERS 環境変数に定義されている値が,XSetLocaleModifiers() 関数呼び出しで指定された修飾子のリストの後に追加されます。 たとえば,Tru64 UNIX システムでは,入力サーバの省略値は DEC です。 次のコマンドは,XMODIFIERS 変数にこの値を明示的に設定します。

% setenv XMODIFIERS @im=DEC

この例では,XSetLocaleModifiers() 関数の呼び出しで指定された修飾子リストの後に値 @im=DEC が追加されます。

X ライブラリ関数は,現在のロケールとロケール修飾子の設定値,あるいは,関数に渡されるオブジェクトにアタッチされているロケールとロケール修飾子の設定値に従って動作します。 ロケール設定に関連するオブジェクトには,次のタイプがあります。

これらのオブジェクトのロケールとロケール修飾子は,オブジェクトが作成された時点のロケール設定に依存します。 そのため,さまざまな言語のオブジェクトを作成し,それらのオブジェクトを同時に使用することにより,複数のロケールのデータを処理できます。 この機能により,多国語対応の X ウィンドウ・アプリケーションが開発できます。 アプリケーションを開発するときは,次の規則に従ってください。

例 5-1 に,X アプリケーションでロケールを設定したり,判定する方法を示します。

例 5-1:  X ウィンドウ・アプリケーションにおけるロケールの設定

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

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

  1. 省略時のロケールの設定値を格納する定数を定義します。

    この例では,この定数の値は明示的に zh_TW.dechanyu に設定されています。 [例に戻る]

  2. アプリケーションのコマンド行でロケールが指定されているかどうかを判定します。

    ユーザは,アプリケーションを起動するコマンド行で -locale オプションを指定することにより,省略時のロケールを無効にできます。 [例に戻る]

  3. アプリケーションのコマンド行でロケールが指定されていない場合,DEFAULT_LOCALE 定数の値をロケールに設定します。

    この定数に zh_TW.dechanyu ではなく,ヌル文字列 ("") が設定されていた場合,省略時のロケールは,アプリケーションを実行しているプロセスの LANG 環境変数の設定値によって決まります。 [例に戻る]

5.3.2    さまざまなロケールでのテキストの表示

一部のロケールのコードセット,特にアジア系言語のコードセットでは,定義されているすべての文字を表示するためには,複数の X ウィンドウ・フォントが必要になります。 そのようなコードセットを扱うために,X ライブラリは,テキストを表示したりそのサイズを調べるのに数種類のフォントを使用できる,フォントセットという概念をサポートしています。 フォントセットの概念は,XFontSet 構造体によって実装されます。 XFontSet 構造体は,リリース 5 より前の X ライブラリでサポートされていた XFontStruct 構造体に置き換わるものです。

フォントセットは,フォントセットを作成したときのロケールにバインドされます。 テキストの表示とサイズ調節を行う関数は,フォントセットのロケールに従ってテキストを解釈します。 したがって,これらの関数は,文字をそのフォント・グリフに正しくマップします。

Tru64 UNIX の実装では,テキストの表示とサイズ調節を行う関数により,文字コードの異なる複数のフォントを使用して母国語テキストを表示できます。

5.3.2.1    フォントセットの作成と操作

表 5-2 に,フォントセットを作成したり操作する関数の要約を示します。 詳細については,各関数のリファレンス・ページを参照してください。

表 5-2:  フォントセットの作成と操作を行う X ライブラリ関数

関数 説明
XCreateFontSet() 指定されたディスプレイ用のフォントセットを作成します。 この関数は,現在のロケールに必要なコードセットを判別し,それらのコードセットをサポートするための一連のフォントをロードします。
XFreeFontSet() 指定されたフォントセットと,ベース・フォント名リスト,フォント名リスト,XFontStruct リスト,XFontSetExtents などの関連コンポーネントを解放します。
XFontsOfFontSet() 指定されたフォントセットの XFontStruct 構造体とフォント名のリストを返します。
XBaseFontNameListOfFontSet() フォントセットの作成時にクライアントが指定した,オリジナルのベース・フォント名リストを返します。
XLocaleOfFontSet() 指定されたフォントセットにバインドされているロケールの名前を返します。

例 5-2 に,フォントセットを作成したり使用する関数を示します。

例 5-2:  X ウィンドウ・アプリケーションにおけるフォントセットの作成と使用


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

  1. DEFAULT_FONT_NAME 定数を,省略時のベース・フォント名リストの値として定義します。

    この例では,省略時のベース・フォント名リストとして,-*-SCREEN-*-*-R-Normal--*-*, -* を設定します。 省略時のベース・フォント名リストには,フォントを完全に指定した形式のリストではなく,総称名 (この例のようにワイルドカード・フィールドを使用) を指定します。 完全に指定した形式のフォント・リストは特定のロケールだけでしか使用できませんが,総称名は複数のロケールで省略値として使用できます。 [例に戻る]

  2. 省略時のベース・フォント名リストが,コマンド行で指定されているかどうかを判定します。

    アプリケーションのコマンド行で -fs オプションを使用すると,省略時のベース・フォント名リストを無効にできます。 [例に戻る]

5.3.2.2    フォントセットのメトリックスの取得

表 5-3 に,フォントセットのメトリックスを調べたり,テキストのサイズを調節する X ライブラリ関数の要約を示します。

表 5-3:  テキストのサイズを調節する X ライブラリ関数

関数 説明
XExtentsOfFontSet() 指定されたフォントセットのフォントの境界ボックス情報が格納されている XFontSetExtents 構造体を返します。
XmbTextEscapement()XwcTextEscapement() 指定されたフォントセットを使用して,特定の文字列を表示するために必要な文字送り幅 (ピクセル数) を計算します。
XmbTextExtents()XwcTextExtents() 文字列イメージ全体の境界ボックスと,スペーシングのための論理的な境界ボックスを計算します。 これらの関数は,それぞれ XmbTextEscapement()XwcTextEscapement() から返される値も返します。
XmbTextPerCharExtents()XwcTextPerCharExtents() 指定されたフォントセット用にロードされたフォントに従って,指定されたテキスト中の各文字のサイズを返します。

5.3.2.3    フォントセットを使用したテキストの表示

表 5-4 に,さまざまな母国語でテキストを表示するための関数の要約を示します。 テキストを表示する他の X ライブラリ関数とは異なり,国際化関数は次のような機能を備えています。

アプリケーションはこれらの関数を使用することで,テキストのエンコードを直接処理しないようにします。

表 5-4:  テキストを表示するための X ライブラリ関数

関数 説明
XmbDrawText()XwcDrawText()

複数のフォントセットを使用してテキストを表示します。 複雑なスペーシングや,テキスト文字列間でのフォントセットの切り替えを可能にします。

これらの関数は,対応する単一フォント用の関数,XDrawText()XDrawText16() の代わりに使用します。

XmbDrawString()XwcDrawString()

1 つのフォントセットを使用して,指定されたテキストだけをフォアグラウンド・ピクセルで表示します。

これらの関数は,対応する単一フォント用の関数,XDrawStringXDrawString16 の代わりに使用します。

XmbDrawImageString()XwcDrawImageString()

表示する長方形をバックグラウンド・ピクセルで塗り潰します。 その後,指定されたイメージ・テキストを 1 つのフォントセットを使用して表示し,そのテキストをフォアグラウンド・ピクセルでペイントします。

これらの関数は,対応する単一フォント用の関数,XDrawImageString()XDrawImageString16() の代わりに使用します。

例 5-3 に,国際化関数でテキストを表示する方法を示します。

例 5-3:  X ウィンドウ・アプリケーションにおけるテキストの表示

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

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

  1. XFillRectangle() を使用して,ブロック・タイプのカーソルを表示します。 [例に戻る]

  2. XmbDrawImageString() を使用して,母国語の文字列を表示します。

    この文字列には,シングルバイト文字とマルチバイト文字の両方が含まれていることがあります。 [例に戻る]

  3. XmbTextEscapement() を使用して,次の文字列の表示位置を計算します。 [例に戻る]

5.3.2.4    X 出力サーバを使用したテキスト処理

前項で説明したフォントセットの概念は,X ライブラリのバージョン 5 で取り入れられました。 X ライブラリのバージョン 6 では,出力サーバと出力コンテキストをさらに汎用化した概念が実装されています。 出力サーバと出力コンテキストは,フォントとコンテキストに依存した処理を実行し,左右両方向のテキスト表示やコンテキストに応じたテキスト出力を可能にします。

ロケールに従ってテキストを表示するためには,アプリケーションは,そのテキストを表示するのに必要なフォント,テキストをコンポーネントに分離する方法,および各コンポーネントに必要なフォントについてのデータが必要です。 このため,X ライブラリのバージョン 6 ではこの要件に対処するために,次のオブジェクトが用意されました。

表 5-5 に,XOM と XOC に関連する X ライブラリ関数をまとめます。 これらの X ライブラリ関数についての詳細は,それぞれのリファレンス・ページを参照してください。

表 5-5:  出力サーバと出力コンテキスト用の X ライブラリ関数

関数 説明
XOpenOM() 現在のロケールと修飾子の指定に合った出力サーバをオープンします。 この関数は,現在のロケールと修飾子が対応する XOM オブジェクトを返します。
XCloseOM() 指定された出力サーバをクローズします。
XSetOMValues() 出力サーバの属性を設定します。
XGetOMValues() 指定された出力サーバのプロパティまたは機能を取得します。
XDisplayOfOM() 指定された出力サーバに対応するディスプレイを返します。
XLocaleOfOM() 指定された出力サーバに対応するロケールを返します。
XCreateOC() 指定された出力サーバ内に出力コンテキストを作成します。
XOMOfOC() 指定された出力コンテキストに対応する出力サーバを返します。
XSetOCValues() XOC オブジェクトの値を設定します。
XGetOCValues() XOC オブジェクトの値を取得します。
XDestroyOC() 指定された出力コンテキストを破棄します。

5.3.2.5    エンコーディングが異なるフォントセット間の変換

次の理由により,エンコーディングの異なる複数の X フォントが利用できることがあります。

システムごとにフォント・エンコーディングが異なると,種類の違うシステムで実行されるアプリケーションでは問題が発生します。 このため,テキストの表示とサイズ調節用の関数の実装には,フォント・エンコーディングを変換するためのメカニズムが組み込まれています。 変換を可能にするには,アプリケーションが実行時環境に適したベース・フォント名リストを決定できるようにしなければなりません。 アプリケーションは,リソース・ファイルから,あるいは,コマンド行でユーザが指定したオプションにより,ベース・フォント名リストを取得できます。 たとえば,ximdemo アプリケーションを実行するコマンド行では,-fs オプションを使用して,ベース・フォント名リストを指定できます。

フォント・エンコーディングのための変換メカニズムは,アプリケーションが X ライブラリの国際化テキスト出力関数を使用している場合にのみ利用できます。 この変換メカニズムは,XDrawText()XDrawString() などの基本的なテキスト出力関数では使用できません。

5.3.3    クライアント間通信の処理

さまざまな言語や国で使用されるアプリケーションを設計する場合は,Latin-1 または ASCII テキストの文字列だけがクライアント間通信に使用されるという前提は成り立ちません。 このため,X ライブラリにはクライアント間通信で任意の言語のテキスト文字列を扱える関数が含まれています。 表 5-6 に,それらの関数の要約を示します。

表 5-6:  クライアント間通信用の X ライブラリ関数

関数 説明
XmbSetWMProperties()

ウィンドウの主要なプロパティを設定する唯一のプログラミング・インタフェースです。

アプリケーションはこれらのプロパティを使用して,他のクライアント,特にウィンドウ・マネージャおよびセッション・マネージャと通信します。 たとえば,この関数はウィンドウ名とアイコン名用の引数を持ちますが,一部のロケールではこの名前にマルチバイト文字を含めることができます。

XmbTextListToTextProperty()XwcTextListToTextProperty() 現在のロケールでエンコードされているテキストを,STRING 型または COMPOUND_TEXT 型のテキスト・プロパティに変換します。
XmbTextPropertyToTextList()XwcTextPropertyToTextList() STRING 型または COMPOUND_TEXT 型のテキスト・プロパティを,マルチバイト文字列またはワイド文字列のリストに変換します。
XwcFreeStringList() XwcTextPropertyToTextList() によって割り当てられたメモリを解放します。
XDefaultString()

文字が変換できなかった場合の置き換えとして,省略時の文字列を調べます。

変換ルーチンは,変換できない文字を含む文字列を検出した場合,ロケールごとの省略時の文字列に置き換えます。 XDefaultString() 関数は,この省略時の文字列を調べます。

例 5-4 は,X アプリケーションにおけるクライアント間通信の例です。

例 5-4:  X ウィンドウ・アプリケーションにおける他のクライアントとの通信


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

  1. strcmp() 関数や strcpy() 関数の引数として,引用符で囲まれた母国語テキストを指定します。

    この例では,テキストはウィンドウ・タイトルです。 わかりやすくするために,関数呼び出しではテキスト文字列を明示的に指定しています。 実際には,X や Motif のアプリケーションはこのような文字列を,ロケール固有のリソース・ファイルまたはユーザ・インタフェース言語 (UIL) ファイルから取り出します。 [例に戻る]

  2. XmbSetWMProperties() 関数にテキストを渡し,ロケールを使用してタイトルを解析して,その結果に応じてウィンドウ・マネージャのプロパティを設定します。 [例に戻る]

5.3.4    地域化されたリソース・データベースの処理

X リソース・ファイルのロケールは,ファイルが作成された時点のロケール設定に依存します。 そのため,リソース・データベースを作成するためにロードされるリソース・ファイルや文字列は,現在のロケールで解析されます。 この状況は,5.3.2 項のロケールとフォントセットのバインドで説明した状況と似ています。

表 5-7 に,地域化されたリソース・データベースを扱う X ライブラリ関数をまとめます。

表 5-7:  地域化されたリソース・データベースを扱う X ライブラリ関数

関数 説明
XrmLocaleOfDatabase() 指定されたデータベースにバインドされているロケール名を返します。
XrmGetFileDatabase()

指定されたファイルをオープンし,新しいリソース・データベースを作成して,ファイルから読み取った仕様をデータベースにロードします。

ファイルは,現在のロケールで解析されます。

XrmGetStringDatabase()

新しいリソース・データベースを作成し,ヌルで終了する文字列で指定されたリソースを格納します。

文字列は,現在のロケールで解析されます。

XrmPutLineResource()

指定されたデータベースに,リソース・エントリを 1 つ追加します。

エントリの文字列は,データベースのロケールで解析されます。

XrmPutFileDatabase()

指定されたデータベースのコピーを,指定されたファイルに格納します。

このファイルは,データベースと同じロケールで書き込まれます。

XResourceManagerString()

STRING 型でエンコードされた RESOURCE_MANAGER プロパティを,現在のロケールでエンコードされたマルチバイト文字列に変換します。

この関数は,XmbTextPropertyToTextList() 関数と同じ方法でエンコーディングを変換します。

5.3.5    X 入力サーバを使用したテキスト入力の処理

国際化対応の X アプリケーションを開発する場合,1 つのキーボードから,さまざまなロケールでデータを入力できなければなりません。 この問題に対処するために,次のオブジェクトが X ライブラリに取り入れられました。

アプリケーションは,ユーザがテキスト・データを入力できる複数のテキスト入力フィールドを用意することができます。 フィールドは,切り換えることができます。 入力データを取得するために,アプリケーションは入力コンテキストを指定して XmbLookupString() または XwcLookupString() を呼び出します。 返される文字列は,常に XIM または XIC オブジェクトに対応するロケールでエンコードされています。 以降の項では,入力オブジェクトの使用方法について説明します。

5.3.5.1    入力サーバへの接続と,接続の解除

入力サーバを使用するためには,アプリケーションはまず,XOpenIM() を呼び出さなければなりません。 この関数は,現在のロケールとロケール修飾子に対応した入力サーバへの接続を確立します。 この関数は,現在のロケールとロケール修飾子がバインドされている XIM オブジェクトを返します。 ロケールと修飾子の XIM オブジェクトへのバインドは,この呼び出しを実行した時点で確立されるため,動的に変更することはできません。

入力サーバを必要としなくなった場合,アプリケーションは XCloseIM() を呼び出して XIM オブジェクトをクローズします。

XIM オブジェクトの情報を取得するためには,次の関数も利用できます。

XOpenIM() 関数によってオープンされる入力サーバは,次のいずれかの方法で決定されます (優先順位の高いものから順に示す)。

  1. XSetLocaleModifiers() の呼び出しで指定した im 修飾子の値

  2. XMODIFIERS 環境変数で指定した入力サーバ

  3. DEC という名前の省略時の入力サーバ

上記の入力サーバが使用できない場合,XOpenIM() は省略時の動作として,ISO Latin-1 の入力だけをサポートします。 次の場合には,XOpenIM() 呼び出しは失敗する可能性があります。

例 5-5 は,入力システムを接続する方法と接続の解除を行う方法の例です。

例 5-5:  X ウィンドウ・アプリケーションにおける入力サーバへの接続と接続の解除

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

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

  1. 入力サーバに固有のリソースを探すために,リソース・データベース rdbXOpenIM() に渡します。

    国際化 Xt 関数により,アプリケーションで作成したリソース・データベースを指定できます。 [例に戻る]

  2. 入力サーバへの接続に成功したかどうかを検査します。 [例に戻る]

  3. 入力サーバとの接続を解除します。 [例に戻る]

5.3.5.2    入力サーバ値の問い合わせ

入力サーバの動作には,ベンダによって異なる部分があります。 たとえば実装によっては,サポートされるユーザ入力スタイルの組み合わせが異なることがあります。

移植性のあるアプリケーションの開発を支援するために,X ライブラリには入力サーバの属性を調べるための XGetIMValues() 関数が含まれています。 XNQueryInputStyle 属性には,入力サーバがサポートしているユーザ入力スタイルを指定します。

例 5-6 に,XGetIMValues() 関数と XNQueryInputStyle 属性を使用して,入力サーバに関する情報を取得する方法を示します。

例 5-6:  入力サーバがサポートするユーザ入力スタイルの取得

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

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

  1. ユーザがアプリケーションのコマンド行で,使用したい入力スタイルを指定したかどうかを判定します。

    ximdemo アプリケーションでは,-Root と -Cb オプションを使用して,ユーザ入力スタイルを指定できます。 これらのオプションは,このアプリケーションでサポートされている 2 つのスタイルを表します。 -Root オプションは,Root-window スタイルを指定します。 このスタイルでは,クライアントと入力サーバ間のやり取りを最小限に抑えることができます。 -Cb オプションは,コールバックを介して前編集を処理するスタイルを指定します。 このスタイルでは,On-the-Spot 前編集が可能になります。 [例に戻る]

  2. アプリケーションがサポートできる 2 種類の入力スタイルを指定するために,app_supported_styles ビットマスクを定義します。 [例に戻る]

  3. XGetIMValues() を呼び出して,入力スタイルを調べます。

    この呼び出しは,入力スタイルを im_styles パラメータに返します。 [例に戻る]

  4. 入力サーバがサポートし,このアプリケーションが正しく処理できる入力スタイルを選択します。

    ユーザが指定した入力スタイルが優先されます。 入力スタイルが指定されていない場合,アプリケーションは,返されたスタイル・リスト中の最後の入力スタイルを選択します。 [例に戻る]

入力サーバでサポートされる入力スタイル (前編集スタイル) は,ロケールごとに異なります。

特定の入力サーバでサポートされている入力スタイルを見つけるには,次の各国のマニュアルを参照してください。

これらのマニュアルは,本オペレーティング・システムのドキュメント Web サイト (http://h50146.www5.hp.com/products/software/oe/tru64unix/manual/) で,プログラミング関連ドキュメントとして掲載されています。

5.3.5.3    入力サーバのコンテキストの作成と使用

X サーバが 1 つのディスプレイ上に複数のウィンドウを持てるのと同様に,アプリケーションも 1 つの入力サーバに対して複数のコンテキストを作成できます。 X ライブラリには,入力コンテキスト (XIC) のオブジェクトを作成するための XCreateIC() 関数が含まれています。 XIC オブジェクトには,他の関数を使用して設定したり取得できるいくつかの属性があります。 そのような属性を次に示します。

XIC オブジェクトを破棄するには,XDestroyIC() 関数を呼び出します。

例 5-7 に,XCreateIC() 関数と XDestroyIC() 関数の使用方法を示します。

例 5-7:  X ウィンドウ・アプリケーションにおける入力コンテキストの作成と破棄


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

  1. XVaCreateNestedList() 関数を呼び出して,前編集属性とステータス属性の,ネストされた引数リストを作成します。

    XNPreeditAttributes 属性と XNStatusAttributes 属性は,2 次属性のリストを含みます。 2 次属性の設定や問い合わせを実行する前に,アプリケーションは,2 次属性を格納するためのネストされたリストを作成しなければなりません。 [例に戻る]

  2. XIC 属性を指定します。

    XIC オブジェクトを作成するときに,アプリケーションはいくつかの XIC 属性を指定しなければなりません。 XNInputStyle 属性は必須です。 他の属性が必要かどうかは,入力スタイルによって異なります。 [例に戻る]

  3. On-the-Spot 入力スタイルのコールバックを登録します。

    入力スタイルが On-the-Spot の場合,アプリケーションは XIC オブジェクトの作成時に,すべてのコールバックを登録しなければなりません。

    アプリケーションは,XIC の作成時に XNClientWindow 属性を設定する必要はありませんが,XIC を使用する前にこの属性を設定しなければなりません。 XNClientWindow を設定する前に XIC を使用すると,結果は予測できません。 [例に戻る]

  4. Root-Window スタイルの入力スタイル属性,クライアント・ウィンドウ属性,およびフォーカス・ウィンドウ属性を設定します。

    入力スタイルが Root-Window の場合,XIC の作成時にアプリケーションが設定する必要のある属性は,これらの属性だけです。 [例に戻る]

  5. XIC の作成に失敗したときの動作を指定します。

    次の場合には,XCreateIC() 呼び出しは失敗します (つまり,NULL を返す)。

    [例に戻る]

  6. XIC をクローズします。 [例に戻る]

表 5-8 に,XIC オブジェクトの管理に利用できる関数の要約を示します。

表 5-8:  入力コンテキスト (XIC) を管理する X ライブラリ関数

関数 説明
XSetICFocus()

キーボード・イベントが入力サーバに送られるようにします。

XIC のフォーカス・ウィンドウが入力フォーカスを受け取ったときは,この関数を呼び出さなければなりません。 この関数を呼び出さないと,キーボード・イベントは入力サーバに送られません。

XUnsetICFocus()

キーボード・イベントを入力サーバに送らないようにします。

XIC のフォーカス・ウィンドウがフォーカスを解除されたときに,この関数を呼び出します。

XmbResetIC()XwcResetIC()

XIC をリセットして初期状態に戻します。

XIC 上で保留されている入力はすべて削除されます。 これらの関数は,現在の前編集文字列または NULL を返します。 どちらが返されるかは,入力サーバの実装によって異なります。

XIMOfIC()

指定された XIC に対応する XIM を返します。

XSetICValues()

指定された XIC に属性を設定します。

XGetICValues()

指定された XIC の属性を調べます。

5.3.5.4    On-the-spot 入力スタイル用の前編集コールバックの作成

アプリケーションが On-the-Spot 入力スタイルをサポートしているときは,一連の前編集コールバックを用意しなければなりません。 XIC には多数のコールバックが関連付けられています。 例 5-8 に,それらのコールバックを示します。

例 5-8:  X ウィンドウ・アプリケーションにおける前編集コールバックの使用


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

  1. 現在の表示位置を保存します。

    前編集文字列の表示操作の一環として,このアプリケーションは,現在の表示位置を PreeditStartCallback 属性の値として保存します。 前編集が完了すると,アプリケーションは前編集文字列を削除し,元の表示位置を復元します。 [例に戻る]

  2. 前編集文字列の長さを返します。

    12 バイトという値は,文字列の長さを制限するためのものです。 この値は,前編集バッファのサイズと同じでなければなりません。 このアプリケーションでは,前編集バッファ (preedit_buffer) を 12 バイトの文字配列として宣言しています。 [例に戻る]

  3. 表示位置を復元し,テキスト・バッファを再表示します。 [例に戻る]

  4. ワイド文字のエンコーディングを処理します。

    この例では,前編集文字列はマルチバイト・エンコーディングされているものとします。 ただしアプリケーションは,マルチバイト・エンコーディングとワイド文字エンコーディングの両方を処理できるように作成しなければなりません。 文字位置などの情報が,バイト数ではなく文字数として XIMPreeditDrawCallbackStruct 構造体に返されるため,ワイド文字エンコーディングの方が好ましいエンコーディングです。 [例に戻る]

  5. 前編集文字列のサイズが 12 バイトを超えた場合は,前編集文字列をクリアします。

    文字列のサイズは,PreeditDrawCallback 属性から取得します。 アプリケーションは,XmbResetIC() 呼び出しで返された文字列を処理せずに,Xfree() を呼び出して解放します。 [例に戻る]

5.3.5.5    入力サーバのためのイベント・フィルタリング

入力サーバは,アプリケーションによってイベントが処理される前に,イベントを受信しなければなりません。 アプリケーションは,KeyPress イベントと KeyRelease イベントだけでなく,他のイベントも入力サーバに渡さなければなりません。 X ライブラリには,イベントを入力サーバに渡すための XfilterEvent() 関数が含まれています。 この関数は,他の関連する関数とともに次のように使用します。

  1. XNFilterEvents 引数を指定して XGetICValues() 関数を呼び出し,入力サーバに渡すイベントのマスクを取得します。

  2. XSelectInput() 関数によりイベント・タイプを登録します。

  3. プログラムのメイン・ループ (通常は XNextEvent() 呼び出しの直後) で,XFilterEvent() を呼び出して入力サーバにイベントを渡します。

    True のリターン・ステータスは,入力サーバがイベントをフィルタ処理したため,アプリケーションではそのイベントをこれ以上処理する必要がないことを示します。

例 5-9 に,上記の処理を示します。

例 5-9:  X ウィンドウ・アプリケーションにおける入力サーバのためのイベント・フィルタリング


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

  1. イベントをフィルタ処理します。

    XtDispatchEvent() 関数は,XFilterEvent() を呼び出します。 したがって,この例の for ループを,XtAppMainLoop() の呼び出しに置き換えることも可能です。 [例に戻る]

5.3.5.6    キーボードからのコンパウンド・ストリングの取得

X アプリケーションで XmbLookupString() 関数や XwcLookupString() 関数を使用すると,母国語の文字とキー・シンボルを取得できます。 アプリケーションでは,1 文字を組み立てるのにキーを数回押す必要がある,複雑な入力システムが存在することも考慮しておかなければなりません。 そのため,これらの関数を呼び出すたびに,コンパウンド・キャラクタやコンパウンド・ストリングが返されることを前提にはできません。

例 5-10 に,X アプリケーションでキーボード入力を取得する方法を示します。

例 5-10:  X ウィンドウ・アプリケーションにおけるキーボード入力の取得


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

  1. FocusIn イベントと FocusOut イベントを処理します。

    この例では,1 つの XIC がフォーカス・ウィンドウに対応しています。 入力サーバの中には,ステータス領域を更新するためにフォーカス変更情報を必要とするものがあります。 そのため,FocusIn イベントのたびに XSetICFocus() を呼び出し,また FocusOut イベントのたびに XUnsetICFocus() を呼び出します。

    また,アプリケーションは,1 つの XIC を複数のフォーカス・ウィンドウに使用することもできます。 この場合,フォーカス変更イベントごとに XSetICFocus() を呼び出す必要はありませんが,XIC に XNFocusWindow 属性を設定しなければなりません。 [例に戻る]

  2. KeyPress イベントを処理します。

    アプリケーションでは,XmbLookupString() または XwcLookupString() に対して,KeyPress イベントだけを渡すようにします。 これらの関数に KeyRelease イベントを渡した場合,結果は予測できません。

    この例ではわかりやすくするために,XmbLookupString() 呼び出しのステータス・フィールドを NULL にしています。 実際のアプリケーションでは,返されたステータスを検査して,適切に対処しなければなりません。 たとえば,返されたステータスが XBufferOverflow であれば,アプリケーションではバッファに割り当てるメモリを追加します。 [例に戻る]

  3. 文字列が返された場合は,その文字列を処理します。

    XmbLookupString() は,コンパウンド・ストリングのサイズ (バイト数) を返します。 [例に戻る]

5.3.5.7    入力サーバが失敗したときの処理

入力サーバの XNDestroyCallback リソースと入力コンテキストは,X11R6 で取り入れられました。 入力サーバが失敗したときに生成されるこれらのリソースは,クライアント・アプリケーションの XIM および XIC オブジェクトをクローズします。 クライアント・アプリケーションがサーバの失敗を検出せずに動作を続行し,XIC および XIM オブジェクトをクローズした場合,結果は予測できません。

例 5-11 に,XIM オブジェクトの XNDestroyCallback リソースの登録方法と,サーバが失敗したときに XIM をクローズする方法を示します。

例 5-11:  入力サーバが失敗したときの処理

static void     _imDestroyCallback();  [1]

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

  1. 何らかの原因で入力サーバ (IMS) が失敗した場合に XIM をクローズする関数を宣言します。 [例に戻る]

  2. 入力サーバがまだ接続されているかどうかを示す IMS_Connected 変数と,リソースの登録に必要なクライアント情報が格納される cb 構造体を宣言します。 [例に戻る]

  3. XIM をオープンする呼び出しに失敗した場合は,エラー・メッセージを表示して終了します。

    成功した場合には,IMS_Connected 変数に True を設定し,適切なクライアント・データを cb 構造体に格納した後,XSetIMValues() 関数を呼び出して XIM の XNDestroyCallback リソースを登録します。 [例に戻る]

  4. 入力サーバが動作している場合,XmbLookupString() 関数を呼び出して,ユーザ入力を処理します。 動作していない場合には,XLookupString() 関数を呼び出します。 [例に戻る]

  5. 入力サーバが失敗した場合に XIM をクローズする関数のプロトタイプを定義します。 [例に戻る]

ximdemo プログラムは極めて簡単なものなので,入力コンテキストは 1 つしか使用しません。 このような場合,入力サーバが失敗したときに,XIC を明示的にクローズする必要はありません。 次の例は,XIC をクローズするコールバック関数のプロトタイプを示します。

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

5.3.6    Xt および X ライブラリの国際化機能の使用法: 要約

以下に示す母国語入力処理の手順は,X ライブラリについてこれまでの項で説明した内容の要約です。 わかりやすくするために,手順の説明では X ツールキット・イントリンシクス・ライブラリ (Xt) 関数を使用するプログラミングと,X ライブラリ関数を使用するプログラミングの間に相違点があれば,その旨を明記します。 X ツールキット・イントリンシクス・ライブラリの国際化機能の説明については,5.1 節を参照してください。

  1. setlocale() を呼び出して,現在のロケールにバインドします。

    XtSetLanguageProc() で初期化コールバック関数を登録しても,同じ結果が得られます。

  2. XSupportsLocale() を呼び出して,X が現在のロケールをサポートしていることを確認します。

  3. XSetLocaleModifiers() を呼び出すか XMODIFIERS 環境変数を設定して,使用する入力サーバを定義します。

  4. XOpenIM() を呼び出して,選択した入力サーバに接続します。

    ウィジェットを作成する場合は,適切な XIM がリソースとしてウィジェットに渡されるため,この手順を省略できます。

  5. XGetIMValues() を呼び出して,入力サーバがサポートしている入力スタイルを調べます。

    ウィジェットを作成する場合,この処理は初期化関数内で行います。

  6. XIC に対応するウィンドウを作成します。

    Xt 関数を使用している場合は,ウィジェットを作成します。

  7. XCreateFontSet() を呼び出して,このウィンドウのフォントセットを作成します。 X11R6 では,代わりに XOpenOM() を使用できます。

    Xt 関数を使用しており,ウィジェットをすでに作成してある場合は,XtDefaultFontSet の値を使用します。

  8. アプリケーションで取得した,サポートされている入力スタイルの値から入力スタイルを選択し,その値を引数として XCreateIC() を呼び出します。

    XIMPreeditCallbacks を使用している場合は,コールバック・ルーチンを作成して,XCreateIC() の呼び出しによりそれらのルーチンを登録しなければなりません。

  9. XGetICValues() を呼び出して,XNFilterEvents 属性を調べ,入力サーバが必要とするフォーカス・ウィンドウからのイベントを登録します。

  10. イベントをディスパッチする前に,メインのイベント・ループで XFilterEvent() を呼び出します。

    この呼び出しで True が返された場合は,そのイベントを破棄できます。

    X イントリンシクス (Xt) ライブラリのルーチンを使用したプログラミングでは,XtDispatchEvent() を使用します。

  11. メインのイベント・ループで,フォーカス・ウィンドウが FocusIn イベントを受信したときは入力フォーカスを設定し,FocusOut イベントを受信したときは入力フォーカスの設定を解除します。

    X イントリンシクス (Xt) ライブラリのルーチンを使用したプログラミングでは,イベント・ハンドラまたはトランスレーション/アクション・テーブルを使用して,フォーカス・イベントを処理します。

  12. フィルタ処理されていない KeyPress イベントに対しては,XmbLookupString() または XwcLookupString() を呼び出して,キー・シンボルとコンパウンド・ストリングを取得します。

    このストリングは,テキスト表示用の国際化関数を使用して表示できます。