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