modernc.org/99c@v1.0.1-0.20181109153923-a9e8197063d9/examples/xcb/mousecursorexample.c (about) 1 // 99c mousecursorexample.c -lxcb && ./a.out 2 3 // +build ignore 4 5 // src: https://www.x.org/releases/current/doc/libxcb/tutorial/index.html#mousecursorexample 6 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <xcb/xcb.h> 12 13 #define WIDTH 300 14 #define HEIGHT 150 15 16 static xcb_gc_t gc_font_get(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, const char *font_name); 17 18 static void button_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label); 19 20 static void text_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label); 21 22 static void cursor_set(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int cursor_id); 23 24 static void button_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label) 25 { 26 xcb_point_t points[5]; 27 xcb_void_cookie_t cookie_gc; 28 xcb_void_cookie_t cookie_line; 29 xcb_void_cookie_t cookie_text; 30 xcb_generic_error_t *error; 31 xcb_gcontext_t gc; 32 int16_t width; 33 int16_t height; 34 uint8_t length; 35 int16_t inset; 36 37 length = strlen(label); 38 inset = 2; 39 40 gc = gc_font_get(c, screen, window, "7x13"); 41 42 width = 7 * length + 2 * (inset + 1); 43 height = 13 + 2 * (inset + 1); 44 points[0].x = x1; 45 points[0].y = y1; 46 points[1].x = x1 + width; 47 points[1].y = y1; 48 points[2].x = x1 + width; 49 points[2].y = y1 - height; 50 points[3].x = x1; 51 points[3].y = y1 - height; 52 points[4].x = x1; 53 points[4].y = y1; 54 cookie_line = xcb_poly_line_checked(c, XCB_COORD_MODE_ORIGIN, window, gc, 5, points); 55 56 error = xcb_request_check(c, cookie_line); 57 if (error) { 58 fprintf(stderr, "ERROR: can't draw lines : %d\n", error->error_code); 59 xcb_disconnect(c); 60 exit(-1); 61 } 62 63 cookie_text = xcb_image_text_8_checked(c, length, window, gc, x1 + inset + 1, y1 - inset - 1, label); 64 error = xcb_request_check(c, cookie_text); 65 if (error) { 66 fprintf(stderr, "ERROR: can't paste text : %d\n", error->error_code); 67 xcb_disconnect(c); 68 exit(-1); 69 } 70 71 cookie_gc = xcb_free_gc(c, gc); 72 error = xcb_request_check(c, cookie_gc); 73 if (error) { 74 fprintf(stderr, "ERROR: can't free gc : %d\n", error->error_code); 75 xcb_disconnect(c); 76 exit(-1); 77 } 78 } 79 80 static void text_draw(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label) 81 { 82 xcb_void_cookie_t cookie_gc; 83 xcb_void_cookie_t cookie_text; 84 xcb_generic_error_t *error; 85 xcb_gcontext_t gc; 86 uint8_t length; 87 88 length = strlen(label); 89 90 gc = gc_font_get(c, screen, window, "7x13"); 91 92 cookie_text = xcb_image_text_8_checked(c, length, window, gc, x1, y1, label); 93 error = xcb_request_check(c, cookie_text); 94 if (error) { 95 fprintf(stderr, "ERROR: can't paste text : %d\n", error->error_code); 96 xcb_disconnect(c); 97 exit(-1); 98 } 99 100 cookie_gc = xcb_free_gc(c, gc); 101 error = xcb_request_check(c, cookie_gc); 102 if (error) { 103 fprintf(stderr, "ERROR: can't free gc : %d\n", error->error_code); 104 xcb_disconnect(c); 105 exit(-1); 106 } 107 } 108 109 static xcb_gc_t gc_font_get(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, const char *font_name) 110 { 111 uint32_t value_list[3]; 112 xcb_void_cookie_t cookie_font; 113 xcb_void_cookie_t cookie_gc; 114 xcb_generic_error_t *error; 115 xcb_font_t font; 116 xcb_gcontext_t gc; 117 uint32_t mask; 118 119 font = xcb_generate_id(c); 120 cookie_font = xcb_open_font_checked(c, font, strlen(font_name), font_name); 121 122 error = xcb_request_check(c, cookie_font); 123 if (error) { 124 fprintf(stderr, "ERROR: can't open font : %d\n", error->error_code); 125 xcb_disconnect(c); 126 return -1; 127 } 128 129 gc = xcb_generate_id(c); 130 mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; 131 value_list[0] = screen->black_pixel; 132 value_list[1] = screen->white_pixel; 133 value_list[2] = font; 134 cookie_gc = xcb_create_gc_checked(c, gc, window, mask, value_list); 135 error = xcb_request_check(c, cookie_gc); 136 if (error) { 137 fprintf(stderr, "ERROR: can't create gc : %d\n", error->error_code); 138 xcb_disconnect(c); 139 exit(-1); 140 } 141 142 cookie_font = xcb_close_font_checked(c, font); 143 error = xcb_request_check(c, cookie_font); 144 if (error) { 145 fprintf(stderr, "ERROR: can't close font : %d\n", error->error_code); 146 xcb_disconnect(c); 147 exit(-1); 148 } 149 150 return gc; 151 } 152 153 static void cursor_set(xcb_connection_t * c, xcb_screen_t * screen, xcb_window_t window, int cursor_id) 154 { 155 uint32_t values_list[3]; 156 xcb_void_cookie_t cookie_font; 157 xcb_void_cookie_t cookie_gc; 158 xcb_generic_error_t *error; 159 xcb_font_t font; 160 xcb_cursor_t cursor; 161 xcb_gcontext_t gc; 162 uint32_t mask; 163 uint32_t value_list; 164 165 font = xcb_generate_id(c); 166 cookie_font = xcb_open_font_checked(c, font, strlen("cursor"), "cursor"); 167 error = xcb_request_check(c, cookie_font); 168 if (error) { 169 fprintf(stderr, "ERROR: can't open font : %d\n", error->error_code); 170 xcb_disconnect(c); 171 exit(-1); 172 } 173 174 cursor = xcb_generate_id(c); 175 xcb_create_glyph_cursor(c, cursor, font, font, cursor_id, cursor_id + 1, 0, 0, 0, 0, 0, 0); 176 177 gc = xcb_generate_id(c); 178 mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; 179 values_list[0] = screen->black_pixel; 180 values_list[1] = screen->white_pixel; 181 values_list[2] = font; 182 cookie_gc = xcb_create_gc_checked(c, gc, window, mask, values_list); 183 error = xcb_request_check(c, cookie_gc); 184 if (error) { 185 fprintf(stderr, "ERROR: can't create gc : %d\n", error->error_code); 186 xcb_disconnect(c); 187 exit(-1); 188 } 189 190 mask = XCB_CW_CURSOR; 191 value_list = cursor; 192 xcb_change_window_attributes(c, window, mask, &value_list); 193 194 xcb_free_cursor(c, cursor); 195 196 cookie_font = xcb_close_font_checked(c, font); 197 error = xcb_request_check(c, cookie_font); 198 if (error) { 199 fprintf(stderr, "ERROR: can't close font : %d\n", error->error_code); 200 xcb_disconnect(c); 201 exit(-1); 202 } 203 } 204 205 int main() 206 { 207 xcb_screen_iterator_t screen_iter; 208 xcb_connection_t *c; 209 const xcb_setup_t *setup; 210 xcb_screen_t *screen; 211 xcb_generic_event_t *e; 212 xcb_generic_error_t *error; 213 xcb_void_cookie_t cookie_window; 214 xcb_void_cookie_t cookie_map; 215 xcb_window_t window; 216 uint32_t mask; 217 uint32_t values[2]; 218 int screen_number; 219 uint8_t is_hand = 0; 220 221 /* getting the connection */ 222 c = xcb_connect(NULL, &screen_number); 223 if (!c) { 224 fprintf(stderr, "ERROR: can't connect to an X server\n"); 225 return -1; 226 } 227 228 /* getting the current screen */ 229 setup = xcb_get_setup(c); 230 231 screen = NULL; 232 screen_iter = xcb_setup_roots_iterator(setup); 233 for (; screen_iter.rem != 0; --screen_number, xcb_screen_next(&screen_iter)) 234 if (screen_number == 0) { 235 screen = screen_iter.data; 236 break; 237 } 238 if (!screen) { 239 fprintf(stderr, "ERROR: can't get the current screen\n"); 240 xcb_disconnect(c); 241 return -1; 242 } 243 244 /* creating the window */ 245 window = xcb_generate_id(c); 246 mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 247 values[0] = screen->white_pixel; 248 values[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION; 249 cookie_window = xcb_create_window_checked(c, screen->root_depth, window, screen->root, 20, 200, WIDTH, HEIGHT, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values); 250 cookie_map = xcb_map_window_checked(c, window); 251 252 /* error managing */ 253 error = xcb_request_check(c, cookie_window); 254 if (error) { 255 fprintf(stderr, "ERROR: can't create window : %d\n", error->error_code); 256 xcb_disconnect(c); 257 return -1; 258 } 259 error = xcb_request_check(c, cookie_map); 260 if (error) { 261 fprintf(stderr, "ERROR: can't map window : %d\n", error->error_code); 262 xcb_disconnect(c); 263 return -1; 264 } 265 266 cursor_set(c, screen, window, 68); 267 268 xcb_flush(c); 269 270 while (1) { 271 e = xcb_poll_for_event(c); 272 if (e) { 273 switch (e->response_type & ~0x80) { 274 case XCB_EXPOSE:{ 275 char *text; 276 277 text = "click here to change cursor"; 278 button_draw(c, screen, window, (WIDTH - 7 * strlen(text)) / 2, (HEIGHT - 16) / 2, text); 279 280 text = "Press ESC key to exit..."; 281 text_draw(c, screen, window, 10, HEIGHT - 10, text); 282 break; 283 } 284 case XCB_BUTTON_PRESS:{ 285 xcb_button_press_event_t *ev; 286 int length; 287 288 ev = (xcb_button_press_event_t *) e; 289 length = strlen("click here to change cursor"); 290 291 if ((ev->event_x >= (WIDTH - 7 * length) / 2) && (ev->event_x <= ((WIDTH - 7 * length) / 2 + 7 * length + 6)) && (ev->event_y >= (HEIGHT - 16) / 2 - 19) && (ev->event_y <= ((HEIGHT - 16) / 2))) 292 is_hand = 1 - is_hand; 293 294 is_hand ? cursor_set(c, screen, window, 58) : cursor_set(c, screen, window, 68); 295 } 296 case XCB_KEY_RELEASE:{ 297 xcb_key_release_event_t *ev; 298 299 ev = (xcb_key_release_event_t *) e; 300 301 switch (ev->detail) { 302 /* ESC */ 303 case 9: 304 free(e); 305 xcb_disconnect(c); 306 return 0; 307 } 308 } 309 } 310 free(e); 311 } 312 } 313 314 return 0; 315 }