#include #include #include #define WINDOW_WIDTH 30 #define WINDOW_HEIGHT 30 #define GLYPH_WIDTH 20 #define GLYPH_HEIGHT 20 static const uint32_t glyph_index = 42; static xcb_connection_t *c; static xcb_screen_t *screen; static xcb_visualtype_t *visual; static xcb_render_pictformat_t pict_format_default; static xcb_render_pictformat_t pict_format_a8; static xcb_render_glyphset_t glyphset; static xcb_window_t window; static xcb_render_picture_t picture; static xcb_render_picture_t solid_white_source; static xcb_visualtype_t *find_visual(xcb_visualid_t visual) { xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen); xcb_visualtype_iterator_t visual_iter; for (; depth_iter.rem; xcb_depth_next(&depth_iter)) for (visual_iter = xcb_depth_visuals_iterator(depth_iter.data); visual_iter.rem; xcb_visualtype_next(&visual_iter)) if (visual == visual_iter.data->visual_id) return visual_iter.data; puts("Couldn't find default visual"); return NULL; } static xcb_render_pictformat_t find_format_for_visual(xcb_render_query_pict_formats_reply_t *formats, xcb_visualid_t visual) { xcb_render_pictscreen_iterator_t screens; xcb_render_pictdepth_iterator_t depths; xcb_render_pictvisual_iterator_t visuals; for (screens = xcb_render_query_pict_formats_screens_iterator (formats); screens.rem; xcb_render_pictscreen_next (&screens)) { for (depths = xcb_render_pictscreen_depths_iterator (screens.data); depths.rem; xcb_render_pictdepth_next (&depths)) { for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data); visuals.rem; xcb_render_pictvisual_next (&visuals)) { if (visuals.data->visual == visual) { xcb_render_pictformat_t format = visuals.data->format; return format; } } } } puts("Couldn't find PictFormat for visual"); return XCB_NONE; } static xcb_render_pictformat_t find_format_a8(xcb_render_query_pict_formats_reply_t *formats) { xcb_render_pictforminfo_iterator_t i; for (i = xcb_render_query_pict_formats_formats_iterator(formats); i.rem; xcb_render_pictforminfo_next(&i)) { if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT) continue; if (i.data->direct.red_mask != 0) continue; if (i.data->direct.green_mask != 0) continue; if (i.data->direct.blue_mask != 0) continue; if (i.data->direct.alpha_mask != 0xff) continue; return i.data->id; } puts("Couldn't find A8 PictFormat"); return XCB_NONE; } static void redraw() { xcb_rectangle_t rect; xcb_render_color_t color; uint8_t glyph_commands[] = { /* len */ 1, /* Padding */ 0, 0, 0, /* x and y shift (16bit) */ 5, 0, 5, 0, /* Glyph */ 42, /* Padding */ 0, 0, 0 }; rect.x = 0; rect.y = 0; rect.width = WINDOW_WIDTH; rect.height = WINDOW_HEIGHT; color.red = 0xffff; color.green = 0xffff; color.blue = 0; xcb_render_fill_rectangles(c, XCB_RENDER_PICT_OP_SRC, picture, color, 1, &rect); xcb_render_composite_glyphs_8(c, XCB_RENDER_PICT_OP_OUT_REVERSE, solid_white_source, picture, XCB_NONE, glyphset, 0, 0, sizeof(glyph_commands), glyph_commands); } int main() { xcb_render_query_pict_formats_reply_t *formats; xcb_render_glyphinfo_t glyph_info; uint8_t *glyph_data; size_t glyph_data_length; if (GLYPH_WIDTH % 4 != 0) puts("Bad glyph width"); glyph_data_length = GLYPH_WIDTH * GLYPH_HEIGHT; glyph_data = malloc(glyph_data_length); for (int y = 0; y < GLYPH_HEIGHT; y++) for (int x = 0; x < GLYPH_WIDTH; x++) { uint8_t data = 0x7f; switch ((x % 2) + (y % 2)) { case 0: data = 0; break; case 1: data = 0xff; break; } glyph_data[y * GLYPH_WIDTH + x] = data; } glyph_info.width = GLYPH_WIDTH; glyph_info.height = GLYPH_WIDTH; glyph_info.x = 0; glyph_info.y = 0; glyph_info.x_off = 42; glyph_info.y_off = 21; c = xcb_connect(NULL, NULL); if (xcb_connection_has_error(c)) puts("Couldn't connect"); screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; visual = find_visual(screen->root_visual); formats = xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats(c), NULL); pict_format_default = find_format_for_visual(formats, screen->root_visual); pict_format_a8 = find_format_a8(formats); free(formats); window = xcb_generate_id(c); xcb_create_window(c, screen->root_depth, window, screen->root, 10, 10, WINDOW_WIDTH, WINDOW_HEIGHT, 0, XCB_COPY_FROM_PARENT, visual->visual_id, XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, (const uint32_t[]) { 1, XCB_EVENT_MASK_EXPOSURE }); picture = xcb_generate_id(c); xcb_render_create_picture(c, picture, window, pict_format_default, XCB_RENDER_CP_POLY_MODE, (const uint32_t[]) { XCB_RENDER_POLY_MODE_IMPRECISE }); glyphset = xcb_generate_id(c); xcb_render_create_glyph_set(c, glyphset, pict_format_a8); xcb_render_add_glyphs(c, glyphset, 1, &glyph_index, &glyph_info, glyph_data_length, glyph_data); solid_white_source = xcb_generate_id(c); xcb_render_create_solid_fill(c, solid_white_source, (xcb_render_color_t) { 0xffff, 0xffff, 0xffff, 0xffff }); xcb_map_window(c, window); xcb_flush(c); while (!xcb_connection_has_error(c)) { xcb_generic_event_t *ev = xcb_wait_for_event(c); switch (ev->response_type) { case XCB_EXPOSE: redraw(); break; default: printf("Unknown event of type %d\n", ev->response_type); break; } free(ev); xcb_flush(c); } xcb_disconnect(c); return 0; }