コンピュータで使われる文字のデザインやその形状のことを『フォント』と いいます。
どのようなフォントが利用できるかは、Xサーバの設定によって 異なっています。 Xサーバで利用することのできるフォントの一覧は、 xlsfonts コマンドによって知ることができます。
フォント一覧 PROMPT$ xlsfonts
... -adobe-times-medium-r-normal--0-0-75-75-p-0-iso8859-1 ... -adobe-times-medium-r-normal--14-140-75-75-p-74-iso8859-1 ... -misc-fixed-medium-r-normal--0-0-75-75-c-0-jisx0201.1976-0 -misc-fixed-medium-r-normal--0-0-75-75-c-0-jisx0208.1983-0 -misc-fixed-medium-r-normal--14-130-75-75-c-70-jisx0201.1976-0 -misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0 ...
![]()
私達が使っているシステム(Solaris2.X)では、Xサーバが 参照するフォントは/usr/openwin/lib/X11/fonts/以下の ディレクトリに置かれています。 Linuxの場合は、普通、/usr/X11R6/lib/X11/fontsの下の ディレクトリに置かれています。 xsetコマンドでフォントの設定を調べたり、変更したりできます。 xsetで表示されるFontPathの値がフォントの置かれている ディレクトリへのパスになります。
フォント・パスを調べる PROMPT$ xset q
... Font Path: /usr/openwin/lib/X11/fonts/F3/, /usr/openwin/lib/X11/fonts/F3bitmaps/, /usr/openwin/lib/X11/fonts/Type1/, /usr/openwin/lib/X11/fonts/Speedo/, /usr/openwin/lib/X11/fonts/misc/, /usr/openwin/lib/X11/fonts/75dpi/, /usr/openwin/lib/X11/fonts/100dpi/
![]()
ファイルとフォント名の対応はそのディレクトリに置かれている fonts.dir というファイルで定義されています。 また、フォントの別名は fonts.alias というファイルで定義されています。
/usr/openwin/lib/X11/fonts/misc/fonts.dir 6x12.pcf.Z -misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso646.1991-irv 6x13.pcf.Z -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1 ...
![]()
/usr/openwin/lib/X11/fonts/misc/fonts.alias k14 -misc-fixed-medium-r-normal--14-*-*-*-*-*-jisx0208.1983-0 a14 -misc-fixed-medium-r-normal--14-*-*-*-*-*-iso8859-1 r14 -misc-fixed-medium-r-normal--14-*-*-*-*-*-jisx0201.1976-0 ...
![]()
ちなみに"jisx0208"が名前に付くのは日本語の漢字用のフォントです。
X-Windows System におけるフォント名は XLFD (X Logical Font Description Convention) という 規則にしたがっています。 XLFD では、フォント名の - (ハイフン)に囲まれた14個のフィールドの 意味はそれぞれ以下のように定義されています。
| コード | 英語名 | 説明 |
| R | Roman | 直立 |
| I | Italic | イタリック、垂直軸から時計方向に傾斜 |
| O | Oblique | 斜め直立、垂直軸から時計方向に傾斜 |
| コード | 英語名 | 説明 |
| P | Proportional | 文字幅が可変のフォント |
| M | Monospaced | 文字幅が一定のフォント |
| C | CharCell | タイプライタ文字セルのモデルに準拠する固定幅フォント |
フォント名を指定するときは必ずしも全てのフィールドを 指定しなくても構いません。 フィールドを省略するときは '*' (アスタリスク)という文字を使います。 '*' は1つまたは複数のフィールドを表します。
[例] -*-times-medium-r-normal--14-140-*-*-*-*-iso8859-1
-*-times-medium-r-normal--14-*
Xサーバがロードできるフォントの一覧は XListFonts()関数によって 得ることができます。 たとえば、上で述べた xlsfonts コマンドは XListFonts() 関数を使って 実現されています。
X11R5以降のXサーバでは、PIXEL_SIZE, POINT_SIZE, AVERATE_WIDTH の フィールド (14個のフィールドをもつXLFDのフォント名の7, 8, 12番目の フィールド)に 0 を指定すると、 XListFonts() はスケーラブルフォントを返すようになりました。 渡されたフォント名パターンがXLFDの妥当な形式(= 14個のハイフンが全て 指定されている形式)で指定されている場合に限ってXサーバは スケーラブルフォントを選択します。
スケーラブルフォントをリストするには、PIXEL_SIZE, POINT_SIZE, AVERATE_WIDTH を 0 または * にした妥当な形式のパターンを指定してXListFonts()を呼び出します。
| xlistfonts.c |
#include <stdio.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int main() {
Display *dpy;
char **list;
int count, i;
if ((dpy = XOpenDisplay(NULL)) == NULL) {
fprintf(stderr,"can not open display\n");
exit(-1);
}
list=XListFonts(dpy,"-*-courier-*-*-*-*-0-0-*-*-*-0-*-*",200,&count);
printf("count=%d\n",count);
for (i=0; i<count; ++i) {
printf("%s\n",*(list++));
}
}
|
| 実行結果 |
PROMPT$ gcc -I/usr/X11R6.4/include xlistfonts.c -L/usr/X11R6.4/lib -lX11 -lnsl -lsocket |
Xサーバにフォントをロードするには関数XLoadQueryFont()を使います。 表示する文字列がウィンドウ上でどれだけの幅になるかを計算するには、 1バイト文字に対しては関数 XTextWidth() を、 2バイト文字に対しては関数 XTextWidth16() を 使います。 ウィンドウ上に文字列を表示するには Xサーバにロードしたフォントを 設定したグラフィックコンテクストを作成しておいてから、 関数 XDrawString() または関数 XDrawString16() を使います。
ウィンドウに文字を表示する手順は以下の通りです。
サーバへのフォントのロード --- XLoadQueryFont()関数 XFontStruct *XLoadQueryFont(Display *dpy, char *name) Display *dpy; Xサーバを指定する char *name; フォント名を指定する
![]()
Xサーバ上にロードされたフォントは、 このFontStruct構造体の fid フィールドで識別されます。 描画関数でフォントを指定するには、 FontStruct構造体の fid フィールドを指定して作成した グラフィックコンテクストを使います。XFontStruct構造体 typedef struct { Font fid; /* Font id for this font */ ... int ascent; /* log. extent above baseline for spacing */ int descent; /* log. descent below baseline for spacing */ } XFontStruct;
![]()
XGCValues gcv; XFontStruct *font; ... font=XLoadQueryFont(dpy,フォント名); ... gcv.font = font->fid; gc = XCreateGC(dpy,win, ... | GCFont, &gcv); ...
![]()
2バイト文字用構造体 --- XChar2b構造体 typedef struct { /* normal 16 bit characters are two bytes */ unsigned char byte1; unsigned char byte2; } XChar2b;
![]()
テキストの幅を計算する関数 int XTextWidth(XFontStruct *fs, char *s, int count) /* テキストの幅を返す */ int XTextWidth16(XFontStruct *fs, XChar2b *str, int count) /* 2バイト文字テキストの幅を返す */ XFontStruct *fs; /* フォント構造体 */ XChar2b *str; /* 出力する2バイト文字列 */ char *str; /* 出力する文字列 */ int count; /* データの個数 */
![]()
XChar2b構造体は2バイトの大きさを持っています。 XDrawString16の第7引数で渡すのはデータの個数ですから、 漢字を普通の文字列に入れておいてその文字列を表示する場合は、 XDrawString16の第7引数に文字列の長さの半分である strlen(s)/2 を指定することになります。描画関数 XDrawString(Display *dpy, Window *win, GC gc, int x, int y, char *s, int len) XDrawString16(Display *dpy, Window *win, GC gc, int x, int y, XChar2b *s, int len)
![]()
| x2.c |
#include <stdio.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define FONTNAME "-adobe-times-medium-r-normal--14-140-75-75-p-74-iso8859-1"
#define KFONTNAME "-misc-fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0"
char *s="sample text";
char *s2="漢字とひらがなのテスト";
char *boff(char *s) {
char *p, *q;
p = (char *) malloc(strlen(s)+1);
for (q=p; *s; ) *q++ = (*s++) & 0x7f;
*q='\0';
return(p);
}
int main() {
Display *dpy;
int scr;
Window win;
XSetWindowAttributes xswa;
char *xservname=NULL;
GC gc, gc2;
XGCValues gcv;
XFontStruct *font,*font2;
if ((dpy=XOpenDisplay(xservname)) == NULL) {
fprintf(stderr,"can not open %s\n",XDisplayName(xservname));
exit(-1);
}
scr = DefaultScreen(dpy);
xswa.background_pixel = WhitePixel(dpy,scr);
xswa.border_pixel = BlackPixel(dpy,scr);
xswa.event_mask = ExposureMask;
win = XCreateWindow(dpy,RootWindow(dpy,scr),0,0,320,240,1,
CopyFromParent,CopyFromParent,CopyFromParent,
CWBackPixel | CWBorderPixel | CWEventMask, &xswa);
if ((font=XLoadQueryFont(dpy,FONTNAME)) == NULL) {
fprintf(stderr,"cannot find font %s\n",FONTNAME);
exit(-1);
}
if ((font2=XLoadQueryFont(dpy,KFONTNAME)) == NULL) {
fprintf(stderr,"cannot find font %s\n",KFONTNAME);
exit(-1);
}
gcv.foreground = BlackPixel(dpy,scr);
gcv.background = WhitePixel(dpy,scr);
gcv.font = font->fid;
gc = XCreateGC(dpy,win,GCForeground|GCBackground|GCFont,&gcv);
gcv.font = font2->fid;
gc2 = XCreateGC(dpy,win,GCForeground|GCBackground|GCFont,&gcv);
XMapWindow(dpy,win);
s2 = boff(s2);
for (;;) {
XEvent ev;
XNextEvent(dpy,&ev);
switch (ev.type) {
case Expose:
XClearWindow(dpy,win);
XDrawString(dpy,win,gc,10,50,s,strlen(s));
XDrawString16(dpy,win,gc2,10,100,(XChar2b *)s2,strlen(s2)/2);
break;
default:
printf("unknown event %d\n",ev.type);
break;
}
}
}
|
XSetWindowAttributes xswa; ... xswa.event_mask = イベントマスク | ... ; win = XCreateWindow(..., ...|CWEventMask, &xswa); ... for (;;) { XEvent ev; XNextEvent(dpy,&ev); if (ev.type == イベントタイプ) ... ... }
![]()
| イベントマスク | イベントタイプ | 説明 |
|---|---|---|
| KeyPressMask | KeyPress | キーボードのキーを押す |
| KeyReleaseMask | KeyRelease | キーボードのキーを放す |
| ButtonPressMask | ButtonPress | マウスボタンを押す |
| ButtonReleaseMask | ButtonRelease | マウスボタンを放す |
| ButtonMotionMask | MotionNotify | マウスをドラッグ |
KeyEvent から ASCII 文字列を得る関数 int XLookupString(event, buffer, num_bytes, keysym, status) XKeyEvent *event; char *buffer; /* RETURN */ int num_bytes; KeySym *keysym; /* RETURN */ XComposeStatus *status; /* not implemented */
![]()
XKeyEvent 構造体 typedef struct { int type; /* of event */ unsigned long serial; /* number of last request processed by server */ Bool send_event; /* true if this came from a SendEvent request */ Display *display; /* Display the event was read from */ Window window; /* "event" window it is reported relative to */ Window root; /* root window that the event occured on */ Window subwindow; /* child window */ Time time; /* milliseconds */ int x, y; /* pointer x, y coordinates in event window */ int x_root, y_root; /* coordinates relative to root */ unsigned int state; /* key or button mask */ unsigned int keycode; /* detail */ Bool same_screen; /* same screen flag */ } XKeyEvent;
![]()
(注) X11R5以降、国際化によって国際化テキストの入出力も できるようになりました。 しかし、まだシステムのlocaleのサポートの状況がまちまち ですので、日本語入力を必要とするプログラムでは注意が必要となります。 今回の授業では国際化機能を使わないプログラミングを説明しましたが、 興味のある人は
Volume One: Xlib Programming Manual, O'Reilly & Associations, Inc
の 11章 「Internationalized Text Input」
および 12 章 「Internationalization」などを
読んでみるとよいでしょう。
日本語入力用フロントエンドプロセッサ kinput2 を使って日本語入力
可能なサンプルプログラムはたとえば
http://nw.tsuda.ac.jp/lec/x/readi18n.c
にあります。
この例は RedHat7.1 の環境でテストはされていますが、全ての
X-Window System の環境でうごくわけではありません。
日本語の平仮名や漢字は2バイトコードで表現されます。 このコード体系には3通りあります。
| kanji.txt |
ABC漢字DEF |
| kanji.txtを JIS で表した場合 |
| kanji.txtを EUC で表した場合 |
| kanji.txtを MS漢字コード で表した場合 |
| kanji.txtを utf-8 で表した場合 |
[1]上記のクライアント(x2.c)を動作させて下さい。
[2]上記のクライアント(x3.c)を動作させて下さい。
[3]英語の文字(iso8859)と「EUC日本語(jisx0208)」の文字が 混ざっている文字列があります。 これをウィンドウに表示する関数DrawEUC()をfont.cとして作成して下さい。 以下の x3.c とリンクして動作確認をして下さい。
x3.c と font.c のコンパイル PROMPT$ gcc -I/usr/X11R6.4/include x3.c font.c -o x3 \ -L/usr/X11R6.4/lib -lX11 -lsocket -lnsl
←Solarisの場合 または PROMPT$ gcc -I/usr/X11R6/include x3.c font.c -o x3 -L/usr/X11R6/lib -lX11
←Linuxの場合
![]()
int DrawEUC(Display *dpy, Window win, GC gc1, GC gc2,
XFontStruct *font1, XFontStruct *font2,
int x, int y, unsigned char *s)
dpy: ディスプレイ
win: ウィンドウ
gc1 : 1バイト文字用のGC
gc2 : 2バイト文字用のGC
font1 : 1バイト文字用のXFontStruct構造体
font2 : 2バイト文字用のXFontStruct構造体
x: 最初の文字が表示されるX座標
y: 最初の文字が表示されるY座標
返り値: 文字列の画面上での幅
| font.c |
#include <stdio.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int DrawEUC(Display *dpy, Window win, GC gc1, GC gc2,
XFontStruct *font1, XFontStruct *font2,
int x, int y, unsigned char *s)
{
int eucflag=0;
unsigned char c, buf[0x100], *p=buf;
while ((c=*s++) != '\0') {
if (c & 0x80) { /* euc */
if (!eucflag) { /* ascii -> euc */
XDrawString(dpy,win,gc1,x,y,buf,p-buf);
x += XTextWidth(font1,buf,p-buf);
p = buf;
}
eucflag = 1;
*p++ = c & 0x7f;
if (p-buf == sizeof(buf)) { /* buffer overflow */
XDrawString16(dpy,win,gc2,x,y,(XChar2b *)buf,(p-buf)/2);
x += XTextWidth16(font2,(XChar2b *)buf,(p-buf)/2);
p=buf;
}
} else {
if (eucflag) { /* euc -> ascii */
XDrawString16(dpy,win,gc2,x,y,(XChar2b *)buf,(p-buf)/2);
x += XTextWidth16(font2,(XChar2b *)buf,(p-buf)/2);
p=buf;
}
eucflag = 0;
*p++ = c;
if (p-buf == sizeof(buf)) { /* buffer overflow */
XDrawString(dpy,win,gc1,x,y,buf,p-buf);
x += XTextWidth(font1,buf,p-buf);
p=buf;
}
}
}
if (p-buf > 0) {
if (eucflag) {
XDrawString16(dpy,win,gc2,x,y,(XChar2b *)buf,(p-buf)/2);
x += XTextWidth16(font2,(XChar2b *)buf,(p-buf)/2);
} else {
XDrawString(dpy,win,gc1,x,y,buf,p-buf);
x += XTextWidth(font1,buf,p-buf);
}
p=buf;
}
return(x);
}
|
| diff -c x2.c x3.c |
*** x2.c Mon May 22 19:51:41 2006
--- x3.c Mon May 22 19:53:11 2006
***************
*** 8,13 ****
--- 8,14 ----
char *s="sample text";
char *s2="漢字とひらがなのテスト";
+ char *s3="漢字とASCII Characterのまざったテキスト";
char *boff(char *s) {
char *p, *q;
***************
*** 60,67 ****
switch (ev.type) {
case Expose:
XClearWindow(dpy,win);
! XDrawString(dpy,win,gc,10,50,s,strlen(s));
! XDrawString16(dpy,win,gc2,10,100,(XChar2b *)s2,strlen(s2)/2);
break;
default:
printf("unknown event %d\n",ev.type);
--- 61,67 ----
switch (ev.type) {
case Expose:
XClearWindow(dpy,win);
! DrawEUC(dpy,win,gc,gc2,font,font2,10,30,s3);
break;
default:
printf("unknown event %d\n",ev.type);
|
[オプション課題4] いろいろなフォントで文字を表示させてみましょう。 とくに大きな文字でテキストを表示するとどうなるか試してみて下さい。
(例)"-misc-fixed-medium-r-normal--80-*-75-75-c-*-jisx0208.1983-0"
[オプション課題5] キー操作によって、文字が上下左右に移動するようにしてみましょう。
[提出物] 課題が完成したら、font.c をp2r8@nw.tsuda.ac.jp へ送って 下さい。 コンパイルできなかったり、きちんと動作しないものを送っても 提出とは認めないので注意して下さい。
オプション課題ができた人は、subjectを option3 または option4 として p2r8@nw.tsuda.ac.jp へ送って下さい。
上記の Email アドレス宛に送ったメイルは http://nw.tsuda.ac.jp/cgi-bin/cgiwrap/p2r8/mailhead で参照できます。Emailを送ったあとで、正しく提出されたかどうか 必ず確認しておいて下さい。
提出期限は来週木曜日の8:50a.m. です。