diff --git a/input.c b/input.c index 11b46cf6..ca7d0ec2 100644 --- a/input.c +++ b/input.c @@ -282,6 +282,11 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, search_begin(term); goto maybe_repeat; } + + else if (sym == XKB_KEY_Return) { + term_spawn_new(term); + goto maybe_repeat; + } } diff --git a/main.c b/main.c index a8776606..540f106c 100644 --- a/main.c +++ b/main.c @@ -223,8 +223,9 @@ main(int argc, char *const *argv) if ((wayl = wayl_init(fdm)) == NULL) goto out; - if (!as_server && (term = term_init(&conf, fdm, wayl, conf.term, argc, argv, - &term_shutdown_cb, &shutdown_ctx)) == NULL) + if (!as_server && (term = term_init( + &conf, fdm, wayl, conf.term, prog_name, argc, argv, + &term_shutdown_cb, &shutdown_ctx)) == NULL) goto out; if (as_server && (server = server_init(&conf, fdm, wayl)) == NULL) diff --git a/server.c b/server.c index 143af512..a8b15eba 100644 --- a/server.c +++ b/server.c @@ -213,7 +213,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data) client->term = term_init( server->conf, server->fdm, server->wayl, strlen(term_env) > 0 ? term_env : server->conf->term, - argc, argv, &term_shutdown_handler, client); + "footclient" /* TODO */, argc, argv, &term_shutdown_handler, client); if (client->term == NULL) { LOG_ERR("failed to instantiate new terminal"); diff --git a/slave.c b/slave.c index 0b453c5d..bffa48a8 100644 --- a/slave.c +++ b/slave.c @@ -64,6 +64,7 @@ err: close(pts); if (ptmx != -1) close(ptmx); + close(err_fd); _exit(errno); } diff --git a/terminal.c b/terminal.c index 836785a0..4dfe5128 100644 --- a/terminal.c +++ b/terminal.c @@ -465,7 +465,7 @@ initialize_fonts(struct terminal *term, const struct config *conf) struct terminal * term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, - const char *term_env, int argc, char *const *argv, + const char *term_env, const char *foot_exe, int argc, char *const *argv, void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data) { int ptmx = -1; @@ -600,6 +600,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, }, .shutdown_cb = shutdown_cb, .shutdown_data = shutdown_data, + .foot_exe = strdup(foot_exe), }; initialize_color_cube(term); @@ -830,6 +831,7 @@ term_destroy(struct terminal *term) free(it->item.data); tll_free(term->ptmx_buffer); tll_free(term->tab_stops); + free(term->foot_exe); int ret = EXIT_SUCCESS; @@ -1642,3 +1644,66 @@ term_flash(struct terminal *term, unsigned duration_ms) term->flash.active = true; } } + +bool +term_spawn_new(const struct terminal *term) +{ + pid_t pid = fork(); + if (pid < 0) { + LOG_ERRNO("failed to fork new terminal"); + return false; + } + + if (pid == 0) { + /* Child */ + int pipe_fds[2] = {-1, -1}; + if (pipe2(pipe_fds, O_CLOEXEC) < 0) { + LOG_ERRNO("failed to create pipe"); + goto err; + } + + /* Double fork */ + pid_t pid2 = fork(); + if (pid2 < 0) { + LOG_ERRNO("failed to double fork new terminal"); + goto err; + } + + if (pid2 == 0) { + /* Child */ + close(pipe_fds[0]); + execl(term->foot_exe, term->foot_exe, NULL); + write(pipe_fds[1], &errno, sizeof(errno)); + _exit(errno); + } + + /* Parent */ + + close(pipe_fds[1]); + + int _errno; + static_assert(sizeof(_errno) == sizeof(errno), "errno size mismatch"); + + ssize_t ret = read(pipe_fds[0], &_errno, sizeof(_errno)); + close(pipe_fds[0]); + + if (ret == 0) + _exit(0); + else if (ret < 0) + LOG_ERRNO("failed to read from pipe"); + else { + LOG_ERRNO_P("%s: failed to spawn new terminal", _errno, term->foot_exe); + errno = _errno; + waitpid(pid2, NULL, 0); + } + + err: + if (pipe_fds[0] != -1) + close(pipe_fds[0]); + _exit(errno); + } + + int result; + waitpid(pid, &result, 0); + return WIFEXITED(result) && WEXITSTATUS(result) == 0; +} diff --git a/terminal.h b/terminal.h index 4d82aeaa..b7a92be4 100644 --- a/terminal.h +++ b/terminal.h @@ -314,12 +314,14 @@ struct terminal { bool is_shutting_down; void (*shutdown_cb)(void *data, int exit_code); void *shutdown_data; + + char *foot_exe; }; struct config; struct terminal *term_init( const struct config *conf, struct fdm *fdm, struct wayland *wayl, - const char *term_env, int argc, char *const *argv, + const char *term_env, const char *foot_exe, int argc, char *const *argv, void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data); bool term_shutdown(struct terminal *term); @@ -379,3 +381,4 @@ void term_xcursor_update(struct terminal *term); void term_set_window_title(struct terminal *term, const char *title); void term_flash(struct terminal *term, unsigned duration_ms); +bool term_spawn_new(const struct terminal *term);