From 9f13ca2e6d4fd6ce388c9cf5cb098abba01d6a0a Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 25 Oct 2014 20:43:37 +0300 Subject: Share client code, add bemenu-run --- client/CMakeLists.txt | 23 ++-- client/bemenu-run.c | 184 +++++++++++++++++++++++++ client/bemenu.c | 100 ++++++++++++++ client/client.c | 359 ------------------------------------------------- client/common/common.c | 274 +++++++++++++++++++++++++++++++++++++ client/common/common.h | 28 ++++ 6 files changed, 600 insertions(+), 368 deletions(-) create mode 100644 client/bemenu-run.c create mode 100644 client/bemenu.c delete mode 100644 client/client.c create mode 100644 client/common/common.c create mode 100644 client/common/common.h (limited to 'client') diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 6af4e3e..b7cc1d4 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,6 +1,10 @@ # Sources -SET(CLIENT_SOURCE client.c) -SET(CLIENT_INCLUDE ${BEMENU_INCLUDE_DIRS}) +SET(CLIENT_SOURCES + bemenu.c + bemenu-run.c +) + +SET(CLIENT_INCLUDES ${BEMENU_INCLUDE_DIRS} "common") SET(CLIENT_LIBRARIES ${BEMENU_LIBRARIES}) # Warnings @@ -17,12 +21,13 @@ IF (UNIX AND CMAKE_COMPILER_IS_GNUCC) ENDIF () # Compile -INCLUDE_DIRECTORIES(${CLIENT_INCLUDE}) -ADD_EXECUTABLE(client ${CLIENT_SOURCE}) -TARGET_LINK_LIBRARIES(client ${CLIENT_LIBRARIES}) -SET_TARGET_PROPERTIES(client PROPERTIES OUTPUT_NAME bemenu) - -# Install -INSTALL(TARGETS client DESTINATION bin) +FOREACH (SOURCE ${CLIENT_SOURCES}) + INCLUDE_DIRECTORIES(${CLIENT_INCLUDES}) + ADD_EXECUTABLE(${SOURCE} ${SOURCE} common/common.c) + TARGET_LINK_LIBRARIES(${SOURCE} ${CLIENT_LIBRARIES}) + get_filename_component(ONAME ${SOURCE} NAME_WE) + SET_TARGET_PROPERTIES(${SOURCE} PROPERTIES OUTPUT_NAME ${ONAME}) + INSTALL(TARGETS ${SOURCE} DESTINATION bin) +ENDFOREACH () # vim: set ts=8 sw=4 tw=0 : diff --git a/client/bemenu-run.c b/client/bemenu-run.c new file mode 100644 index 0000000..6c7228d --- /dev/null +++ b/client/bemenu-run.c @@ -0,0 +1,184 @@ +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "../lib/3rdparty/tinydir.h" + +static struct client client = { + .prioritory = BM_PRIO_ANY, + .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, + .monitor = 0 +}; + +struct paths { + char *path; + char *paths; +}; + +static char* +c_strdup(const char *str) +{ + size_t size = strlen(str); + char *cpy = calloc(1, size + 1); + return (cpy ? memcpy(cpy, str, size) : NULL); +} + + static char* +strip_slash(char *str) +{ + size_t size = strlen(str); + if (size > 0) + for (char *s = str + size - 1; *s == '/'; --s) + *s = 0; + return str; +} + +static const char* +get_paths(const char *env, const char *default_paths, struct paths *state) +{ + if (state->path && !*state->path) { + free(state->paths); + return NULL; + } + + if (!state->paths) { + const char *paths; + if (!(paths = getenv(env)) || !paths[0]) + paths = default_paths; + + state->path = state->paths = c_strdup(paths); + } + + if (!state->path || !state->paths) + return NULL; + + char *path; + do { + size_t f; + path = state->path; + if ((f = strcspn(state->path, ":")) > 0) { + state->path += f + (path[f] ? 1 : 0); + path[f] = 0; + } + + if (!*path) { + free(state->paths); + return NULL; + } + } while (path[0] != '/'); + + return strip_slash(path); +} + +static void +read_items_to_menu_from_dir(struct bm_menu *menu, const char *path) +{ + assert(menu && path); + + tinydir_dir dir; + if (tinydir_open(&dir, path) == -1) + return; + + while (dir.has_next) { + tinydir_file file; + memset(&file, 0, sizeof(file)); + tinydir_readfile(&dir, &file); + + if (!file.is_dir) { + struct bm_item *item; + if (!(item = bm_item_new(file.name))) + break; + + bm_menu_add_item(menu, item); + } + + tinydir_next(&dir); + } + + tinydir_close(&dir); +} + +static void +read_items_to_menu_from_path(struct bm_menu *menu) +{ + assert(menu); + + const char *path; + struct paths state; + memset(&state, 0, sizeof(state)); + while ((path = get_paths("PATH", "/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/bin:/sbin", &state))) + read_items_to_menu_from_dir(menu, path); +} + +static void +launch(const char *bin) +{ + if (!bin) + return; + + if (fork() == 0) { + setsid(); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + execlp(bin, bin, NULL); + _exit(EXIT_SUCCESS); + } +} + +int +main(int argc, char **argv) +{ + struct sigaction action = { + .sa_handler = SIG_DFL, + .sa_flags = SA_NOCLDWAIT + }; + + // do not care about childs + sigaction(SIGCHLD, &action, NULL); + + if (!bm_init()) + return EXIT_FAILURE; + + parse_args(&client, &argc, &argv); + + struct bm_menu *menu; + if (!(menu = menu_with_options(&client))) + return EXIT_FAILURE; + + read_items_to_menu_from_path(menu); + bm_menu_set_highlighted_index(menu, client.selected); + + enum bm_run_result status = run_menu(menu); + + if (status == BM_RUN_RESULT_SELECTED) { + uint32_t i, count; + struct bm_item **items = bm_menu_get_selected_items(menu, &count); + for (i = 0; i < count; ++i) { + const char *text = bm_item_get_text(items[i]); + launch(text); + } + + if (!count && bm_menu_get_filter(menu)) + launch(bm_menu_get_filter(menu)); + } + + free(client.font); + bm_menu_free(menu); + return (status == BM_RUN_RESULT_SELECTED ? EXIT_SUCCESS : EXIT_FAILURE); +} + +/* vim: set ts=8 sw=4 tw=0 :*/ diff --git a/client/bemenu.c b/client/bemenu.c new file mode 100644 index 0000000..96ad72e --- /dev/null +++ b/client/bemenu.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include "common.h" + +static struct client client = { + .prioritory = BM_PRIO_ANY, + .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, + .monitor = 0 +}; + +static void +read_items_to_menu_from_stdin(struct bm_menu *menu) +{ + assert(menu); + + size_t step = 1024, allocated; + char *buffer; + + if (!(buffer = malloc((allocated = step)))) + return; + + size_t read; + while ((read = fread(buffer + (allocated - step), 1, step, stdin)) == step) { + void *tmp; + if (!(tmp = realloc(buffer, (allocated += step)))) { + free(buffer); + return; + } + buffer = tmp; + } + buffer[allocated - step + read - 1] = 0; + + char *s = buffer; + while ((size_t)(s - buffer) < allocated - step + read) { + size_t pos = strcspn(s, "\n"); + if (pos == 0) { + s += 1; + continue; + } + + s[pos] = 0; + + struct bm_item *item; + if (!(item = bm_item_new(s))) + break; + + bm_menu_add_item(menu, item); + s += pos + 1; + } + + free(buffer); +} + +int +main(int argc, char **argv) +{ + if (!bm_init()) + return EXIT_FAILURE; + + parse_args(&client, &argc, &argv); + + struct bm_menu *menu; + if (!(menu = menu_with_options(&client))) + return EXIT_FAILURE; + + read_items_to_menu_from_stdin(menu); + bm_menu_set_highlighted_index(menu, client.selected); + + enum bm_run_result status = run_menu(menu); + + if (status == BM_RUN_RESULT_SELECTED) { + uint32_t i, count; + struct bm_item **items = bm_menu_get_selected_items(menu, &count); + for (i = 0; i < count; ++i) { + const char *text = bm_item_get_text(items[i]); + printf("%s\n", (text ? text : "")); + } + + if (!count && bm_menu_get_filter(menu)) + 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); +} + +/* vim: set ts=8 sw=4 tw=0 :*/ diff --git a/client/client.c b/client/client.c deleted file mode 100644 index 52933d1..0000000 --- a/client/client.c +++ /dev/null @@ -1,359 +0,0 @@ -#define _DEFAULT_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -static struct { - enum bm_prioritory prioritory; - 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; - int32_t monitor; -} client = { - .prioritory = BM_PRIO_ANY, - .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, - .monitor = 0 -}; - -static void -disco_trap(int sig) -{ - (void)sig; - printf("\e[?25h\n"); - fflush(stdout); - exit(EXIT_FAILURE); -} - -static void -disco(void) -{ - struct sigaction action; - memset(&action, 0, sizeof(struct sigaction)); - action.sa_handler = disco_trap; - sigaction(SIGABRT, &action, NULL); - sigaction(SIGSEGV, &action, NULL); - sigaction(SIGTRAP, &action, NULL); - sigaction(SIGINT, &action, NULL); - - uint32_t cc, c = 80; - printf("\e[?25l"); - while (1) { - for (uint32_t i = 1; i < c - 1; ++i) { - printf("\r %*s%s %s %s ", (i > c / 2 ? c - i : i), " ", ((i % 2) ? ""), ((i % 4) ? "DISCO" : " "), ((i %2) ? "\\o>" : ""), ((i % 2) ? "*" : "•")); - for (cc = 2; cc < (i > c / 2 ? c - i : i); ++cc) printf(((i % 2) ? "^" : "'")); - fflush(stdout); - usleep(140 * 1000); - } - } - printf("\e[?25h"); - exit(EXIT_SUCCESS); -} - -static void -version(const char *name) -{ - char *base = strrchr(name, '/'); - printf("%s v%s\n", (base ? base + 1 : name), bm_version()); - exit(EXIT_SUCCESS); -} - -static void -usage(FILE *out, const char *name) -{ - char *base = strrchr(name, '/'); - fprintf(out, "usage: %s [options]\n", (base ? base + 1 : name)); - fputs("Options\n" - " -h, --help display this help and exit.\n" - " -v, --version display version.\n" - " -i, --ignorecase match items case insensitively.\n" - " -w, --wrap wraps cursor selection.\n" - " -l, --list list items vertically with the given number of lines.\n" - " -p, --prompt defines the prompt text to be displayed.\n" - " -I, --index select item at index automatically.\n" - " --backend options: curses, wayland\n" - " --prioritory options: terminal, gui\n\n" - - "Backend specific options\n" - " c = ncurses, w == wayland\n" - " (...) At end of help indicates the backend support for option.\n\n" - - " -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. (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)); -} - -static void -parse_args(int *argc, char **argv[]) -{ - static const struct option opts[] = { - { "help", no_argument, 0, 'h' }, - { "version", no_argument, 0, 'v' }, - - { "ignorecase", no_argument, 0, 'i' }, - { "wrap", no_argument, 0, 'w' }, - { "list", required_argument, 0, 'l' }, - { "prompt", required_argument, 0, 'p' }, - { "index", required_argument, 0, 'I' }, - { "backend", required_argument, 0, 0x100 }, - { "prioritory", required_argument, 0, 0x101 }, - - { "bottom", no_argument, 0, 'b' }, - { "grab", no_argument, 0, 'f' }, - { "monitor", required_argument, 0, 'm' }, - { "fn", required_argument, 0, 0x102 }, - { "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 } - }; - - /* TODO: getopt does not support -sf, -sb etc.. - * Either break the interface and make them --sf, --sb (like they are now), - * or parse them before running getopt.. */ - - for (;;) { - int32_t opt = getopt_long(*argc, *argv, "hviwl:I:p:I:bfm:", opts, NULL); - if (opt < 0) - break; - - switch (opt) { - case 'h': - usage(stdout, *argv[0]); - break; - case 'v': - version(*argv[0]); - break; - - case 'i': - client.filter_mode = BM_FILTER_MODE_DMENU_CASE_INSENSITIVE; - break; - case 'w': - client.wrap = 1; - break; - case 'l': - client.lines = strtol(optarg, NULL, 10); - break; - case 'p': - client.title = optarg; - break; - case 'I': - client.selected = strtol(optarg, NULL, 10); - break; - - case 0x100: - client.renderer = optarg; - break; - - case 0x101: - if (!strcmp(optarg, "terminal")) - client.prioritory = BM_PRIO_TERMINAL; - else if (!strcmp(optarg, "gui")) - client.prioritory = BM_PRIO_GUI; - break; - - case 'b': - client.bottom = 1; - break; - case 'f': - client.grab = 1; - break; - case 'm': - client.monitor = strtol(optarg, NULL, 10); - 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; - - case ':': - case '?': - fputs("\n", stderr); - usage(stderr, *argv[0]); - break; - } - } - - *argc -= optind; - *argv += optind; -} - -static void -read_items_to_menu_from_stdin(struct bm_menu *menu) -{ - assert(menu); - - size_t step = 1024, allocated; - char *buffer; - - if (!(buffer = malloc((allocated = step)))) - return; - - size_t read; - while ((read = fread(buffer + (allocated - step), 1, step, stdin)) == step) { - void *tmp; - if (!(tmp = realloc(buffer, (allocated += step)))) { - free(buffer); - return; - } - buffer = tmp; - } - buffer[allocated - step + read - 1] = 0; - - char *s = buffer; - while ((size_t)(s - buffer) < allocated - step + read) { - size_t pos = strcspn(s, "\n"); - if (pos == 0) { - s += 1; - continue; - } - - s[pos] = 0; - - struct bm_item *item; - if (!(item = bm_item_new(s))) - break; - - bm_menu_add_item(menu, item); - s += pos + 1; - } - - free(buffer); -} - -int -main(int argc, char **argv) -{ - if (!bm_init()) - return EXIT_FAILURE; - - parse_args(&argc, &argv); - - struct bm_menu *menu; - 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); - - enum bm_key key; - uint32_t unicode; - int32_t status = 0; - do { - bm_menu_render(menu); - key = bm_menu_poll_key(menu, &unicode); - } while ((status = bm_menu_run_with_key(menu, key, unicode)) == BM_RUN_RESULT_RUNNING); - - if (status == BM_RUN_RESULT_SELECTED) { - uint32_t i, count; - struct bm_item **items = bm_menu_get_selected_items(menu, &count); - for (i = 0; i < count; ++i) { - const char *text = bm_item_get_text(items[i]); - printf("%s\n", (text ? text : "")); - } - - if (!count && bm_menu_get_filter(menu)) - 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); -} - -/* vim: set ts=8 sw=4 tw=0 :*/ diff --git a/client/common/common.c b/client/common/common.c new file mode 100644 index 0000000..e34a34f --- /dev/null +++ b/client/common/common.c @@ -0,0 +1,274 @@ +#define _DEFAULT_SOURCE +#include "common.h" +#include +#include +#include +#include +#include +#include +#include + +static void +disco_trap(int sig) +{ + (void)sig; + printf("\e[?25h\n"); + fflush(stdout); + exit(EXIT_FAILURE); +} + +static void +disco(void) +{ + struct sigaction action; + memset(&action, 0, sizeof(struct sigaction)); + action.sa_handler = disco_trap; + sigaction(SIGABRT, &action, NULL); + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGTRAP, &action, NULL); + sigaction(SIGINT, &action, NULL); + + uint32_t cc, c = 80; + printf("\e[?25l"); + while (1) { + for (uint32_t i = 1; i < c - 1; ++i) { + printf("\r %*s%s %s %s ", (i > c / 2 ? c - i : i), " ", ((i % 2) ? ""), ((i % 4) ? "DISCO" : " "), ((i %2) ? "\\o>" : ""), ((i % 2) ? "*" : "•")); + for (cc = 2; cc < (i > c / 2 ? c - i : i); ++cc) printf(((i % 2) ? "^" : "'")); + fflush(stdout); + usleep(140 * 1000); + } + } + printf("\e[?25h"); + exit(EXIT_SUCCESS); +} + +static void +version(const char *name) +{ + assert(name); + char *base = strrchr(name, '/'); + printf("%s v%s\n", (base ? base + 1 : name), bm_version()); + exit(EXIT_SUCCESS); +} + +static void +usage(FILE *out, const char *name) +{ + assert(out && name); + + char *base = strrchr(name, '/'); + fprintf(out, "usage: %s [options]\n", (base ? base + 1 : name)); + fputs("Options\n" + " -h, --help display this help and exit.\n" + " -v, --version display version.\n" + " -i, --ignorecase match items case insensitively.\n" + " -w, --wrap wraps cursor selection.\n" + " -l, --list list items vertically with the given number of lines.\n" + " -p, --prompt defines the prompt text to be displayed.\n" + " -I, --index select item at index automatically.\n" + " --backend options: curses, wayland\n" + " --prioritory options: terminal, gui\n\n" + + "Backend specific options\n" + " c = ncurses, w == wayland\n" + " (...) At end of help indicates the backend support for option.\n\n" + + " -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. (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)); +} + +void +parse_args(struct client *client, int *argc, char **argv[]) +{ + assert(client && argc && argv); + + static const struct option opts[] = { + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + + { "ignorecase", no_argument, 0, 'i' }, + { "wrap", no_argument, 0, 'w' }, + { "list", required_argument, 0, 'l' }, + { "prompt", required_argument, 0, 'p' }, + { "index", required_argument, 0, 'I' }, + { "backend", required_argument, 0, 0x100 }, + { "prioritory", required_argument, 0, 0x101 }, + + { "bottom", no_argument, 0, 'b' }, + { "grab", no_argument, 0, 'f' }, + { "monitor", required_argument, 0, 'm' }, + { "fn", required_argument, 0, 0x102 }, + { "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 } + }; + + /* TODO: getopt does not support -sf, -sb etc.. + * Either break the interface and make them --sf, --sb (like they are now), + * or parse them before running getopt.. */ + + for (;;) { + int32_t opt = getopt_long(*argc, *argv, "hviwl:I:p:I:bfm:", opts, NULL); + if (opt < 0) + break; + + switch (opt) { + case 'h': + usage(stdout, *argv[0]); + break; + case 'v': + version(*argv[0]); + break; + + case 'i': + client->filter_mode = BM_FILTER_MODE_DMENU_CASE_INSENSITIVE; + break; + case 'w': + client->wrap = 1; + break; + case 'l': + client->lines = strtol(optarg, NULL, 10); + break; + case 'p': + client->title = optarg; + break; + case 'I': + client->selected = strtol(optarg, NULL, 10); + break; + + case 0x100: + client->renderer = optarg; + break; + + case 0x101: + if (!strcmp(optarg, "terminal")) + client->prioritory = BM_PRIO_TERMINAL; + else if (!strcmp(optarg, "gui")) + client->prioritory = BM_PRIO_GUI; + break; + + case 'b': + client->bottom = 1; + break; + case 'f': + client->grab = 1; + break; + case 'm': + client->monitor = strtol(optarg, NULL, 10); + 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; + + case ':': + case '?': + fputs("\n", stderr); + usage(stderr, *argv[0]); + break; + } + } + + *argc -= optind; + *argv += optind; +} + +struct bm_menu* +menu_with_options(struct client *client) +{ + struct bm_menu *menu; + if (!(menu = bm_menu_new(client->renderer, client->prioritory))) + return NULL; + + 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]); + + return menu; +} + +enum bm_run_result +run_menu(struct bm_menu *menu) +{ + uint32_t unicode; + enum bm_key key; + enum bm_run_result status = BM_RUN_RESULT_RUNNING; + do { + bm_menu_render(menu); + key = bm_menu_poll_key(menu, &unicode); + } while ((status = bm_menu_run_with_key(menu, key, unicode)) == BM_RUN_RESULT_RUNNING); + return status; +} + +/* vim: set ts=8 sw=4 tw=0 :*/ diff --git a/client/common/common.h b/client/common/common.h new file mode 100644 index 0000000..b87b974 --- /dev/null +++ b/client/common/common.h @@ -0,0 +1,28 @@ +#ifndef _BM_COMMON_H_ +#define _BM_COMMON_H_ + +#include + +struct client { + enum bm_prioritory prioritory; + 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; + int32_t monitor; +}; + +void parse_args(struct client *client, int *argc, char **argv[]); +struct bm_menu* menu_with_options(struct client *client); +enum bm_run_result run_menu(struct bm_menu *menu); + +#endif /* _BM_COMMON_H_ */ + +/* vim: set ts=8 sw=4 tw=0 :*/ -- cgit v1.2.3-70-g09d2