文字を書き出します。あまり深く考えなければ次のようにすれば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は文字数ではなく バイト数を渡します。