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