Share client code, add bemenu-run

This commit is contained in:
Jari Vetoniemi 2014-10-25 20:43:37 +03:00
parent 595ff4f687
commit 9f13ca2e6d
5 changed files with 380 additions and 148 deletions

View File

@ -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 :

184
client/bemenu-run.c Normal file
View File

@ -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 :*/

100
client/bemenu.c Normal file
View File

@ -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 :*/

View File

@ -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)
struct bm_menu*
menu_with_options(struct client *client)
{
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;
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);
return menu;
}
bm_menu_set_highlighted_index(menu, client.selected);
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 :*/

28
client/common/common.h Normal file
View File

@ -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 :*/