[Xcb] cursor example for the tutorial

Vincent Torri vtorri at univ-evry.fr
Wed Jan 24 04:59:53 PST 2007


Hey,

here is a simple cursor example that I want to add to the tutorial

Anything wrong with it ? (use of errors, better code, etc...)

thank you

Vincent

PS: there are always some reads of uninitialized mem reported by valgrind
-------------- next part --------------
/* gcc -g -Wall -o xcb_cursor xcb_cursor.c `pkg-config --cflags --libs xcb` */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <xcb/xcb.h>

#define WIDTH 300
#define HEIGHT 150



static xcb_gc_t _gc_font_get (xcb_connection_t *c,
                              xcb_screen_t     *screen,
                              xcb_window_t      window,
                              const char       *font_name);

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)
{
  xcb_point_t          points[5];
  xcb_void_cookie_t    cookie_gc;
  xcb_void_cookie_t    cookie_line;
  xcb_void_cookie_t    cookie_text;
  xcb_generic_error_t *error;
  xcb_gcontext_t       gc;
  int16_t              width;
  int16_t              height;
  uint8_t              length;
  int16_t              inset;

  length = strlen (label);
  inset = 2;

  gc = _gc_font_get(c, screen, window, "7x13");

  width = 7 * length + 2 * (inset + 1);
  height = 13 + 2 * (inset + 1);
  points[0].x = x1;
  points[0].y = y1;
  points[1].x = x1 + width;
  points[1].y = y1;
  points[2].x = x1 + width;
  points[2].y = y1 - height;
  points[3].x = x1;
  points[3].y = y1 - height;
  points[4].x = x1;
  points[4].y = y1;
  cookie_line = xcb_poly_line_checked (c, XCB_COORD_MODE_ORIGIN,
                                       window, gc, 5, points);

  error = xcb_request_check (c, cookie_line);
  if (error) {
    fprintf (stderr, "ERROR: can't draw lines : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }

  cookie_text = xcb_image_text_8_checked (c, length, window, gc,
                                          x1 + inset + 1,
                                          y1 - inset - 1, label);
  error = xcb_request_check (c, cookie_text);
  if (error) {
    fprintf (stderr, "ERROR: can't paste text : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }

  cookie_gc = xcb_free_gc (c, gc);
  error = xcb_request_check (c, cookie_gc);
  if (error) {
    fprintf (stderr, "ERROR: can't free gc : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }
}

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)
{
  xcb_void_cookie_t    cookie_gc;
  xcb_void_cookie_t    cookie_text;
  xcb_generic_error_t *error;
  xcb_gcontext_t       gc;
  uint8_t              length;

  length = strlen (label);

  gc = _gc_font_get(c, screen, window, "7x13");

  cookie_text = xcb_image_text_8_checked (c, length, window, gc,
                                          x1,
                                          y1, label);
  error = xcb_request_check (c, cookie_text);
  if (error) {
    fprintf (stderr, "ERROR: can't paste text : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }

  cookie_gc = xcb_free_gc (c, gc);
  error = xcb_request_check (c, cookie_gc);
  if (error) {
    fprintf (stderr, "ERROR: can't free gc : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }
}

static xcb_gc_t
_gc_font_get (xcb_connection_t *c,
              xcb_screen_t     *screen,
              xcb_window_t      window,
              const char       *font_name)
{
  uint32_t             value_list[3];
  xcb_void_cookie_t    cookie_font;
  xcb_void_cookie_t    cookie_gc;
  xcb_generic_error_t *error;
  xcb_font_t           font;
  xcb_gcontext_t       gc;
  uint32_t             mask;

  font = xcb_generate_id (c);
  cookie_font = xcb_open_font_checked (c, font,
                                       strlen (font_name),
                                       font_name);

  error = xcb_request_check (c, cookie_font);
  if (error) {
    fprintf (stderr, "ERROR: can't open font : %d\n", error->error_code);
    xcb_disconnect (c);
    return -1;
  }

  gc = xcb_generate_id (c);
  mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
  value_list[0] = screen->black_pixel;
  value_list[1] = screen->white_pixel;
  value_list[2] = font;
  cookie_gc = xcb_create_gc_checked (c, gc, window, mask, value_list);
  error = xcb_request_check (c, cookie_gc);
  if (error) {
    fprintf (stderr, "ERROR: can't create gc : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }

  cookie_font = xcb_close_font_checked (c, font);
  error = xcb_request_check (c, cookie_font);
  if (error) {
    fprintf (stderr, "ERROR: can't close font : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }

  return gc;
}

static void
_cursor_set (xcb_connection_t *c,
             xcb_screen_t     *screen,
             xcb_window_t      window,
             int               cursor_id)
{
  uint32_t             values_list[3];
  xcb_void_cookie_t    cookie_font;
  xcb_void_cookie_t    cookie_gc;
  xcb_generic_error_t *error;
  xcb_font_t           font;
  xcb_cursor_t         cursor;
  xcb_gcontext_t       gc;
  uint32_t             mask;
  uint32_t             value_list;

  font = xcb_generate_id (c);
  cookie_font = xcb_open_font_checked (c, font,
                                       strlen ("cursor"),
                                       "cursor");
  error = xcb_request_check (c, cookie_font);
  if (error) {
    fprintf (stderr, "ERROR: can't open font : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }

  cursor = xcb_generate_id (c);
  xcb_create_glyph_cursor (c, cursor, font, font,
                           cursor_id, cursor_id + 1,
                           0, 0, 0,
                           0, 0, 0);



  gc = xcb_generate_id (c);
  mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
  values_list[0] = screen->black_pixel;
  values_list[1] = screen->white_pixel;
  values_list[2] = font;
  cookie_gc = xcb_create_gc_checked (c, gc, window, mask, values_list);
  error = xcb_request_check (c, cookie_gc);
  if (error) {
    fprintf (stderr, "ERROR: can't create gc : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }

  mask = XCB_CW_CURSOR;
  value_list = cursor;
  xcb_change_window_attributes (c, window, mask, &value_list);

  xcb_free_cursor (c, cursor);

  cookie_font = xcb_close_font_checked (c, font);
  error = xcb_request_check (c, cookie_font);
  if (error) {
    fprintf (stderr, "ERROR: can't close font : %d\n", error->error_code);
    xcb_disconnect (c);
    exit (-1);
  }
}

int main ()
{
  xcb_screen_iterator_t screen_iter;
  xcb_connection_t     *c;
  const xcb_setup_t    *setup;
  xcb_screen_t         *screen;
  xcb_generic_event_t  *e;
  xcb_generic_error_t  *error;
  xcb_void_cookie_t     cookie_window;
  xcb_void_cookie_t     cookie_map;
  xcb_window_t          window;
  uint32_t              mask;
  uint32_t              values[2];
  int                   screen_number;
  uint8_t               is_hand = 0;

  /* getting the connection */
  c = xcb_connect (NULL, &screen_number);
  if (!c) {
    fprintf (stderr, "ERROR: can't connect to an X server\n");
    return -1;
  }

  /* getting the current screen */
  setup = xcb_get_setup (c);

  screen = NULL;
  screen_iter = xcb_setup_roots_iterator (setup);
  for (; screen_iter.rem != 0; --screen_number, xcb_screen_next (&screen_iter))
    if (screen_number == 0)
      {
        screen = screen_iter.data;
        break;
      }
  if (!screen) {
    fprintf (stderr, "ERROR: can't get the current screen\n");
    xcb_disconnect (c);
    return -1;
  }

  /* creating the window */
  window = xcb_generate_id (c);
  mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
  values[0] = screen->white_pixel;
  values[1] =
    XCB_EVENT_MASK_KEY_RELEASE |
    XCB_EVENT_MASK_BUTTON_PRESS |
    XCB_EVENT_MASK_EXPOSURE |
    XCB_EVENT_MASK_POINTER_MOTION;
  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);
  cookie_map = xcb_map_window_checked (c, window);

  /* error managing */
  error = xcb_request_check (c, cookie_window);
  if (error) {
    fprintf (stderr, "ERROR: can't create window : %d\n", error->error_code);
    xcb_disconnect (c);
    return -1;
  }
  error = xcb_request_check (c, cookie_map);
  if (error) {
    fprintf (stderr, "ERROR: can't map window : %d\n", error->error_code);
    xcb_disconnect (c);
    return -1;
  }

  _cursor_set (c, screen, window, 68);

  xcb_flush(c);

  while (1) {
    e = xcb_poll_for_event(c);
    if (e) {
      switch (e->response_type) {
      case XCB_EXPOSE: {
        char *text;

        text = "click here to change cursor";
        _button_draw (c, screen, window,
                      (WIDTH - 7*strlen(text)) / 2,
                      (HEIGHT - 16) / 2, text);

        text = "Press ESC key to exit...";
        _text_draw (c, screen, window, 10, HEIGHT - 10, text);
        break;
      }
      case XCB_BUTTON_PRESS: {
        xcb_button_press_event_t *ev;
        int                       length;

        ev = (xcb_button_press_event_t *)e;
        length = strlen ("click here to change cursor");

        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)))
          is_hand = 1 - is_hand;

        is_hand ? _cursor_set (c, screen, window, 58) : _cursor_set (c, screen, window, 68);
      }
      case XCB_KEY_RELEASE: {
        xcb_key_release_event_t *ev;

        ev = (xcb_key_release_event_t *)e;

        switch (ev->detail) {
          /* ESC */
        case 9:
          free (e);
          goto beach;
        }
      }
      }
      free (e);
    }
  }

 beach:
  xcb_disconnect (c);

  return 0;
}


More information about the Xcb mailing list