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_window_t xcb_root;
|
||||||
xcb_font_t xcb_font;
|
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;
|
Display *xkb_dpy;
|
||||||
int xkb_event_base;
|
int xkb_event_base;
|
||||||
int mod_pressed;
|
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 */
|
/* Event-Watchers, to interact with the user */
|
||||||
ev_prepare *xcb_prep;
|
ev_prepare *xcb_prep;
|
||||||
ev_check *xcb_chk;
|
ev_check *xcb_chk;
|
||||||
ev_io *xcb_io;
|
ev_io *xcb_io;
|
||||||
ev_io *xkb_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.
|
* Converts a colorstring to a colorpixel as expected from xcb_change_gc.
|
||||||
* s is assumed to be in the format "rrggbb"
|
* 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);
|
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)
|
* Hides all bars (unmaps them)
|
||||||
*
|
*
|
||||||
|
@ -353,6 +450,10 @@ void init_xcb(char *fontname) {
|
||||||
strlen(fontname),
|
strlen(fontname),
|
||||||
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) {
|
if (config.hide_on_modifier) {
|
||||||
int xkb_major, xkb_minor, xkb_errbase, xkb_err;
|
int xkb_major, xkb_minor, xkb_errbase, xkb_err;
|
||||||
xkb_major = XkbMajorVersion;
|
xkb_major = XkbMajorVersion;
|
||||||
|
@ -392,6 +493,22 @@ void init_xcb(char *fontname) {
|
||||||
XFlush(xkb_dpy);
|
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 */
|
/* The varios Watchers to communicate with xcb */
|
||||||
xcb_io = malloc(sizeof(ev_io));
|
xcb_io = malloc(sizeof(ev_io));
|
||||||
xcb_prep = malloc(sizeof(ev_prepare));
|
xcb_prep = malloc(sizeof(ev_prepare));
|
||||||
|
@ -416,7 +533,27 @@ void init_xcb(char *fontname) {
|
||||||
font_height = reply->font_ascent + reply->font_descent;
|
font_height = reply->font_ascent + reply->font_descent;
|
||||||
FREE(reply);
|
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);
|
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() {
|
void draw_bars() {
|
||||||
printf("Drawing Bars...\n");
|
printf("Drawing Bars...\n");
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
refresh_statusline();
|
||||||
|
|
||||||
i3_output *outputs_walk;
|
i3_output *outputs_walk;
|
||||||
SLIST_FOREACH(outputs_walk, outputs, slist) {
|
SLIST_FOREACH(outputs_walk, outputs, slist) {
|
||||||
if (!outputs_walk->active) {
|
if (!outputs_walk->active) {
|
||||||
|
@ -627,34 +767,21 @@ void draw_bars() {
|
||||||
&rect);
|
&rect);
|
||||||
if (statusline != NULL) {
|
if (statusline != NULL) {
|
||||||
printf("Printing statusline!\n");
|
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,
|
outputs_walk->bargc,
|
||||||
XCB_GC_BACKGROUND,
|
0, 0,
|
||||||
&color);
|
MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width)), 1,
|
||||||
color = get_colorpixel("FFFFFF");
|
(uint16_t)outputs_walk->rect.w, font_height);
|
||||||
xcb_change_gc(xcb_connection,
|
xcb_generic_error_t *err;
|
||||||
outputs_walk->bargc,
|
if ((err = xcb_request_check(xcb_connection, ca_cookie)) != NULL) {
|
||||||
XCB_GC_FOREGROUND,
|
printf("ERROR: Can not copy statusline-buffer! XCB-error: %d\n", err->error_code);
|
||||||
&color);
|
free(err);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i3_ws *ws_walk;
|
i3_ws *ws_walk;
|
||||||
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
|
TAILQ_FOREACH(ws_walk, outputs_walk->workspaces, tailq) {
|
||||||
printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i);
|
printf("Drawing Button for WS %s at x = %d\n", ws_walk->name, i);
|
||||||
|
|
Loading…
Reference in New Issue