文字出力

とりあえずテキスト表示

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

Back to TOP