xruler.c (6927B)
1 /** 2 * xruler -- a screen ruler for X11 3 * Copyright 2019 Matthias Balk 4 */ 5 6 #include <stdint.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <xcb/xcb.h> 12 13 14 static uint32_t width = 1500; 15 static uint32_t height = 50; 16 17 18 static void set_crosshair_cursor( 19 xcb_connection_t *c, 20 xcb_screen_t *screen, 21 xcb_window_t window) 22 { 23 int cursor_id = 33; /* Crosshair */ 24 25 xcb_font_t font = xcb_generate_id(c); 26 xcb_void_cookie_t cookie_font = 27 xcb_open_font_checked(c, font, strlen("cursor"), "cursor"); 28 29 xcb_generic_error_t *error; 30 error = xcb_request_check(c, cookie_font); 31 if (error) { 32 fprintf(stderr, "ERROR: can't open font : %d\n", error->error_code); 33 xcb_disconnect(c); 34 exit(-1); 35 } 36 37 xcb_cursor_t cursor = xcb_generate_id(c); 38 xcb_create_glyph_cursor(c, cursor, font, font, 39 cursor_id, cursor_id + 1, 40 0, 0, 0, 41 0, 0, 0); 42 43 xcb_gcontext_t gc = xcb_generate_id(c); 44 uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; 45 uint32_t values_list[] = {screen->black_pixel, screen->white_pixel, font}; 46 xcb_void_cookie_t cookie_gc = 47 xcb_create_gc_checked(c, gc, window, mask, values_list); 48 49 error = xcb_request_check(c, cookie_gc); 50 if (error) { 51 fprintf(stderr, "ERROR: can't create gc : %d\n", error->error_code); 52 xcb_disconnect(c); 53 exit(-1); 54 } 55 56 mask = XCB_CW_CURSOR; 57 uint32_t value_list = cursor; 58 xcb_change_window_attributes(c, window, mask, &value_list); 59 60 xcb_free_cursor(c, cursor); 61 62 cookie_font = xcb_close_font_checked(c, font); 63 error = xcb_request_check(c, cookie_font); 64 if (error) { 65 fprintf(stderr, "ERROR: can't close font : %d\n", error->error_code); 66 xcb_disconnect(c); 67 exit(-1); 68 } 69 } 70 71 72 static xcb_gc_t get_gc_font( 73 xcb_connection_t *c, 74 xcb_screen_t *screen, 75 xcb_window_t window, 76 const char *font_name) 77 { 78 xcb_font_t font = xcb_generate_id(c); 79 xcb_void_cookie_t cookie_font = 80 xcb_open_font_checked(c, font, strlen(font_name), font_name); 81 82 xcb_generic_error_t *error; 83 error = xcb_request_check(c, cookie_font); 84 if (error) { 85 fprintf(stderr, "ERROR: can't open font : %d\n", error->error_code); 86 xcb_disconnect(c); 87 return -1; 88 } 89 90 xcb_gcontext_t gc = xcb_generate_id(c); 91 uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT; 92 uint32_t value_list[] = {screen->black_pixel, screen->white_pixel, font}; 93 xcb_void_cookie_t cookie_gc = 94 xcb_create_gc_checked(c, gc, window, mask, value_list); 95 96 error = xcb_request_check(c, cookie_gc); 97 if (error) { 98 fprintf(stderr, "ERROR: can't create gc : %d\n", error->error_code); 99 xcb_disconnect(c); 100 exit(-1); 101 } 102 103 cookie_font = xcb_close_font_checked(c, font); 104 error = xcb_request_check(c, cookie_font); 105 if (error) { 106 fprintf(stderr, "ERROR: can't close font : %d\n", error->error_code); 107 xcb_disconnect(c); 108 exit(-1); 109 } 110 111 return gc; 112 } 113 114 115 static void draw_text( 116 xcb_connection_t *c, 117 xcb_screen_t *screen, 118 xcb_window_t window, 119 int16_t x, 120 int16_t y, 121 const char *label) 122 { 123 xcb_gcontext_t gc = get_gc_font(c, screen, window, "8x13"); 124 xcb_void_cookie_t cookie_text = 125 xcb_image_text_8_checked(c, strlen(label), window, gc, x, y, label); 126 127 xcb_generic_error_t *error; 128 error = xcb_request_check(c, cookie_text); 129 if (error) { 130 fprintf(stderr, "ERROR: can't paste text : %d\n", error->error_code); 131 xcb_disconnect(c); 132 exit(-1); 133 } 134 135 xcb_void_cookie_t cookie_gc = xcb_free_gc(c, gc); 136 error = xcb_request_check(c, cookie_gc); 137 if (error) { 138 fprintf(stderr, "ERROR: can't free gc : %d\n", error->error_code); 139 xcb_disconnect(c); 140 exit(-1); 141 } 142 } 143 144 145 int main(int argc, char** argv) 146 { 147 /* Open the connection to the X server */ 148 xcb_connection_t* connection = xcb_connect(NULL, NULL); 149 150 151 /* Get the first screen */ 152 xcb_screen_t* screen = 153 xcb_setup_roots_iterator(xcb_get_setup(connection)).data; 154 155 156 /* Create black (foreground) graphic context */ 157 xcb_drawable_t window = screen->root; 158 xcb_gcontext_t foreground = xcb_generate_id(connection); 159 uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; 160 uint32_t values[2] = {screen->black_pixel, 0}; 161 162 xcb_create_gc(connection, foreground, window, mask, values); 163 164 165 /* Create a window */ 166 window = xcb_generate_id(connection); 167 168 mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 169 values[0] = screen->white_pixel; 170 values[1] = XCB_EVENT_MASK_EXPOSURE | 171 XCB_EVENT_MASK_KEY_PRESS | 172 XCB_EVENT_MASK_POINTER_MOTION; 173 174 xcb_create_window(connection, /* connection */ 175 XCB_COPY_FROM_PARENT, /* depth */ 176 window, /* window Id */ 177 screen->root, /* parent window */ 178 0, 0, /* x, y */ 179 width, height, /* width, height */ 180 0, /* border_width */ 181 XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ 182 screen->root_visual, /* visual */ 183 mask, values); /* masks */ 184 185 186 /* Map the window on the screen and flush*/ 187 xcb_map_window(connection, window); 188 xcb_flush(connection); 189 190 set_crosshair_cursor(connection, screen, window); 191 192 /* draw primitives */ 193 xcb_generic_event_t* event; 194 while (event = xcb_wait_for_event(connection)) { 195 switch (event->response_type & ~0x80) { 196 case XCB_EXPOSE: 197 { 198 for (int i = 1; i < 1000; i++) 199 { 200 int y = 15; 201 if (i % 50 == 0) y = 45; 202 else if (i % 10 == 0) y = 35; 203 else if (i % 5 == 0) y = 25; 204 205 xcb_point_t polyline[] = { {5*i, 0}, {0, y} }; 206 xcb_poly_line( 207 connection, XCB_COORD_MODE_PREVIOUS, window, foreground, 208 2, polyline); 209 } 210 211 /* flush the request */ 212 xcb_flush(connection); 213 214 break; 215 } 216 217 case XCB_KEY_PRESS: 218 { 219 xcb_key_press_event_t* kp = (xcb_key_press_event_t*) event; 220 221 if (kp->detail == 24 || kp->detail == 9) /* q or ESC */ 222 { 223 free(event); 224 xcb_disconnect(connection); 225 return 0; 226 } 227 } 228 229 case XCB_MOTION_NOTIFY: 230 { 231 xcb_motion_notify_event_t* motion = (xcb_motion_notify_event_t*) event; 232 char buf[16]; 233 snprintf(buf, 16, "%04d,%04d ", motion->event_x, motion->event_y); 234 draw_text(connection, screen, window, 5, height - 5, buf); 235 break; 236 } 237 238 default: 239 /* Unknown event type, ignore it */ 240 break; 241 } 242 243 free(event); 244 } 245 }