diff options
| author | Jari Vetoniemi <mailroxas@gmail.com> | 2015-01-15 22:18:23 +0200 | 
|---|---|---|
| committer | Jari Vetoniemi <mailroxas@gmail.com> | 2015-01-15 22:18:23 +0200 | 
| commit | 2bf8bbfcde0f2cb4d2ddc7a633d1f03933368c0a (patch) | |
| tree | bb41f5c4abacd887f257004ebb171388ac95df11 | |
| parent | 9baca87123f9da3fbf53360fee7527b43197efc5 (diff) | |
| download | bemenu-2bf8bbfcde0f2cb4d2ddc7a633d1f03933368c0a.tar.gz bemenu-2bf8bbfcde0f2cb4d2ddc7a633d1f03933368c0a.tar.bz2 bemenu-2bf8bbfcde0f2cb4d2ddc7a633d1f03933368c0a.zip | |
Working pango code.
| -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); | 
