clients: Make -f option show menu immediately

This commit is contained in:
Jari Vetoniemi 2017-02-14 19:14:08 +02:00
parent 91d929ecf4
commit 208af51c0e
2 changed files with 72 additions and 17 deletions

View File

@ -82,7 +82,7 @@ usage(FILE *out, const char *name)
" (...) At end of help indicates the backend support for option.\n\n"
" -b, --bottom appears at the bottom of the screen. (x)\n"
" -f, --grab grabs the keyboard before reading stdin. (x)\n"
" -f, --grab show the menu before reading stdin. (wx)\n"
" -m, --monitor index of monitor where menu will appear. (x)\n"
" --fn defines the font to be used ('name [size]'). (wx)\n"
" --tb defines the title background color. (wx)\n"
@ -264,8 +264,12 @@ menu_with_options(struct client *client)
for (uint32_t i = 0; i < BM_COLOR_LAST; ++i)
bm_menu_set_color(menu, i, client->colors[i]);
if (client->grab)
if (client->grab) {
bm_menu_set_filter(menu, "Loading...");
bm_menu_grab_keyboard(menu, true);
bm_menu_render(menu);
bm_menu_set_filter(menu, NULL);
}
return menu;
}

View File

@ -32,8 +32,52 @@ static struct curses {
size_t blen;
int old_stdin;
int old_stdout;
bool polled_once;
bool should_terminate;
} curses;
static void
reopen_stdin(void)
{
freopen(TTY, "r", stdin);
}
static void
reopen_stdin_stdout(void)
{
reopen_stdin();
freopen(TTY, "w", stdout);
}
static void
store_stdin_stdout(void)
{
curses.old_stdin = dup(STDIN_FILENO);
curses.old_stdout = dup(STDOUT_FILENO);
}
static void
restore_stdin(void)
{
if (curses.old_stdin != -1) {
dup2(curses.old_stdin, STDIN_FILENO);
close(curses.old_stdin);
curses.old_stdin = -1;
}
}
static void
restore_stdin_stdout(void)
{
restore_stdin();
if (curses.old_stdout != -1) {
dup2(curses.old_stdout, STDOUT_FILENO);
close(curses.old_stdout);
curses.old_stdout = -1;
}
}
static void
terminate(void)
{
@ -46,16 +90,10 @@ terminate(void)
if (!curses.stdscr)
return;
freopen(TTY, "w", stdout);
reopen_stdin_stdout();
refresh();
endwin();
dup2(curses.old_stdin, STDIN_FILENO);
dup2(curses.old_stdout, STDOUT_FILENO);
close(curses.old_stdin);
close(curses.old_stdout);
restore_stdin_stdout();
curses.stdscr = NULL;
}
@ -139,13 +177,14 @@ draw_line(int32_t pair, int32_t y, const char *fmt, ...)
static void
render(const struct bm_menu *menu)
{
if (curses.should_terminate) {
terminate();
curses.should_terminate = false;
}
if (!curses.stdscr) {
curses.old_stdin = dup(STDIN_FILENO);
curses.old_stdout = dup(STDOUT_FILENO);
freopen(TTY, "w", stdout);
freopen(TTY, "r", stdin);
store_stdin_stdout();
reopen_stdin_stdout();
setlocale(LC_CTYPE, "");
if ((curses.stdscr = initscr()) == NULL)
@ -225,6 +264,15 @@ render(const struct bm_menu *menu)
move(0, title_len + (menu->curses_cursor < ccols ? menu->curses_cursor : ccols));
refresh();
// Make it possible to read stdin even after rendering
// Only make it impossible to read original stdin after poll_key is called once
// This is mainly to make -f work even on curses backend
if (!curses.polled_once) {
reopen_stdin();
restore_stdin();
curses.should_terminate = true;
}
}
static uint32_t
@ -240,8 +288,9 @@ poll_key(const struct bm_menu *menu, uint32_t *unicode)
(void)menu;
assert(unicode);
*unicode = 0;
curses.polled_once = true;
if (!curses.stdscr)
if (!curses.stdscr || curses.should_terminate)
return BM_KEY_NONE;
get_wch((wint_t*)unicode);
@ -360,6 +409,8 @@ constructor(struct bm_menu *menu)
assert(!curses.stdscr && "bemenu supports only one curses instance");
memset(&curses, 0, sizeof(curses));
curses.old_stdin = -1;
curses.old_stdout = -1;
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));