Draw the statusline to a seperate buffer-pixmap
This commit is contained in:
parent
4ec3e7a619
commit
2ce9c4024f
177
i3bar/src/xcb.c
177
i3bar/src/xcb.c
|
@ -42,16 +42,67 @@ xcb_screen_t *xcb_screens;
|
|||
xcb_window_t xcb_root;
|
||||
xcb_font_t xcb_font;
|
||||
|
||||
/* We need to cache some data to speed up text-width-prediction */
|
||||
xcb_query_font_reply_t *font_info;
|
||||
xcb_charinfo_t *font_table;
|
||||
|
||||
/* These are only relevant for XKB, which we only need for grabbing modifiers */
|
||||
Display *xkb_dpy;
|
||||
int xkb_event_base;
|
||||
int mod_pressed;
|
||||
|
||||
/* Because the statusline is the same on all outputs, we have
|
||||
* global buffer to render it on */
|
||||
xcb_gcontext_t statusline_ctx;
|
||||
xcb_pixmap_t statusline_pm;
|
||||
uint32_t statusline_width;
|
||||
|
||||
/* Event-Watchers, to interact with the user */
|
||||
ev_prepare *xcb_prep;
|
||||
ev_check *xcb_chk;
|
||||
ev_io *xcb_io;
|
||||
ev_io *xkb_io;
|
||||
|
||||
/*
|
||||
* Predicts the length of text based on cached data
|
||||
*
|
||||
*/
|
||||
uint32_t predict_text_extents(xcb_char2b_t *text, uint32_t length) {
|
||||
/* If we don't have per-character data, return the maximum width */
|
||||
if (font_table == NULL) {
|
||||
return (font_info->max_bounds.character_width * length);
|
||||
}
|
||||
|
||||
uint32_t width = 0;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
xcb_charinfo_t *info;
|
||||
int row = text[i].byte1;
|
||||
int col = text[i].byte2;
|
||||
|
||||
if (row < font_info->min_byte1 || row > font_info->max_byte1 ||
|
||||
col < font_info->min_char_or_byte2 || col > font_info->max_char_or_byte2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Don't you ask me, how this one works… */
|
||||
info = &font_table[((row - font_info->min_byte1) *
|
||||
(font_info->max_char_or_byte2 - font_info->min_char_or_byte2 + 1)) +
|
||||
(col - font_info->min_char_or_byte2)];
|
||||
|
||||
if (info->character_width != 0 ||
|
||||
(info->right_side_bearing |
|
||||
info->left_side_bearing |
|
||||
info->ascent |
|
||||
info->descent) != 0) {
|
||||
width += info->character_width;
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a colorstring to a colorpixel as expected from xcb_change_gc.
|
||||
* s is assumed to be in the format "rrggbb"
|
||||
|
@ -67,6 +118,52 @@ uint32_t get_colorpixel(const char *s) {
|
|||
return (r << 16 | g << 8 | b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Redraws the statusline to the buffer
|
||||
*
|
||||
*/
|
||||
void refresh_statusline() {
|
||||
int glyph_count;
|
||||
uint32_t root_width = xcb_screens->width_in_pixels;
|
||||
if (statusline == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count);
|
||||
statusline_width = predict_text_extents(text, glyph_count);
|
||||
int crop_x = MIN(0, ((int32_t)root_width) - ((int32_t)statusline_width));
|
||||
printf("Cropping statusline with %d glyphs at x=%d\n", glyph_count, crop_x);
|
||||
statusline_width = MIN((int32_t)statusline_width, (int32_t)root_width);
|
||||
|
||||
xcb_free_pixmap(xcb_connection, statusline_pm);
|
||||
statusline_pm = xcb_generate_id(xcb_connection);
|
||||
xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
||||
xcb_screens->root_depth,
|
||||
statusline_pm,
|
||||
xcb_root,
|
||||
statusline_width,
|
||||
font_height);
|
||||
|
||||
xcb_void_cookie_t text_cookie = xcb_image_text_16(xcb_connection,
|
||||
glyph_count,
|
||||
statusline_pm,
|
||||
statusline_ctx,
|
||||
0,
|
||||
font_height,
|
||||
text);
|
||||
|
||||
xcb_generic_error_t *err;
|
||||
if ((err = xcb_request_check(xcb_connection, sl_pm_cookie)) != NULL) {
|
||||
printf("ERROR: Could not allocate statusline-buffer! XCB-error: %d\n", err->error_code);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ((err = xcb_request_check(xcb_connection, text_cookie)) != NULL) {
|
||||
printf("ERROR: Could not draw text to buffer! XCB-error: %d\n", err->error_code);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hides all bars (unmaps them)
|
||||
*
|
||||
|
@ -353,6 +450,10 @@ void init_xcb(char *fontname) {
|
|||
strlen(fontname),
|
||||
fontname);
|
||||
|
||||
xcb_query_font_cookie_t query_font_cookie;
|
||||
query_font_cookie = xcb_query_font(xcb_connection,
|
||||
xcb_font);
|
||||
|
||||
if (config.hide_on_modifier) {
|
||||
int xkb_major, xkb_minor, xkb_errbase, xkb_err;
|
||||
xkb_major = XkbMajorVersion;
|
||||
|
@ -392,6 +493,22 @@ void init_xcb(char *fontname) {
|
|||
XFlush(xkb_dpy);
|
||||
}
|
||||
|
||||
/* We draw the statusline to a seperate pixmap, because it looks the same on all bars and
|
||||
* this way, we can choose to crop it */
|
||||
statusline_ctx = xcb_generate_id(xcb_connection);
|
||||
uint32_t mask = XCB_GC_FOREGROUND |
|
||||
XCB_GC_BACKGROUND |
|
||||
XCB_GC_FONT;
|
||||
uint32_t vals[3] = { xcb_screens->white_pixel, xcb_screens->black_pixel, xcb_font };
|
||||
|
||||
xcb_void_cookie_t sl_ctx_cookie = xcb_create_gc_checked(xcb_connection,
|
||||
statusline_ctx,
|
||||
xcb_root,
|
||||
mask,
|
||||
vals);
|
||||
|
||||
statusline_pm = xcb_generate_id(xcb_connection);
|
||||
|
||||
/* The varios Watchers to communicate with xcb */
|
||||
xcb_io = malloc(sizeof(ev_io));
|
||||
xcb_prep = malloc(sizeof(ev_prepare));
|
||||
|
@ -416,7 +533,27 @@ void init_xcb(char *fontname) {
|
|||
font_height = reply->font_ascent + reply->font_descent;
|
||||
FREE(reply);
|
||||
|
||||
font_info = xcb_query_font_reply(xcb_connection,
|
||||
query_font_cookie,
|
||||
&err);
|
||||
|
||||
if (err != NULL) {
|
||||
printf("ERROR: Could not query font! XCB-error: %d\n", err->error_code);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (xcb_query_font_char_infos_length(font_info) == 0) {
|
||||
font_table = NULL;
|
||||
} else {
|
||||
font_table = xcb_query_font_char_infos(font_info);
|
||||
}
|
||||
|
||||
printf("Calculated Font-height: %d\n", font_height);
|
||||
|
||||
if((err = xcb_request_check(xcb_connection, sl_ctx_cookie)) != NULL) {
|
||||
printf("ERROR: Could not create context for statusline! XCB-error: %d\n", err->error_code);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -605,6 +742,9 @@ void reconfig_windows() {
|
|||
void draw_bars() {
|
||||
printf("Drawing Bars...\n");
|
||||
int i = 0;
|
||||
|
||||
refresh_statusline();
|
||||
|
||||
i3_output *outputs_walk;
|
||||
SLIST_FOREACH(outputs_walk, outputs, slist) {
|
||||
if (!outputs_walk->active) {
|
||||
|
@ -627,34 +767,21 @@ void draw_bars() {
|
|||
&rect);
|
||||
if (statusline != NULL) {
|
||||
printf("Printing statusline!\n");
|
||||
xcb_change_gc(xcb_connection,
|
||||
|
||||
xcb_void_cookie_t ca_cookie = xcb_copy_area(xcb_connection,
|
||||
statusline_pm,
|
||||
outputs_walk->buffer,
|
||||
outputs_walk->bargc,
|
||||
XCB_GC_BACKGROUND,
|
||||
&color);
|
||||
color = get_colorpixel("FFFFFF");
|
||||
xcb_change_gc(xcb_connection,
|
||||
outputs_walk->bargc,
|
||||
XCB_GC_FOREGROUND,
|
||||
&color);
|
||||
|
||||
int glyph_count;
|
||||
xcb_char2b_t *text = (xcb_char2b_t*) convert_utf8_to_ucs2(statusline, &glyph_count);
|
||||
|
||||
xcb_void_cookie_t cookie;
|
||||
cookie = xcb_image_text_16(xcb_connection,
|
||||
glyph_count,
|
||||
outputs_walk->buffer,
|
||||
outputs_walk->bargc,
|
||||
outputs_walk->rect.w - get_string_width(text, glyph_count) - 4,
|
||||
font_height + 1,
|
||||
(xcb_char2b_t*) text);
|
||||
|
||||
xcb_generic_error_t *err = xcb_request_check(xcb_connection, cookie);
|
||||
|
||||
if (err != NULL) {
|
||||
printf("XCB-Error: %d\n", err->error_code);
|
||||
0, 0,
|
||||
MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width)), 1,
|
||||
(uint16_t)outputs_walk->rect.w, font_height);
|
||||
xcb_generic_error_t *err;
|
||||
if ((err = xcb_request_check(xcb_connection, ca_cookie)) != NULL) {
|
||||
printf("ERROR: Can not copy statusline-buffer! XCB-error: %d\n", err->error_code);
|
||||
free(err);
|
||||
}
|
||||
}
|
||||
|
||||
i3_ws *ws_walk;
|
||||
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
|
||||
printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i);
|
||||
|
|
Loading…
Reference in New Issue