summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2014-10-25 20:02:34 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2014-10-25 20:02:34 +0300
commitd3db039136ad66d2c83c1c0fbf0964bfbb5afb16 (patch)
tree93af6d73ad168e0169183a9c4f625acd5492e08c
parent2820734ec01ad6d2e1a0611fa480c3dd533588c7 (diff)
downloadbemenu-d3db039136ad66d2c83c1c0fbf0964bfbb5afb16.tar.gz
bemenu-d3db039136ad66d2c83c1c0fbf0964bfbb5afb16.tar.bz2
bemenu-d3db039136ad66d2c83c1c0fbf0964bfbb5afb16.zip
Single line mode, color customization, etc..
-rw-r--r--client/client.c81
-rw-r--r--lib/bemenu.h77
-rw-r--r--lib/internal.h48
-rw-r--r--lib/library.c2
-rw-r--r--lib/menu.c111
-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
10 files changed, 526 insertions, 118 deletions
diff --git a/client/client.c b/client/client.c
index 95c270e..52933d1 100644
--- a/client/client.c
+++ b/client/client.c
@@ -13,8 +13,11 @@ static struct {
enum bm_filter_mode filter_mode;
int32_t wrap;
uint32_t lines;
+ const char *colors[BM_COLOR_LAST];
const char *title;
const char *renderer;
+ char *font;
+ uint32_t font_size;
int32_t selected;
int32_t bottom;
int32_t grab;
@@ -24,8 +27,11 @@ static struct {
.filter_mode = BM_FILTER_MODE_DMENU,
.wrap = 0,
.lines = 0,
+ .colors = {0},
.title = "bemenu",
.renderer = NULL,
+ .font = NULL,
+ .font_size = 0,
.selected = 0,
.bottom = 0,
.grab = 0,
@@ -99,11 +105,18 @@ usage(FILE *out, const char *name)
" -b, --bottom appears at the bottom of the screen. ()\n"
" -f, --grab grabs the keyboard before reading stdin. ()\n"
" -m, --monitor index of monitor where menu will appear. ()\n"
- " --fn defines the font to be used. ()\n"
- " --nb defines the normal background color. ()\n"
- " --nf defines the normal foreground color. ()\n"
- " --sb defines the selected background color. ()\n"
- " --sf defines the selected foreground color. ()\n", out);
+ " --fn defines the font to be used. (w)\n"
+ " --bg defines the background color. (w)\n"
+ " --tb defines the title background color. (w)\n"
+ " --tf defines the title foreground color. (w)\n"
+ " --fb defines the filter background color. (w)\n"
+ " --ff defines the filter foreground color. (w)\n"
+ " --nb defines the normal background color. (w)\n"
+ " --nf defines the normal foreground color. (w)\n"
+ " --hb defines the highlighted background color. (w)\n"
+ " --hf defines the highlighted foreground color. (w)\n"
+ " --sb defines the selected background color. (w)\n"
+ " --sf defines the selected foreground color. (w)\n", out);
exit((out == stderr ? EXIT_FAILURE : EXIT_SUCCESS));
}
@@ -126,12 +139,19 @@ parse_args(int *argc, char **argv[])
{ "grab", no_argument, 0, 'f' },
{ "monitor", required_argument, 0, 'm' },
{ "fn", required_argument, 0, 0x102 },
- { "nb", required_argument, 0, 0x103 },
- { "nf", required_argument, 0, 0x104 },
- { "sb", required_argument, 0, 0x105 },
- { "sf", required_argument, 0, 0x106 },
-
- { "disco", no_argument, 0, 0x107 },
+ { "bg", required_argument, 0, 0x103 },
+ { "tb", required_argument, 0, 0x104 },
+ { "tf", required_argument, 0, 0x105 },
+ { "fb", required_argument, 0, 0x106 },
+ { "ff", required_argument, 0, 0x107 },
+ { "nb", required_argument, 0, 0x108 },
+ { "nf", required_argument, 0, 0x109 },
+ { "hb", required_argument, 0, 0x110 },
+ { "hf", required_argument, 0, 0x111 },
+ { "sb", required_argument, 0, 0x112 },
+ { "sf", required_argument, 0, 0x113 },
+
+ { "disco", no_argument, 0, 0x114 },
{ 0, 0, 0, 0 }
};
@@ -190,13 +210,44 @@ parse_args(int *argc, char **argv[])
break;
case 0x102:
+ if (sscanf(optarg, "%ms:%u", &client.font, &client.font_size) < 2)
+ sscanf(optarg, "%ms", &client.font);
+ break;
case 0x103:
+ client.colors[BM_COLOR_BG] = optarg;
+ break;
case 0x104:
+ client.colors[BM_COLOR_TITLE_BG] = optarg;
+ break;
case 0x105:
+ client.colors[BM_COLOR_TITLE_FG] = optarg;
+ break;
case 0x106:
+ client.colors[BM_COLOR_FILTER_BG] = optarg;
break;
-
case 0x107:
+ client.colors[BM_COLOR_FILTER_FG] = optarg;
+ break;
+ case 0x108:
+ client.colors[BM_COLOR_ITEM_BG] = optarg;
+ break;
+ case 0x109:
+ client.colors[BM_COLOR_ITEM_FG] = optarg;
+ break;
+ case 0x110:
+ client.colors[BM_COLOR_HIGHLIGHTED_BG] = optarg;
+ break;
+ case 0x111:
+ client.colors[BM_COLOR_HIGHLIGHTED_FG] = optarg;
+ break;
+ case 0x112:
+ client.colors[BM_COLOR_SELECTED_BG] = optarg;
+ break;
+ case 0x113:
+ client.colors[BM_COLOR_SELECTED_FG] = optarg;
+ break;
+
+ case 0x114:
disco();
break;
@@ -267,10 +318,15 @@ main(int argc, char **argv)
if (!(menu = bm_menu_new(client.renderer, client.prioritory)))
return EXIT_FAILURE;
+ bm_menu_set_font(menu, client.font, client.font_size);
bm_menu_set_title(menu, client.title);
bm_menu_set_filter_mode(menu, client.filter_mode);
+ bm_menu_set_lines(menu, client.lines);
bm_menu_set_wrap(menu, client.wrap);
+ for (uint32_t i = 0; i < BM_COLOR_LAST; ++i)
+ bm_menu_set_color(menu, i, client.colors[i]);
+
read_items_to_menu_from_stdin(menu);
bm_menu_set_highlighted_index(menu, client.selected);
@@ -295,6 +351,7 @@ main(int argc, char **argv)
printf("%s\n", bm_menu_get_filter(menu));
}
+ free(client.font);
bm_menu_free(menu);
return (status == BM_RUN_RESULT_SELECTED ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/lib/bemenu.h b/lib/bemenu.h
index 20574f6..c52135d 100644
--- a/lib/bemenu.h
+++ b/lib/bemenu.h
@@ -183,6 +183,26 @@ enum bm_key {
};
/**
+ * Colorable element constants.
+ *
+ * @link ::bm_color BM_COLOR_LAST @endlink is provided for enumerating colors.
+ */
+enum bm_color {
+ BM_COLOR_BG,
+ BM_COLOR_TITLE_BG,
+ BM_COLOR_TITLE_FG,
+ BM_COLOR_FILTER_BG,
+ BM_COLOR_FILTER_FG,
+ BM_COLOR_ITEM_BG,
+ BM_COLOR_ITEM_FG,
+ BM_COLOR_HIGHLIGHTED_BG,
+ BM_COLOR_HIGHLIGHTED_FG,
+ BM_COLOR_SELECTED_BG,
+ BM_COLOR_SELECTED_FG,
+ BM_COLOR_LAST
+};
+
+/**
* @name Menu Memory
* @{ */
@@ -265,10 +285,27 @@ void bm_menu_set_filter_mode(struct bm_menu *menu, enum bm_filter_mode mode);
enum bm_filter_mode bm_menu_get_filter_mode(const struct bm_menu *menu);
/**
+ * Set amount of max vertical lines to be shown.
+ * Some renderers such as ncurses may ignore this when it does not make sense.
+ *
+ * @param menu bm_menu instance where to set max vertical line amount.
+ * @param lines 0 for single line layout, > 0 to show that many lines.
+ */
+void bm_menu_set_lines(struct bm_menu *menu, uint32_t lines);
+
+/**
+ * Get amount of max vertical lines to be shown.
+ *
+ * @param menu bm_menu instance where to get max vertical line amount.
+ * @return uint32_t for max amount of vertical lines to be shown.
+ */
+uint32_t bm_menu_get_lines(struct bm_menu *menu);
+
+/**
* Set selection wrapping on/off.
*
* @param menu bm_menu instance where to toggle selection wrapping.
- * @param bool true/false.
+ * @param wrap true/false.
*/
void bm_menu_set_wrap(struct bm_menu *menu, bool wrap);
@@ -297,6 +334,44 @@ bool bm_menu_set_title(struct bm_menu *menu, const char *title);
*/
const char* bm_menu_get_title(const struct bm_menu *menu);
+/**
+ * Set font to bm_menu instance.
+ *
+ * @param font C "string" to set as font, can be **NULL** for default (Terminus).
+ * @param size Size for the font, may be set 0 for default.
+ * @return true if set was succesful, false if out of memory.
+ */
+bool bm_menu_set_font(struct bm_menu *menu, const char *font, uint32_t size);
+
+/**
+ * Get font from bm_menu instance.
+ *
+ * @param menu bm_menu instance where to get font from.
+ * @param out_size Reference to uint32_t, will be se to size of the font. May set **NULL** for no-op.
+ * @return Pointer to null terminated C "string".
+ */
+const char* bm_menu_get_font(const struct bm_menu *menu, uint32_t *out_size);
+
+/**
+ * Set a hexadecimal color for element.
+ *
+ * @param menu bm_menu instance where to set color.
+ * @param color bm_color type.
+ * @param hex Color in hexadecimal format starting with '#'.
+ * @return true if set was succesful, false if out of memory.
+ */
+bool bm_menu_set_color(struct bm_menu *menu, enum bm_color color, const char *hex);
+
+/**
+ * Get hexadecimal color for element.
+ *
+ * @param menu bm_menu instance where to get color from.
+ * @param color bm_color type.
+ * @return Pointer to null terminated C "string".
+ */
+const char* bm_menu_get_color(const struct bm_menu *menu, enum bm_color color);
+
+
/** @} Properties */
/**
diff --git a/lib/internal.h b/lib/internal.h
index 6613cef..b9b4a5e 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -134,6 +134,38 @@ struct bm_item {
};
/**
+ * Internal bm_hex_color struct that is not exposed to public.
+ * Represent a color for element.
+ */
+struct bm_hex_color {
+ /**
+ * Provided hex for the color.
+ */
+ char *hex;
+
+ /**
+ * RGB values.
+ */
+ uint8_t r, g, b;
+};
+
+/**
+ * Internal bm_font struct that is not exposed to public.
+ * Represent a font for text.
+ */
+struct bm_font {
+ /**
+ * Name of the font.
+ */
+ char *name;
+
+ /**
+ * Size of font.
+ */
+ uint32_t size;
+};
+
+/**
* Internal bm_menu struct that is not exposed to public.
*/
struct bm_menu {
@@ -169,6 +201,16 @@ struct bm_menu {
char *title;
/**
+ * Font.
+ */
+ struct bm_font font;
+
+ /**
+ * Colors.
+ */
+ struct bm_hex_color colors[BM_COLOR_LAST];
+
+ /**
* Text used to filter matches.
*/
char *filter;
@@ -200,6 +242,12 @@ struct bm_menu {
uint32_t index;
/**
+ * Max number of vertical lines to be shown.
+ * Some renderers such as ncurses may ignore this when it does not make sense.
+ */
+ uint32_t lines;
+
+ /**
* Current filtering method in menu instance.
*/
enum bm_filter_mode filter_mode;
diff --git a/lib/library.c b/lib/library.c
index 7fca099..4d7e212 100644
--- a/lib/library.c
+++ b/lib/library.c
@@ -30,7 +30,7 @@ load(const char *file, struct bm_renderer *renderer)
const char *error = NULL;
if (!(handle = chckDlLoad(file, &error)))
- goto fail;
+ goto load_fail;
const char* (*regfun)(struct render_api*);
if (!(regfun = chckDlLoadSymbol(handle, "register_renderer", &error)))
diff --git a/lib/menu.c b/lib/menu.c
index 594344c..43de830 100644
--- a/lib/menu.c
+++ b/lib/menu.c
@@ -1,10 +1,33 @@
#include "internal.h"
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
/**
+ * Default font.
+ */
+static const char *default_font = "Terminus";
+
+/**
+ * Default hexadecimal colors.
+ */
+static const char *default_colors[BM_COLOR_LAST] = {
+ "#121212", // BM_COLOR_BG
+ "#121212", // BM_COLOR_TITLE_BG
+ "#D81860", // BM_COLOR_TITLE_FG
+ "#121212", // BM_COLOR_FILTER_BG
+ "#CACACA", // BM_COLOR_FILTER_FG
+ "#121212", // BM_COLOR_ITEM_BG
+ "#CACACA", // BM_COLOR_ITEM_FG
+ "#121212", // BM_COLOR_HIGHLIGHTED_BG
+ "#D81860", // BM_COLOR_HIGHLIGHTED_FG
+ "#121212", // BM_COLOR_SELECTED_BG
+ "#D81860" // BM_COLOR_SELECTED_FG
+};
+
+/**
* Filter function map.
*/
static struct bm_item** (*filter_func[BM_FILTER_MODE_LAST])(struct bm_menu *menu, bool addition, uint32_t *out_nmemb) = {
@@ -51,12 +74,21 @@ bm_menu_new(const char *renderer, enum bm_prioritory prioritory)
break;
}
- if (!menu->renderer) {
- bm_menu_free(menu);
- return NULL;
- }
+ if (!menu->renderer)
+ goto fail;
+ if (!bm_menu_set_font(menu, NULL, 0))
+ goto fail;
+
+ for (uint32_t i = 0; i < BM_COLOR_LAST; ++i) {
+ if (!bm_menu_set_color(menu, i, NULL))
+ goto fail;
+ }
return menu;
+
+fail:
+ bm_menu_free(menu);
+ return NULL;
}
void
@@ -71,6 +103,11 @@ bm_menu_free(struct bm_menu *menu)
free(menu->filter);
free(menu->old_filter);
+ free(menu->font.name);
+
+ for (uint32_t i = 0; i < BM_COLOR_LAST; ++i)
+ free(menu->colors[i].hex);
+
bm_menu_free_items(menu);
free(menu);
}
@@ -130,6 +167,20 @@ bm_menu_get_filter_mode(const struct bm_menu *menu)
}
void
+bm_menu_set_lines(struct bm_menu *menu, uint32_t lines)
+{
+ assert(menu);
+ menu->lines = lines;
+}
+
+uint32_t
+bm_menu_get_lines(struct bm_menu *menu)
+{
+ assert(menu);
+ return menu->lines;
+}
+
+void
bm_menu_set_wrap(struct bm_menu *menu, bool wrap)
{
assert(menu);
@@ -165,6 +216,58 @@ bm_menu_get_title(const struct bm_menu *menu)
}
bool
+bm_menu_set_font(struct bm_menu *menu, const char *font, uint32_t size)
+{
+ assert(menu);
+
+ const char *nfont = (font ? font : default_font);
+
+ char *copy = NULL;
+ if (!(copy = bm_strdup(nfont)))
+ return false;
+
+ free(menu->font.name);
+ menu->font.name = copy;
+ menu->font.size = (size > 0 ? size : 12);
+ return true;
+}
+
+const char* bm_menu_get_font(const struct bm_menu *menu, uint32_t *out_size)
+{
+ assert(menu);
+ if (out_size) *out_size = menu->font.size;
+ return menu->font.name;
+}
+
+bool bm_menu_set_color(struct bm_menu *menu, enum bm_color color, const char *hex)
+{
+ assert(menu);
+
+ const char *nhex = (hex ? hex : default_colors[color]);
+
+ int32_t r, g, b;
+ if (sscanf(nhex,"#%2x%2x%2x", &r, &b, &g) != 3)
+ return false;
+
+ char *copy = NULL;
+ if (!(copy = bm_strdup(nhex)))
+ return false;
+
+ free(menu->colors[color].hex);
+ menu->colors[color].hex = copy;
+ menu->colors[color].r = r;
+ menu->colors[color].g = g;
+ menu->colors[color].b = b;
+ return true;
+}
+
+const char* bm_menu_get_color(const struct bm_menu *menu, enum bm_color color)
+{
+ assert(menu);
+ return menu->colors[color].hex;
+}
+
+bool
bm_menu_add_items_at(struct bm_menu *menu, struct bm_item *item, uint32_t index)
{
assert(menu);
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);