· 8 years ago · Aug 05, 2018, 05:46 PM
1From c52f74124c4c60c074b5a6e4524ca34dd6fd308d Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?Fernando=20Tarl=C3=A1=20Cardoso=20Lemos?=
3 <fernandotcl@gmail.com>
4Date: Mon, 14 Nov 2011 21:39:03 -0200
5Subject: [PATCH 1/2] Implement Pango rendering.
6
7---
8 common.mk | 9 ++
9 i3-config-wizard/main.c | 2 +
10 i3-input/main.c | 2 +
11 i3-nagbar/main.c | 2 +
12 i3bar/src/xcb.c | 30 +++---
13 include/libi3.h | 42 ++++++--
14 libi3/font.c | 258 ++++++++++++++++++++++++++++++++++++++++++-----
15 libi3/get_visualtype.c | 24 +++++
16 src/config.c | 2 +-
17 src/main.c | 2 +
18 src/xcb.c | 10 +-
19 11 files changed, 331 insertions(+), 52 deletions(-)
20 create mode 100644 libi3/get_visualtype.c
21
22diff --git a/common.mk b/common.mk
23index 4394905..a09e496 100644
24--- a/common.mk
25+++ b/common.mk
26@@ -92,6 +92,15 @@ LIBS += $(call ldflags_for_lib, libev,ev)
27 LIBS += $(call ldflags_for_lib, libpcre,pcre)
28 LIBS += $(call ldflags_for_lib, libstartup-notification-1.0,startup-notification-1)
29
30+# Enable Pango support if available
31+ifeq ($(shell pkg-config --exists cairo pangocairo && echo 1),1)
32+CPPFLAGS += -DPANGO_SUPPORT=1
33+CFLAGS += $(shell pkg-config --cflags cairo pangocairo)
34+LIBS += $(shell pkg-config --libs cairo pangocairo)
35+else
36+CPPFLAGS += -DPANGO_SUPPORT=0
37+endif
38+
39 # Please test if -Wl,--as-needed works on your platform and send me a patch.
40 # it is known not to work on Darwin (Mac OS X)
41 ifneq (,$(filter Linux GNU GNU/%, $(UNAME)))
42diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c
43index be04267..a5b9ed5 100644
44--- a/i3-config-wizard/main.c
45+++ b/i3-config-wizard/main.c
46@@ -77,6 +77,7 @@ static xcb_window_t win;
47 static xcb_pixmap_t pixmap;
48 static xcb_gcontext_t pixmap_gc;
49 static xcb_key_symbols_t *symbols;
50+xcb_visualtype_t *root_visual_type;
51 xcb_window_t root;
52 Display *dpy;
53
54@@ -457,6 +458,7 @@ int main(int argc, char *argv[]) {
55 #undef xmacro
56
57 xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screens);
58+ root_visual_type = get_visualtype(root_screen);
59 root = root_screen->root;
60
61 if (!(modmap_reply = xcb_get_modifier_mapping_reply(conn, modmap_cookie, NULL)))
62diff --git a/i3-input/main.c b/i3-input/main.c
63index b570952..2f88052 100644
64--- a/i3-input/main.c
65+++ b/i3-input/main.c
66@@ -52,6 +52,7 @@ static i3Font font;
67 static char *prompt;
68 static size_t prompt_len;
69 static int limit;
70+xcb_visualtype_t *root_visual_type;
71 xcb_window_t root;
72 xcb_connection_t *conn;
73
74@@ -358,6 +359,7 @@ int main(int argc, char *argv[]) {
75 die("Cannot open display\n");
76
77 xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screens);
78+ root_visual_type = get_visualtype(root_screen);
79 root = root_screen->root;
80
81 symbols = xcb_key_symbols_alloc(conn);
82diff --git a/i3-nagbar/main.c b/i3-nagbar/main.c
83index 1dbd773..1bdb8d6 100644
84--- a/i3-nagbar/main.c
85+++ b/i3-nagbar/main.c
86@@ -52,6 +52,7 @@ static uint32_t color_border; /* color of the button border */
87 static uint32_t color_border_bottom; /* color of the bottom border */
88 static uint32_t color_text; /* color of the text */
89
90+xcb_visualtype_t *root_visual_type;
91 xcb_window_t root;
92 xcb_connection_t *conn;
93
94@@ -281,6 +282,7 @@ int main(int argc, char *argv[]) {
95 #undef xmacro
96
97 xcb_screen_t *root_screen = xcb_aux_get_screen(conn, screens);
98+ root_visual_type = get_visualtype(root_screen);
99 root = root_screen->root;
100
101 if (bar_type == TYPE_ERROR) {
102diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c
103index 87926d3..683c6b6 100644
104--- a/i3bar/src/xcb.c
105+++ b/i3bar/src/xcb.c
106@@ -48,10 +48,11 @@ xcb_atom_t atoms[NUM_ATOMS];
107 xcb_connection_t *xcb_connection;
108 int screen;
109 xcb_screen_t *xcb_screen;
110-xcb_window_t xcb_root;
111+xcb_window_t root;
112
113 /* This is needed for integration with libi3 */
114 xcb_connection_t *conn;
115+xcb_visualtype_t *root_visual_type;
116
117 /* The font we'll use */
118 static i3Font font;
119@@ -827,7 +828,8 @@ char *init_xcb_early() {
120 #include "xcb_atoms.def"
121
122 xcb_screen = xcb_aux_get_screen(xcb_connection, screen);
123- xcb_root = xcb_screen->root;
124+ root_visual_type = get_visualtype(xcb_screen);
125+ root = xcb_screen->root;
126
127 /* We draw the statusline to a seperate pixmap, because it looks the same on all bars and
128 * this way, we can choose to crop it */
129@@ -837,14 +839,14 @@ char *init_xcb_early() {
130 statusline_clear = xcb_generate_id(xcb_connection);
131 xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
132 statusline_clear,
133- xcb_root,
134+ root,
135 mask,
136 vals);
137
138 statusline_ctx = xcb_generate_id(xcb_connection);
139 xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
140 statusline_ctx,
141- xcb_root,
142+ root,
143 0,
144 NULL);
145
146@@ -852,7 +854,7 @@ char *init_xcb_early() {
147 xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
148 xcb_screen->root_depth,
149 statusline_pm,
150- xcb_root,
151+ root,
152 xcb_screen->width_in_pixels,
153 xcb_screen->height_in_pixels);
154
155@@ -876,7 +878,7 @@ char *init_xcb_early() {
156 xcb_get_property_cookie_t path_cookie;
157 path_cookie = xcb_get_property_unchecked(xcb_connection,
158 0,
159- xcb_root,
160+ root,
161 atoms[I3_SOCKET_PATH],
162 XCB_GET_PROPERTY_TYPE_ANY,
163 0, PATH_MAX);
164@@ -984,7 +986,7 @@ void init_tray() {
165 xcb_create_window(xcb_connection,
166 xcb_screen->root_depth,
167 selwin,
168- xcb_root,
169+ root,
170 -1, -1,
171 1, 1,
172 1,
173@@ -1037,7 +1039,7 @@ void init_tray() {
174 void *event = scalloc(32);
175 xcb_client_message_event_t *ev = event;
176 ev->response_type = XCB_CLIENT_MESSAGE;
177- ev->window = xcb_root;
178+ ev->window = root;
179 ev->type = atoms[MANAGER];
180 ev->format = 32;
181 ev->data.data32[0] = XCB_CURRENT_TIME;
182@@ -1045,7 +1047,7 @@ void init_tray() {
183 ev->data.data32[2] = selwin;
184 xcb_send_event(xcb_connection,
185 0,
186- xcb_root,
187+ root,
188 XCB_EVENT_MASK_STRUCTURE_NOTIFY,
189 (char*)ev);
190 free(event);
191@@ -1116,7 +1118,7 @@ void kick_tray_clients(i3_output *output) {
192 xcb_unmap_window(xcb_connection, trayclient->win);
193 xcb_reparent_window(xcb_connection,
194 trayclient->win,
195- xcb_root,
196+ root,
197 0,
198 0);
199
200@@ -1155,7 +1157,7 @@ void realloc_sl_buffer() {
201 xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
202 xcb_screen->root_depth,
203 statusline_pm,
204- xcb_root,
205+ root,
206 MAX(xcb_screen->width_in_pixels, statusline_width),
207 xcb_screen->height_in_pixels);
208
209@@ -1165,7 +1167,7 @@ void realloc_sl_buffer() {
210 statusline_clear = xcb_generate_id(xcb_connection);
211 xcb_void_cookie_t clear_ctx_cookie = xcb_create_gc_checked(xcb_connection,
212 statusline_clear,
213- xcb_root,
214+ root,
215 mask,
216 vals);
217
218@@ -1175,7 +1177,7 @@ void realloc_sl_buffer() {
219 xcb_free_gc(xcb_connection, statusline_ctx);
220 xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
221 statusline_ctx,
222- xcb_root,
223+ root,
224 mask,
225 vals);
226
227@@ -1229,7 +1231,7 @@ void reconfig_windows() {
228 xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection,
229 xcb_screen->root_depth,
230 walk->bar,
231- xcb_root,
232+ root,
233 walk->rect.x, walk->rect.y + walk->rect.h - font.height - 6,
234 walk->rect.w, font.height + 6,
235 1,
236diff --git a/include/libi3.h b/include/libi3.h
237index b88bcb6..1de92d4 100644
238--- a/include/libi3.h
239+++ b/include/libi3.h
240@@ -18,6 +18,10 @@
241 #include <xcb/xproto.h>
242 #include <xcb/xcb_keysyms.h>
243
244+#if PANGO_SUPPORT
245+#include <pango/pango.h>
246+#endif
247+
248 typedef struct Font i3Font;
249
250 /**
251@@ -27,17 +31,33 @@ typedef struct Font i3Font;
252 *
253 */
254 struct Font {
255- /** The xcb-id for the font */
256- xcb_font_t id;
257-
258- /** Font information gathered from the server */
259- xcb_query_font_reply_t *info;
260-
261- /** Font table for this font (may be NULL) */
262- xcb_charinfo_t *table;
263+ /** The type of font */
264+ enum {
265+ FONT_TYPE_NONE = 0,
266+ FONT_TYPE_XCB,
267+ FONT_TYPE_PANGO
268+ } type;
269
270 /** The height of the font, built from font_ascent + font_descent */
271 int height;
272+
273+ union {
274+ struct {
275+ /** The xcb-id for the font */
276+ xcb_font_t id;
277+
278+ /** Font information gathered from the server */
279+ xcb_query_font_reply_t *info;
280+
281+ /** Font table for this font (may be NULL) */
282+ xcb_charinfo_t *table;
283+ } xcb;
284+
285+#if PANGO_SUPPORT
286+ /** The pango font description */
287+ PangoFontDescription *pango_desc;
288+#endif
289+ } specific;
290 };
291
292 /* Since this file also gets included by utilities which don’t use the i3 log
293@@ -242,4 +262,10 @@ void draw_text(char *text, size_t text_len, bool is_ucs2, xcb_drawable_t drawabl
294 */
295 int predict_text_width(char *text, size_t text_len, bool is_ucs2);
296
297+/*
298+ * Returns the visual type associated with the given screen.
299+ *
300+ */
301+xcb_visualtype_t *get_visualtype(xcb_screen_t *s);
302+
303 #endif
304diff --git a/libi3/font.c b/libi3/font.c
305index 0b276b0..88ee915 100644
306--- a/libi3/font.c
307+++ b/libi3/font.c
308@@ -12,11 +12,131 @@
309 #include <stdbool.h>
310 #include <err.h>
311
312+#if PANGO_SUPPORT
313+#include <cairo/cairo-xcb.h>
314+#include <pango/pangocairo.h>
315+#endif
316+
317 #include "libi3.h"
318
319 extern xcb_connection_t *conn;
320+extern xcb_visualtype_t *root_visual_type;
321+extern xcb_window_t root;
322+
323 static const i3Font *savedFont = NULL;
324
325+#if PANGO_SUPPORT
326+static double pango_font_red;
327+static double pango_font_green;
328+static double pango_font_blue;
329+
330+/*
331+ * Loads a Pango font description into an i3Font structure. Returns true
332+ * on success, false otherwise.
333+ *
334+ */
335+static bool load_pango_font(i3Font *font, const char *desc) {
336+ /* Load the font description */
337+ font->specific.pango_desc = pango_font_description_from_string(desc);
338+ if (!font->specific.pango_desc)
339+ return false;
340+
341+ /* Create a dummy Pango layout */
342+ cairo_surface_t *surface = cairo_xcb_surface_create(conn, root, root_visual_type, 100, 100);
343+ cairo_t *cr = cairo_create(surface);
344+ PangoLayout *layout = pango_cairo_create_layout(cr);
345+ pango_layout_set_font_description(layout, font->specific.pango_desc);
346+
347+ /* Get the font height */
348+ gint height;
349+ pango_layout_get_pixel_size(layout, NULL, &height);
350+ font->height = height;
351+
352+ /* Free resources */
353+ g_object_unref(layout);
354+ cairo_destroy(cr);
355+ cairo_surface_destroy(surface);
356+
357+ /* Set the font type and return successfully */
358+ font->type = FONT_TYPE_PANGO;
359+ return true;
360+}
361+
362+/*
363+ * Draws text using Pango rendering.
364+ *
365+ */
366+void draw_text_pango(char *text, size_t text_len, bool is_ucs2,
367+ xcb_drawable_t drawable, int x, int y, int max_width) {
368+ /* Create the Pango layout */
369+ cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable,
370+ root_visual_type, x + max_width, y + savedFont->height);
371+ cairo_t *cr = cairo_create(surface);
372+ PangoLayout *layout = pango_cairo_create_layout(cr);
373+ pango_layout_set_font_description(layout, savedFont->specific.pango_desc);
374+ pango_layout_set_width(layout, max_width * PANGO_SCALE);
375+ pango_layout_set_wrap(layout, PANGO_WRAP_CHAR);
376+ pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
377+
378+ /* If the text is UCS-2, convert it to UTF-8 and get the number
379+ * of bytes into text_len */
380+ if (is_ucs2) {
381+ text = convert_ucs2_to_utf8((xcb_char2b_t*)text, text_len);
382+ if (!text)
383+ return;
384+ text_len = strlen(text);
385+ }
386+
387+ /* Do the drawing */
388+ cairo_set_source_rgb(cr, pango_font_red, pango_font_green, pango_font_blue);
389+ cairo_move_to(cr, x, y);
390+ pango_layout_set_text(layout, text, text_len);
391+ pango_cairo_update_layout(cr, layout);
392+ pango_cairo_show_layout(cr, layout);
393+
394+ /* Free resources */
395+ g_object_unref(layout);
396+ cairo_destroy(cr);
397+ cairo_surface_destroy(surface);
398+ if (is_ucs2)
399+ free(text);
400+}
401+
402+/*
403+ * Calculate the text width using Pango rendering.
404+ *
405+ */
406+int predict_text_width_pango(char *text, size_t text_len, bool is_ucs2) {
407+ /* If the text is UCS-2, convert it to UTF-8 */
408+ if (is_ucs2) {
409+ text = convert_ucs2_to_utf8((xcb_char2b_t*)text, text_len);
410+ if (!text)
411+ return 10 * text_len;
412+ }
413+
414+ /* Create a dummy Pango layout */
415+ cairo_surface_t *surface = cairo_xcb_surface_create(conn, root, root_visual_type, 100, 100);
416+ cairo_t *cr = cairo_create(surface);
417+ PangoLayout *layout = pango_cairo_create_layout(cr);
418+
419+ /* Get the font height */
420+ gint width;
421+ pango_layout_set_font_description(layout, savedFont->specific.pango_desc);
422+ pango_layout_set_text(layout, text, text_len);
423+ pango_cairo_update_layout(cr, layout);
424+ pango_layout_get_pixel_size(layout, &width, NULL);
425+
426+ /* Free resources */
427+ g_object_unref(layout);
428+ cairo_destroy(cr);
429+ cairo_surface_destroy(surface);
430+ if (is_ucs2)
431+ free(text);
432+
433+ return width;
434+}
435+#endif
436+
437 /*
438 * Loads a font for usage, also getting its metrics. If fallback is true,
439 * the fonts 'fixed' or '-misc-*' will be loaded instead of exiting.
440@@ -24,12 +144,22 @@ static const i3Font *savedFont = NULL;
441 */
442 i3Font load_font(const char *pattern, const bool fallback) {
443 i3Font font;
444+ font.type = FONT_TYPE_NONE;
445+
446+#if PANGO_SUPPORT
447+ /* Try to load a pango font if specified */
448+ if (strlen(pattern) > 6 && !strncmp(pattern, "xft:", 4)) {
449+ pattern += 4;
450+ if (load_pango_font(&font, pattern))
451+ return font;
452+ }
453+#endif
454
455 /* Send all our requests first */
456- font.id = xcb_generate_id(conn);
457- xcb_void_cookie_t font_cookie = xcb_open_font_checked(conn, font.id,
458+ font.specific.xcb.id = xcb_generate_id(conn);
459+ xcb_void_cookie_t font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
460 strlen(pattern), pattern);
461- xcb_query_font_cookie_t info_cookie = xcb_query_font(conn, font.id);
462+ xcb_query_font_cookie_t info_cookie = xcb_query_font(conn, font.specific.xcb.id);
463
464 /* Check for errors. If errors, fall back to default font. */
465 xcb_generic_error_t *error;
466@@ -40,8 +170,9 @@ i3Font load_font(const char *pattern, const bool fallback) {
467 ELOG("Could not open font %s (X error %d). Trying fallback to 'fixed'.\n",
468 pattern, error->error_code);
469 pattern = "fixed";
470- font_cookie = xcb_open_font_checked(conn, font.id, strlen(pattern), pattern);
471- info_cookie = xcb_query_font(conn, font.id);
472+ font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
473+ strlen(pattern), pattern);
474+ info_cookie = xcb_query_font(conn, font.specific.xcb.id);
475
476 /* Check if we managed to open 'fixed' */
477 error = xcb_request_check(conn, font_cookie);
478@@ -50,8 +181,9 @@ i3Font load_font(const char *pattern, const bool fallback) {
479 if (error != NULL) {
480 ELOG("Could not open fallback font 'fixed', trying with '-misc-*'.\n");
481 pattern = "-misc-*";
482- font_cookie = xcb_open_font_checked(conn, font.id, strlen(pattern), pattern);
483- info_cookie = xcb_query_font(conn, font.id);
484+ font_cookie = xcb_open_font_checked(conn, font.specific.xcb.id,
485+ strlen(pattern), pattern);
486+ info_cookie = xcb_query_font(conn, font.specific.xcb.id);
487
488 if ((error = xcb_request_check(conn, font_cookie)) != NULL)
489 errx(EXIT_FAILURE, "Could open neither requested font nor fallbacks "
490@@ -60,18 +192,20 @@ i3Font load_font(const char *pattern, const bool fallback) {
491 }
492
493 /* Get information (height/name) for this font */
494- if (!(font.info = xcb_query_font_reply(conn, info_cookie, NULL)))
495+ if (!(font.specific.xcb.info = xcb_query_font_reply(conn, info_cookie, NULL)))
496 errx(EXIT_FAILURE, "Could not load font \"%s\"", pattern);
497
498 /* Get the font table, if possible */
499- if (xcb_query_font_char_infos_length(font.info) == 0)
500- font.table = NULL;
501+ if (xcb_query_font_char_infos_length(font.specific.xcb.info) == 0)
502+ font.specific.xcb.table = NULL;
503 else
504- font.table = xcb_query_font_char_infos(font.info);
505+ font.specific.xcb.table = xcb_query_font_char_infos(font.specific.xcb.info);
506
507 /* Calculate the font height */
508- font.height = font.info->font_ascent + font.info->font_descent;
509+ font.height = font.specific.xcb.info->font_ascent + font.specific.xcb.info->font_descent;
510
511+ /* Set the font type and return successfully */
512+ font.type = FONT_TYPE_XCB;
513 return font;
514 }
515
516@@ -88,10 +222,27 @@ void set_font(i3Font *font) {
517 *
518 */
519 void free_font(void) {
520- /* Close the font and free the info */
521- xcb_close_font(conn, savedFont->id);
522- if (savedFont->info)
523- free(savedFont->info);
524+ switch (savedFont->type) {
525+ case FONT_TYPE_NONE:
526+ /* Nothing to do */
527+ break;
528+ case FONT_TYPE_XCB: {
529+ /* Close the font and free the info */
530+ xcb_close_font(conn, savedFont->specific.xcb.id);
531+ if (savedFont->specific.xcb.info)
532+ free(savedFont->specific.xcb.info);
533+ break;
534+ }
535+#if PANGO_SUPPORT
536+ case FONT_TYPE_PANGO:
537+ /* Free the font description */
538+ pango_font_description_free(savedFont->specific.pango_desc);
539+ break;
540+#endif
541+ default:
542+ assert(false);
543+ break;
544+ }
545 }
546
547 /*
548@@ -100,9 +251,30 @@ void free_font(void) {
549 */
550 void set_font_colors(xcb_gcontext_t gc, uint32_t foreground, uint32_t background) {
551 assert(savedFont != NULL);
552- uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
553- uint32_t values[] = { foreground, background, savedFont->id };
554- xcb_change_gc(conn, gc, mask, values);
555+
556+ switch (savedFont->type) {
557+ case FONT_TYPE_NONE:
558+ /* Nothing to do */
559+ break;
560+ case FONT_TYPE_XCB: {
561+ /* Change the font and colors in the GC */
562+ uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
563+ uint32_t values[] = { foreground, background, savedFont->specific.xcb.id };
564+ xcb_change_gc(conn, gc, mask, values);
565+ break;
566+ }
567+#if PANGO_SUPPORT
568+ case FONT_TYPE_PANGO:
569+ /* Save the foreground font */
570+ pango_font_red = ((foreground >> 16) & 0xff) / 255.0;
571+ pango_font_green = ((foreground >> 8) & 0xff) / 255.0;
572+ pango_font_blue = (foreground & 0xff) / 255.0;
573+ break;
574+#endif
575+ default:
576+ assert(false);
577+ break;
578+ }
579 }
580
581 /*
582@@ -121,8 +293,25 @@ void draw_text(char *text, size_t text_len, bool is_ucs2, xcb_drawable_t drawabl
583 assert(savedFont != NULL);
584 assert(text_len != 0);
585
586+ switch (savedFont->type) {
587+ case FONT_TYPE_NONE:
588+ /* Nothing to do */
589+ return;
590+ case FONT_TYPE_XCB:
591+ /* Continue below */
592+ break;
593+#if PANGO_SUPPORT
594+ case FONT_TYPE_PANGO:
595+ /* Render the text using Pango */
596+ draw_text_pango(text, text_len, is_ucs2, drawable, x, y, max_width);
597+ return;
598+#endif
599+ default:
600+ assert(false);
601+ }
602+
603 /* X11 coordinates for fonts start at the baseline */
604- int pos_y = y + savedFont->info->font_ascent;
605+ int pos_y = y + savedFont->specific.xcb.info->font_ascent;
606
607 /* As an optimization, check if we can bypass conversion */
608 if (!is_ucs2 && text_len <= 255) {
609@@ -173,7 +362,7 @@ static int xcb_query_text_width(xcb_char2b_t *text, size_t text_len) {
610 /* Query the text width */
611 xcb_generic_error_t *error;
612 xcb_query_text_extents_cookie_t cookie = xcb_query_text_extents(conn,
613- savedFont->id, text_len, (xcb_char2b_t*)text);
614+ savedFont->specific.xcb.id, text_len, (xcb_char2b_t*)text);
615 xcb_query_text_extents_reply_t *reply = xcb_query_text_extents_reply(conn,
616 cookie, &error);
617 if (reply == NULL) {
618@@ -181,7 +370,7 @@ static int xcb_query_text_width(xcb_char2b_t *text, size_t text_len) {
619 * a crash. Plus, the user will see the error in his log. */
620 fprintf(stderr, "Could not get text extents (X error code %d)\n",
621 error->error_code);
622- return savedFont->info->max_bounds.character_width * text_len;
623+ return savedFont->specific.xcb.info->max_bounds.character_width * text_len;
624 }
625
626 int width = reply->overall_width;
627@@ -195,6 +384,25 @@ static int xcb_query_text_width(xcb_char2b_t *text, size_t text_len) {
628 *
629 */
630 int predict_text_width(char *text, size_t text_len, bool is_ucs2) {
631+ assert(savedFont != NULL);
632+
633+ switch (savedFont->type) {
634+ case FONT_TYPE_NONE:
635+ /* Nothing to do */
636+ return 0;
637+ case FONT_TYPE_XCB:
638+ /* Continue below */
639+ break;
640+#if PANGO_SUPPORT
641+ case FONT_TYPE_PANGO:
642+ /* Calculate extents using Pango */
643+ return predict_text_width_pango(text, text_len, is_ucs2);
644+#endif
645+ default:
646+ assert(false);
647+ return 0;
648+ }
649+
650 /* Convert the text into UTF-16 so we can do basic pointer math */
651 xcb_char2b_t *input;
652 if (is_ucs2)
653@@ -203,13 +411,13 @@ int predict_text_width(char *text, size_t text_len, bool is_ucs2) {
654 input = convert_utf8_to_ucs2(text, &text_len);
655
656 int width;
657- if (savedFont->table == NULL) {
658+ if (savedFont->specific.xcb.table == NULL) {
659 /* If we don't have a font table, fall back to querying the server */
660 width = xcb_query_text_width(input, text_len);
661 } else {
662 /* Save some pointers for convenience */
663- xcb_query_font_reply_t *font_info = savedFont->info;
664- xcb_charinfo_t *font_table = savedFont->table;
665+ xcb_query_font_reply_t *font_info = savedFont->specific.xcb.info;
666+ xcb_charinfo_t *font_table = savedFont->specific.xcb.table;
667
668 /* Calculate the width using the font table */
669 width = 0;
670diff --git a/libi3/get_visualtype.c b/libi3/get_visualtype.c
671new file mode 100644
672index 0000000..c639443
673--- /dev/null
674+++ b/libi3/get_visualtype.c
675@@ -0,0 +1,24 @@
676+/*
677+ * vim:ts=4:sw=4:expandtab
678+ *
679+ * i3 - an improved dynamic tiling window manager
680+ * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
681+ *
682+ */
683+#include "libi3.h"
684+
685+/*
686+ * Returns the visual type associated with the given screen.
687+ *
688+ */
689+xcb_visualtype_t *get_visualtype(xcb_screen_t *s) {
690+ xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(s);
691+ for (; depth_iter.rem;xcb_depth_next(&depth_iter)) {
692+ xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
693+ for (; visual_iter.rem;xcb_visualtype_next(&visual_iter)) {
694+ if (s->root_visual == visual_iter.data->visual_id)
695+ return visual_iter.data;
696+ }
697+ }
698+ return NULL;
699+}
700diff --git a/src/config.c b/src/config.c
701index 50ec282..3542d1c 100644
702--- a/src/config.c
703+++ b/src/config.c
704@@ -392,7 +392,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
705 grab_all_keys(conn, false);
706 }
707
708- if (config.font.id == 0) {
709+ if (config.font.type == FONT_TYPE_NONE) {
710 ELOG("You did not specify required configuration option \"font\"\n");
711 config.font = load_font("fixed", true);
712 set_font(&config.font);
713diff --git a/src/main.c b/src/main.c
714index 14786d2..e3957aa 100644
715--- a/src/main.c
716+++ b/src/main.c
717@@ -51,6 +51,7 @@ SnDisplay *sndisplay;
718 * notification). */
719 xcb_timestamp_t last_timestamp = XCB_CURRENT_TIME;
720
721+xcb_visualtype_t *root_visual_type;
722 xcb_screen_t *root_screen;
723 xcb_window_t root;
724
725@@ -517,6 +518,7 @@ int main(int argc, char *argv[]) {
726 * usually is TrueColor (24 bit depth) and the corresponding visual.
727 * However, we also check if a 32 bit depth and visual are available (for
728 * transparency) and use it if so. */
729+ root_visual_type = get_visualtype(root_screen);
730 root_depth = root_screen->root_depth;
731 visual_id = root_screen->root_visual;
732 colormap = root_screen->default_colormap;
733diff --git a/src/xcb.c b/src/xcb.c
734index 4d7a8c4..4bc68c9 100644
735--- a/src/xcb.c
736+++ b/src/xcb.c
737@@ -48,8 +48,9 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims,
738 xcb_cursor_t cursor_id = xcb_generate_id(conn);
739 i3Font cursor_font = load_font("cursor", false);
740 int xcb_cursor = xcursor_get_xcb_cursor(cursor);
741- xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
742- xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
743+ xcb_create_glyph_cursor(conn, cursor_id, cursor_font.specific.xcb.id,
744+ cursor_font.specific.xcb.id, xcb_cursor, xcb_cursor + 1, 0, 0, 0,
745+ 65535, 65535, 65535);
746 xcb_change_window_attributes(conn, result, XCB_CW_CURSOR, &cursor_id);
747 xcb_free_cursor(conn, cursor_id);
748 }
749@@ -193,8 +194,9 @@ void xcb_set_root_cursor(int cursor) {
750 xcb_cursor_t cursor_id = xcb_generate_id(conn);
751 i3Font cursor_font = load_font("cursor", false);
752 int xcb_cursor = xcursor_get_xcb_cursor(cursor);
753- xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
754- xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
755+ xcb_create_glyph_cursor(conn, cursor_id, cursor_font.specific.xcb.id,
756+ cursor_font.specific.xcb.id, xcb_cursor, xcb_cursor + 1, 0, 0, 0,
757+ 65535, 65535, 65535);
758 xcb_change_window_attributes(conn, root, XCB_CW_CURSOR, &cursor_id);
759 xcb_free_cursor(conn, cursor_id);
760 xcb_flush(conn);
761--
7621.7.10