GUI 程式皆為事件驅動。XCB 透過 xcb_wait_for_event() 從 X Server 取得事件,在迴圈中依類型分派處理。
#include <stdlib.h> #include <stdio.h> #include <inttypes.h> #include <xcb/xcb.h>
void print_modifiers(uint32_t mask) {
const char *MODS[] = {"Shift","Lock","Ctrl","Alt","Mod2","Mod3","Mod4","Mod5",
"Button1","Button2","Button3","Button4","Button5"};
printf("Modifier mask: ");
for (const char **m = MODS; mask; mask >>= 1, ++m)
if (mask & 1) printf("%s ", *m);
printf("\n");
}
int main() {
xcb_connection_t *conn = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
xcb_window_t win = xcb_generate_id(conn);
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t vals[2] = {screen->white_pixel,
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE};
xcb_create_window(conn, 0, win, screen->root, 0, 0, 600, 400, 10,
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, vals);
xcb_map_window(conn, win); xcb_flush(conn);
xcb_generic_event_t *ev;
while ((ev = xcb_wait_for_event(conn))) {
switch (ev->response_type & ~0x80) {
case XCB_EXPOSE: {
xcb_expose_event_t *ex = (xcb_expose_event_t*)ev;
printf("Window %u exposed. Redraw at (%u,%u) size (%u,%u)\n",
ex->window, ex->x, ex->y, ex->width, ex->height);
break;
}
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *bp = (xcb_button_press_event_t*)ev;
print_modifiers(bp->state);
switch (bp->detail) {
case 4: printf("Wheel Up in win %u at (%d,%d)\n", bp->event, bp->event_x, bp->event_y); break;
case 5: printf("Wheel Down in win %u at (%d,%d)\n", bp->event, bp->event_x, bp->event_y); break;
default: printf("Button %u pressed in win %u at (%d,%d)\n", bp->detail, bp->event, bp->event_x, bp->event_y);
}
break;
}
case XCB_BUTTON_RELEASE: {
xcb_button_release_event_t *br = (xcb_button_release_event_t*)ev;
print_modifiers(br->state);
printf("Button %u released in win %u at (%d,%d)\n", br->detail, br->event, br->event_x, br->event_y);
break;
}
case XCB_MOTION_NOTIFY: {
xcb_motion_notify_event_t *mv = (xcb_motion_notify_event_t*)ev;
printf("Mouse moved in win %u at (%d,%d)\n", mv->event, mv->event_x, mv->event_y);
break;
}
case XCB_ENTER_NOTIFY: {
xcb_enter_notify_event_t *en = (xcb_enter_notify_event_t*)ev;
printf("Mouse entered win %u at (%d,%d)\n", en->event, en->event_x, en->event_y);
break;
}
case XCB_LEAVE_NOTIFY: {
xcb_leave_notify_event_t *lv = (xcb_leave_notify_event_t*)ev;
printf("Mouse left win %u at (%d,%d)\n", lv->event, lv->event_x, lv->event_y);
break;
}
case XCB_KEY_PRESS: {
xcb_key_press_event_t *kp = (xcb_key_press_event_t*)ev;
print_modifiers(kp->state);
printf("Key pressed in win %u\n", kp->event); break;
}
case XCB_KEY_RELEASE: {
xcb_key_release_event_t *kr = (xcb_key_release_event_t*)ev;
print_modifiers(kr->state);
printf("Key released in win %u\n", kr->event);
if (kr->detail == 9) { free(ev); xcb_disconnect(conn); return 0; } // ESC
break;
}
default: printf("Unknown event: %u\n", ev->response_type);
}
free(ev);
}
return 0;
}

mask = XCB_CW_EVENT_MASK,values 填入關心的事件位元組合(XCB_EVENT_MASK_*)。
所有事件固定 32 bytes,第一 byte 為 response_type。用 xcb_generic_event_t* 接收,再依類型強轉具體結構(如 xcb_button_press_event_t*)。
response_type & ~0x80 目的SendEvent 發送的合成事件。
核心協定定義 33 種事件,Vim Ctrl+] 可跳轉查看各結構定義。