/* * Attempt to implement picture viewer XCB with kbd and pointer grabbing, fullscreen * * Author: Peter Wu * Date: 2012-09-24 * gcc -o xcbviewfs xcbviewfs.c -lxcb-image -lxcb-shm -lxcb */ #include //#include #include #include #include #include #define die(msg) do { \ fprintf(stderr, msg); \ exit(EXIT_FAILURE); \ } while (0) #define bail(lbl, msg) do { \ fprintf(stderr, msg); \ goto lbl; \ } while (0) static const char empty_cursor_data[32]; int main(int argc, char **argv) { xcb_connection_t *c; xcb_screen_t *screen; xcb_window_t win; xcb_cursor_t cursor; if (argc < 2) { fprintf(stderr, "Usage: %s filename\n", *argv); return 1; } c = xcb_connect(NULL, NULL); if (!c) { fprintf(stderr, "Cannot open display\n"); return 1; } screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; win = xcb_generate_id(c); /* For each mask, need to add valwin item in order as defined by the * enum, see See http://xcb.freedesktop.org/tutorial/events/ */ uint32_t mask = XCB_CW_EVENT_MASK; uint32_t valwin[] = { XCB_EVENT_MASK_KEY_PRESS, }; xcb_create_window(c, 0, win, /* conn, depth, WinID */ screen->root, /* parent */ 0, 0, /* x y */ 100, 100, /* width height */ 0, /* border_width */ XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ screen->root_visual, mask, valwin); xcb_map_window(c, win); xcb_flush(c); /* options */ int grab_pointer = 0; int hide_cursor = 0; int grab_kbd = 0; int fullscreen = 0; grab_kbd = !(fullscreen = grab_pointer = hide_cursor = 0 ); if (grab_pointer) { xcb_grab_pointer_cookie_t cookie; xcb_grab_pointer_reply_t *reply; cookie = xcb_grab_pointer(c, 1, screen->root, XCB_NONE, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME); if (!(reply = xcb_grab_pointer_reply(c, cookie, NULL))) { bail(disconnect, "No pointer grab reply\n"); } if (reply->status != XCB_GRAB_STATUS_SUCCESS) { bail(disconnect, "Grab pointer FAILED\n"); } free(reply); } if (hide_cursor) { xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(c, win, empty_cursor_data, 16, 16, 1, 0, 0, 0); xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(c, win, empty_cursor_data, 16, 16, 1, 0, 0, 0); cursor = xcb_generate_id(c); xcb_create_cursor(c, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); xcb_free_pixmap(c, cp); xcb_free_pixmap(c, mp); xcb_change_window_attributes(c, win, XCB_CW_CURSOR, &cursor); xcb_free_cursor(c, cursor); xcb_flush(c); } if (grab_kbd) { xcb_grab_keyboard_cookie_t cookie; xcb_grab_keyboard_reply_t *reply; cookie = xcb_grab_keyboard(c, 1, screen->root, XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); if (!(reply = xcb_grab_keyboard_reply(c, cookie, NULL))) { bail(ungrab_pointer, "No kbd grab reply\n"); } if (reply->status != XCB_GRAB_STATUS_SUCCESS) { bail(ungrab_pointer, "Grab kbd FAILED\n"); } free(reply); } if (fullscreen) { xcb_intern_atom_cookie_t cookie; xcb_intern_atom_reply_t *reply; xcb_atom_t property, data; cookie = xcb_intern_atom(c, 0, 13, "_NET_WM_STATE"); if (!(reply = xcb_intern_atom_reply(c, cookie, 0))) { bail(ungrab_kbd, "Failed to get _NET_WM_STATE atom\n"); } property = reply->atom; free(reply); cookie = xcb_intern_atom(c, 0, 24, "_NET_WM_STATE_FULLSCREEN"); if (!(reply = xcb_intern_atom_reply(c, cookie, 0))) { bail(ungrab_kbd, "Failed to get _NET_WM_STATE_FULLSCREEN atom\n"); } data = reply->atom; free(reply); xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property, XCB_ATOM_ATOM, 32, 1, &data); xcb_flush(c); } xcb_generic_event_t *e; int running = 1; while (running && (e = xcb_wait_for_event(c))) { switch (e->response_type) { case XCB_KEY_PRESS: ; xcb_button_press_event_t *press = (xcb_button_press_event_t *)e; xcb_keycode_t key = press->detail; if (key == 9 /* ESC */) running = 0; break; } free(e); } ungrab_kbd: xcb_ungrab_keyboard(c, XCB_CURRENT_TIME); ungrab_pointer: xcb_ungrab_pointer(c, XCB_CURRENT_TIME); disconnect: xcb_disconnect(c); return 0; }