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"))
|
||||
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"))
|
||||
return value_to_str(ctx, &conf->title);
|
||||
|
||||
|
|
@ -3592,6 +3595,7 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.presentation_timings = false,
|
||||
.selection_target = SELECTION_TARGET_PRIMARY,
|
||||
.hold_at_exit = false,
|
||||
.wait_for_mapped = false,
|
||||
.desktop_notifications = {
|
||||
.command = {
|
||||
.argv = {.args = NULL},
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -237,6 +237,7 @@ struct config {
|
|||
char32_t *word_delimiters;
|
||||
bool login_shell;
|
||||
bool locked_title;
|
||||
bool wait_for_mapped;
|
||||
|
||||
struct {
|
||||
enum conf_size_type type;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ the foot command line
|
|||
*-L*,*--login-shell*
|
||||
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*
|
||||
Display an existing pty instead of creating one. This is useful
|
||||
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,
|
||||
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*
|
||||
Value to set the environment variable *TERM* to. Default:
|
||||
_@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"
|
||||
" -F,--fullscreen start in fullscreen mode\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"
|
||||
" -D,--working-directory=DIR directory to start in (CWD)\n"
|
||||
" -w,--window-size-pixels=WIDTHxHEIGHT initial width and height, in pixels\n"
|
||||
|
|
@ -187,6 +188,7 @@ sanitize_signals(void)
|
|||
enum {
|
||||
PTY_OPTION = CHAR_MAX + 1,
|
||||
TOPLEVEL_TAG_OPTION = CHAR_MAX + 2,
|
||||
WAIT_FOR_MAPPED_OPTION = CHAR_MAX + 3,
|
||||
};
|
||||
|
||||
int
|
||||
|
|
@ -218,6 +220,7 @@ main(int argc, char *const *argv)
|
|||
{"app-id", required_argument, NULL, 'a'},
|
||||
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
|
||||
{"login-shell", no_argument, NULL, 'L'},
|
||||
{"wait-for-mapped", no_argument, NULL, WAIT_FOR_MAPPED_OPTION},
|
||||
{"working-directory", required_argument, NULL, 'D'},
|
||||
{"font", required_argument, NULL, 'f'},
|
||||
{"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"));
|
||||
break;
|
||||
|
||||
case WAIT_FOR_MAPPED_OPTION:
|
||||
tll_push_back(overrides, xstrdup("wait-for-mapped=yes"));
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
tll_push_back(overrides, xstrjoin("title=", optarg));
|
||||
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);
|
||||
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 csd = term->render.pending.csd;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (!pty_path) {
|
||||
/* 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;
|
||||
}
|
||||
if (conf->wait_for_mapped) {
|
||||
/* Deep-copy: server.c frees argv/envp after term_init() returns */
|
||||
char **argv_copy = xcalloc(argc + 1, sizeof(char *));
|
||||
for (int i = 0; i < argc; i++)
|
||||
argv_copy[i] = xstrdup(argv[i]);
|
||||
|
||||
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
|
||||
|
|
@ -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
|
||||
*
|
||||
|
|
@ -1825,6 +1896,9 @@ term_destroy(struct terminal *term)
|
|||
|
||||
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->render.app_sync_updates.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;
|
||||
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 grid *grid;
|
||||
struct grid normal;
|
||||
|
|
@ -868,6 +877,7 @@ int term_pt_or_px_as_pixels(
|
|||
|
||||
|
||||
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_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_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, "locked-title", &conf.locked_title);
|
||||
test_boolean(&ctx, &parse_section_main, "dpi-aware", &conf.dpi_aware);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue