#include #include #include #include #include #include const int ESC_BUTTON = 9; typedef struct xhorse_position { int32_t x, y; } xhorse_position_t; typedef struct xhorse_size { int32_t w, h; } xhorse_size_t; typedef struct xhorse { xcb_connection_t *conn; xcb_screen_t *scr; xcb_window_t win; xhorse_position_t p_root, p_win; xhorse_size_t s_win; bool f_running, f_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_update_window_state(xhorse_t *xh) { xcb_translate_coordinates_cookie_t coords_c; xcb_get_geometry_cookie_t geom_c; xcb_translate_coordinates_reply_t *coords_r; xcb_get_geometry_reply_t *geom_r; coords_c = xcb_translate_coordinates(xh->conn, xh->win, xh->scr->root, 0, 0); coords_r = xcb_translate_coordinates_reply(xh->conn, coords_c, NULL); geom_c = xcb_get_geometry(xh->conn, xh->win); geom_r = xcb_get_geometry_reply(xh->conn, geom_c, NULL); if (NULL != coords_r) { xh->p_win.x = coords_r->dst_x; xh->p_win.y = coords_r->dst_y; free(coords_r); } if (NULL != geom_r) { xh->s_win.w = geom_r->width; xh->s_win.h = geom_r->height; free(geom_r); } } 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); 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); xh->f_running = true; xh_update_window_state(xh); } void xh_handle_btn_press(xhorse_t *xh, xcb_generic_event_t *ev) { xh_update_window_state(xh); if (false == xh->f_dragging) xh->f_dragging = true; xcb_key_press_event_t *kp_ev = (xcb_key_press_event_t *)ev; xh->p_root.x = kp_ev->root_x; xh->p_root.y = kp_ev->root_y; } void xh_handle_btn_release(xhorse_t *xh, xcb_generic_event_t *ev) { if (true == xh->f_dragging) xh->f_dragging = false; } void xh_handle_key_press(xhorse_t *xh, xcb_generic_event_t *ev) { xcb_keycode_t btn = ((xcb_key_press_event_t *)ev)->detail; if (ESC_BUTTON == btn) xh->f_running = false; } void xh_handle_motion(xhorse_t *xh, xcb_generic_event_t *generic_ev) { if (!xh->f_dragging) return; xcb_motion_notify_event_t *motion_ev = (xcb_motion_notify_event_t *)generic_ev; int32_t pos[2] = { xh->p_win.x + (motion_ev->root_x - xh->p_root.x), xh->p_win.y + (motion_ev->root_y - xh->p_root.y) }; xcb_configure_window(xh->conn, xh->win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, pos); xcb_flush(xh->conn); } void xh_poll_for_events(xhorse_t *xh) { xcb_generic_event_t *ev; while (NULL != (ev = xcb_poll_for_event(xh->conn))) { switch (ev->response_type & ~0x80) { case XCB_BUTTON_PRESS: xh_handle_btn_press(xh, ev); break; case XCB_BUTTON_RELEASE: xh_handle_btn_release(xh, ev); break; case XCB_KEY_PRESS: xh_handle_key_press(xh, ev); break; case XCB_MOTION_NOTIFY: xh_handle_motion(xh, ev); break; } free(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); while (xh->f_running) { xh_poll_for_events(xh); // xh_gravity_step(xh) } xh_disconnect(xh); free(xh); return EXIT_SUCCESS; }