summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2014-10-25 20:43:37 +0300
committerJari Vetoniemi <mailroxas@gmail.com>2014-10-25 20:43:52 +0300
commit9f13ca2e6d4fd6ce388c9cf5cb098abba01d6a0a (patch)
treebddab809d8f492727ed522331a9432b0d4d7c670 /client
parent595ff4f687868392e3fb6e8fe03fb6499e4da11c (diff)
downloadbemenu-9f13ca2e6d4fd6ce388c9cf5cb098abba01d6a0a.tar.gz
bemenu-9f13ca2e6d4fd6ce388c9cf5cb098abba01d6a0a.tar.bz2
bemenu-9f13ca2e6d4fd6ce388c9cf5cb098abba01d6a0a.zip
Share client code, add bemenu-run
Diffstat (limited to 'client')
-rw-r--r--client/CMakeLists.txt23
-rw-r--r--client/bemenu-run.c184
-rw-r--r--client/bemenu.c100
-rw-r--r--client/common/common.c (renamed from client/client.c)193
-rw-r--r--client/common/common.h28
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 :*/