mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-09 10:06:20 -05:00
commit
e7a4378f18
8 changed files with 115 additions and 42 deletions
|
|
@ -55,6 +55,8 @@
|
|||
sequences (https://codeberg.org/dnkl/foot/issues/235).
|
||||
* Support for transparent sixels (DCS parameter `P2=1`)
|
||||
(https://codeberg.org/dnkl/foot/issues/391).
|
||||
* `-N,--no-wait` to `footclient`
|
||||
(https://codeberg.org/dnkl/foot/issues/395).
|
||||
|
||||
|
||||
### Changed
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ struct client_data {
|
|||
uint8_t fullscreen:1;
|
||||
uint8_t hold:1;
|
||||
uint8_t login_shell:1;
|
||||
uint8_t no_wait:1;
|
||||
|
||||
uint16_t cwd_len;
|
||||
uint16_t term_len;
|
||||
|
|
|
|||
10
client.c
10
client.c
|
|
@ -58,6 +58,7 @@ print_usage(const char *prog_name)
|
|||
" -D,--working-directory=DIR directory to start in (CWD)\n"
|
||||
" -s,--server-socket=PATH path to the server UNIX domain socket (default=$XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock)\n"
|
||||
" -H,--hold remain open after child process exits\n"
|
||||
" -N,--no-wait detach the client process from the running terminal, exiting immediately\n"
|
||||
" -d,--log-level={info|warning|error} log level (info)\n"
|
||||
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
|
||||
" -v,--version show the version number and quit\n");
|
||||
|
|
@ -82,6 +83,7 @@ main(int argc, char *const *argv)
|
|||
{"working-directory", required_argument, NULL, 'D'},
|
||||
{"server-socket", required_argument, NULL, 's'},
|
||||
{"hold", no_argument, NULL, 'H'},
|
||||
{"no-wait", no_argument, NULL, 'N'},
|
||||
{"log-level", required_argument, NULL, 'd'},
|
||||
{"log-colorize", optional_argument, NULL, 'l'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
|
|
@ -103,9 +105,10 @@ main(int argc, char *const *argv)
|
|||
bool maximized = false;
|
||||
bool fullscreen = false;
|
||||
bool hold = false;
|
||||
bool no_wait = false;
|
||||
|
||||
while (true) {
|
||||
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:Hd:l::vh", longopts, NULL);
|
||||
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNd:l::vh", longopts, NULL);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
|
|
@ -170,6 +173,10 @@ main(int argc, char *const *argv)
|
|||
hold = true;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
no_wait = true;
|
||||
break;
|
||||
|
||||
case 'd': {
|
||||
int lvl = log_level_from_string(optarg);
|
||||
if (unlikely(lvl < 0)) {
|
||||
|
|
@ -290,6 +297,7 @@ main(int argc, char *const *argv)
|
|||
.fullscreen = fullscreen,
|
||||
.hold = hold,
|
||||
.login_shell = login_shell,
|
||||
.no_wait = no_wait,
|
||||
.cwd_len = cwd_len,
|
||||
.term_len = term_len,
|
||||
.title_len = title_len,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ complete -c footclient -x -s w -l window-size-pixels
|
|||
complete -c footclient -x -s W -l window-size-chars -d "window WIDTHxHEIGHT, in characters (not set)"
|
||||
complete -c footclient -F -s s -l server-socket -d "override the default path to the foot server socket ($XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock)"
|
||||
complete -c footclient -s H -l hold -d "remain open after child process exits"
|
||||
complete -c footclient -s N -l no-wait -d "detach the client process from the running terminal, exiting immediately"
|
||||
complete -c footclient -x -s d -l log-level -a "info warning error" -d "log-level (info)"
|
||||
complete -c footclient -x -s l -l log-colorize -a "always never auto" -d "enable or disable colorization of log output on stderr"
|
||||
complete -c footclient -s v -l version -d "show the version number and quit"
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ _arguments \
|
|||
'(-W --window-size-chars)'{-W,--window-size-chars}'[window WIDTHxHEIGHT, in characters (not set)]:size_chars:()' \
|
||||
'(-s --server-socket)'{-s,--server-socket}'[override the default path to the foot server socket ($XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock)]:server:_files' \
|
||||
'(-H --hold)'{-H,--hold}'[remain open after child process exits]' \
|
||||
'(-N --no-wait)'{-N,--no-wait}'[detach the client process from the running terminal, exiting immediately]' \
|
||||
'(-d --log-level)'{-d,--log-level}'[log level (info)]:loglevel:(info warning error)' \
|
||||
'(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \
|
||||
'(-v --version)'{-v,--version}'[show the version number and quit]' \
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -72,6 +72,7 @@ struct config {
|
|||
wchar_t *word_delimiters;
|
||||
wchar_t *jump_label_letters;
|
||||
bool login_shell;
|
||||
bool no_wait;
|
||||
|
||||
struct {
|
||||
enum conf_size_type type;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ terminal has terminated).
|
|||
*-H*,*--hold*
|
||||
Remain open after child process exits.
|
||||
|
||||
*-N*,*--no-wait*
|
||||
Detach the client process from the running terminal, exiting
|
||||
immediately.
|
||||
|
||||
*-d*,*--log-level*={*info*,*warning*,*error*}
|
||||
Log level, used both for log output on stderr as well as
|
||||
syslog. Default: _info_.
|
||||
|
|
|
|||
137
server.c
137
server.c
|
|
@ -23,6 +23,8 @@
|
|||
#include "xmalloc.h"
|
||||
|
||||
struct client;
|
||||
struct terminal_instance;
|
||||
|
||||
struct server {
|
||||
const struct config *conf;
|
||||
struct fdm *fdm;
|
||||
|
|
@ -33,6 +35,7 @@ struct server {
|
|||
const char *sock_path;
|
||||
|
||||
tll(struct client *) clients;
|
||||
tll(struct terminal_instance *) terminals;
|
||||
};
|
||||
|
||||
struct client {
|
||||
|
|
@ -45,9 +48,17 @@ struct client {
|
|||
size_t idx;
|
||||
} buffer;
|
||||
|
||||
struct config conf;
|
||||
struct terminal *term;
|
||||
struct terminal_instance *instance;
|
||||
};
|
||||
static void client_destroy(struct client *client);
|
||||
|
||||
struct terminal_instance {
|
||||
struct terminal *terminal;
|
||||
struct server *server;
|
||||
struct client *client;
|
||||
struct config conf;
|
||||
};
|
||||
static void instance_destroy(struct terminal_instance *instance, int exit_code);
|
||||
|
||||
static void
|
||||
client_destroy(struct client *client)
|
||||
|
|
@ -55,9 +66,10 @@ client_destroy(struct client *client)
|
|||
if (client == NULL)
|
||||
return;
|
||||
|
||||
if (client->term != NULL) {
|
||||
if (client->instance != NULL) {
|
||||
LOG_WARN("client FD=%d: terminal still alive", client->fd);
|
||||
term_destroy(client->term);
|
||||
client->instance->client = NULL;
|
||||
instance_destroy(client->instance, 1);
|
||||
}
|
||||
|
||||
if (client->fd != -1) {
|
||||
|
|
@ -73,13 +85,6 @@ client_destroy(struct client *client)
|
|||
}
|
||||
|
||||
free(client->buffer.data);
|
||||
|
||||
/* TODO: clone server conf completely, so that we can just call
|
||||
* conf_destroy() here */
|
||||
free(client->conf.term);
|
||||
free(client->conf.title);
|
||||
free(client->conf.app_id);
|
||||
|
||||
free(client);
|
||||
}
|
||||
|
||||
|
|
@ -93,23 +98,48 @@ client_send_exit_code(struct client *client, int exit_code)
|
|||
LOG_ERRNO("failed to write slave exit code to client");
|
||||
}
|
||||
|
||||
static void
|
||||
instance_destroy(struct terminal_instance *instance, int exit_code)
|
||||
{
|
||||
if (instance->terminal != NULL)
|
||||
term_destroy(instance->terminal);
|
||||
|
||||
tll_foreach(instance->server->terminals, it) {
|
||||
if (it->item == instance) {
|
||||
tll_remove(instance->server->terminals, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (instance->client != NULL) {
|
||||
instance->client->instance = NULL;
|
||||
client_send_exit_code(instance->client, exit_code);
|
||||
client_destroy(instance->client);
|
||||
}
|
||||
|
||||
/* TODO: clone server conf completely, so that we can just call
|
||||
* conf_destroy() here */
|
||||
free(instance->conf.term);
|
||||
free(instance->conf.title);
|
||||
free(instance->conf.app_id);
|
||||
free(instance);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
term_shutdown_handler(void *data, int exit_code)
|
||||
{
|
||||
struct client *client = data;
|
||||
struct terminal_instance *instance = data;
|
||||
|
||||
struct wl_shm *shm = client->server->wayl->shm;
|
||||
struct terminal *term = client->term;
|
||||
struct wl_shm *shm = instance->server->wayl->shm;
|
||||
|
||||
shm_purge(shm, shm_cookie_grid(term));
|
||||
shm_purge(shm, shm_cookie_search(term));
|
||||
shm_purge(shm, shm_cookie_grid(instance->terminal));
|
||||
shm_purge(shm, shm_cookie_search(instance->terminal));
|
||||
for (enum csd_surface surf = 0; surf < CSD_SURF_COUNT; surf++)
|
||||
shm_purge(shm, shm_cookie_csd(term, surf));
|
||||
shm_purge(shm, shm_cookie_csd(instance->terminal, surf));
|
||||
|
||||
client_send_exit_code(client, exit_code);
|
||||
|
||||
client->term = NULL;
|
||||
client_destroy(client);
|
||||
instance->terminal = NULL;
|
||||
instance_destroy(instance, exit_code);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -125,7 +155,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
|
||||
xassert(events & EPOLLIN);
|
||||
|
||||
if (client->term != NULL) {
|
||||
if (client->instance != NULL) {
|
||||
uint8_t dummy[128];
|
||||
ssize_t count = read(fd, dummy, sizeof(dummy));
|
||||
LOG_WARN("client unexpectedly sent %zd bytes", count);
|
||||
|
|
@ -186,7 +216,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
|
||||
/* All initialization data received - time to instantiate a terminal! */
|
||||
|
||||
xassert(client->term == NULL);
|
||||
xassert(client->instance == NULL);
|
||||
xassert(client->buffer.data != NULL);
|
||||
xassert(client->buffer.left == 0);
|
||||
|
||||
|
|
@ -248,38 +278,57 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
#undef CHECK_BUF_AND_NULL
|
||||
#undef CHECK_BUF
|
||||
|
||||
client->conf = *server->conf;
|
||||
client->conf.term = strlen(term_env) > 0
|
||||
struct terminal_instance *instance = malloc(sizeof(struct terminal_instance));
|
||||
|
||||
*instance = (struct terminal_instance) {
|
||||
.client = NULL,
|
||||
.server = server,
|
||||
.conf = *server->conf,
|
||||
};
|
||||
instance->conf.term = strlen(term_env) > 0
|
||||
? xstrdup(term_env) : xstrdup(server->conf->term);
|
||||
client->conf.title = strlen(title) > 0
|
||||
instance->conf.title = strlen(title) > 0
|
||||
? xstrdup(title) : xstrdup(server->conf->title);
|
||||
client->conf.app_id = strlen(app_id) > 0
|
||||
instance->conf.app_id = strlen(app_id) > 0
|
||||
? xstrdup(app_id) : xstrdup(server->conf->app_id);
|
||||
client->conf.hold_at_exit = cdata.hold;
|
||||
client->conf.login_shell = cdata.login_shell;
|
||||
instance->conf.hold_at_exit = cdata.hold;
|
||||
instance->conf.login_shell = cdata.login_shell;
|
||||
instance->conf.no_wait = cdata.no_wait;
|
||||
|
||||
if (cdata.maximized)
|
||||
client->conf.startup_mode = STARTUP_MAXIMIZED;
|
||||
instance->conf.startup_mode = STARTUP_MAXIMIZED;
|
||||
else if (cdata.fullscreen)
|
||||
client->conf.startup_mode = STARTUP_FULLSCREEN;
|
||||
instance->conf.startup_mode = STARTUP_FULLSCREEN;
|
||||
|
||||
if (cdata.width > 0 && cdata.height > 0) {
|
||||
client->conf.size.type = cdata.size_type;
|
||||
client->conf.size.width = cdata.width;
|
||||
client->conf.size.height = cdata.height;
|
||||
instance->conf.size.type = cdata.size_type;
|
||||
instance->conf.size.width = cdata.width;
|
||||
instance->conf.size.height = cdata.height;
|
||||
}
|
||||
|
||||
client->term = term_init(
|
||||
&client->conf, server->fdm, server->reaper, server->wayl,
|
||||
"footclient", cwd, cdata.argc, argv, &term_shutdown_handler, client);
|
||||
instance->terminal = term_init(
|
||||
&instance->conf, server->fdm, server->reaper, server->wayl,
|
||||
"footclient", cwd, cdata.argc, argv, &term_shutdown_handler, instance);
|
||||
|
||||
if (client->term == NULL) {
|
||||
if (instance->terminal == NULL) {
|
||||
LOG_ERR("failed to instantiate new terminal");
|
||||
client_send_exit_code(client, -1);
|
||||
instance_destroy(instance, -1);
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
free(argv);
|
||||
if (instance->conf.no_wait) {
|
||||
// the server owns the instance
|
||||
tll_push_back(server->terminals, instance);
|
||||
client_send_exit_code(client, 0);
|
||||
goto shutdown;
|
||||
} else {
|
||||
// the instance is attached to the client
|
||||
instance->client = client;
|
||||
client->instance = instance;
|
||||
free(argv);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
shutdown:
|
||||
|
|
@ -289,8 +338,8 @@ shutdown:
|
|||
fdm_del(fdm, fd);
|
||||
client->fd = -1;
|
||||
|
||||
if (client->term != NULL && !client->term->is_shutting_down)
|
||||
term_shutdown(client->term);
|
||||
if (client->instance != NULL && !client->instance->terminal->is_shutting_down)
|
||||
term_shutdown(client->instance->terminal);
|
||||
else
|
||||
client_destroy(client);
|
||||
|
||||
|
|
@ -421,6 +470,7 @@ server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
.sock_path = sock_path,
|
||||
|
||||
.clients = tll_init(),
|
||||
.terminals = tll_init(),
|
||||
};
|
||||
|
||||
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_server, server))
|
||||
|
|
@ -453,6 +503,11 @@ server_destroy(struct server *server)
|
|||
|
||||
tll_free(server->clients);
|
||||
|
||||
tll_foreach(server->terminals, it)
|
||||
instance_destroy(it->item, 1);
|
||||
|
||||
tll_free(server->terminals);
|
||||
|
||||
fdm_del(server->fdm, server->fd);
|
||||
if (server->sock_path != NULL)
|
||||
unlink(server->sock_path);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue