xlib2.html (5800B)
1 <h1>Xlibで遊んでみる</h1> 2 <time>2022-12-16</time> 3 4 <h2>はじめに</h2> 5 <p>X11でGUIのプログラミングをしてみようと思い、してみた。\ 6 X11用の低レベルのライブラリはXlibとxcbの二つがあるようだ。\ 7 x.orgのウェブページを見てみると、Xlibは古く、xcbに置きかわりつつあるという。\ 8 そのため、新しくなにかを作る場合はxcbを使うようにとのことである。\ 9 ところがこのxcbはドキュメンテーションに乏しく、\ 10 X11を触るのが初めての人間にはなにをどうすればいいのかほとんど分からなかった。\ 11 知らない関数や構造体やらがでてきても(殆ど全部知らないものだが)、\ 12 その関数なり構造体なりの説明がどこにも見当たらない。\ 13 manページもない。あるのはdoxygenなるものでソースコードのコメントから\ 14 自動生成したいい加減なものだけで、使いものにならない。</p> 15 <p>とりあえずX11のことを少しは理解してからでないと初められそうもないと思い、\ 16 もう少しましな情報があるXlibから始めることにした。\ 17 </p> 18 <p>言語はC言語である。ソースコードは\ 19 <a href="https://git.mtkn.jp/xlib_playground">ここ</a>にある。 20 21 <h2>初期設定</h2> 22 <p>ディスプレイを開き、ウィンドウを作成する。\ 23 変数はとりあえずグローバルに宣言することにした。\ 24 <code>main</code>関数はできるだけ小さくして実際の処理は\ 25 それぞれの関数にさせてみる:</p> 26 <pre><code> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <X11/Xlib.h> 30 31 /* macros */ 32 #define INIT_WIDTH 800 33 #define INIT_HEIGHT 600 34 35 /* variables */ 36 Display *display; 37 Window window; 38 unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT; 39 GC gc; 40 Atom wm_delete_window; 41 42 void 43 setup(void) 44 { 45 // Open a display. 46 if ((display = XOpenDisplay(NULL)) == NULL){ 47 fprintf(stderr, "ERROR: could not open display\n"); 48 exit(1); 49 } 50 // Create a window. 51 window = XCreateSimpleWindow( 52 display, 53 XDefaultRootWindow(display), 54 0, 0, 55 win_width, win_height, 56 0, 0, 57 0); 58 XStoreName(display, window, "UNKO"); 59 60 // Setup a graphical context. 61 gc = XCreateGC(display, window, 0, NULL); 62 XSetForeground(display, gc, 0xFFFFFF); 63 64 // Kill the application when the window is destroyed. 65 wm_delete_window = XInternAtom(display, 66 "WM_DELETE_WINDOW", False); 67 XSetWMProtocols(display, window, &wm_delete_window, 1); 68 69 // Setup which input to process. 70 XSelectInput(display, window, 71 ExposureMask|KeyPressMask|KeyReleaseMask); 72 73 // Actually draw the window. 74 XMapWindow(display, window); 75 } 76 77 void 78 clean_up(void) 79 { 80 XCloseDisplay(display); 81 } 82 </code></pre> 83 84 <p>適当な四角形のものを表示し、その位置を時間の関数として動かしてみる。\ 85 </p> 86 <pre><code>#include <time.h> 87 88 int 89 main(void) 90 { 91 int px, py; 92 int quit; 93 struct timespec ts; 94 XEvent event; 95 96 setup(); 97 quit = 0; 98 99 while (!quit){ 100 while(XPending(display) > 0){ 101 XNextEvent(display, &event); 102 switch (event.type){ 103 case KeyPress: { 104 switch (XLookupKeysym(&event.xkey, 0)){ 105 case 'q': 106 quit = 1; 107 break; 108 default: 109 break; 110 } 111 } break; 112 case ClientMessage: { 113 if ((Atom) event.xclient.data.l[0] == wm_delete_window) { 114 quit = 1; 115 } 116 } break; 117 default: 118 break; 119 } 120 } 121 clock_gettime(CLOCK_MONOTONIC, &ts); 122 px = 200 + (int) (100 * sinf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000)); 123 py = 200 + (int) (100 * cosf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000)); 124 XClearArea(display, window, 125 0, 0, // position 126 win_width, win_height, // width and height 127 False); 128 XFillRectangle(display, window, gc, 129 px, py, // position 130 100, 100); // width and height 131 132 ts.tv_sec = 0; 133 ts.tv_nsec = 10 * 1000 * 1000; 134 nanosleep(&ts, NULL); 135 } 136 137 cleanup(); 138 return 0; 139 } 140 </code></pre> 141 142 <p>文字を表示。<code>XDrawString</code></p> 143 144 <h2>キーボード入力</h2> 145 <p>キーボードの入力を受け付けるようにする。\ 146 入力によって四角形の位置や速度を変化させる。</p> 147 <p>ここまでできればかなりなんでもできるようになる。</p> 148 149 <h2>FPSの固定</h2> 150 <p>前のフレームからの経過時間を計測して1/FPSを越えるまで待機させる。\ 151 このときに<code>nanosleep</code>を使うとなぜか上手くいかなかった。\ 152 OSに処理をブロックされる為か?とりあえず<code>while</code>ループの中で\ 153 ひたすら時刻を読んでいるのだが、これでいいんかな。\ 154 リソースの無駄遣いではないんかな。</p> 155 156 <h2>メニューの実装</h2> 157 <p>メニューとゲームの推移を実装した。</p> 158 159 <h2>当たり判定</h2> 160 <p>とりあえず適当に実装した。\ 161 2体間の衝突のみ判定しているので近くに別の物体がいるとめりこむ場合がある。</p> 162 </p> 163 164 165 <h2>参考</h2> 166 <ul> 167 <li><a href="https://tronche.com/gui/x/xlib/">The Xlib Manual(html conversion)</a></li> 168 <li><a href="https://www.youtube.com/watch?v=764fnfEb1_c">X11 App in C with Xlib(youtube video by tsoding)</a></li> 169 </ul>