mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-05-29 21:38:03 -04:00
add wait-for-mapped option
This commit is contained in:
parent
4bf60d0fbc
commit
5b87139670
9 changed files with 121 additions and 9 deletions
4
config.c
4
config.c
|
|
@ -916,6 +916,9 @@ parse_section_main(struct context *ctx)
|
||||||
else if (streq(key, "login-shell"))
|
else if (streq(key, "login-shell"))
|
||||||
return value_to_bool(ctx, &conf->login_shell);
|
return value_to_bool(ctx, &conf->login_shell);
|
||||||
|
|
||||||
|
else if (streq(key, "wait-for-mapped"))
|
||||||
|
return value_to_bool(ctx, &conf->wait_for_mapped);
|
||||||
|
|
||||||
else if (streq(key, "title"))
|
else if (streq(key, "title"))
|
||||||
return value_to_str(ctx, &conf->title);
|
return value_to_str(ctx, &conf->title);
|
||||||
|
|
||||||
|
|
@ -3592,6 +3595,7 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
.presentation_timings = false,
|
.presentation_timings = false,
|
||||||
.selection_target = SELECTION_TARGET_PRIMARY,
|
.selection_target = SELECTION_TARGET_PRIMARY,
|
||||||
.hold_at_exit = false,
|
.hold_at_exit = false,
|
||||||
|
.wait_for_mapped = false,
|
||||||
.desktop_notifications = {
|
.desktop_notifications = {
|
||||||
.command = {
|
.command = {
|
||||||
.argv = {.args = NULL},
|
.argv = {.args = NULL},
|
||||||
|
|
|
||||||
1
config.h
1
config.h
|
|
@ -237,6 +237,7 @@ struct config {
|
||||||
char32_t *word_delimiters;
|
char32_t *word_delimiters;
|
||||||
bool login_shell;
|
bool login_shell;
|
||||||
bool locked_title;
|
bool locked_title;
|
||||||
|
bool wait_for_mapped;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
enum conf_size_type type;
|
enum conf_size_type type;
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,10 @@ the foot command line
|
||||||
*-L*,*--login-shell*
|
*-L*,*--login-shell*
|
||||||
Start a login shell, by prepending a '-' to argv[0].
|
Start a login shell, by prepending a '-' to argv[0].
|
||||||
|
|
||||||
|
*--wait-for-mapped*
|
||||||
|
Defer spawning the client application until the window has been
|
||||||
|
mapped. See *wait-for-mapped* in *foot.ini*(5).
|
||||||
|
|
||||||
*--pty*
|
*--pty*
|
||||||
Display an existing pty instead of creating one. This is useful
|
Display an existing pty instead of creating one. This is useful
|
||||||
for interacting with VM consoles.
|
for interacting with VM consoles.
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,14 @@ empty string to be set, but it must be quoted: *KEY=""*
|
||||||
Boolean. If enabled, the shell will be launched as a login shell,
|
Boolean. If enabled, the shell will be launched as a login shell,
|
||||||
by prepending a '-' to argv[0]. Default: _no_.
|
by prepending a '-' to argv[0]. Default: _no_.
|
||||||
|
|
||||||
|
*wait-for-mapped*
|
||||||
|
Boolean. If enabled, defer spawning the client application until
|
||||||
|
the window has been mapped and the first frame has been
|
||||||
|
displayed. The client's first *TIOCGWINSZ* will then return the
|
||||||
|
final window size, working around startup issues in TUI
|
||||||
|
applications that mishandle early *SIGWINCH* signals.
|
||||||
|
Default: _no_.
|
||||||
|
|
||||||
*term*
|
*term*
|
||||||
Value to set the environment variable *TERM* to. Default:
|
Value to set the environment variable *TERM* to. Default:
|
||||||
_@default_terminfo@_
|
_@default_terminfo@_
|
||||||
|
|
|
||||||
7
main.c
7
main.c
|
|
@ -88,6 +88,7 @@ print_usage(const char *prog_name)
|
||||||
" -m,--maximized start in maximized mode\n"
|
" -m,--maximized start in maximized mode\n"
|
||||||
" -F,--fullscreen start in fullscreen mode\n"
|
" -F,--fullscreen start in fullscreen mode\n"
|
||||||
" -L,--login-shell start shell as a login shell\n"
|
" -L,--login-shell start shell as a login shell\n"
|
||||||
|
" --wait-for-mapped defer client spawn until window is mapped\n"
|
||||||
" --pty=PATH display an existing PTY instead of creating one\n"
|
" --pty=PATH display an existing PTY instead of creating one\n"
|
||||||
" -D,--working-directory=DIR directory to start in (CWD)\n"
|
" -D,--working-directory=DIR directory to start in (CWD)\n"
|
||||||
" -w,--window-size-pixels=WIDTHxHEIGHT initial width and height, in pixels\n"
|
" -w,--window-size-pixels=WIDTHxHEIGHT initial width and height, in pixels\n"
|
||||||
|
|
@ -187,6 +188,7 @@ sanitize_signals(void)
|
||||||
enum {
|
enum {
|
||||||
PTY_OPTION = CHAR_MAX + 1,
|
PTY_OPTION = CHAR_MAX + 1,
|
||||||
TOPLEVEL_TAG_OPTION = CHAR_MAX + 2,
|
TOPLEVEL_TAG_OPTION = CHAR_MAX + 2,
|
||||||
|
WAIT_FOR_MAPPED_OPTION = CHAR_MAX + 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -218,6 +220,7 @@ main(int argc, char *const *argv)
|
||||||
{"app-id", required_argument, NULL, 'a'},
|
{"app-id", required_argument, NULL, 'a'},
|
||||||
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
|
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
|
||||||
{"login-shell", no_argument, NULL, 'L'},
|
{"login-shell", no_argument, NULL, 'L'},
|
||||||
|
{"wait-for-mapped", no_argument, NULL, WAIT_FOR_MAPPED_OPTION},
|
||||||
{"working-directory", required_argument, NULL, 'D'},
|
{"working-directory", required_argument, NULL, 'D'},
|
||||||
{"font", required_argument, NULL, 'f'},
|
{"font", required_argument, NULL, 'f'},
|
||||||
{"window-size-pixels", required_argument, NULL, 'w'},
|
{"window-size-pixels", required_argument, NULL, 'w'},
|
||||||
|
|
@ -280,6 +283,10 @@ main(int argc, char *const *argv)
|
||||||
tll_push_back(overrides, xstrdup("login-shell=yes"));
|
tll_push_back(overrides, xstrdup("login-shell=yes"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WAIT_FOR_MAPPED_OPTION:
|
||||||
|
tll_push_back(overrides, xstrdup("wait-for-mapped=yes"));
|
||||||
|
break;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
tll_push_back(overrides, xstrjoin("title=", optarg));
|
tll_push_back(overrides, xstrjoin("title=", optarg));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
3
render.c
3
render.c
|
|
@ -4317,6 +4317,9 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da
|
||||||
wl_callback_destroy(wl_callback);
|
wl_callback_destroy(wl_callback);
|
||||||
term->window->frame_callback = NULL;
|
term->window->frame_callback = NULL;
|
||||||
|
|
||||||
|
/* --wait-for-mapped: first frame done, on-screen size is final */
|
||||||
|
term_spawn_pending(term);
|
||||||
|
|
||||||
bool grid = term->render.pending.grid;
|
bool grid = term->render.pending.grid;
|
||||||
bool csd = term->render.pending.csd;
|
bool csd = term->render.pending.csd;
|
||||||
bool search = term->is_searching && term->render.pending.search;
|
bool search = term->is_searching && term->render.pending.search;
|
||||||
|
|
|
||||||
92
terminal.c
92
terminal.c
|
|
@ -294,6 +294,7 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
xassert(term->interactive_resizing.grid == NULL);
|
xassert(term->interactive_resizing.grid == NULL);
|
||||||
|
|
||||||
vt_from_slave(term, buf, count);
|
vt_from_slave(term, buf, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1435,16 +1436,38 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
add_utmp_record(conf, reaper, ptmx);
|
add_utmp_record(conf, reaper, ptmx);
|
||||||
|
|
||||||
if (!pty_path) {
|
if (!pty_path) {
|
||||||
/* Start the slave/client */
|
if (conf->wait_for_mapped) {
|
||||||
if ((term->slave = slave_spawn(
|
/* Deep-copy: server.c frees argv/envp after term_init() returns */
|
||||||
term->ptmx, argc, term->cwd, argv, envp, &conf->env_vars,
|
char **argv_copy = xcalloc(argc + 1, sizeof(char *));
|
||||||
conf->term, conf->shell, conf->login_shell,
|
for (int i = 0; i < argc; i++)
|
||||||
&conf->notifications)) == -1)
|
argv_copy[i] = xstrdup(argv[i]);
|
||||||
{
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
reaper_add(term->reaper, term->slave, &fdm_client_terminated, term);
|
char **envp_copy = NULL;
|
||||||
|
if (envp != NULL) {
|
||||||
|
size_t n = 0;
|
||||||
|
while (envp[n] != NULL) n++;
|
||||||
|
envp_copy = xcalloc(n + 1, sizeof(char *));
|
||||||
|
for (size_t i = 0; i < n; i++)
|
||||||
|
envp_copy[i] = xstrdup(envp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
term->pending_spawn.armed = true;
|
||||||
|
term->pending_spawn.argc = argc;
|
||||||
|
term->pending_spawn.argv = argv_copy;
|
||||||
|
term->pending_spawn.envp = envp_copy;
|
||||||
|
term->pending_spawn.cwd = cwd != NULL ? xstrdup(cwd) : NULL;
|
||||||
|
} else {
|
||||||
|
/* Start the slave/client */
|
||||||
|
if ((term->slave = slave_spawn(
|
||||||
|
term->ptmx, argc, term->cwd, argv, envp, &conf->env_vars,
|
||||||
|
conf->term, conf->shell, conf->login_shell,
|
||||||
|
&conf->notifications)) == -1)
|
||||||
|
{
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
reaper_add(term->reaper, term->slave, &fdm_client_terminated, term);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Guess scale; we're not mapped yet, so we don't know on which
|
/* Guess scale; we're not mapped yet, so we don't know on which
|
||||||
|
|
@ -1517,6 +1540,54 @@ term_window_configured(struct terminal *term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free deferred spawn args in --wait-for-mapped */
|
||||||
|
static void
|
||||||
|
pending_spawn_free(struct terminal *term)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < term->pending_spawn.argc; i++)
|
||||||
|
free(term->pending_spawn.argv[i]);
|
||||||
|
free(term->pending_spawn.argv);
|
||||||
|
if (term->pending_spawn.envp != NULL) {
|
||||||
|
for (char **e = term->pending_spawn.envp; *e != NULL; e++)
|
||||||
|
free(*e);
|
||||||
|
free(term->pending_spawn.envp);
|
||||||
|
}
|
||||||
|
free(term->pending_spawn.cwd);
|
||||||
|
|
||||||
|
term->pending_spawn.argc = 0;
|
||||||
|
term->pending_spawn.argv = NULL;
|
||||||
|
term->pending_spawn.envp = NULL;
|
||||||
|
term->pending_spawn.cwd = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --wait-for-mapped: spawn the deferred client. Idempotent. */
|
||||||
|
void
|
||||||
|
term_spawn_pending(struct terminal *term)
|
||||||
|
{
|
||||||
|
if (!term->pending_spawn.armed || term->shutdown.in_progress)
|
||||||
|
return;
|
||||||
|
|
||||||
|
term->pending_spawn.armed = false;
|
||||||
|
|
||||||
|
term->slave = slave_spawn(
|
||||||
|
term->ptmx, term->pending_spawn.argc, term->pending_spawn.cwd,
|
||||||
|
term->pending_spawn.argv,
|
||||||
|
(const char *const *)term->pending_spawn.envp,
|
||||||
|
&term->conf->env_vars, term->conf->term, term->conf->shell,
|
||||||
|
term->conf->login_shell, &term->conf->notifications);
|
||||||
|
|
||||||
|
pending_spawn_free(term);
|
||||||
|
|
||||||
|
if (term->slave == -1) {
|
||||||
|
LOG_ERR("deferred slave_spawn() failed");
|
||||||
|
if (!term->conf->hold_at_exit)
|
||||||
|
term_shutdown(term);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reaper_add(term->reaper, term->slave, &fdm_client_terminated, term);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shutdown logic
|
* Shutdown logic
|
||||||
*
|
*
|
||||||
|
|
@ -1825,6 +1896,9 @@ term_destroy(struct terminal *term)
|
||||||
|
|
||||||
del_utmp_record(term->conf, term->reaper, term->ptmx);
|
del_utmp_record(term->conf, term->reaper, term->ptmx);
|
||||||
|
|
||||||
|
/* Frees deferred spawn args if --wait-for-mapped never spawned; else no-op */
|
||||||
|
pending_spawn_free(term);
|
||||||
|
|
||||||
fdm_del(term->fdm, term->selection.auto_scroll.fd);
|
fdm_del(term->fdm, term->selection.auto_scroll.fd);
|
||||||
fdm_del(term->fdm, term->render.app_sync_updates.timer_fd);
|
fdm_del(term->fdm, term->render.app_sync_updates.timer_fd);
|
||||||
fdm_del(term->fdm, term->render.app_id.timer_fd);
|
fdm_del(term->fdm, term->render.app_id.timer_fd);
|
||||||
|
|
|
||||||
10
terminal.h
10
terminal.h
|
|
@ -419,6 +419,15 @@ struct terminal {
|
||||||
pid_t slave;
|
pid_t slave;
|
||||||
int ptmx;
|
int ptmx;
|
||||||
|
|
||||||
|
/* --wait-for-mapped: deferred slave_spawn() args (#453) */
|
||||||
|
struct {
|
||||||
|
bool armed;
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
char **envp;
|
||||||
|
char *cwd;
|
||||||
|
} pending_spawn;
|
||||||
|
|
||||||
struct vt vt;
|
struct vt vt;
|
||||||
struct grid *grid;
|
struct grid *grid;
|
||||||
struct grid normal;
|
struct grid normal;
|
||||||
|
|
@ -868,6 +877,7 @@ int term_pt_or_px_as_pixels(
|
||||||
|
|
||||||
|
|
||||||
void term_window_configured(struct terminal *term);
|
void term_window_configured(struct terminal *term);
|
||||||
|
void term_spawn_pending(struct terminal *term);
|
||||||
|
|
||||||
void term_damage_rows(struct terminal *term, int start, int end);
|
void term_damage_rows(struct terminal *term, int start, int end);
|
||||||
void term_damage_rows_in_view(struct terminal *term, int start, int end);
|
void term_damage_rows_in_view(struct terminal *term, int start, int end);
|
||||||
|
|
|
||||||
|
|
@ -488,6 +488,7 @@ test_section_main(void)
|
||||||
test_c32string(&ctx, &parse_section_main, "word-delimiters", &conf.word_delimiters);
|
test_c32string(&ctx, &parse_section_main, "word-delimiters", &conf.word_delimiters);
|
||||||
|
|
||||||
test_boolean(&ctx, &parse_section_main, "login-shell", &conf.login_shell);
|
test_boolean(&ctx, &parse_section_main, "login-shell", &conf.login_shell);
|
||||||
|
test_boolean(&ctx, &parse_section_main, "wait-for-mapped", &conf.wait_for_mapped);
|
||||||
test_boolean(&ctx, &parse_section_main, "box-drawings-uses-font-glyphs", &conf.box_drawings_uses_font_glyphs);
|
test_boolean(&ctx, &parse_section_main, "box-drawings-uses-font-glyphs", &conf.box_drawings_uses_font_glyphs);
|
||||||
test_boolean(&ctx, &parse_section_main, "locked-title", &conf.locked_title);
|
test_boolean(&ctx, &parse_section_main, "locked-title", &conf.locked_title);
|
||||||
test_boolean(&ctx, &parse_section_main, "dpi-aware", &conf.dpi_aware);
|
test_boolean(&ctx, &parse_section_main, "dpi-aware", &conf.dpi_aware);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue