#include #include #include #include #include #include const int ESC_BUTTON = 9; typedef struct xhorse { xcb_connection_t *conn; xcb_screen_t *scr; xcb_window_t win; int16_t root_x, root_y; int16_t win_x, win_y; bool dragging; } xhorse_t; bool xh_connect(xhorse_t *xh) { xh->conn = xcb_connect(NULL, NULL); if (!xh->conn || xcb_connection_has_error(xh->conn)) { return false; } return true; } void xh_disconnect(xhorse_t *xh) { xcb_unmap_window(xh->conn, xh->win); xcb_flush(xh->conn); xcb_disconnect(xh->conn); } void xh_setup(xhorse_t *xh) { const xcb_setup_t *set = xcb_get_setup(xh->conn); xh->scr = xcb_setup_roots_iterator(set).data; uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; uint32_t vals[] = { xh->scr->white_pixel, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION }; xh->win = xcb_generate_id(xh->conn); xh->win_x = xh->win_y = 0; xcb_void_cookie_t cookie = xcb_create_window(xh->conn, /* depth */ XCB_COPY_FROM_PARENT, xh->win, xh->scr->root, /* x */ 0, /* y */ 0, /* w */ 150, /* h */ 75, /* border width*/ 10, XCB_WINDOW_CLASS_INPUT_OUTPUT, xh->scr->root_visual, mask, vals); xcb_map_window(xh->conn, xh->win); } void xh_update_current_position(xhorse_t *xh) { xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xh->conn, xh->win, xh->scr->root, 0, 0); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xh->conn, cookie, NULL); if (reply) { xh->win_x = reply->dst_x; xh->win_y = reply->dst_y; free(reply); } } void xh_handle_motion(xhorse_t *xh, xcb_generic_event_t *generic_ev) { if (!xh->dragging) return; xcb_motion_notify_event_t *motion_ev = (xcb_motion_notify_event_t *)generic_ev; int32_t pos[2] = { xh->win_x + (motion_ev->root_x - xh->root_x), xh->win_y + (motion_ev->root_y - xh->root_y) }; xcb_configure_window(xh->conn, xh->win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, pos); xcb_flush(xh->conn); } void xh_event_loop(xhorse_t *xh) { xcb_generic_event_t *generic_ev; while ((generic_ev = xcb_wait_for_event(xh->conn))) { uint8_t response_type = generic_ev->response_type & ~0x80; switch (response_type) { case XCB_EXPOSE: case XCB_BUTTON_RELEASE: xh->dragging = false; break; case XCB_KEY_PRESS: { xcb_key_press_event_t *press_ev = (xcb_key_press_event_t *)generic_ev; if (ESC_BUTTON == press_ev->detail) return; break; } case XCB_BUTTON_PRESS: { xcb_button_press_event_t *mouse_ev = (xcb_button_press_event_t *)generic_ev; xh_update_current_position(xh); xh->root_x = mouse_ev->root_x; xh->root_y = mouse_ev->root_y; xh->dragging = true; break; } case XCB_MOTION_NOTIFY: { xh_handle_motion(xh, generic_ev); break; } } free(generic_ev); } } int main(void) { xhorse_t *xh = malloc(sizeof(xhorse_t)); if (false == xh_connect(xh)) { puts("can't connect to X"); return EXIT_FAILURE; } xh_setup(xh); xcb_flush(xh->conn); xh_event_loop(xh); xh_disconnect(xh); free(xh); return EXIT_SUCCESS; }