主頁 | 自己紹介 | 日記 | 農業 | 台所 | 電算機 | | 本棚 | | Git

Xlibで遊んでみる1

はじめに

X11でGUIのプログラミングをしてみようと思い、してみた。X11用の低レベルのライブラリはXlibとxcbの二つがあるようだ。x.orgのウェブページを見てみると、Xlibは古く、xcbに置きかわりつつあるという。そのため、新しくなにかを作る場合はxcbを使うようにとのことである。ところがこのxcbはドキュメンテーションに乏しく、X11を触るのが初めての人間にはなにをどうすればいいのかほとんど分からなかった。知らない関数や構造体やらがでてきても(殆ど全部知らないものだが)、その関数なり構造体なりの説明がどこにも見当たらない。manページもない。あるのはdoxygenなるものでソースコードのコメントから自動生成したいい加減なものだけで、使いものにならない。

とりあえずX11のことを少しは理解してからでないと初められそうもないと思い、もう少しましな情報があるXlibから始めることにした。

言語はC言語である。ソースコードはここにある。

初期設定

ディスプレイを開き、ウィンドウを作成する。変数はとりあえずグローバルに宣言することにした。main関数はできるだけ小さくして実際の処理はそれぞれの関数にさせてみる:


#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>

/* macros */
#define INIT_WIDTH 800
#define INIT_HEIGHT 600

/* variables */
Display     *display;
Window       window;
unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT;
GC           gc;
Atom         wm_delete_window;

void
setup(void)
{
	// Open a display.
	if ((display = XOpenDisplay(NULL)) == NULL){
	    fprintf(stderr, "ERROR: could not open display\n");
	    exit(1);
	}
	// Create a window.
	window = XCreateSimpleWindow(
	                    display,
	                    XDefaultRootWindow(display),
	                    0, 0,
	                    win_width, win_height,
	                    0, 0, // border properties
	                    0);   // background color: black
	XStoreName(display, window, "UNKO");

	// Setup a graphical context.
	gc = XCreateGC(display, window, 0, NULL);
	XSetForeground(display, gc, 0x0000FF);

	// Kill the application when the window is destroyed.	
	wm_delete_window = XInternAtom(display,
	                               "WM_DELETE_WINDOW", False);
	XSetWMProtocols(display, window, &wm_delete_window, 1);

	// Setup which input to process.
	XSelectInput(display, window,
	             ExposureMask|KeyPressMask|KeyReleaseMask);

	// Actually draw the window.
	XMapWindow(display, window);
}

void
clean_up(void)
{
	XCloseDisplay(display);
}

適当な四角形のものを表示し、その位置を時間の関数として動かしてみる。

#include <time.h>
#include <math.h>

int
main(void)
{
    int px, py;
    int quit;
    struct timespec ts;
    XEvent event;

    setup();
    quit = 0;

    while (!quit){
        while(XPending(display) > 0){
            XNextEvent(display, &event);
            switch (event.type){
            case KeyPress: {
                switch (XLookupKeysym(&event.xkey, 0)){
                case 'q':
                    quit = 1;
                    break;
                default:
                    break;
                }
            } break;
            case ClientMessage: {
                if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
                    quit = 1;
                }
            } break;
            default:
                break;
            }
        }
        clock_gettime(CLOCK_MONOTONIC, &ts);
        px = 200 + (int) (100 * sinf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000));
        py = 200 + (int) (100 * cosf(ts.tv_sec + ts.tv_nsec / 1000.0 / 1000 / 1000));
        XClearArea(display, window,
                   0, 0,                  // position
                   win_width, win_height, // width and height
                   False);
        XFillRectangle(display, window, gc,
                       px, py,    // position
                       100, 100);   // width and height

        ts.tv_sec = 0;
        ts.tv_nsec = 10 * 1000 * 1000;
        nanosleep(&ts, NULL);
	}

	cleanup();
	return 0;
}

ここまでのコードはgitリポジトリのex1/ex1.cにある。

完成品:

参考

次の記事