diff options
Diffstat (limited to 'client')
| -rw-r--r-- | client/CMakeLists.txt | 23 | ||||
| -rw-r--r-- | client/bemenu-run.c | 184 | ||||
| -rw-r--r-- | client/bemenu.c | 100 | ||||
| -rw-r--r-- | client/common/common.c (renamed from client/client.c) | 193 | ||||
| -rw-r--r-- | client/common/common.h | 28 | 
5 files changed, 380 insertions, 148 deletions
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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <assert.h> +#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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#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/common/common.c index 52933d1..e34a34f 100644 --- a/client/client.c +++ b/client/common/common.c @@ -1,42 +1,12 @@  #define _DEFAULT_SOURCE +#include "common.h"  #include <stdlib.h> -#include <stdio.h>  #include <string.h> -#include <assert.h> -#include <unistd.h>  #include <signal.h> +#include <stdio.h> +#include <unistd.h>  #include <getopt.h> -#include <bemenu.h> - -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 -}; +#include <assert.h>  static void  disco_trap(int sig) @@ -77,6 +47,7 @@ disco(void)  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); @@ -85,6 +56,8 @@ version(const char *name)  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" @@ -117,12 +90,15 @@ usage(FILE *out, const char *name)            " --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[]) +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' }, @@ -173,78 +149,78 @@ parse_args(int *argc, char **argv[])                  break;              case 'i': -                client.filter_mode = BM_FILTER_MODE_DMENU_CASE_INSENSITIVE; +                client->filter_mode = BM_FILTER_MODE_DMENU_CASE_INSENSITIVE;                  break;              case 'w': -                client.wrap = 1; +                client->wrap = 1;                  break;              case 'l': -                client.lines = strtol(optarg, NULL, 10); +                client->lines = strtol(optarg, NULL, 10);                  break;              case 'p': -                client.title = optarg; +                client->title = optarg;                  break;              case 'I': -                client.selected = strtol(optarg, NULL, 10); +                client->selected = strtol(optarg, NULL, 10);                  break;              case 0x100: -                client.renderer = optarg; +                client->renderer = optarg;                  break;              case 0x101:                  if (!strcmp(optarg, "terminal")) -                    client.prioritory = BM_PRIO_TERMINAL; +                    client->prioritory = BM_PRIO_TERMINAL;                  else if (!strcmp(optarg, "gui")) -                    client.prioritory = BM_PRIO_GUI; +                    client->prioritory = BM_PRIO_GUI;                  break;              case 'b': -                client.bottom = 1; +                client->bottom = 1;                  break;              case 'f': -                client.grab = 1; +                client->grab = 1;                  break;              case 'm': -                client.monitor = strtol(optarg, NULL, 10); +                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); +                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; +                client->colors[BM_COLOR_BG] = optarg;                  break;              case 0x104: -                client.colors[BM_COLOR_TITLE_BG] = optarg; +                client->colors[BM_COLOR_TITLE_BG] = optarg;                  break;              case 0x105: -                client.colors[BM_COLOR_TITLE_FG] = optarg; +                client->colors[BM_COLOR_TITLE_FG] = optarg;                  break;              case 0x106: -                client.colors[BM_COLOR_FILTER_BG] = optarg; +                client->colors[BM_COLOR_FILTER_BG] = optarg;                  break;              case 0x107: -                client.colors[BM_COLOR_FILTER_FG] = optarg; +                client->colors[BM_COLOR_FILTER_FG] = optarg;                  break;              case 0x108: -                client.colors[BM_COLOR_ITEM_BG] = optarg; +                client->colors[BM_COLOR_ITEM_BG] = optarg;                  break;              case 0x109: -                client.colors[BM_COLOR_ITEM_FG] = optarg; +                client->colors[BM_COLOR_ITEM_FG] = optarg;                  break;              case 0x110: -                client.colors[BM_COLOR_HIGHLIGHTED_BG] = optarg; +                client->colors[BM_COLOR_HIGHLIGHTED_BG] = optarg;                  break;              case 0x111: -                client.colors[BM_COLOR_HIGHLIGHTED_FG] = optarg; +                client->colors[BM_COLOR_HIGHLIGHTED_FG] = optarg;                  break;              case 0x112: -                client.colors[BM_COLOR_SELECTED_BG] = optarg; +                client->colors[BM_COLOR_SELECTED_BG] = optarg;                  break;              case 0x113: -                client.colors[BM_COLOR_SELECTED_FG] = optarg; +                client->colors[BM_COLOR_SELECTED_FG] = optarg;                  break;              case 0x114: @@ -263,97 +239,36 @@ parse_args(int *argc, char **argv[])      *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) +struct bm_menu* +menu_with_options(struct client *client)  { -    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; +    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); +    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]); +        bm_menu_set_color(menu, i, client->colors[i]); -    read_items_to_menu_from_stdin(menu); - -    bm_menu_set_highlighted_index(menu, client.selected); +    return menu; +} -    enum bm_key key; +enum bm_run_result +run_menu(struct bm_menu *menu) +{      uint32_t unicode; -    int32_t status = 0; +    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); - -    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); +    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 <bemenu.h> + +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 :*/  | 
