2013/03
- いつのまにやら3月
03/01
XCBを使ったWMを書き始めて3ヶ月くらいになるが、ようやくXCBが分かってきた。
- 結局のところXプロトコルをしゃべるための薄いラッパーで、リクエストとリプライを投げつけ合うための道具
- 分からない時期に見てもさっぱり分からないが、しばらく触って分かるようになるとすごく明瞭
- ドキュメンテーションの整備が進まないのがよく分かる
- ほぼプロトコルとの一対一対応で、XCB特有の部分というのはほとんどない
- ライブラリの大部分が仕様から自動生成されているだけあって、インターフェースの一貫性が非常に高い
- 超がつくレベルのパターンゲー
- ある程度Xlibを知っていれば移行は難しくない
- XlibだろうがXCBだろうが、数多くの規約を知らなければならないのは変わらない
- GUIプログラミングで苦労するのはむしろこちら
この手の「分かる人には説明するまでもないんだけど、分からない人にはさっぱり」という類のものは敷居が高くなりがちなので、チュートリアルが大事だと思う。XCBに関して言えば、公式にチュートリアルがあるもののXlibを知っている人向けに書かれている感じが強い(そもそもWMでも書かない限りはXCBなんかよりGTKなりQtを使うべきなので、それでも問題はないのかもしれないが)。
03/07
_NET_ACTIVE_WINDOWの追跡
EWMHにおいて現在アクティブなウィンドウを表す_NET_ACTIVE_WINDOWの変化を監視する。WMのデバッグ用。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <xcb/xcb.h>
5
6 xcb_connection_t *conn;
7 xcb_screen_t *screen;
8 xcb_atom_t net_active_window;
9
10 int main(void)
11 {
12 int screen_num, i;
13 xcb_screen_iterator_t iter;
14
15 conn = xcb_connect(NULL, &screen_num);
16
17 iter = xcb_setup_roots_iterator(xcb_get_setup(conn));
18 for (i = 0; i < screen_num; ++i)
19 xcb_screen_next(&iter);
20 screen = iter.data;
21
22 xcb_intern_atom_reply_t *r = xcb_intern_atom_reply(conn,
23 xcb_intern_atom(conn, 0, strlen("_NET_ACTIVE_WINDOW"), "_NET_ACTIVE_WINDOW"),
24 NULL);
25 if (r) {
26 net_active_window = r->atom;
27 free(r);
28 } else {
29 fputs("cannot intern atom\n", stderr);
30 exit(EXIT_FAILURE);
31 }
32
33 xcb_void_cookie_t cookie = xcb_change_window_attributes(conn, screen->root,
34 XCB_CW_EVENT_MASK, (const uint32_t[]){ XCB_EVENT_MASK_PROPERTY_CHANGE });
35 xcb_flush(conn);
36
37 xcb_generic_event_t *event;
38 xcb_property_notify_event_t *e;
39 while (event = xcb_wait_for_event(conn)) {
40 switch (event->response_type & 0x7f) {
41 case XCB_PROPERTY_NOTIFY:
42 e = (xcb_property_notify_event_t *)event;
43 if ((e->atom == net_active_window) && (e->state == XCB_PROPERTY_NEW_VALUE)) {
44 xcb_get_property_reply_t *r = xcb_get_property_reply(conn,
45 xcb_get_property(conn, 0, screen->root, net_active_window, XCB_ATOM_WINDOW, 0, 1),
46 NULL);
47 if (r) {
48 xcb_window_t *win = xcb_get_property_value(r);
49 printf("%x\n", *win);
50 free(r);
51 }
52 }
53 break;
54 }
55 free(event);
56 }
57 xcb_disconnect(conn);
58 return 0;
59 }
この程度のツールなら、Cで書かずにpythonとかでさくっと作ってしまうのが良いだろう…と書いた後に思う。
03/21
居るだけのウィンドウマネージャ
- 機能: ルートウィンドウに居座って他のウィンドウマネージャを起動不能にする。他は無いのと同じ
- ほとんど意味はないが、ウィンドウマネージャが何をしているかという意味では有用かも?
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <xcb/xcb.h>
4 #include <xcb/xcb_aux.h>
5 #include <xcb/xcb_event.h>
6
7 void configure_window(xcb_connection_t *conn, xcb_configure_request_event_t *e)
8 {
9 uint32_t values[7];
10 int i = 0;
11 if (e->value_mask & XCB_CONFIG_WINDOW_X)
12 values[i++] = e->x;
13 if (e->value_mask & XCB_CONFIG_WINDOW_Y)
14 values[i++] = e->y;
15 if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH)
16 values[i++] = e->width;
17 if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
18 values[i++] = e->height;
19 if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
20 values[i++] = e->border_width;
21 if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING)
22 values[i++] = e->sibling;
23 if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
24 values[i++] = e->stack_mode;
25 xcb_configure_window(conn, e->window, e->value_mask, values);
26 xcb_flush(conn);
27 }
28
29 int main(void)
30 {
31 int screen_num;
32 xcb_connection_t *conn = xcb_connect(NULL, &screen_num);
33 xcb_screen_t *screen = xcb_aux_get_screen(conn, screen_num);
34
35 xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK,
36 &(const uint32_t){ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT });
37 xcb_flush(conn);
38
39 xcb_generic_event_t *event;
40 while ((event = xcb_wait_for_event(conn))) {
41 if (event->response_type == 0) {
42 xcb_generic_error_t *e = (xcb_generic_error_t *)event;
43 fprintf(stderr, "X protocol error: request=%s, error=%s\n",
44 xcb_event_get_request_label(e->major_code),
45 xcb_event_get_error_label(e->error_code));
46 exit(EXIT_FAILURE);
47 } else {
48 switch (event->response_type & 0x7f) {
49 case XCB_MAP_REQUEST:
50 puts("MapRequest");
51 xcb_map_window(conn, ((xcb_map_request_event_t *)event)->window);
52 xcb_flush(conn);
53 break;
54 case XCB_CONFIGURE_REQUEST:
55 puts("ConfigureRequest");
56 configure_window(conn, (void *)event);
57 break;
58 }
59 }
60 free(event);
61 }
62 xcb_disconnect(conn);
63 return 0;
64 }
ウィンドウマネージャはMapRequest(ウィンドウの表示要求)とConfigureRequest(座標とかサイズの変更要求)をインターセプトする
ルートウィンドウのSubstructureRedirectMaskというイベントマスクを立てると上の2つがリダイレクトされてくるようになる。このマスクは同時に1つのクライアントしか立てられない=複数のウィンドウマネージャを起動することはできない
- 普通のウィンドウマネージャはイベントがリダイレクトされてきた段階で色々するが、ここでは要求通りに右から左へ流している=表面上居ないのと同じ