xruler

a screen ruler for X11
Log | Files | Refs | LICENSE

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 }