サイズ: 299
コメント:
|
サイズ: 6200
コメント:
|
削除された箇所はこのように表示されます。 | 追加された箇所はこのように表示されます。 |
行 3: | 行 3: |
* 資料: http://users.actcom.co.il/~choo/lupg/tutorials/xlib-programming/xlib-programming.html | * http://users.actcom.co.il/~choo/lupg/tutorials/xlib-programming/xlib-programming.html こんなのがあったのでざっと読んでみると、割とWindowsでAPI叩いてプログラム書くのに似ている(むしろ逆なのだろう)。GC(Graphics Context)とかハンドルとかは大体同じような理解で良さそう。 |
行 5: | 行 6: |
== 「何もしない」やつ == ウィンドウが出るだけというアレ。 |
== 「何もしない」やつを作ってみる == お約束のウィンドウが出るだけというアレをステップを追いつつ作ってみる。 === Xサーバへの接続 === 何はともあれまずXサーバに接続する。必要なのはXサーバの動いているホストのアドレスとディスプレイ番号。ちなみに最初のディスプレイは0番。この辺は普通に使ってるだけでもわかるか。 XOpenDisplay:: Xサーバと接続する {{{ Display *XOpenDisplay(char *display_name); }}} * `name`に"<address>:<displaynumber>"の形式で指定する。`NULL`だと`DISPLAY`環境変数を見に行くらしい * `Display`型のポインタが帰ってくるので、これを使ってXサーバとやりとりする。失敗すると`NULL`が来る 終了時に接続を切るときは`XCloseDisplay()`を使うらしい。これによって全てのウィンドウと確保したリソースが解放される。プログラムは終了しない。 とりあえず接続して終了するだけならこんな感じか。 {{{#!highlight c numbers=no Display *d; d = XOpenDisplay(NULL); if (!d) { fprintf(stderr, "failed to connect X server\n"); exit(1); } /* ... */ XCloseDisplay(d); }}} === ディスプレイの情報を取得してみる === ちょっと逸れて、接続したXサーバから情報を取得してみる。いろいろマクロがある。 {{{#!highlight c #include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdio.h> #include <stdlib.h> void show(Display *d) { int def_screen = DefaultScreen(d); printf("Server Vendor: %s, release %d\n", ServerVendor(d), VendorRelease(d)); printf("\tProtocol version %d, revision %d\n", ProtocolVersion(d), ProtocolRevision(d)); printf("Found %d screen\n", ScreenCount(d)); printf("Number of default screen: %d\n", def_screen); printf("Size of default screen: %dx%d\n", DisplayWidth(d, def_screen), DisplayHeight(d, def_screen)); printf("\tDepth of Root Window: %d\n", DefaultDepth(d, def_screen)); } int main(void) { Display *d; d = XOpenDisplay(NULL); if (!d) { fprintf(stderr, "failed to connect X server\n"); exit(1); } else { show(d); } XCloseDisplay(d); return 0; } }}} 試しに手元で実行。 {{{ Server Vendor: The X.Org Foundation, release 10707000 Protocol version 11, revision 0 Found 1 screen Number of default screen: 0 Size of default screen: 1920x1080 Depth of Root Window: 24 }}} === ウィンドウの生成 === Windowsだとウィンドウクラスを登録して`CreateWindow(Ex)`して…となるが、Xlibの場合`XCreateSimpleWindow()`というのがあった。 {{{ w = XCreateSimpleWindow( d, DefaultRootWindow(d), 0, 0, 400, 300, 1, BlackPixel(d, 0), WhitePixel(d, 0)); }}} 生成したウィンドウを表示する。 {{{ XMapWindow(d, w); }}} === イベントの処理 === まずどんな種類のイベントを受け取るかのマスクを指定する。とりあえず、ウィンドウの破棄(`DestroyNotify`)を受け取りたいので、`StructureNotifyMask`を立てておく。 {{{ XSelectInput(d, w, StructureNotifyMask); }}} 続いてイベントループに入る。Windowsだと`GetMessage()`やら`PeekMessage()`を使ったお決まりのパターンがあるけれど、Xlibでは`XNextEvent()`というのがあるらしい。イベントループの部分は関数に追い出してみることにする。 {{{#!highlight c void event_loop(void) { XEvent event; for (;;) { XNextEvent(d, &event); switch (event.type) { case DestroyNotify: return; } } } }}} 大体揃ったのでこれまでのコードをまとめる。 {{{#!highlight c #include <X11/Xlib.h> #include <X11/Xutil.h> #include <stdio.h> #include <stdlib.h> void event_loop(void); Display *d; Window w; int main(int argc, char **argv) { d = XOpenDisplay(NULL); if (!d) { fprintf(stderr, "failed to open display\n"); exit(1); } w = XCreateSimpleWindow( d, DefaultRootWindow(d), 0, 0, 400, 300, 1, BlackPixel(d, 0), WhitePixel(d, 0)); XMapWindow(d, w); XSelectInput(d, w, StructureNotifyMask); event_loop(); XCloseDisplay(d); return 0; } void event_loop(void) { XEvent event; for (;;) { XNextEvent(d, &event); switch (event.type) { case DestroyNotify: return; } } } }}} == ウィンドウマネージャとやりとりする == 上記のプログラムをコンパイルすると動くことは動くのだが、いくつか問題が発生する。 === ウィンドウを閉じるとき === クライアント側で特に終了動作を規定していない(例えば、クリックされたら終了、とか)ので、ウィンドウマネージャから閉じてやるなり`xkill`を使うなりしてウィンドウを閉じてやる必要がある。しかし、実際にそうすると {{{ XIO: fatal IO error 35 (Resource temporarily unavailable) on X server ":0.0" after 16 requests (16 known processed) with 0 events remaining. }}} きゃー。調べてみると、どうやらウィンドウを閉じようとしている際の通知(`WM_DELETE_WINDOW`)はウィンドウマネージャからやってくるらしく、それを受け取らないとこうなるらしい。 * http://stackoverflow.com/questions/1157364/intercept-wm-delete-window-on-x11 * http://www.lemoda.net/c/xlib-wmclose/ |
Xクライアントの作成
しばらくXクライアントを作って感覚をつかんでみる。
こんなのがあったのでざっと読んでみると、割とWindowsでAPI叩いてプログラム書くのに似ている(むしろ逆なのだろう)。GC(Graphics Context)とかハンドルとかは大体同じような理解で良さそう。
「何もしない」やつを作ってみる
お約束のウィンドウが出るだけというアレをステップを追いつつ作ってみる。
Xサーバへの接続
何はともあれまずXサーバに接続する。必要なのはXサーバの動いているホストのアドレスとディスプレイ番号。ちなみに最初のディスプレイは0番。この辺は普通に使ってるだけでもわかるか。
- XOpenDisplay
- Xサーバと接続する
Display *XOpenDisplay(char *display_name);
nameに"<address>:<displaynumber>"の形式で指定する。NULLだとDISPLAY環境変数を見に行くらしい
Display型のポインタが帰ってくるので、これを使ってXサーバとやりとりする。失敗するとNULLが来る
終了時に接続を切るときはXCloseDisplay()を使うらしい。これによって全てのウィンドウと確保したリソースが解放される。プログラムは終了しない。
とりあえず接続して終了するだけならこんな感じか。
Display *d;
d = XOpenDisplay(NULL);
if (!d) {
fprintf(stderr, "failed to connect X server\n");
exit(1);
}
/* ... */
XCloseDisplay(d);
ディスプレイの情報を取得してみる
ちょっと逸れて、接続したXサーバから情報を取得してみる。いろいろマクロがある。
1 #include <X11/Xlib.h>
2 #include <X11/Xutil.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 void show(Display *d)
7 {
8 int def_screen = DefaultScreen(d);
9
10 printf("Server Vendor: %s, release %d\n", ServerVendor(d), VendorRelease(d));
11 printf("\tProtocol version %d, revision %d\n", ProtocolVersion(d), ProtocolRevision(d));
12 printf("Found %d screen\n", ScreenCount(d));
13 printf("Number of default screen: %d\n", def_screen);
14 printf("Size of default screen: %dx%d\n", DisplayWidth(d, def_screen), DisplayHeight(d, def_screen));
15 printf("\tDepth of Root Window: %d\n", DefaultDepth(d, def_screen));
16 }
17
18 int main(void)
19 {
20 Display *d;
21
22 d = XOpenDisplay(NULL);
23 if (!d) {
24 fprintf(stderr, "failed to connect X server\n");
25 exit(1);
26 } else {
27 show(d);
28 }
29
30 XCloseDisplay(d);
31
32 return 0;
33 }
試しに手元で実行。
Server Vendor: The X.Org Foundation, release 10707000 Protocol version 11, revision 0 Found 1 screen Number of default screen: 0 Size of default screen: 1920x1080 Depth of Root Window: 24
ウィンドウの生成
Windowsだとウィンドウクラスを登録してCreateWindow(Ex)して…となるが、Xlibの場合XCreateSimpleWindow()というのがあった。
w = XCreateSimpleWindow( d, DefaultRootWindow(d), 0, 0, 400, 300, 1, BlackPixel(d, 0), WhitePixel(d, 0));
生成したウィンドウを表示する。
XMapWindow(d, w);
イベントの処理
まずどんな種類のイベントを受け取るかのマスクを指定する。とりあえず、ウィンドウの破棄(DestroyNotify)を受け取りたいので、StructureNotifyMaskを立てておく。
XSelectInput(d, w, StructureNotifyMask);
続いてイベントループに入る。WindowsだとGetMessage()やらPeekMessage()を使ったお決まりのパターンがあるけれど、XlibではXNextEvent()というのがあるらしい。イベントループの部分は関数に追い出してみることにする。
大体揃ったのでこれまでのコードをまとめる。
1 #include <X11/Xlib.h>
2 #include <X11/Xutil.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 void event_loop(void);
7
8 Display *d;
9 Window w;
10
11 int main(int argc, char **argv)
12 {
13 d = XOpenDisplay(NULL);
14 if (!d) {
15 fprintf(stderr, "failed to open display\n");
16 exit(1);
17 }
18 w = XCreateSimpleWindow(
19 d, DefaultRootWindow(d), 0, 0, 400, 300, 1,
20 BlackPixel(d, 0), WhitePixel(d, 0));
21 XMapWindow(d, w);
22
23 XSelectInput(d, w, StructureNotifyMask);
24 event_loop();
25 XCloseDisplay(d);
26
27 return 0;
28 }
29
30 void event_loop(void)
31 {
32 XEvent event;
33
34 for (;;) {
35 XNextEvent(d, &event);
36
37 switch (event.type) {
38 case DestroyNotify:
39 return;
40 }
41 }
42 }
ウィンドウマネージャとやりとりする
上記のプログラムをコンパイルすると動くことは動くのだが、いくつか問題が発生する。
ウィンドウを閉じるとき
クライアント側で特に終了動作を規定していない(例えば、クリックされたら終了、とか)ので、ウィンドウマネージャから閉じてやるなりxkillを使うなりしてウィンドウを閉じてやる必要がある。しかし、実際にそうすると
XIO: fatal IO error 35 (Resource temporarily unavailable) on X server ":0.0" after 16 requests (16 known processed) with 0 events remaining.
きゃー。調べてみると、どうやらウィンドウを閉じようとしている際の通知(WM_DELETE_WINDOW)はウィンドウマネージャからやってくるらしく、それを受け取らないとこうなるらしい。
...