テキストの描画
"hello, world."とか表示してみる。
GC
何かを描画するには、なにはともあれGC(Graphics Context)が必要になる。ということで作る。
- XCreateGC
- グラフィクスコンテキストを作成する
GC XCreateGC(Display *display, Drawable d, unsigned long valuemask, XGCValues *values);
Drawableとは描画対象のことで、WindowかPixmap(バックバッファみたいなやつ)
GCはたくさんの属性を持っているため、特に設定したい属性だけをvaluemaskで指定し、valuesに属性値を渡す
ということで何も考えずに作るとこんな感じ。
行番号表示/非表示切替
1 Display *d;
2 Window w;
3 GC gc = XCreateGC(d, w, 0, NULL);
破棄はXFreeGC()で行う。
文字列描画
とりあえず非マルチバイト文字のみ。一番単純なのはこれ。
- XDrawString
- 文字列を描画する
int XDrawString(Display *display, Drawable d, GC gc, int x, int y, char *string, int length);
これだけでは物足りないのでフォントを設定する。といっても難しくない。
hello, world
ということで、ウィンドウの中央に"hello, world."と表示するだけのプログラム。
行番号表示/非表示切替
1 #include <X11/Xlib.h>
2 #include <X11/Xutil.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <locale.h>
7
8 /* functions */
9 int event_loop(void);
10 GC initgc(void);
11 void draw(GC gc);
12
13 /* global variables */
14 Display *d;
15 Window w;
16 Atom wm_delete_window;
17 XFontStruct *fn;
18
19 int main(int argc, char **argv)
20 {
21 int status;
22
23 if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
24 fputs("warning: locale not supported", stderr);
25
26 d = XOpenDisplay(NULL);
27 if (!d) {
28 fprintf(stderr, "failed to open display\n");
29 exit(1);
30 }
31 w = XCreateSimpleWindow(
32 d, DefaultRootWindow(d), 0, 0, 400, 300, 1,
33 BlackPixel(d, 0), WhitePixel(d, 0));
34 XmbSetWMProperties(d, w, "文字列の描画", NULL, argv, argc, NULL, NULL, NULL);
35
36 wm_delete_window = XInternAtom(d, "WM_DELETE_WINDOW", False);
37 XSetWMProtocols(d, w, &wm_delete_window, 1);
38
39 XMapWindow(d, w);
40 XFlush(d);
41
42 XSelectInput(d, w, ExposureMask | StructureNotifyMask);
43 status = event_loop();
44 XCloseDisplay(d);
45
46 return status;
47 }
48
49 int event_loop(void)
50 {
51 XEvent event;
52 GC gc;
53
54 if (!(gc = initgc())) {
55 fputs("failed to initialize GC", stderr);
56 return 1;
57 }
58 fn = XLoadQueryFont(d, "-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-*-*");
59 if (!fn) {
60 fputs("failed to load fn", stderr);
61 } else {
62 XSetFont(d, gc, fn->fid);
63 }
64 for (;;) {
65 XNextEvent(d, &event);
66
67 switch (event.type) {
68 case Expose:
69 draw(gc);
70 break;
71
72 case ClientMessage:
73 if ((Atom)event.xclient.data.l[0] == wm_delete_window)
74 XDestroyWindow(d, w);
75 break;
76
77 case DestroyNotify:
78 return 0;
79 }
80 }
81 XFreeGC(d, gc);
82 XFreeFont(d, fn);
83 }
84
85 GC initgc(void)
86 {
87 GC gc = XCreateGC(d, w, 0, NULL);
88 return gc;
89 }
90
91 void draw(GC gc)
92 {
93 char *text = "hello, world.";
94 int len = strlen(text);
95 XWindowAttributes att;
96 int t_width, t_height;
97 int x, y;
98
99 XGetWindowAttributes(d, w, &att);
100 t_width = XTextWidth(fn, text, len);
101 t_height = fn->ascent + fn->descent;
102
103 x = (att.width - t_width) / 2;
104 y = (att.height - t_height) / 2;
105
106 XDrawString(d, w, gc, x, y, text, len);
107 }
問題点
- 実はy方向が微妙に中央にならない
- イベント処理の構造をもう少し考えておいた方が、多分後々になって幸せになれる
- フォントはGC作成時に指定してしまって構わないだろう
- マルチバイト文字は表示できない
フォントセットを使い、Xmb*系関数で描画する必要がある
- アンチエイリアスやスケーラブルフォントを使いたければXftを使う必要がある