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  }