= 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のデバッグ用。 {{{#!highlight c #include #include #include #include xcb_connection_t *conn; xcb_screen_t *screen; xcb_atom_t net_active_window; int main(void) { int screen_num, i; xcb_screen_iterator_t iter; conn = xcb_connect(NULL, &screen_num); iter = xcb_setup_roots_iterator(xcb_get_setup(conn)); for (i = 0; i < screen_num; ++i) xcb_screen_next(&iter); screen = iter.data; xcb_intern_atom_reply_t *r = xcb_intern_atom_reply(conn, xcb_intern_atom(conn, 0, strlen("_NET_ACTIVE_WINDOW"), "_NET_ACTIVE_WINDOW"), NULL); if (r) { net_active_window = r->atom; free(r); } else { fputs("cannot intern atom\n", stderr); exit(EXIT_FAILURE); } xcb_void_cookie_t cookie = xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK, (const uint32_t[]){ XCB_EVENT_MASK_PROPERTY_CHANGE }); xcb_flush(conn); xcb_generic_event_t *event; xcb_property_notify_event_t *e; while (event = xcb_wait_for_event(conn)) { switch (event->response_type & 0x7f) { case XCB_PROPERTY_NOTIFY: e = (xcb_property_notify_event_t *)event; if ((e->atom == net_active_window) && (e->state == XCB_PROPERTY_NEW_VALUE)) { xcb_get_property_reply_t *r = xcb_get_property_reply(conn, xcb_get_property(conn, 0, screen->root, net_active_window, XCB_ATOM_WINDOW, 0, 1), NULL); if (r) { xcb_window_t *win = xcb_get_property_value(r); printf("%x\n", *win); free(r); } } break; } free(event); } xcb_disconnect(conn); return 0; } }}} この程度のツールなら、Cで書かずにpythonとかでさくっと作ってしまうのが良いだろう…と書いた後に思う。 == 03/21 == === 居るだけのウィンドウマネージャ === * 機能: ルートウィンドウに居座って他のウィンドウマネージャを起動不能にする。他は無いのと同じ * ほとんど意味はないが、ウィンドウマネージャが何をしているかという意味では有用かも? {{{#!highlight c #include #include #include #include #include void configure_window(xcb_connection_t *conn, xcb_configure_request_event_t *e) { uint32_t values[7]; int i = 0; if (e->value_mask & XCB_CONFIG_WINDOW_X) values[i++] = e->x; if (e->value_mask & XCB_CONFIG_WINDOW_Y) values[i++] = e->y; if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) values[i++] = e->width; if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) values[i++] = e->height; if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH) values[i++] = e->border_width; if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) values[i++] = e->sibling; if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) values[i++] = e->stack_mode; xcb_configure_window(conn, e->window, e->value_mask, values); xcb_flush(conn); } int main(void) { int screen_num; xcb_connection_t *conn = xcb_connect(NULL, &screen_num); xcb_screen_t *screen = xcb_aux_get_screen(conn, screen_num); xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK, &(const uint32_t){ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT }); xcb_flush(conn); xcb_generic_event_t *event; while ((event = xcb_wait_for_event(conn))) { if (event->response_type == 0) { xcb_generic_error_t *e = (xcb_generic_error_t *)event; fprintf(stderr, "X protocol error: request=%s, error=%s\n", xcb_event_get_request_label(e->major_code), xcb_event_get_error_label(e->error_code)); exit(EXIT_FAILURE); } else { switch (event->response_type & 0x7f) { case XCB_MAP_REQUEST: puts("MapRequest"); xcb_map_window(conn, ((xcb_map_request_event_t *)event)->window); xcb_flush(conn); break; case XCB_CONFIGURE_REQUEST: puts("ConfigureRequest"); configure_window(conn, (void *)event); break; } } free(event); } xcb_disconnect(conn); return 0; } }}} * ウィンドウマネージャはMapRequest(ウィンドウの表示要求)とConfigureRequest(座標とかサイズの変更要求)をインターセプトする * ルートウィンドウのSubstructureRedirectMaskというイベントマスクを立てると上の2つがリダイレクトされてくるようになる。このマスクは同時に1つのクライアントしか立てられない=複数のウィンドウマネージャを起動することはできない * 普通のウィンドウマネージャはイベントがリダイレクトされてきた段階で色々するが、ここでは要求通りに右から左へ流している=表面上居ないのと同じ == 03/26 == === 画面のロック(gnome-screensaverで) === あらかじめgnome-screensaverを上げておく。 {{{ # .xinitrcとか.xsessionとかで gnome-screensaver & }}} ロックしたくなったら {{{ gnome-screensaver-command -l }}}