summaryrefslogtreecommitdiff
path: root/lib/renderers
diff options
context:
space:
mode:
Diffstat (limited to 'lib/renderers')
-rw-r--r--lib/renderers/cairo.h172
-rw-r--r--lib/renderers/curses/curses.c14
-rw-r--r--lib/renderers/wayland/wayland.c44
-rw-r--r--lib/renderers/wayland/wayland.h3
-rw-r--r--lib/renderers/wayland/window.c92
5 files changed, 225 insertions, 100 deletions
diff --git a/lib/renderers/cairo.h b/lib/renderers/cairo.h
index 9c1ff5a..1dc052f 100644
--- a/lib/renderers/cairo.h
+++ b/lib/renderers/cairo.h
@@ -6,6 +6,10 @@
#include <assert.h>
#include <cairo/cairo.h>
+#ifndef MAX
+# define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
struct cairo {
cairo_t *cr;
cairo_surface_t *surface;
@@ -15,26 +19,23 @@ struct cairo_color {
float r, g, b, a;
};
-struct cairo_font {
- const char *name;
- uint32_t size;
-};
-
struct cairo_paint {
- struct cairo_color color;
- struct cairo_font font;
+ struct cairo_color fg;
+ struct cairo_color bg;
+ cairo_font_extents_t fe;
};
struct cairo_result {
cairo_text_extents_t te;
};
-__attribute__((unused)) BM_LOG_ATTR(6, 7) static bool
-bm_cairo_draw_line(struct cairo *cairo, struct cairo_paint *paint, struct cairo_result *result, int32_t x, int32_t y, const char *fmt, ...)
+static size_t blen = 0;
+static char *buffer = NULL;
+
+__attribute__((unused)) BM_LOG_ATTR(3, 4) static bool
+bm_cairo_get_text_extents(struct cairo *cairo, struct cairo_result *result, const char *fmt, ...)
{
- static size_t blen = 0;
- static char *buffer = NULL;
- assert(cairo && paint && result && fmt);
+ assert(cairo && result && fmt);
memset(result, 0, sizeof(struct cairo_result));
va_list args;
@@ -45,13 +46,33 @@ bm_cairo_draw_line(struct cairo *cairo, struct cairo_paint *paint, struct cairo_
if (!ret)
return false;
- cairo_set_source_rgba(cairo->cr, paint->color.r, paint->color.b, paint->color.g, paint->color.a);
+ cairo_text_extents(cairo->cr, buffer, &result->te);
+ return true;
+}
+
+__attribute__((unused)) BM_LOG_ATTR(8, 9) static bool
+bm_cairo_draw_line(struct cairo *cairo, struct cairo_paint *paint, struct cairo_result *result, uint32_t xoff, uint32_t w, int32_t x, int32_t y, const char *fmt, ...)
+{
+ assert(cairo && paint && result && fmt);
+ memset(result, 0, sizeof(struct cairo_result));
+
+ va_list args;
+ va_start(args, fmt);
+ bool ret = bm_vrprintf(&buffer, &blen, fmt, args);
+ va_end(args);
+
+ if (!ret)
+ return false;
cairo_text_extents_t te;
- cairo_select_font_face(cairo->cr, paint->font.name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size(cairo->cr, paint->font.size);
cairo_text_extents(cairo->cr, buffer, &te);
- cairo_move_to(cairo->cr, x, y * te.height + te.height);
+
+ cairo_set_source_rgba(cairo->cr, paint->bg.r, paint->bg.b, paint->bg.g, paint->bg.a);
+ cairo_rectangle(cairo->cr, x - xoff, y, (w > 0 ? w : te.width) + xoff, paint->fe.height);
+ 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, x, y + paint->fe.descent + paint->fe.height * 0.5);
cairo_show_text(cairo->cr, buffer);
memcpy(&result->te, &te, sizeof(te));
@@ -59,41 +80,108 @@ bm_cairo_draw_line(struct cairo *cairo, struct cairo_paint *paint, struct cairo_
}
__attribute__((unused)) static void
+bm_cairo_color_from_menu_color(const struct bm_menu *menu, enum bm_color color, struct cairo_color *c)
+{
+ assert(menu);
+ c->r = (float)menu->colors[color].r / 255.0f;
+ c->g = (float)menu->colors[color].g / 255.0f;
+ c->b = (float)menu->colors[color].b / 255.0f;
+ 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)
{
- cairo_set_source_rgb(cairo->cr, 18.0f / 255.0f, 18 / 255.0f, 18.0f / 255.0f);
+ assert(cairo && menu);
+
+ struct cairo_color c;
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_BG, &c);
+ cairo_set_source_rgb(cairo->cr, c.r, c.g, c.b);
cairo_rectangle(cairo->cr, 0, 0, width, height);
cairo_fill(cairo->cr);
- struct cairo_result result;
- memset(&result, 0, sizeof(result));
+ cairo_select_font_face(cairo->cr, menu->font.name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(cairo->cr, menu->font.size);
struct cairo_paint paint;
memset(&paint, 0, sizeof(paint));
- paint.font.name = "Terminus";
- paint.font.size = 12;
- paint.color = (struct cairo_color){ 1.0, 0.0, 0.0, 1.0 };
-
- if (menu->title)
- bm_cairo_draw_line(cairo, &paint, &result, result.te.x_advance, 0, "%s ", menu->title);
- if (menu->filter)
- bm_cairo_draw_line(cairo, &paint, &result, result.te.x_advance, 0, "%s", menu->filter);
-
- uint32_t count, cl = 1;
- uint32_t lines = height / paint.font.size;
- 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) {
- bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
-
- if (highlighted)
- paint.color = (struct cairo_color){ 1.0, 0.0, 0.0, 1.0 };
- else if (bm_menu_item_is_selected(menu, items[i]))
- paint.color = (struct cairo_color){ 1.0, 0.0, 0.0, 1.0 };
- else
- paint.color = (struct cairo_color){ 1.0, 1.0, 1.0, 1.0 };
-
- bm_cairo_draw_line(cairo, &paint, &result, 0, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : ""));
+ cairo_font_extents(cairo->cr, &paint.fe);
+
+ struct cairo_result result;
+ memset(&result, 0, sizeof(result));
+
+ 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);
+ bm_cairo_draw_line(cairo, &paint, &result, 0, 0, result.te.x_advance, 4, "%s", menu->title);
+ }
+
+ 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_draw_line(cairo, &paint, &result, 0, width, result.te.x_advance, 4, "%s%s", (menu->title ? " " : ""), (menu->filter ? menu->filter : ""));
+
+ uint32_t displayed = 1;
+ uint32_t lines = MAX(height / paint.fe.height, menu->lines);
+ if (lines > 1) {
+ 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) {
+ bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
+
+ if (highlighted) {
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_FG, &paint.fg);
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_BG, &paint.bg);
+ } else if (bm_menu_item_is_selected(menu, items[i])) {
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_SELECTED_FG, &paint.fg);
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_SELECTED_BG, &paint.bg);
+ } else {
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_ITEM_FG, &paint.fg);
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_ITEM_BG, &paint.bg);
+ }
+
+ bm_cairo_draw_line(cairo, &paint, &result, 0, width, 0, 4 + paint.fe.height * cl++,
+ "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : ""));
+
+ ++displayed;
+ }
+ } else {
+ uint32_t count;
+ struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
+
+ uint32_t cl = width / 4;
+ if (menu->wrap || menu->index > 0) {
+ bm_cairo_draw_line(cairo, &paint, &result, 0, 0, cl, 4, "<");
+ cl += result.te.x_advance + 4;
+ }
+
+ for (uint32_t i = menu->index; i < count && cl < width; ++i) {
+ bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
+
+ if (highlighted) {
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_FG, &paint.fg);
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_HIGHLIGHTED_BG, &paint.bg);
+ } else if (bm_menu_item_is_selected(menu, items[i])) {
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_SELECTED_FG, &paint.fg);
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_SELECTED_BG, &paint.bg);
+ } else {
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_ITEM_FG, &paint.fg);
+ bm_cairo_color_from_menu_color(menu, BM_COLOR_ITEM_BG, &paint.bg);
+ }
+
+ bm_cairo_draw_line(cairo, &paint, &result, 0, 0, cl, 4, "%s", (items[i]->text ? items[i]->text : ""));
+ cl += result.te.x_advance + 4;
+ displayed += (cl < width);
+ }
+
+ 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, ">");
+ bm_cairo_draw_line(cairo, &paint, &result, 4, result.te.x_advance + 4, width - result.te.x_advance - 4, 4, ">");
+ }
}
+
+ return displayed;
}
#endif /* _BM_CAIRO_H */
diff --git a/lib/renderers/curses/curses.c b/lib/renderers/curses/curses.c
index c40e833..5771afa 100644
--- a/lib/renderers/curses/curses.c
+++ b/lib/renderers/curses/curses.c
@@ -156,7 +156,6 @@ render(const struct bm_menu *menu)
init_pair(2, COLOR_RED, -1);
}
- const uint32_t lines = getmaxy(curses.stdscr);
erase();
uint32_t ncols = getmaxx(curses.stdscr);
@@ -183,11 +182,14 @@ render(const struct bm_menu *menu)
}
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) {
- bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
- int32_t color = (highlighted ? 2 : (bm_menu_item_is_selected(menu, items[i]) ? 1 : 0));
- draw_line(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : ""));
+ const uint32_t lines = getmaxy(curses.stdscr);
+ if (lines > 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) {
+ bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
+ int32_t color = (highlighted ? 2 : (bm_menu_item_is_selected(menu, items[i]) ? 1 : 0));
+ draw_line(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : ""));
+ }
}
move(0, title_len + (menu->curses_cursor < ccols ? menu->curses_cursor : ccols));
diff --git a/lib/renderers/wayland/wayland.c b/lib/renderers/wayland/wayland.c
index 0d5fcde..c6f8f8b 100644
--- a/lib/renderers/wayland/wayland.c
+++ b/lib/renderers/wayland/wayland.c
@@ -11,6 +11,9 @@ static void
render(const struct bm_menu *menu)
{
struct wayland *wayland = menu->renderer->internal;
+ uint32_t count;
+ bm_menu_get_filtered_items(menu, &count);
+ wayland->window.height = ((count < menu->lines ? count : menu->lines) + 1) * menu->font.size + 4;
bm_wl_window_render(&wayland->window, menu);
wl_display_dispatch(wayland->display);
}
@@ -25,6 +28,7 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode)
if (wayland->input.sym == XKB_KEY_NoSymbol)
return BM_KEY_UNICODE;
+ uint32_t mods = wayland->input.modifiers;
*unicode = xkb_state_key_get_utf32(wayland->input.xkb.state, wayland->input.code);
switch (wayland->input.sym) {
@@ -47,16 +51,16 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode)
return BM_KEY_END;
case XKB_KEY_SunPageUp:
- return BM_KEY_PAGE_UP;
+ return (mods & MOD_SHIFT ? BM_KEY_SHIFT_PAGE_UP : BM_KEY_PAGE_UP);
case XKB_KEY_SunPageDown:
- return BM_KEY_PAGE_DOWN;
+ return (mods & MOD_SHIFT ? BM_KEY_SHIFT_PAGE_DOWN : BM_KEY_PAGE_DOWN);
case XKB_KEY_BackSpace:
return BM_KEY_BACKSPACE;
case XKB_KEY_Delete:
- return BM_KEY_DELETE;
+ return (mods & MOD_SHIFT ? BM_KEY_LINE_DELETE_LEFT : BM_KEY_DELETE);
case XKB_KEY_Tab:
return BM_KEY_TAB;
@@ -65,11 +69,41 @@ poll_key(const struct bm_menu *menu, unsigned int *unicode)
return BM_KEY_SHIFT_RETURN;
case XKB_KEY_Return:
- return BM_KEY_RETURN;
+ return (mods & MOD_CTRL ? BM_KEY_CONTROL_RETURN : (mods & MOD_SHIFT ? BM_KEY_SHIFT_RETURN : BM_KEY_RETURN));
case XKB_KEY_Escape:
return BM_KEY_ESCAPE;
+ case XKB_KEY_p:
+ return (mods & MOD_CTRL ? BM_KEY_UP : BM_KEY_UNICODE);
+
+ case XKB_KEY_n:
+ return (mods & MOD_CTRL ? BM_KEY_DOWN : BM_KEY_UNICODE);
+
+ case XKB_KEY_l:
+ return (mods & MOD_CTRL ? BM_KEY_LEFT : BM_KEY_UNICODE);
+
+ case XKB_KEY_f:
+ return (mods & MOD_CTRL ? BM_KEY_RIGHT : BM_KEY_UNICODE);
+
+ case XKB_KEY_a:
+ return (mods & MOD_CTRL ? BM_KEY_HOME : BM_KEY_UNICODE);
+
+ case XKB_KEY_e:
+ return (mods & MOD_CTRL ? BM_KEY_END : BM_KEY_UNICODE);
+
+ case XKB_KEY_h:
+ return (mods & MOD_CTRL ? BM_KEY_BACKSPACE : BM_KEY_UNICODE);
+
+ case XKB_KEY_u:
+ return (mods & MOD_CTRL ? BM_KEY_LINE_DELETE_LEFT : BM_KEY_UNICODE);
+
+ case XKB_KEY_k:
+ return (mods & MOD_CTRL ? BM_KEY_LINE_DELETE_RIGHT : BM_KEY_UNICODE);
+
+ case XKB_KEY_w:
+ return (mods & MOD_CTRL ? BM_KEY_WORD_DELETE : BM_KEY_UNICODE);
+
default: break;
}
@@ -81,7 +115,7 @@ get_displayed_count(const struct bm_menu *menu)
{
struct wayland *wayland = menu->renderer->internal;
assert(wayland);
- return wayland->window.height / 12;
+ return wayland->window.displayed;
}
static void
diff --git a/lib/renderers/wayland/wayland.h b/lib/renderers/wayland/wayland.h
index fd29405..d698218 100644
--- a/lib/renderers/wayland/wayland.h
+++ b/lib/renderers/wayland/wayland.h
@@ -70,9 +70,10 @@ struct window {
struct wl_shm *shm;
struct buffer buffers[2];
uint32_t width, height;
+ uint32_t displayed;
struct {
- void (*render)(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu);
+ uint32_t (*render)(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu);
} notify;
};
diff --git a/lib/renderers/wayland/window.c b/lib/renderers/wayland/window.c
index 9234ef2..21555b8 100644
--- a/lib/renderers/wayland/window.c
+++ b/lib/renderers/wayland/window.c
@@ -13,79 +13,79 @@
static int
set_cloexec_or_close(int fd)
{
- if (fd == -1)
- return -1;
+ if (fd == -1)
+ return -1;
- long flags = fcntl(fd, F_GETFD);
- if (flags == -1)
- goto err;
+ long flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ goto err;
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
- goto err;
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ goto err;
- return fd;
+ return fd;
err:
- close(fd);
- return -1;
+ close(fd);
+ return -1;
}
static int
create_tmpfile_cloexec(char *tmpname)
{
- int fd;
+ int fd;
#ifdef HAVE_MKOSTEMP
- if ((fd = mkostemp(tmpname, O_CLOEXEC)) >= 0)
- unlink(tmpname);
+ if ((fd = mkostemp(tmpname, O_CLOEXEC)) >= 0)
+ unlink(tmpname);
#else
- if ((fd = mkstemp(tmpname)) >= 0) {
- fd = set_cloexec_or_close(fd);
- unlink(tmpname);
- }
+ if ((fd = mkstemp(tmpname)) >= 0) {
+ fd = set_cloexec_or_close(fd);
+ unlink(tmpname);
+ }
#endif
- return fd;
+ return fd;
}
static int
os_create_anonymous_file(off_t size)
{
- static const char template[] = "/bemenu-shared-XXXXXX";
- int fd;
- int ret;
-
- const char *path;
- if (!(path = getenv("XDG_RUNTIME_DIR")) || strlen(path) <= 0) {
- errno = ENOENT;
- return -1;
- }
+ static const char template[] = "/bemenu-shared-XXXXXX";
+ int fd;
+ int ret;
+
+ const char *path;
+ if (!(path = getenv("XDG_RUNTIME_DIR")) || strlen(path) <= 0) {
+ errno = ENOENT;
+ return -1;
+ }
- char *name;
- int ts = (path[strlen(path) - 1] == '/');
- if (!(name = bm_dprintf("%s%s%s", path, (ts ? "" : "/"), template)))
- return -1;
+ char *name;
+ int ts = (path[strlen(path) - 1] == '/');
+ if (!(name = bm_dprintf("%s%s%s", path, (ts ? "" : "/"), template)))
+ return -1;
- fd = create_tmpfile_cloexec(name);
- free(name);
+ fd = create_tmpfile_cloexec(name);
+ free(name);
- if (fd < 0)
- return -1;
+ if (fd < 0)
+ return -1;
#ifdef HAVE_POSIX_FALLOCATE
- if ((ret = posix_fallocate(fd, 0, size)) != 0) {
- close(fd);
- errno = ret;
- return -1;
- }
+ if ((ret = posix_fallocate(fd, 0, size)) != 0) {
+ close(fd);
+ errno = ret;
+ return -1;
+ }
#else
- if ((ret = ftruncate(fd, size)) < 0) {
- close(fd);
- return -1;
- }
+ if ((ret = ftruncate(fd, size)) < 0) {
+ close(fd);
+ return -1;
+ }
#endif
- return fd;
+ return fd;
}
static void
@@ -256,7 +256,7 @@ bm_wl_window_render(struct window *window, const struct bm_menu *menu)
return;
if (window->notify.render)
- window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu);
+ window->displayed = window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu);
wl_surface_damage(window->surface, 0, 0, buffer->width, buffer->height);
wl_surface_attach(window->surface, buffer->buffer, 0, 0);