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にある。