diff options
-rw-r--r-- | lib/renderers/cairo.h | 135 | ||||
-rw-r--r-- | lib/renderers/wayland/wayland.c | 5 | ||||
-rw-r--r-- | lib/renderers/wayland/wayland.h | 4 | ||||
-rw-r--r-- | lib/renderers/wayland/window.c | 31 |
4 files changed, 95 insertions, 80 deletions
diff --git a/lib/renderers/cairo.h b/lib/renderers/cairo.h index 130af4f..09aebf7 100644 --- a/lib/renderers/cairo.h +++ b/lib/renderers/cairo.h @@ -7,14 +7,6 @@ #include <cairo/cairo.h> #include <pango/pangocairo.h> -#ifndef MAX -# define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - struct cairo { cairo_t *cr; cairo_surface_t *surface; @@ -28,7 +20,7 @@ struct cairo_color { struct cairo_paint { struct cairo_color fg; struct cairo_color bg; - cairo_font_extents_t fe; + const char *font; struct box { int32_t lx, rx; // left/right offset (pos.x - lx, box.w + rx) @@ -42,7 +34,13 @@ struct cairo_paint { }; struct cairo_result { - cairo_text_extents_t te; + uint32_t x_advance; + uint32_t height; +}; + +struct cairo_paint_result { + uint32_t displayed; + uint32_t height; }; static size_t blen = 0; @@ -76,19 +74,22 @@ bm_cairo_destroy(struct cairo *cairo) cairo_surface_destroy(cairo->surface); } -__attribute__((unused)) static void -bm_cairo_get_font_extents(struct cairo *cairo, const struct bm_font *font, cairo_font_extents_t *fe) +__attribute__((unused)) static PangoLayout* +bm_pango_get_layout(struct cairo *cairo, struct cairo_paint *paint, const char *buffer) { - assert(cairo && font && fe); - cairo_select_font_face(cairo->cr, font->name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cairo->cr, font->size); - cairo_font_extents(cairo->cr, fe); + PangoLayout *layout = pango_cairo_create_layout(cairo->cr); + pango_layout_set_text(layout, buffer, -1); + PangoFontDescription *desc = pango_font_description_from_string(paint->font); + pango_layout_set_font_description(layout, desc); + pango_layout_set_single_paragraph_mode(layout, 1); + pango_font_description_free(desc); + return layout; } -__attribute__((unused)) BM_LOG_ATTR(3, 4) static bool -bm_cairo_get_text_extents(struct cairo *cairo, struct cairo_result *result, const char *fmt, ...) +__attribute__((unused)) BM_LOG_ATTR(4, 5) static bool +bm_pango_get_text_extents(struct cairo *cairo, struct cairo_paint *paint, struct cairo_result *result, const char *fmt, ...) { - assert(cairo && result && fmt); + assert(cairo && paint && result && fmt); memset(result, 0, sizeof(struct cairo_result)); va_list args; @@ -99,7 +100,13 @@ bm_cairo_get_text_extents(struct cairo *cairo, struct cairo_result *result, cons if (!ret) return false; - cairo_text_extents(cairo->cr, buffer, &result->te); + PangoRectangle rect; + PangoLayout *layout = bm_pango_get_layout(cairo, paint, buffer); + pango_layout_get_pixel_extents(layout, &rect, NULL); + g_object_unref(layout); + + result->x_advance = rect.x + rect.width; + result->height = rect.height; return true; } @@ -117,33 +124,29 @@ bm_cairo_draw_line(struct cairo *cairo, struct cairo_paint *paint, struct cairo_ if (!ret) return false; - PangoLayout *layout = pango_cairo_create_layout(cairo->cr); - pango_layout_set_text(layout, buffer, -1); - PangoFontDescription *desc = pango_font_description_from_string("Terminus 12"); - pango_layout_set_font_description(layout, desc); - pango_font_description_free(desc); + PangoLayout *layout = bm_pango_get_layout(cairo, paint, buffer); pango_cairo_update_layout(cairo->cr, layout); int width, height; - pango_layout_get_size(layout, &width, &height); + pango_layout_get_pixel_size(layout, &width, &height); + int base = pango_layout_get_baseline(layout) / PANGO_SCALE; + int yoff = height - base; cairo_set_source_rgba(cairo->cr, paint->bg.r, paint->bg.b, paint->bg.g, paint->bg.a); cairo_rectangle(cairo->cr, paint->pos.x - paint->box.lx, paint->pos.y - paint->box.ty, - (paint->box.w > 0 ? paint->box.w : width / PANGO_SCALE) + paint->box.rx + paint->box.lx, - (paint->box.h > 0 ? paint->box.h : paint->fe.height) + paint->box.by + paint->box.ty); + (paint->box.w > 0 ? paint->box.w : width) + paint->box.rx + paint->box.lx, + (paint->box.h > 0 ? paint->box.h : height) + paint->box.by + paint->box.ty); cairo_fill(cairo->cr); cairo_set_source_rgba(cairo->cr, paint->fg.r, paint->fg.b, paint->fg.g, paint->fg.a); - cairo_move_to(cairo->cr, paint->box.lx + paint->pos.x, paint->pos.y - ((height * 0.25) / PANGO_SCALE) + paint->box.ty); + cairo_move_to(cairo->cr, paint->box.lx + paint->pos.x, paint->pos.y - yoff + paint->box.ty); pango_cairo_show_layout(cairo->cr, layout); - g_object_unref(layout); - cairo_text_extents_t te; - cairo_text_extents(cairo->cr, buffer, &te); + g_object_unref(layout); - te.x_advance = width / PANGO_SCALE + paint->box.rx; - memcpy(&result->te, &te, sizeof(te)); + result->x_advance = width + paint->box.rx; + result->height = height + paint->box.by; return true; } @@ -157,10 +160,16 @@ bm_cairo_color_from_menu_color(const struct bm_menu *menu, enum bm_color color, c->a = 1.0f; } -__attribute__((unused)) static uint32_t -bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu) +__attribute__((unused)) static void +bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu, struct cairo_paint_result *out_result) { - assert(cairo && menu); + assert(cairo && menu && out_result); + + memset(out_result, 0, sizeof(struct cairo_paint_result)); + out_result->displayed = 1; + + char font[128]; + snprintf(font, sizeof(font), "%s %d", menu->font.name, menu->font.size); struct cairo_color c; bm_cairo_color_from_menu_color(menu, BM_COLOR_BG, &c); @@ -170,37 +179,42 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struc struct cairo_paint paint; memset(&paint, 0, sizeof(paint)); - bm_cairo_get_font_extents(cairo, &menu->font, &paint.fe); + paint.font = font; struct cairo_result result; memset(&result, 0, sizeof(result)); + uint32_t title_x = 0; if (menu->title) { bm_cairo_color_from_menu_color(menu, BM_COLOR_TITLE_FG, &paint.fg); bm_cairo_color_from_menu_color(menu, BM_COLOR_TITLE_BG, &paint.bg); - paint.pos = (struct pos){ result.te.x_advance, 2 }; + paint.pos = (struct pos){ result.x_advance, 2 }; paint.box = (struct box){ 4, 8, 2, 2, 0, 0 }; bm_cairo_draw_line(cairo, &paint, &result, "%s", menu->title); + title_x = result.x_advance; } bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_FG, &paint.fg); bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_BG, &paint.bg); - paint.pos = (struct pos){ (menu->title ? 2 : 0) + result.te.x_advance, 2 }; + paint.pos = (struct pos){ (menu->title ? 2 : 0) + result.x_advance, 2 }; paint.box = (struct box){ (menu->title ? 2 : 4), 0, 2, 2, width - paint.pos.x, 0 }; bm_cairo_draw_line(cairo, &paint, &result, "%s", (menu->filter ? menu->filter : "")); + out_result->height = result.height; + + uint32_t count; + struct bm_item **items = bm_menu_get_filtered_items(menu, &count); + uint32_t lines = (menu->lines > 0 ? menu->lines : 1); - uint32_t displayed = 1; - uint32_t lines = MAX(height / (paint.fe.height + 4), 1); if (lines > 1) { + /* vertical mode */ uint32_t start_x = 0; if (menu->prefix) { - bm_cairo_get_text_extents(cairo, &result, "%s ", menu->prefix); - start_x = result.te.x_advance; + bm_pango_get_text_extents(cairo, &paint, &result, "%s ", menu->prefix); + start_x = result.x_advance; } - uint32_t count, cl = 1; - struct bm_item **items = bm_menu_get_filtered_items(menu, &count); - for (uint32_t i = (menu->index / (lines - 1)) * (lines - 1); i < count && cl < lines; ++i) { + uint32_t posy = out_result->height; + for (uint32_t l = 0, i = (menu->index / lines) * lines; l < lines && i < count; ++i, ++l) { bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu)); if (highlighted) { @@ -215,27 +229,29 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struc } if (menu->prefix && highlighted) { - paint.pos = (struct pos){ 0, 2 + (paint.fe.height + 4) * cl++ }; + paint.pos = (struct pos){ 0, 2 + posy }; paint.box = (struct box){ 4, 0, 2, 2, width - paint.pos.x, 0 }; bm_cairo_draw_line(cairo, &paint, &result, "%s %s", menu->prefix, (items[i]->text ? items[i]->text : "")); } else { - paint.pos = (struct pos){ 0, 2 + (paint.fe.height + 4) * cl++ }; + paint.pos = (struct pos){ 0, 2 + posy }; paint.box = (struct box){ 4 + start_x, 0, 2, 2, width - paint.pos.x, 0 }; bm_cairo_draw_line(cairo, &paint, &result, "%s", (items[i]->text ? items[i]->text : "")); } - ++displayed; + posy += result.height; + out_result->height = posy + 2; + out_result->displayed++; } } else { - uint32_t count; - struct bm_item **items = bm_menu_get_filtered_items(menu, &count); + /* single-line mode */ + bm_pango_get_text_extents(cairo, &paint, &result, "lorem ipsum lorem ipsum lorem ipsum lorem"); + uint32_t cl = fmin(title_x + result.x_advance, width / 4); - uint32_t cl = width / 4; if (menu->wrap || menu->index > 0) { paint.pos = (struct pos){ cl, 2 }; paint.box = (struct box){ 1, 2, 2, 2, 0, 0 }; bm_cairo_draw_line(cairo, &paint, &result, "<"); - cl += result.te.x_advance + 1; + cl += result.x_advance + 1; } for (uint32_t i = menu->index; i < count && cl < width; ++i) { @@ -255,21 +271,20 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struc paint.pos = (struct pos){ cl, 2 }; paint.box = (struct box){ 2, 4, 2, 2, 0, 0 }; bm_cairo_draw_line(cairo, &paint, &result, "%s", (items[i]->text ? items[i]->text : "")); - cl += result.te.x_advance + 2; - displayed += (cl < width); + cl += result.x_advance + 2; + out_result->displayed += (cl < width); + out_result->height = fmax(out_result->height, result.height); } if (menu->wrap || menu->index + 1 < count) { bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_FG, &paint.fg); bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_BG, &paint.bg); - bm_cairo_get_text_extents(cairo, &result, ">"); - paint.pos = (struct pos){ width - result.te.x_advance - 2, 2 }; + bm_pango_get_text_extents(cairo, &paint, &result, ">"); + paint.pos = (struct pos){ width - result.x_advance - 2, 2 }; paint.box = (struct box){ 1, 2, 2, 2, 0, 0 }; bm_cairo_draw_line(cairo, &paint, &result, ">"); } } - - return displayed; } #endif /* _BM_CAIRO_H */ diff --git a/lib/renderers/wayland/wayland.c b/lib/renderers/wayland/wayland.c index 3852a6d..18f335f 100644 --- a/lib/renderers/wayland/wayland.c +++ b/lib/renderers/wayland/wayland.c @@ -39,10 +39,7 @@ render(const struct bm_menu *menu) } if (wayland->input.code != wayland->input.last_code) { - uint32_t count; - bm_menu_get_filtered_items(menu, &count); - uint32_t lines = (count < menu->lines ? count : menu->lines) + 1; - bm_wl_window_render(&wayland->window, menu, lines); + bm_wl_window_render(&wayland->window, menu); wayland->input.last_code = wayland->input.code; } } diff --git a/lib/renderers/wayland/wayland.h b/lib/renderers/wayland/wayland.h index 886a0fd..d6c0915 100644 --- a/lib/renderers/wayland/wayland.h +++ b/lib/renderers/wayland/wayland.h @@ -85,7 +85,7 @@ struct window { uint32_t displayed; struct { - uint32_t (*render)(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu); + void (*render)(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu, struct cairo_paint_result *result); } notify; }; @@ -111,7 +111,7 @@ struct wayland { void bm_wl_repeat(struct wayland *wayland); bool bm_wl_registry_register(struct wayland *wayland); void bm_wl_registry_destroy(struct wayland *wayland); -void bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines); +void bm_wl_window_render(struct window *window, const struct bm_menu *menu); bool bm_wl_window_create(struct window *window, struct wl_shm *shm, struct wl_shell *shell, struct xdg_shell *xdg_shell, struct wl_surface *surface); void bm_wl_window_destroy(struct window *window); diff --git a/lib/renderers/wayland/window.c b/lib/renderers/wayland/window.c index d70d43b..a9c9edc 100644 --- a/lib/renderers/wayland/window.c +++ b/lib/renderers/wayland/window.c @@ -248,7 +248,7 @@ static const struct wl_callback_listener listener = { }; void -bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines) +bm_wl_window_render(struct window *window, const struct bm_menu *menu) { assert(window && menu); @@ -256,22 +256,25 @@ bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t return; struct buffer *buffer; - if (!(buffer = next_buffer(window))) { - fprintf(stderr, "could not get next buffer"); - exit(EXIT_FAILURE); - } + for (int tries = 0; tries < 2; ++tries) { + if (!(buffer = next_buffer(window))) { + fprintf(stderr, "could not get next buffer"); + exit(EXIT_FAILURE); + } - cairo_font_extents_t fe; - bm_cairo_get_font_extents(&buffer->cairo, &menu->font, &fe); - window->height = MIN(lines * (fe.height + 4), window->max_height); + if (!window->notify.render) + break; - if (window->height != buffer->height && !(buffer = next_buffer(window))) { - fprintf(stderr, "could not get next buffer"); - exit(EXIT_FAILURE); - } + struct cairo_paint_result result; + window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu, &result); + window->displayed = result.displayed; + + if (window->height == result.height) + break; - if (window->notify.render) - window->displayed = window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu); + window->height = result.height; + destroy_buffer(buffer); + } window->frame_cb = wl_surface_frame(window->surface); wl_callback_add_listener(window->frame_cb, &listener, window); |