www.mtkn.jp

Manuscripts for my personal webpage.
git clone https://git.mtkn.jp/www.mtkn.jp
Log | Files | Refs | LICENSE

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 &lt;stdio.h&gt;
     28 #include &lt;stdlib.h&gt;
     29 #include &lt;X11/Xlib.h&gt;
     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 &lt;time.h&gt;
     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>