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  }