mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-27 07:58:07 -04:00
commit
e7a4378f18
8 changed files with 115 additions and 42 deletions
|
|
@ -55,6 +55,8 @@
|
||||||
sequences (https://codeberg.org/dnkl/foot/issues/235).
|
sequences (https://codeberg.org/dnkl/foot/issues/235).
|
||||||
* Support for transparent sixels (DCS parameter `P2=1`)
|
* Support for transparent sixels (DCS parameter `P2=1`)
|
||||||
(https://codeberg.org/dnkl/foot/issues/391).
|
(https://codeberg.org/dnkl/foot/issues/391).
|
||||||
|
* `-N,--no-wait` to `footclient`
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/395).
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ struct client_data {
|
||||||
uint8_t fullscreen:1;
|
uint8_t fullscreen:1;
|
||||||
uint8_t hold:1;
|
uint8_t hold:1;
|
||||||
uint8_t login_shell:1;
|
uint8_t login_shell:1;
|
||||||
|
uint8_t no_wait:1;
|
||||||
|
|
||||||
uint16_t cwd_len;
|
uint16_t cwd_len;
|
||||||
uint16_t term_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"
|
" -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"
|
" -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"
|
" -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"
|
" -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"
|
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
|
||||||
" -v,--version show the version number and quit\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'},
|
{"working-directory", required_argument, NULL, 'D'},
|
||||||
{"server-socket", required_argument, NULL, 's'},
|
{"server-socket", required_argument, NULL, 's'},
|
||||||
{"hold", no_argument, NULL, 'H'},
|
{"hold", no_argument, NULL, 'H'},
|
||||||
|
{"no-wait", no_argument, NULL, 'N'},
|
||||||
{"log-level", required_argument, NULL, 'd'},
|
{"log-level", required_argument, NULL, 'd'},
|
||||||
{"log-colorize", optional_argument, NULL, 'l'},
|
{"log-colorize", optional_argument, NULL, 'l'},
|
||||||
{"version", no_argument, NULL, 'v'},
|
{"version", no_argument, NULL, 'v'},
|
||||||
|
|
@ -103,9 +105,10 @@ main(int argc, char *const *argv)
|
||||||
bool maximized = false;
|
bool maximized = false;
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
bool hold = false;
|
bool hold = false;
|
||||||
|
bool no_wait = false;
|
||||||
|
|
||||||
while (true) {
|
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)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -170,6 +173,10 @@ main(int argc, char *const *argv)
|
||||||
hold = true;
|
hold = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'N':
|
||||||
|
no_wait = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'd': {
|
case 'd': {
|
||||||
int lvl = log_level_from_string(optarg);
|
int lvl = log_level_from_string(optarg);
|
||||||
if (unlikely(lvl < 0)) {
|
if (unlikely(lvl < 0)) {
|
||||||
|
|
@ -290,6 +297,7 @@ main(int argc, char *const *argv)
|
||||||
.fullscreen = fullscreen,
|
.fullscreen = fullscreen,
|
||||||
.hold = hold,
|
.hold = hold,
|
||||||
.login_shell = login_shell,
|
.login_shell = login_shell,
|
||||||
|
.no_wait = no_wait,
|
||||||
.cwd_len = cwd_len,
|
.cwd_len = cwd_len,
|
||||||
.term_len = term_len,
|
.term_len = term_len,
|
||||||
.title_len = title_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 -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 -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 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 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 -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"
|
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:()' \
|
'(-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' \
|
'(-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]' \
|
'(-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)' \
|
'(-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)' \
|
'(-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]' \
|
'(-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 *word_delimiters;
|
||||||
wchar_t *jump_label_letters;
|
wchar_t *jump_label_letters;
|
||||||
bool login_shell;
|
bool login_shell;
|
||||||
|
bool no_wait;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
enum conf_size_type type;
|
enum conf_size_type type;
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,10 @@ terminal has terminated).
|
||||||
*-H*,*--hold*
|
*-H*,*--hold*
|
||||||
Remain open after child process exits.
|
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*}
|
*-d*,*--log-level*={*info*,*warning*,*error*}
|
||||||
Log level, used both for log output on stderr as well as
|
Log level, used both for log output on stderr as well as
|
||||||
syslog. Default: _info_.
|
syslog. Default: _info_.
|
||||||
|
|
|
||||||
137
server.c
137
server.c
|
|
@ -23,6 +23,8 @@
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
struct client;
|
struct client;
|
||||||
|
struct terminal_instance;
|
||||||
|
|
||||||
struct server {
|
struct server {
|
||||||
const struct config *conf;
|
const struct config *conf;
|
||||||
struct fdm *fdm;
|
struct fdm *fdm;
|
||||||
|
|
@ -33,6 +35,7 @@ struct server {
|
||||||
const char *sock_path;
|
const char *sock_path;
|
||||||
|
|
||||||
tll(struct client *) clients;
|
tll(struct client *) clients;
|
||||||
|
tll(struct terminal_instance *) terminals;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct client {
|
struct client {
|
||||||
|
|
@ -45,9 +48,17 @@ struct client {
|
||||||
size_t idx;
|
size_t idx;
|
||||||
} buffer;
|
} buffer;
|
||||||
|
|
||||||
struct config conf;
|
struct terminal_instance *instance;
|
||||||
struct terminal *term;
|
|
||||||
};
|
};
|
||||||
|
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
|
static void
|
||||||
client_destroy(struct client *client)
|
client_destroy(struct client *client)
|
||||||
|
|
@ -55,9 +66,10 @@ client_destroy(struct client *client)
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (client->term != NULL) {
|
if (client->instance != NULL) {
|
||||||
LOG_WARN("client FD=%d: terminal still alive", client->fd);
|
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) {
|
if (client->fd != -1) {
|
||||||
|
|
@ -73,13 +85,6 @@ client_destroy(struct client *client)
|
||||||
}
|
}
|
||||||
|
|
||||||
free(client->buffer.data);
|
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);
|
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");
|
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
|
static void
|
||||||
term_shutdown_handler(void *data, int exit_code)
|
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 wl_shm *shm = instance->server->wayl->shm;
|
||||||
struct terminal *term = client->term;
|
|
||||||
|
|
||||||
shm_purge(shm, shm_cookie_grid(term));
|
shm_purge(shm, shm_cookie_grid(instance->terminal));
|
||||||
shm_purge(shm, shm_cookie_search(term));
|
shm_purge(shm, shm_cookie_search(instance->terminal));
|
||||||
for (enum csd_surface surf = 0; surf < CSD_SURF_COUNT; surf++)
|
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);
|
instance->terminal = NULL;
|
||||||
|
instance_destroy(instance, exit_code);
|
||||||
client->term = NULL;
|
|
||||||
client_destroy(client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -125,7 +155,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
|
|
||||||
xassert(events & EPOLLIN);
|
xassert(events & EPOLLIN);
|
||||||
|
|
||||||
if (client->term != NULL) {
|
if (client->instance != NULL) {
|
||||||
uint8_t dummy[128];
|
uint8_t dummy[128];
|
||||||
ssize_t count = read(fd, dummy, sizeof(dummy));
|
ssize_t count = read(fd, dummy, sizeof(dummy));
|
||||||
LOG_WARN("client unexpectedly sent %zd bytes", count);
|
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! */
|
/* 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.data != NULL);
|
||||||
xassert(client->buffer.left == 0);
|
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_AND_NULL
|
||||||
#undef CHECK_BUF
|
#undef CHECK_BUF
|
||||||
|
|
||||||
client->conf = *server->conf;
|
struct terminal_instance *instance = malloc(sizeof(struct terminal_instance));
|
||||||
client->conf.term = strlen(term_env) > 0
|
|
||||||
|
*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);
|
? 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);
|
? 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);
|
? xstrdup(app_id) : xstrdup(server->conf->app_id);
|
||||||
client->conf.hold_at_exit = cdata.hold;
|
instance->conf.hold_at_exit = cdata.hold;
|
||||||
client->conf.login_shell = cdata.login_shell;
|
instance->conf.login_shell = cdata.login_shell;
|
||||||
|
instance->conf.no_wait = cdata.no_wait;
|
||||||
|
|
||||||
if (cdata.maximized)
|
if (cdata.maximized)
|
||||||
client->conf.startup_mode = STARTUP_MAXIMIZED;
|
instance->conf.startup_mode = STARTUP_MAXIMIZED;
|
||||||
else if (cdata.fullscreen)
|
else if (cdata.fullscreen)
|
||||||
client->conf.startup_mode = STARTUP_FULLSCREEN;
|
instance->conf.startup_mode = STARTUP_FULLSCREEN;
|
||||||
|
|
||||||
if (cdata.width > 0 && cdata.height > 0) {
|
if (cdata.width > 0 && cdata.height > 0) {
|
||||||
client->conf.size.type = cdata.size_type;
|
instance->conf.size.type = cdata.size_type;
|
||||||
client->conf.size.width = cdata.width;
|
instance->conf.size.width = cdata.width;
|
||||||
client->conf.size.height = cdata.height;
|
instance->conf.size.height = cdata.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
client->term = term_init(
|
instance->terminal = term_init(
|
||||||
&client->conf, server->fdm, server->reaper, server->wayl,
|
&instance->conf, server->fdm, server->reaper, server->wayl,
|
||||||
"footclient", cwd, cdata.argc, argv, &term_shutdown_handler, client);
|
"footclient", cwd, cdata.argc, argv, &term_shutdown_handler, instance);
|
||||||
|
|
||||||
if (client->term == NULL) {
|
if (instance->terminal == NULL) {
|
||||||
LOG_ERR("failed to instantiate new terminal");
|
LOG_ERR("failed to instantiate new terminal");
|
||||||
client_send_exit_code(client, -1);
|
client_send_exit_code(client, -1);
|
||||||
|
instance_destroy(instance, -1);
|
||||||
goto shutdown;
|
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;
|
return true;
|
||||||
|
|
||||||
shutdown:
|
shutdown:
|
||||||
|
|
@ -289,8 +338,8 @@ shutdown:
|
||||||
fdm_del(fdm, fd);
|
fdm_del(fdm, fd);
|
||||||
client->fd = -1;
|
client->fd = -1;
|
||||||
|
|
||||||
if (client->term != NULL && !client->term->is_shutting_down)
|
if (client->instance != NULL && !client->instance->terminal->is_shutting_down)
|
||||||
term_shutdown(client->term);
|
term_shutdown(client->instance->terminal);
|
||||||
else
|
else
|
||||||
client_destroy(client);
|
client_destroy(client);
|
||||||
|
|
||||||
|
|
@ -421,6 +470,7 @@ server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
.sock_path = sock_path,
|
.sock_path = sock_path,
|
||||||
|
|
||||||
.clients = tll_init(),
|
.clients = tll_init(),
|
||||||
|
.terminals = tll_init(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_server, server))
|
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_server, server))
|
||||||
|
|
@ -453,6 +503,11 @@ server_destroy(struct server *server)
|
||||||
|
|
||||||
tll_free(server->clients);
|
tll_free(server->clients);
|
||||||
|
|
||||||
|
tll_foreach(server->terminals, it)
|
||||||
|
instance_destroy(it->item, 1);
|
||||||
|
|
||||||
|
tll_free(server->terminals);
|
||||||
|
|
||||||
fdm_del(server->fdm, server->fd);
|
fdm_del(server->fdm, server->fd);
|
||||||
if (server->sock_path != NULL)
|
if (server->sock_path != NULL)
|
||||||
unlink(server->sock_path);
|
unlink(server->sock_path);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue