Handling text and fonts
Besides drawing graphics on a window, we often want to draw text. Text strings have two major properties: the characters to be drawn and the font with which they are drawn. In order to draw text, we need to first request the X server to load a font. We then assign a font to a Graphic Context, and finally, we draw the text in a window, using the Graphic Context.
The Font structure
In order to support flexible fonts, a font type is defined. You know what ? It's an Id:
typedef uint32_t xcb_font_t;typedef uint32_t xcb_font_t;It is used to contain information about a font, and is passed to several functions that handle fonts selection and text drawing. We ask the X server to attribute an Id to our font with the function:
xcb_font_t xcb_generate_id (xcb_connection_t *c);xcb_font_t xcb_generate_id (xcb_connection_t *c);
Opening a Font
To open a font, we use the following function:
xcb_void_cookie_t xcb_open_font (xcb_connection_t *c, xcb_font_t fid, uint16_t name_len, const char *name);xcb_void_cookie_t xcb_open_font (xcb_connection_t *c, xcb_font_t fid, uint16_t name_len, const char *name);The
fidparameter is the font Id defined byxcb_generate_id()(see above). Thenameparameter is the name of the font you want to open. Use the commandxlsfontsin a terminal to know which are the fonts available on your computer. The parametername_lenis the length of the name of the font (given bystrlen()).Assigning a Font to a Graphic Context
Once a font is opened, you have to create a Graphic Context that will contain the informations about the color of the foreground and the background used when you draw a text in a Drawable. Here is an exemple of a Graphic Context that will allow us to draw an opened font with a black foreground and a white background:
/* * c is the connection * screen is the screen where the window is displayed * window is the window in which we will draw the text * font is the opened font */ uint32_t value_list[3]; xcb_gcontext_t gc; uint32_t mask; 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; xcb_create_gc (c, gc, window, mask, value_list); /* The font is not needed anymore, so we close it */ xcb_close_font (c, font);/* * c is the connection * screen is the screen where the window is displayed * window is the window in which we will draw the text * font is the opened font */ uint32_t value_list[3]; xcb_gcontext_t gc; uint32_t mask; 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; xcb_create_gc (c, gc, window, mask, value_list); /* The font is not needed anymore, so we close it */ xcb_close_font (c, font);Drawing text in a drawable
To draw a text in a drawable, we use the following function:
xcb_void_cookie_t xcb_image_text_8 (xcb_connection_t *c, uint8_t string_len, xcb_drawable_t drawable, xcb_gcontext_t gc, int16_t x, int16_t y, const char *string);xcb_void_cookie_t xcb_image_text_8 (xcb_connection_t *c, uint8_t string_len, xcb_drawable_t drawable, xcb_gcontext_t gc, int16_t x, int16_t y, const char *string);The
stringparameter is the text to draw. The location of the drawing is given by the parametersxandy. The base line of the text is exactly the parametery.Complete example
This example draw a text at 10 pixels (for the base line) of the bottom of a window. Pressing the Esc key exits the program.
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <xcb/xcb.h> #define WIDTH 300 #define HEIGHT 100 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 text_draw (xcb_connection_t *c, xcb_screen_t *screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label); 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; } 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; /* 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; } xcb_flush(c); while (1) { e = xcb_poll_for_event(c); if (e) { switch (e->response_type & ~0x80) { case XCB_EXPOSE: { char *text; text = "Press ESC key to exit..."; text_draw (c, screen, window, 10, HEIGHT - 10, text); break; } 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); xcb_disconnect (c); return 0; } } } free (e); } } return 0; }#include <stdlib.h> #include <stdio.h> #include <string.h> #include <xcb/xcb.h> #define WIDTH 300 #define HEIGHT 100 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 text_draw (xcb_connection_t *c, xcb_screen_t *screen, xcb_window_t window, int16_t x1, int16_t y1, const char *label); 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; } 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; /* 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; } xcb_flush(c); while (1) { e = xcb_poll_for_event(c); if (e) { switch (e->response_type & ~0x80) { case XCB_EXPOSE: { char *text; text = "Press ESC key to exit..."; text_draw (c, screen, window, 10, HEIGHT - 10, text); break; } 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); xcb_disconnect (c); return 0; } } } free (e); } } return 0; }