mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-31 07:11:09 -04:00
commit
68494956b7
11 changed files with 161 additions and 137 deletions
|
|
@ -64,7 +64,8 @@
|
||||||
* Support for LS2 and LS3 (locking shift) escape sequences
|
* Support for LS2 and LS3 (locking shift) escape sequences
|
||||||
(https://codeberg.org/dnkl/foot/issues/581).
|
(https://codeberg.org/dnkl/foot/issues/581).
|
||||||
* Support for overriding configuration options on the command line
|
* Support for overriding configuration options on the command line
|
||||||
(https://codeberg.org/dnkl/foot/issues/554).
|
(https://codeberg.org/dnkl/foot/issues/554,
|
||||||
|
https://codeberg.org/dnkl/foot/issues/600).
|
||||||
* `underline-offset` option to `foot.ini`
|
* `underline-offset` option to `foot.ini`
|
||||||
(https://codeberg.org/dnkl/foot/issues/490).
|
(https://codeberg.org/dnkl/foot/issues/490).
|
||||||
* `csd.button-color` option to `foot.ini`.
|
* `csd.button-color` option to `foot.ini`.
|
||||||
|
|
|
||||||
|
|
@ -4,32 +4,23 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct client_argv {
|
struct client_string {
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
/* char arg[static len]; */
|
/* char str[static len]; */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct client_data {
|
struct client_data {
|
||||||
unsigned width;
|
bool hold:1;
|
||||||
unsigned height;
|
bool no_wait:1;
|
||||||
uint8_t size_type:1; // Values correspond to enum conf_size_type
|
uint8_t reserved:6;
|
||||||
uint8_t maximized:1;
|
|
||||||
uint8_t fullscreen:1;
|
|
||||||
uint8_t hold: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 override_count;
|
||||||
uint16_t title_len;
|
|
||||||
uint16_t app_id_len;
|
|
||||||
|
|
||||||
uint16_t argc;
|
uint16_t argc;
|
||||||
|
|
||||||
/* char cwd[static cwd_len]; */
|
/* char cwd[static cwd_len]; */
|
||||||
/* char term[static term_len]; */
|
/* struct client_string overrides[static override_count]; */
|
||||||
/* char title[static title_len]; */
|
/* struct client_string argv[static argc]; */
|
||||||
/* char app_id[static app_id_len]; */
|
} __attribute__((packed));
|
||||||
|
|
||||||
/* struct client_argv argv[static argc]; */
|
_Static_assert(sizeof(struct client_data) == 7, "protocol struct size error");
|
||||||
};
|
|
||||||
|
|
|
||||||
169
client.c
169
client.c
|
|
@ -12,6 +12,8 @@
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <tllist.h>
|
||||||
|
|
||||||
#define LOG_MODULE "foot-client"
|
#define LOG_MODULE "foot-client"
|
||||||
#define LOG_ENABLE_DBG 0
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
@ -23,6 +25,12 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
struct override {
|
||||||
|
size_t len;
|
||||||
|
char *str;
|
||||||
|
};
|
||||||
|
typedef tll(struct override) override_list_t;
|
||||||
|
|
||||||
static volatile sig_atomic_t aborted = 0;
|
static volatile sig_atomic_t aborted = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -61,11 +69,27 @@ print_usage(const char *prog_name)
|
||||||
" -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"
|
" -N,--no-wait detach the client process from the running terminal, exiting immediately\n"
|
||||||
|
" -o,--override=[section.]key=value override configuration option\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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool NOINLINE
|
||||||
|
push_override(override_list_t *overrides, const char *s, uint64_t *total_len)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s) + 1;
|
||||||
|
if (len >= 1 << (8 * sizeof(struct client_string))) {
|
||||||
|
LOG_ERR("override length overflow");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct override o = {len, xstrdup(s)};
|
||||||
|
tll_push_back(*overrides, o);
|
||||||
|
*total_len += sizeof(struct client_string) + o.len;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *const *argv)
|
main(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
|
|
@ -89,6 +113,7 @@ main(int argc, char *const *argv)
|
||||||
{"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'},
|
{"no-wait", no_argument, NULL, 'N'},
|
||||||
|
{"override", required_argument, NULL, 'o'},
|
||||||
{"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'},
|
||||||
|
|
@ -96,78 +121,98 @@ main(int argc, char *const *argv)
|
||||||
{NULL, no_argument, NULL, 0},
|
{NULL, no_argument, NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *term = "";
|
|
||||||
const char *title = "";
|
|
||||||
const char *app_id = "";
|
|
||||||
const char *custom_cwd = NULL;
|
const char *custom_cwd = NULL;
|
||||||
unsigned size_type = 0; // enum conf_size_type (without pulling in tllist/fcft via config.h)
|
|
||||||
unsigned width = 0;
|
|
||||||
unsigned height = 0;
|
|
||||||
const char *server_socket_path = NULL;
|
const char *server_socket_path = NULL;
|
||||||
enum log_class log_level = LOG_CLASS_INFO;
|
enum log_class log_level = LOG_CLASS_INFO;
|
||||||
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
|
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
|
||||||
bool login_shell = false;
|
|
||||||
bool maximized = false;
|
|
||||||
bool fullscreen = false;
|
|
||||||
bool hold = false;
|
bool hold = false;
|
||||||
|
|
||||||
|
/* Used to format overrides */
|
||||||
bool no_wait = false;
|
bool no_wait = false;
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
/* Total packet length, not (yet) including overrides or argv[] */
|
||||||
|
uint64_t total_len = 0;
|
||||||
|
|
||||||
|
/* malloc:ed and needs to be in scope of all goto's */
|
||||||
|
char *_cwd = NULL;
|
||||||
|
override_list_t overrides = tll_init();
|
||||||
|
struct client_string *cargv = NULL;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNd:l::vh", longopts, NULL);
|
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNo:d:l::vh", longopts, NULL);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 't':
|
case 't':
|
||||||
term = optarg;
|
snprintf(buf, sizeof(buf), "term=%s", optarg);
|
||||||
|
if (!push_override(&overrides, buf, &total_len))
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
title = optarg;
|
snprintf(buf, sizeof(buf), "title=%s", optarg);
|
||||||
|
if (!push_override(&overrides, buf, &total_len))
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
app_id = optarg;
|
snprintf(buf, sizeof(buf), "app-id=%s", optarg);
|
||||||
|
if (!push_override(&overrides, buf, &total_len))
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
login_shell = true;
|
if (!push_override(&overrides, "login-shell=yes", &total_len))
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D': {
|
case 'D': {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(optarg, &st) < 0 || !(st.st_mode & S_IFDIR)) {
|
if (stat(optarg, &st) < 0 || !(st.st_mode & S_IFDIR)) {
|
||||||
fprintf(stderr, "error: %s: not a directory\n", optarg);
|
fprintf(stderr, "error: %s: not a directory\n", optarg);
|
||||||
return ret;
|
goto err;
|
||||||
}
|
}
|
||||||
custom_cwd = optarg;
|
custom_cwd = optarg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'w':
|
case 'w': {
|
||||||
|
unsigned width, height;
|
||||||
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
||||||
fprintf(stderr, "error: invalid window-size-pixels: %s\n", optarg);
|
fprintf(stderr, "error: invalid window-size-pixels: %s\n", optarg);
|
||||||
return ret;
|
goto err;
|
||||||
}
|
}
|
||||||
size_type = 0; // CONF_SIZE_PX
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'W':
|
snprintf(buf, sizeof(buf), "initial-window-size-pixels=%ux%u", width, height);
|
||||||
|
if (!push_override(&overrides, buf, &total_len))
|
||||||
|
goto err;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'W': {
|
||||||
|
unsigned width, height;
|
||||||
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
||||||
fprintf(stderr, "error: invalid window-size-chars: %s\n", optarg);
|
fprintf(stderr, "error: invalid window-size-chars: %s\n", optarg);
|
||||||
return ret;
|
goto err;
|
||||||
}
|
}
|
||||||
size_type = 1; // CONF_SIZE_CELLS
|
|
||||||
|
snprintf(buf, sizeof(buf), "initial-window-size-chars=%ux%u", width, height);
|
||||||
|
if (!push_override(&overrides, buf, &total_len))
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
maximized = true;
|
if (!push_override(&overrides, "initial-window-mode=maximized", &total_len))
|
||||||
fullscreen = false;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
fullscreen = true;
|
if (!push_override(&overrides, "initial-window-mode=fullscreen", &total_len))
|
||||||
maximized = false;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
|
|
@ -182,6 +227,11 @@ main(int argc, char *const *argv)
|
||||||
no_wait = true;
|
no_wait = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
if (!push_override(&overrides, optarg, &total_len))
|
||||||
|
goto err;
|
||||||
|
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)) {
|
||||||
|
|
@ -190,7 +240,7 @@ main(int argc, char *const *argv)
|
||||||
"-d,--log-level: %s: argument must be one of %s\n",
|
"-d,--log-level: %s: argument must be one of %s\n",
|
||||||
optarg,
|
optarg,
|
||||||
log_level_string_hint());
|
log_level_string_hint());
|
||||||
return ret;
|
goto err;
|
||||||
}
|
}
|
||||||
log_level = lvl;
|
log_level = lvl;
|
||||||
break;
|
break;
|
||||||
|
|
@ -205,20 +255,22 @@ main(int argc, char *const *argv)
|
||||||
log_colorize = LOG_COLORIZE_ALWAYS;
|
log_colorize = LOG_COLORIZE_ALWAYS;
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "%s: argument must be one of 'never', 'always' or 'auto'\n", optarg);
|
fprintf(stderr, "%s: argument must be one of 'never', 'always' or 'auto'\n", optarg);
|
||||||
return ret;
|
goto err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("footclient %s\n", version_and_features());
|
printf("footclient %s\n", version_and_features());
|
||||||
return EXIT_SUCCESS;
|
ret = EXIT_SUCCESS;
|
||||||
|
goto err;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
print_usage(prog_name);
|
print_usage(prog_name);
|
||||||
return EXIT_SUCCESS;
|
ret = EXIT_SUCCESS;
|
||||||
|
goto err;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return ret;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,10 +279,6 @@ main(int argc, char *const *argv)
|
||||||
|
|
||||||
log_init(log_colorize, false, LOG_FACILITY_USER, log_level);
|
log_init(log_colorize, false, LOG_FACILITY_USER, log_level);
|
||||||
|
|
||||||
/* malloc:ed and needs to be in scope of all goto's */
|
|
||||||
char *_cwd = NULL;
|
|
||||||
struct client_argv *cargv = NULL;
|
|
||||||
|
|
||||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
LOG_ERRNO("failed to create socket");
|
LOG_ERRNO("failed to create socket");
|
||||||
|
|
@ -290,37 +338,21 @@ main(int argc, char *const *argv)
|
||||||
|
|
||||||
/* String lengths, including NULL terminator */
|
/* String lengths, including NULL terminator */
|
||||||
const size_t cwd_len = strlen(cwd) + 1;
|
const size_t cwd_len = strlen(cwd) + 1;
|
||||||
const size_t term_len = strlen(term) + 1;
|
const size_t override_count = tll_length(overrides);
|
||||||
const size_t title_len = strlen(title) + 1;
|
|
||||||
const size_t app_id_len = strlen(app_id) + 1;
|
|
||||||
|
|
||||||
const struct client_data data = {
|
const struct client_data data = {
|
||||||
.width = width,
|
|
||||||
.height = height,
|
|
||||||
.size_type = size_type,
|
|
||||||
.maximized = maximized,
|
|
||||||
.fullscreen = fullscreen,
|
|
||||||
.hold = hold,
|
.hold = hold,
|
||||||
.login_shell = login_shell,
|
|
||||||
.no_wait = no_wait,
|
.no_wait = no_wait,
|
||||||
.cwd_len = cwd_len,
|
.cwd_len = cwd_len,
|
||||||
.term_len = term_len,
|
.override_count = override_count,
|
||||||
.title_len = title_len,
|
|
||||||
.app_id_len = app_id_len,
|
|
||||||
.argc = argc,
|
.argc = argc,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Total packet length, not (yet) including argv[] */
|
/* Total packet length, not (yet) including argv[] */
|
||||||
uint64_t total_len = (
|
total_len += sizeof(data) + cwd_len;
|
||||||
sizeof(data) +
|
|
||||||
cwd_len +
|
|
||||||
term_len +
|
|
||||||
title_len +
|
|
||||||
app_id_len);
|
|
||||||
|
|
||||||
cargv = xmalloc(argc * sizeof(cargv[0]));
|
|
||||||
|
|
||||||
/* Add argv[] size to total packet length */
|
/* Add argv[] size to total packet length */
|
||||||
|
cargv = xmalloc(argc * sizeof(cargv[0]));
|
||||||
for (size_t i = 0; i < argc; i++) {
|
for (size_t i = 0; i < argc; i++) {
|
||||||
const size_t arg_len = strlen(argv[i]) + 1;
|
const size_t arg_len = strlen(argv[i]) + 1;
|
||||||
|
|
||||||
|
|
@ -336,9 +368,7 @@ main(int argc, char *const *argv)
|
||||||
/* Check for size overflows */
|
/* Check for size overflows */
|
||||||
if (total_len >= 1llu << (8 * sizeof(uint32_t)) ||
|
if (total_len >= 1llu << (8 * sizeof(uint32_t)) ||
|
||||||
cwd_len >= 1 << (8 * sizeof(data.cwd_len)) ||
|
cwd_len >= 1 << (8 * sizeof(data.cwd_len)) ||
|
||||||
term_len >= 1 << (8 * sizeof(data.term_len)) ||
|
override_count > (size_t)(unsigned int)data.override_count ||
|
||||||
title_len >= 1 << (8 * sizeof(data.title_len)) ||
|
|
||||||
app_id_len >= 1 << (8 * sizeof(data.app_id_len)) ||
|
|
||||||
argc > (int)(unsigned int)data.argc)
|
argc > (int)(unsigned int)data.argc)
|
||||||
{
|
{
|
||||||
LOG_ERR("size overflow");
|
LOG_ERR("size overflow");
|
||||||
|
|
@ -348,21 +378,30 @@ main(int argc, char *const *argv)
|
||||||
/* Send everything except argv[] */
|
/* Send everything except argv[] */
|
||||||
if (send(fd, &(uint32_t){total_len}, sizeof(uint32_t), 0) != sizeof(uint32_t) ||
|
if (send(fd, &(uint32_t){total_len}, sizeof(uint32_t), 0) != sizeof(uint32_t) ||
|
||||||
send(fd, &data, sizeof(data), 0) != sizeof(data) ||
|
send(fd, &data, sizeof(data), 0) != sizeof(data) ||
|
||||||
send(fd, cwd, cwd_len, 0) != cwd_len ||
|
send(fd, cwd, cwd_len, 0) != cwd_len)
|
||||||
send(fd, term, term_len, 0) != term_len ||
|
|
||||||
send(fd, title, title_len, 0) != title_len ||
|
|
||||||
send(fd, app_id, app_id_len, 0) != app_id_len)
|
|
||||||
{
|
{
|
||||||
LOG_ERRNO("failed to send setup packet to server");
|
LOG_ERRNO("failed to send setup packet to server");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send overrides */
|
||||||
|
tll_foreach(overrides, it) {
|
||||||
|
const struct override *o = &it->item;
|
||||||
|
struct client_string s = {o->len};
|
||||||
|
if (send(fd, &s, sizeof(s), 0) != sizeof(s) ||
|
||||||
|
send(fd, o->str, o->len, 0) != o->len)
|
||||||
|
{
|
||||||
|
LOG_ERRNO("failed to send setup packet (overrides) to server");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Send argv[] */
|
/* Send argv[] */
|
||||||
for (size_t i = 0; i < argc; i++) {
|
for (size_t i = 0; i < argc; i++) {
|
||||||
if (send(fd, &cargv[i], sizeof(cargv[i]), 0) != sizeof(cargv[i]) ||
|
if (send(fd, &cargv[i], sizeof(cargv[i]), 0) != sizeof(cargv[i]) ||
|
||||||
send(fd, argv[i], cargv[i].len, 0) != cargv[i].len)
|
send(fd, argv[i], cargv[i].len, 0) != cargv[i].len)
|
||||||
{
|
{
|
||||||
LOG_ERRNO("failed to send setup packet to server");
|
LOG_ERRNO("failed to send setup packet (argv) to server");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -386,6 +425,10 @@ main(int argc, char *const *argv)
|
||||||
ret = exit_code;
|
ret = exit_code;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
tll_foreach(overrides, it) {
|
||||||
|
free(it->item.str);
|
||||||
|
tll_remove(overrides, it);
|
||||||
|
}
|
||||||
free(cargv);
|
free(cargv);
|
||||||
free(_cwd);
|
free(_cwd);
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ _footclient()
|
||||||
"--log-level"
|
"--log-level"
|
||||||
"--log-colorize"
|
"--log-colorize"
|
||||||
"--maximized"
|
"--maximized"
|
||||||
|
"--override"
|
||||||
"--server-socket"
|
"--server-socket"
|
||||||
"--term"
|
"--term"
|
||||||
"--title"
|
"--title"
|
||||||
|
|
@ -61,7 +62,7 @@ _footclient()
|
||||||
COMPREPLY=( $(compgen -W "error warning info" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "error warning info" -- ${cur}) )
|
||||||
elif [[ ${prev} == '--log-colorize' ]] ; then
|
elif [[ ${prev} == '--log-colorize' ]] ; then
|
||||||
COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) )
|
||||||
elif [[ ${prev} =~ ^(--app-id|--help|--title|--version|--window-size-chars|--window-size-pixels|)$ ]] ; then
|
elif [[ ${prev} =~ ^(--app-id|--help|--override|--title|--version|--window-size-chars|--window-size-pixels|)$ ]] ; then
|
||||||
: # don't autocomplete for these flags
|
: # don't autocomplete for these flags
|
||||||
else
|
else
|
||||||
# complete commands from $PATH
|
# complete commands from $PATH
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ complete -c footclient -x -s W -l window-size-chars
|
||||||
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 -s N -l no-wait -d "detach the client process from the running terminal, exiting immediately"
|
||||||
|
complete -c footclient -x -s o -l override -d "configuration option to override, in form SECTION.KEY=VALUE"
|
||||||
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"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ _arguments \
|
||||||
'(-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]' \
|
'(-N --no-wait)'{-N,--no-wait}'[detach the client process from the running terminal, exiting immediately]' \
|
||||||
|
'(-o --override)'{-o,--override}'[configuration option to override, in form SECTION.KEY=VALUE]:()' \
|
||||||
'(-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]' \
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ the foot command line
|
||||||
Verify configuration and then exit with 0 if ok, otherwise exit
|
Verify configuration and then exit with 0 if ok, otherwise exit
|
||||||
with 230 (see *EXIT STATUS*).
|
with 230 (see *EXIT STATUS*).
|
||||||
|
|
||||||
*-o*,*--override* [_SECTION_.]_KEY_=_VALUE_
|
*-o*,*--override*=[_SECTION_.]_KEY_=_VALUE_
|
||||||
Override an option set in the configuration file. If _SECTION_ is not
|
Override an option set in the configuration file. If _SECTION_ is not
|
||||||
given, defaults to _main_.
|
given, defaults to _main_.
|
||||||
|
|
||||||
*-f*,*--font*=_FONT_
|
*-f*,*--font*=_FONT_
|
||||||
Comma separated list of fonts to use, in fontconfig format (see
|
Comma separated list of fonts to use, in fontconfig format (see
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,10 @@ terminal has terminated.
|
||||||
Detach the client process from the running terminal, exiting
|
Detach the client process from the running terminal, exiting
|
||||||
immediately.
|
immediately.
|
||||||
|
|
||||||
|
*-o*,*--override*=[_SECTION_.]_KEY_=_VALUE_
|
||||||
|
Override an option set in the configuration file. If _SECTION_ is not
|
||||||
|
given, defaults to _main_.
|
||||||
|
|
||||||
*-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_.
|
||||||
|
|
|
||||||
2
main.c
2
main.c
|
|
@ -62,7 +62,7 @@ print_usage(const char *prog_name)
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -c,--config=PATH load configuration from PATH ($XDG_CONFIG_HOME/foot/foot.ini)\n"
|
" -c,--config=PATH load configuration from PATH ($XDG_CONFIG_HOME/foot/foot.ini)\n"
|
||||||
" -C,--check-config verify configuration, exit with 0 if ok, otherwise exit with 1\n"
|
" -C,--check-config verify configuration, exit with 0 if ok, otherwise exit with 1\n"
|
||||||
" -o,--override [section.]key=value override configuration option\n"
|
" -o,--override=[section.]key=value override configuration option\n"
|
||||||
" -f,--font=FONT comma separated list of fonts in fontconfig format (monospace)\n"
|
" -f,--font=FONT comma separated list of fonts in fontconfig format (monospace)\n"
|
||||||
" -t,--term=TERM value to set the environment variable TERM to (%s)\n"
|
" -t,--term=TERM value to set the environment variable TERM to (%s)\n"
|
||||||
" -T,--title=TITLE initial window title (foot)\n"
|
" -T,--title=TITLE initial window title (foot)\n"
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,7 @@ executable(
|
||||||
'macros.h',
|
'macros.h',
|
||||||
'util.h',
|
'util.h',
|
||||||
version,
|
version,
|
||||||
|
dependencies: [tllist],
|
||||||
link_with: common,
|
link_with: common,
|
||||||
install: true)
|
install: true)
|
||||||
|
|
||||||
|
|
|
||||||
81
server.c
81
server.c
|
|
@ -120,11 +120,9 @@ instance_destroy(struct terminal_instance *instance, int exit_code)
|
||||||
/* TODO: clone server conf completely, so that we can just call
|
/* TODO: clone server conf completely, so that we can just call
|
||||||
* conf_destroy() here */
|
* conf_destroy() here */
|
||||||
if (instance->conf != NULL) {
|
if (instance->conf != NULL) {
|
||||||
free(instance->conf->term);
|
config_free(*instance->conf);
|
||||||
free(instance->conf->title);
|
free(instance->conf);
|
||||||
free(instance->conf->app_id);
|
|
||||||
}
|
}
|
||||||
free(instance->conf);
|
|
||||||
free(instance);
|
free(instance);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -242,6 +240,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
|
|
||||||
uint8_t *p = client->buffer.data;
|
uint8_t *p = client->buffer.data;
|
||||||
const uint8_t *end = &client->buffer.data[client->buffer.idx];
|
const uint8_t *end = &client->buffer.data[client->buffer.idx];
|
||||||
|
config_override_t overrides = tll_init();
|
||||||
|
|
||||||
struct client_data cdata;
|
struct client_data cdata;
|
||||||
CHECK_BUF(sizeof(cdata));
|
CHECK_BUF(sizeof(cdata));
|
||||||
|
|
@ -252,25 +251,25 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
const char *cwd = (const char *)p; p += cdata.cwd_len;
|
const char *cwd = (const char *)p; p += cdata.cwd_len;
|
||||||
LOG_DBG("CWD = %.*s", cdata.cwd_len, cwd);
|
LOG_DBG("CWD = %.*s", cdata.cwd_len, cwd);
|
||||||
|
|
||||||
CHECK_BUF_AND_NULL(cdata.term_len);
|
/* Overrides */
|
||||||
const char *term_env = (const char *)p; p += cdata.term_len;
|
for (uint16_t i = 0; i < cdata.override_count; i++) {
|
||||||
LOG_DBG("TERM = %.*s", cdata.term_len, term_env);
|
struct client_string arg;
|
||||||
|
|
||||||
CHECK_BUF_AND_NULL(cdata.title_len);
|
|
||||||
const char *title = (const char *)p; p += cdata.title_len;
|
|
||||||
LOG_DBG("title = %.*s", cdata.title_len, title);
|
|
||||||
|
|
||||||
CHECK_BUF_AND_NULL(cdata.app_id_len);
|
|
||||||
const char *app_id = (const char *)p; p += cdata.app_id_len;
|
|
||||||
LOG_DBG("app-id = %.*s", cdata.app_id_len, app_id);
|
|
||||||
|
|
||||||
argv = xcalloc(cdata.argc + 1, sizeof(argv[0]));
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < cdata.argc; i++) {
|
|
||||||
struct client_argv arg;
|
|
||||||
CHECK_BUF(sizeof(arg));
|
CHECK_BUF(sizeof(arg));
|
||||||
memcpy(&arg, p, sizeof(arg));
|
memcpy(&arg, p, sizeof(arg)); p += sizeof(arg);
|
||||||
p += sizeof(arg);
|
|
||||||
|
CHECK_BUF_AND_NULL(arg.len);
|
||||||
|
const char *str = (const char *)p;
|
||||||
|
p += arg.len;
|
||||||
|
|
||||||
|
tll_push_back(overrides, xstrdup(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* argv */
|
||||||
|
argv = xcalloc(cdata.argc + 1, sizeof(argv[0]));
|
||||||
|
for (uint16_t i = 0; i < cdata.argc; i++) {
|
||||||
|
struct client_string arg;
|
||||||
|
CHECK_BUF(sizeof(arg));
|
||||||
|
memcpy(&arg, p, sizeof(arg)); p += sizeof(arg);
|
||||||
|
|
||||||
CHECK_BUF_AND_NULL(arg.len);
|
CHECK_BUF_AND_NULL(arg.len);
|
||||||
argv[i] = (char *)p; p += arg.len;
|
argv[i] = (char *)p; p += arg.len;
|
||||||
|
|
@ -284,41 +283,21 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
struct terminal_instance *instance = malloc(sizeof(struct terminal_instance));
|
struct terminal_instance *instance = malloc(sizeof(struct terminal_instance));
|
||||||
|
|
||||||
const bool need_to_clone_conf =
|
const bool need_to_clone_conf =
|
||||||
strlen(term_env) > 0 ||
|
tll_length(overrides)> 0 ||
|
||||||
strlen(title) > 0 ||
|
|
||||||
strlen(app_id) > 0 ||
|
|
||||||
cdata.hold != server->conf->hold_at_exit ||
|
cdata.hold != server->conf->hold_at_exit ||
|
||||||
cdata.login_shell != server->conf->login_shell ||
|
cdata.no_wait != server->conf->no_wait;
|
||||||
cdata.no_wait != server->conf->no_wait ||
|
|
||||||
(cdata.maximized && server->conf->startup_mode != STARTUP_MAXIMIZED) ||
|
|
||||||
(cdata.fullscreen && server->conf->startup_mode != STARTUP_FULLSCREEN) ||
|
|
||||||
(cdata.width > 0 && cdata.height > 0);
|
|
||||||
|
|
||||||
struct config *conf = NULL;
|
struct config *conf = NULL;
|
||||||
if (need_to_clone_conf) {
|
if (need_to_clone_conf) {
|
||||||
conf = xmalloc(sizeof(*conf));
|
conf = config_clone(server->conf);
|
||||||
*conf = *server->conf;
|
|
||||||
|
|
||||||
conf->term = strlen(term_env) > 0
|
if (cdata.no_wait != server->conf->no_wait)
|
||||||
? xstrdup(term_env) : xstrdup(server->conf->term);
|
conf->no_wait = cdata.no_wait;
|
||||||
conf->title = strlen(title) > 0
|
|
||||||
? xstrdup(title) : xstrdup(server->conf->title);
|
|
||||||
conf->app_id = strlen(app_id) > 0
|
|
||||||
? xstrdup(app_id) : xstrdup(server->conf->app_id);
|
|
||||||
conf->hold_at_exit = cdata.hold;
|
|
||||||
conf->login_shell = cdata.login_shell;
|
|
||||||
conf->no_wait = cdata.no_wait;
|
|
||||||
|
|
||||||
if (cdata.maximized)
|
if (cdata.hold != server->conf->hold_at_exit)
|
||||||
conf->startup_mode = STARTUP_MAXIMIZED;
|
conf->hold_at_exit = cdata.hold;
|
||||||
else if (cdata.fullscreen)
|
|
||||||
conf->startup_mode = STARTUP_FULLSCREEN;
|
|
||||||
|
|
||||||
if (cdata.width > 0 && cdata.height > 0) {
|
config_override_apply(conf, &overrides, false);
|
||||||
conf->size.type = cdata.size_type;
|
|
||||||
conf->size.width = cdata.width;
|
|
||||||
conf->size.height = cdata.height;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*instance = (struct terminal_instance) {
|
*instance = (struct terminal_instance) {
|
||||||
|
|
@ -349,6 +328,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
instance->client = client;
|
instance->client = client;
|
||||||
client->instance = instance;
|
client->instance = instance;
|
||||||
free(argv);
|
free(argv);
|
||||||
|
tll_free_and_free(overrides, free);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -357,6 +337,7 @@ shutdown:
|
||||||
LOG_DBG("client FD=%d: disconnected", client->fd);
|
LOG_DBG("client FD=%d: disconnected", client->fd);
|
||||||
|
|
||||||
free(argv);
|
free(argv);
|
||||||
|
tll_free_and_free(overrides, free);
|
||||||
fdm_del(fdm, fd);
|
fdm_del(fdm, fd);
|
||||||
client->fd = -1;
|
client->fd = -1;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue