文字を書き出します。あまり深く考えなければ次のようにすればOKです。
0001: /* 0002: font-x.c 0003: gcc font-x.c -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 0004: */ 0005: 0006: #include <X11/Xlib.h> 0007: #include <X11/keysym.h> 0008: 0009: #define DEFAULT_SIZE 256 0010: 0011: int main( int argc, char *argv[] ) 0012: { 0013: Display *dpy; 0014: int screen; 0015: Window win, root; 0016: GC gc; 0017: unsigned int win_width=DEFAULT_SIZE, win_height=DEFAULT_SIZE; 0018: XEvent event; 0019: KeySym key_sym; 0020: int i; 0021: 0022: dpy = XOpenDisplay( NULL ); /* Xサーバに接続する */ 0023: 0024: screen = DefaultScreen( dpy ); /* スクリーン設定 */ 0025: 0026: win = XCreateSimpleWindow( /* ウィンドウを開く */ 0027: dpy, /* Xサーバ */ 0028: RootWindow(dpy,screen), /* 親ウィンドウ */ 0029: 0, 0, /* 表示時の左上隅の座標 x, y */ 0030: win_width, win_height, /* ウィンドウの幅と高さ */ 0031: 1, BlackPixel(dpy,screen),/* ボーダーの幅と色 */ 0032: WhitePixel(dpy,screen) /* ウィンドウの背景色 */ 0033: ); 0034: XSelectInput( dpy, win, ExposureMask|KeyPressMask); 0035: XMapWindow( dpy, win ); /* ウィンドウのマッピング */ 0036: 0037: gc = DefaultGC( dpy, screen ); /* グラフィックコンテキストの設定 */ 0038: XSetForeground( dpy, gc, BlackPixel(dpy,screen) ); /* 描画色設定 */ 0039: 0040: /* 文字列出力 */ 0041: XDrawString( dpy, win, gc, 100, 100, "Hello", strlen("Hello") ); 0042: 0043: XFlush( dpy ); /* バッファのフラッシュ */ 0044: 0045: while( 1 ){ 0046: XNextEvent( dpy, &event ); 0047: switch( event.type ){ 0048: case Expose: 0049: XDrawString( dpy, win, gc, 100, 100, "Hello", strlen("Hello") ); 0050: XFlush( dpy ); /* バッファのフラッシュ */ 0051: break; 0052: case KeyPress: 0053: key_sym = XKeycodeToKeysym( dpy, event.xkey.keycode, 0 ); 0054: if( key_sym == XK_Escape ){ 0055: XDestroyWindow( dpy, win ); 0056: exit(0); 0057: } 0058: break; 0059: default: 0060: ; 0061: } 0062: } 0063: }
増えたのはXDrawStringだけです。
0040: /* 文字列出力 */ 0041: XDrawString( dpy, win, gc, 100, 100, "Hello", strlen("Hello") );
int XDrawString( display, d, gc, x, y, string, length ); Display * display; Drawable d; GC gc; int x; int y; char * string; int length;
今までのDraw系関数と同様、drawableに対して、座標とともににstringとそのデータ長 lengthを指定すると文字が書けます。 この場合、フォントはデフォルトのものが利用されるので、意図した書体やサイ ズにならないことがありますし、日本語は文字化けしてしまいます。
日本語を表示できるXDrawString16という関数 もありますが、ここでは最近の国際化のルールに則った表示を行ってみましょう。
Xの国際化はRelease5から行われています。現在はRelease6が普通です。4以前の 場合はこの方法は使えません。
0001: /* 0002: font-x2.c 0003: gcc font-x2.c -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 0004: */ 0005: 0006: #include <X11/Xlib.h> 0007: #include <X11/keysym.h> 0008: #include <X11/Xlocale.h> 0009: 0010: #define DEFAULT_SIZE 256 0011: 0012: int main( int argc, char *argv[] ) 0013: { 0014: Display *dpy; 0015: int screen; 0016: Window win, root; 0017: GC gc; 0018: unsigned int win_width=DEFAULT_SIZE, win_height=DEFAULT_SIZE; 0019: XEvent event; 0020: KeySym key_sym; 0021: XFontSet fs; 0022: char **missing, *def_return; 0023: int missing_count; 0024: int i; 0025: 0026: /* ロケールの設定 */ 0027: if( setlocale( LC_ALL, "" ) == NULL ){ 0028: exit( 0 ); 0029: }else{ 0030: printf( "Locale: \n", setlocale( LC_ALL, "" ) ); 0031: } 0032: 0033: dpy = XOpenDisplay( NULL ); /* Xサーバに接続する */ 0034: 0035: /* ロケールの確認 */ 0036: if( XSupportsLocale() == False ){ 0037: exit( 0 ); 0038: } 0039: 0040: screen = DefaultScreen( dpy ); /* スクリーン設定 */ 0041: 0042: win = XCreateSimpleWindow( /* ウィンドウを開く */ 0043: dpy, /* Xサーバ */ 0044: RootWindow(dpy,screen), /* 親ウィンドウ */ 0045: 0, 0, /* 表示時の左上隅の座標 x, y */ 0046: win_width, win_height, /* ウィンドウの幅と高さ */ 0047: 1, BlackPixel(dpy,screen),/* ボーダーの幅と色 */ 0048: WhitePixel(dpy,screen) /* ウィンドウの背景色 */ 0049: ); 0050: XSelectInput( dpy, win, ExposureMask|KeyPressMask); 0051: XMapWindow( dpy, win ); /* ウィンドウのマッピング */ 0052: 0053: gc = DefaultGC( dpy, screen ); /* グラフィックコンテキストの設定 */ 0054: XSetForeground( dpy, gc, BlackPixel(dpy,screen) ); /* 描画色設定 */ 0055: 0056: /* フォントの設定 */ 0057: fs = XCreateFontSet( dpy, "-*-*-medium-r-normal-*-16-*-*-*-*-*-*-*", 0058: &missing, &missing_count, &def_return ); 0059: if( missing_count != 0 ){ 0060: for( i=0; i<missing_count; i++ ){ 0061: printf( "missing 0: \n", i, missing[i] ); 0062: } 0063: if( def_return != NULL ){ 0064: printf( "Default font: .\n", def_return ); 0065: } 0066: }else{ 0067: printf( "No missing font\n" ); 0068: } 0069: 0070: /* 文字列の出力 */ 0071: XmbDrawString( dpy, win, fs, gc, 50, 100, "Hello,こんにちは", strlen("Hello,こんにちは") ); 0072: 0073: XFlush( dpy ); /* バッファのフラッシュ */ 0074: 0075: while( 1 ){ 0076: XNextEvent( dpy, &event ); 0077: switch( event.type ){ 0078: case Expose: 0079: XmbDrawString( dpy, win, fs, gc, 50, 100, "Hello,こんにちは", strlen("Hello,こんにちは") ); 0080: XFlush( dpy ); /* バッファのフラッシュ */ 0081: break; 0082: case KeyPress: 0083: key_sym = XKeycodeToKeysym( dpy, event.xkey.keycode, 0 ); 0084: if( key_sym == XK_Escape ){ 0085: XDestroyWindow( dpy, win ); 0086: exit(0); 0087: } 0088: break; 0089: default: 0090: ; 0091: } 0092: } 0093: }
まず、日本語を使うためにsetlocaleを呼びま す。
0026: /* ロケールの設定 */ 0027: if( setlocale( LC_ALL, "" ) == NULL ){ 0028: exit( 0 ); 0029: }else{ 0030: printf( "Locale: \n", setlocale( LC_ALL, "" ) ); 0031: }
char * setlocale( category, locale ); int category; const char * locale;
一つ目の引数であるcategoryに設定するカテゴリ には、LC_CTYPE, LC_TIMEなどを指定します。それぞれが何を示し ているのかはmanに任せるとして、これらは各国で表現形式の違うものを吸収す るためにあります。たとえば、時刻の表示の仕方は日本では年月日の順に書きます が、アメリカでは月日年の順に書いたりします。
実験してみましょう。ターミナルからdate コマンドを叩いてみてください。私 の環境だと日本語で表示されます。そこで、環境変数 LC_TIMEに "English"を指定してみます。 すると、表示のされ方が変わります。さらに"Korean"を指定するとさ らに変わります。
$ date 2005年 6月 15日 水曜日 00:14:29 JST $ export LC_TIME="English" $ date Wed Jun 15 00:14:53 JST 2005 $ export LC_TIME="Korean" $ date 2005. 06. 17. (榎) 00:15:07 JST
このように、「時刻」や「文字列」などの国や地域によって表記方法などが違う ものを設定するのがロケールです。この例でわかるように LC_*というのが「カテゴリ」で、それを指定する 文字列localeがロケール名です。
大抵の場合は、全てのロケールをそろえるために、カテゴリには LC_ALLを指定することが普通です。そして、 localeに空の文字列を渡すと、現在の環境設定が利用さ れます。カテゴリには優先順位があるので、今のように LC_TIMEだけを設定した場合は、 LC_CTYPEやLC_NUMERIC の設定が優先されます。
Bool XSupportsLocale( void );
サーバに接続した後に、XSupportsLocaleで、 サーバが現在のロケールをサポートしているかを問い合わせます。サポートして いる場合はTrueが返ります。サポートしていない 場合はFalseが返り、"C"ロケールが使用されます。ここでは、サポー トされていない場合は終了させています。
さて、希望どおりの文字を書くためには、まずフォントを指定する必要があります。 21行目にXFontSetというのがあります。これが今回 のキモです。54行目のXCreateFontSetでフォン トを指定します。
XFontSet XCreateFontSet(display, base_font_name_list, missing_charset_list_return, missing_charset_count_return, def_string_return ) Display * display; char * base_font_name_list; char *** missing_charset_list_return; int * missing_charset_count_return; char ** def_string_return;
FontSetというのは、簡単にいうと1バイトのフォン トと2バイトのフォントをまとめて扱うためのものです。国際化の際、たとえば 日本語の場合など、アルファベットはASCIIを使い、漢字は2バイトのコードを使 う場合があります。従来ですとXLoadFontとい う関数を用いて、それぞれのために別々のフォントを用意する必要がありました。 それらをまとめて利用できるようにしたのがFontSetです。
base_font_name_listには、使用したいフォント名 の論理フォント名をコンマで区切って指定します。論理フォント名についての詳 しい説明はしませんが、xfontselを使うと実際 のフォントを確認しながらフォント名をXバッファにコピーできるので便利です。 フォントを厳密に指定することもできますが、全ての環境においてそのフォント が利用できるとは限りません。指定を*にして省略 すると、指定したパラメータにマッチするフォントが使用されます。
missing_charset_list_returnにはロード出来なかっ たフォントのリストと、その個数 missing_charset_count_returnが返ります。 その際、表示できなかった文字を表すのに使われた文字が def_string_returnに返ります。
実際のテキスト表示はXmbDrawStringを使用し ます。
void XmbDrawString( display, d, font_set, gc, x, y, string, num_bytes ); Display *display; Drawable d; XFontSet font_set; GC gc; int x; int y; char *string; int num_bytes;
XDrawStringと同様ですが、font_setを明確に指定しています。さらに、文字列stringは1バイト系と2バイト系が混在していても構いま せん。そのかわり、 num_bytesは文字数ではなく バイト数を渡します。