2019-06-12 20:08:54 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdbool.h>
|
2021-12-10 17:40:59 +00:00
|
|
|
#include <limits.h>
|
2019-06-13 21:23:52 +02:00
|
|
|
#include <locale.h>
|
2019-07-03 09:46:13 +02:00
|
|
|
#include <getopt.h>
|
2019-11-01 20:35:42 +01:00
|
|
|
#include <signal.h>
|
2019-07-03 15:16:38 +02:00
|
|
|
#include <errno.h>
|
2019-12-21 19:57:28 +01:00
|
|
|
#include <unistd.h>
|
2019-06-12 20:08:54 +02:00
|
|
|
|
2020-02-05 19:53:50 +01:00
|
|
|
#include <sys/types.h>
|
2021-01-19 14:38:45 +00:00
|
|
|
#include <sys/stat.h>
|
2020-06-09 20:35:21 +02:00
|
|
|
#include <sys/utsname.h>
|
2020-02-05 19:53:50 +01:00
|
|
|
#include <fcntl.h>
|
2019-08-12 21:22:38 +02:00
|
|
|
|
2019-12-01 14:03:24 +01:00
|
|
|
#include <fcft/fcft.h>
|
2019-12-01 13:43:51 +01:00
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
#define LOG_MODULE "main"
|
2019-10-28 18:35:16 +01:00
|
|
|
#define LOG_ENABLE_DBG 0
|
2019-06-12 20:08:54 +02:00
|
|
|
#include "log.h"
|
2019-06-13 15:19:10 +02:00
|
|
|
|
2019-07-16 11:52:22 +02:00
|
|
|
#include "config.h"
|
2019-10-27 11:46:18 +01:00
|
|
|
#include "fdm.h"
|
key-binding: new API, for handling sets of key bindings
Up until now, our Wayland seats have been tracking key bindings. This
makes sense, since the seat’s keymap determines how the key bindings
are resolved.
However, tying bindings to the seat/keymap alone isn’t enough, since
we also depend on the current configuration (i.e. user settings) when
resolving a key binding.
This means configurations that doesn’t match the wayland object’s
configuration, currently don’t resolve key bindings correctly. This
applies to footclients where the user has overridden key bindings on
the command line (e.g. --override key-bindings.foo=bar).
Thus, to correctly resolve key bindings, each set of key bindings must
be tied *both* to a seat/keymap, *and* a configuration.
This patch introduces a key-binding manager, with an API to
add/remove/lookup, and load/unload keymaps from sets of key bindings.
In the API, sets are tied to a seat and terminal instance, since this
makes the most sense (we need to instantiate, or incref a set whenever
a new terminal instance is created). Internally, the set is tied to a
seat and the terminal’s configuration.
Sets are *added* when a new seat is added, and when a new terminal
instance is created. Since there can only be one instance of each
seat, sets are always removed when a seat is removed.
Terminals on the other hand can re-use the same configuration (and
typically do). Thus, sets ref-count the configuration. In other words,
when instantiating a new terminal, we may not have to instantiate a
new set of key bindings, but can often be incref:ed instead.
Whenever the keymap changes on a seat, all key bindings sets
associated with that seat reloads (re-resolves) their key bindings.
Closes #931
2022-04-17 15:39:51 +02:00
|
|
|
#include "foot-features.h"
|
|
|
|
|
#include "key-binding.h"
|
2021-02-11 11:08:18 +00:00
|
|
|
#include "macros.h"
|
2020-05-21 20:15:10 +02:00
|
|
|
#include "reaper.h"
|
2020-01-04 19:49:26 +01:00
|
|
|
#include "render.h"
|
2019-11-01 20:37:22 +01:00
|
|
|
#include "server.h"
|
2019-06-12 20:08:54 +02:00
|
|
|
#include "shm.h"
|
2019-06-15 22:22:44 +02:00
|
|
|
#include "terminal.h"
|
2020-10-20 21:04:47 +02:00
|
|
|
#include "util.h"
|
2020-08-08 20:34:30 +01:00
|
|
|
#include "xmalloc.h"
|
2021-01-14 21:30:06 +00:00
|
|
|
#include "xsnprintf.h"
|
2019-06-19 14:17:43 +02:00
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
#if !defined(__STDC_UTF_32__) || !__STDC_UTF_32__
|
|
|
|
|
#error "char32_t does not use UTF-32"
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-02-10 16:21:56 +01:00
|
|
|
static bool
|
|
|
|
|
fdm_sigint(struct fdm *fdm, int signo, void *data)
|
2019-11-01 20:35:42 +01:00
|
|
|
{
|
2021-02-10 16:21:56 +01:00
|
|
|
*(volatile sig_atomic_t *)data = true;
|
|
|
|
|
return true;
|
2019-11-01 20:35:42 +01:00
|
|
|
}
|
|
|
|
|
|
2025-07-30 12:23:39 +02:00
|
|
|
struct sigusr_context {
|
|
|
|
|
struct terminal *term;
|
|
|
|
|
struct server *server;
|
|
|
|
|
};
|
|
|
|
|
|
2025-06-09 07:38:26 +02:00
|
|
|
static bool
|
2025-07-17 10:18:17 +02:00
|
|
|
fdm_sigusr(struct fdm *fdm, int signo, void *data)
|
2025-06-09 07:38:26 +02:00
|
|
|
{
|
2025-07-17 10:18:17 +02:00
|
|
|
xassert(signo == SIGUSR1 || signo == SIGUSR2);
|
|
|
|
|
|
2025-07-30 12:23:39 +02:00
|
|
|
struct sigusr_context *ctx = data;
|
|
|
|
|
|
|
|
|
|
if (ctx->server != NULL) {
|
|
|
|
|
if (signo == SIGUSR1)
|
config: add [colors-dark] and [colors-light], replacing [colors] and [colors2]
The main reason for having two color sections is to be able to switch
between dark and light. Thus, it's better if the section names reflect
this, rather than the more generic 'colors' and 'colors2' (which was
the dark one and which was the light one, now again?)
When the second color section was added, we kept the original name,
colors, to make sure we didn't break existing configurations, and
third-party themes.
However, in the long run, it's probably better to be specific in the
section naming, to avoid confusion.
So, add 'colors-dark', and 'colors-light'. Keep 'colors' and 'colors2'
as aliases for now, but mark them as deprecated. They WILL be removed
in a future release.
Also rename the option values for initial-color-theme, from 1/2, to
dark/light. Keep the old ones for now, marked as deprecated.
Update all bundled themes to use the new names. In the light-only
themes (i.e. themes that define a single, light, theme), use
colors-light, and set initial-color-theme=light.
Possible improvements: disable color switching if only one color
section has been explicitly configured (todo: figure out how to handle
the default color theme values...)
2025-12-19 09:29:06 +01:00
|
|
|
server_global_theme_switch_to_dark(ctx->server);
|
2025-07-30 12:23:39 +02:00
|
|
|
else
|
config: add [colors-dark] and [colors-light], replacing [colors] and [colors2]
The main reason for having two color sections is to be able to switch
between dark and light. Thus, it's better if the section names reflect
this, rather than the more generic 'colors' and 'colors2' (which was
the dark one and which was the light one, now again?)
When the second color section was added, we kept the original name,
colors, to make sure we didn't break existing configurations, and
third-party themes.
However, in the long run, it's probably better to be specific in the
section naming, to avoid confusion.
So, add 'colors-dark', and 'colors-light'. Keep 'colors' and 'colors2'
as aliases for now, but mark them as deprecated. They WILL be removed
in a future release.
Also rename the option values for initial-color-theme, from 1/2, to
dark/light. Keep the old ones for now, marked as deprecated.
Update all bundled themes to use the new names. In the light-only
themes (i.e. themes that define a single, light, theme), use
colors-light, and set initial-color-theme=light.
Possible improvements: disable color switching if only one color
section has been explicitly configured (todo: figure out how to handle
the default color theme values...)
2025-12-19 09:29:06 +01:00
|
|
|
server_global_theme_switch_to_light(ctx->server);
|
2025-07-17 10:18:17 +02:00
|
|
|
} else {
|
2025-07-30 12:23:39 +02:00
|
|
|
if (signo == SIGUSR1)
|
config: add [colors-dark] and [colors-light], replacing [colors] and [colors2]
The main reason for having two color sections is to be able to switch
between dark and light. Thus, it's better if the section names reflect
this, rather than the more generic 'colors' and 'colors2' (which was
the dark one and which was the light one, now again?)
When the second color section was added, we kept the original name,
colors, to make sure we didn't break existing configurations, and
third-party themes.
However, in the long run, it's probably better to be specific in the
section naming, to avoid confusion.
So, add 'colors-dark', and 'colors-light'. Keep 'colors' and 'colors2'
as aliases for now, but mark them as deprecated. They WILL be removed
in a future release.
Also rename the option values for initial-color-theme, from 1/2, to
dark/light. Keep the old ones for now, marked as deprecated.
Update all bundled themes to use the new names. In the light-only
themes (i.e. themes that define a single, light, theme), use
colors-light, and set initial-color-theme=light.
Possible improvements: disable color switching if only one color
section has been explicitly configured (todo: figure out how to handle
the default color theme values...)
2025-12-19 09:29:06 +01:00
|
|
|
term_theme_switch_to_dark(ctx->term);
|
2025-07-30 12:23:39 +02:00
|
|
|
else
|
config: add [colors-dark] and [colors-light], replacing [colors] and [colors2]
The main reason for having two color sections is to be able to switch
between dark and light. Thus, it's better if the section names reflect
this, rather than the more generic 'colors' and 'colors2' (which was
the dark one and which was the light one, now again?)
When the second color section was added, we kept the original name,
colors, to make sure we didn't break existing configurations, and
third-party themes.
However, in the long run, it's probably better to be specific in the
section naming, to avoid confusion.
So, add 'colors-dark', and 'colors-light'. Keep 'colors' and 'colors2'
as aliases for now, but mark them as deprecated. They WILL be removed
in a future release.
Also rename the option values for initial-color-theme, from 1/2, to
dark/light. Keep the old ones for now, marked as deprecated.
Update all bundled themes to use the new names. In the light-only
themes (i.e. themes that define a single, light, theme), use
colors-light, and set initial-color-theme=light.
Possible improvements: disable color switching if only one color
section has been explicitly configured (todo: figure out how to handle
the default color theme values...)
2025-12-19 09:29:06 +01:00
|
|
|
term_theme_switch_to_light(ctx->term);
|
2025-06-09 07:38:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-11 16:03:29 +02:00
|
|
|
static void
|
|
|
|
|
print_usage(const char *prog_name)
|
|
|
|
|
{
|
2021-09-18 19:44:04 +01:00
|
|
|
static const char options[] =
|
|
|
|
|
"\nOptions:\n"
|
2021-06-26 22:15:09 +01:00
|
|
|
" -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"
|
|
|
|
|
" -o,--override=[section.]key=value override configuration option\n"
|
|
|
|
|
" -f,--font=FONT comma separated list of fonts in fontconfig format (monospace)\n"
|
2021-09-18 19:44:04 +01:00
|
|
|
" -t,--term=TERM value to set the environment variable TERM to (" FOOT_DEFAULT_TERM ")\n"
|
2021-06-26 22:15:09 +01:00
|
|
|
" -T,--title=TITLE initial window title (foot)\n"
|
|
|
|
|
" -a,--app-id=ID window application ID (foot)\n"
|
2025-11-12 11:04:25 +01:00
|
|
|
" --toplevel-tag=TAG set a custom toplevel tag\n"
|
2021-06-26 22:15:09 +01:00
|
|
|
" -m,--maximized start in maximized mode\n"
|
|
|
|
|
" -F,--fullscreen start in fullscreen mode\n"
|
|
|
|
|
" -L,--login-shell start shell as a login shell\n"
|
2021-12-10 17:40:59 +00:00
|
|
|
" --pty=PATH display an existing PTY instead of creating one\n"
|
2021-06-26 22:15:09 +01:00
|
|
|
" -D,--working-directory=DIR directory to start in (CWD)\n"
|
|
|
|
|
" -w,--window-size-pixels=WIDTHxHEIGHT initial width and height, in pixels\n"
|
|
|
|
|
" -W,--window-size-chars=WIDTHxHEIGHT initial width and height, in characters\n"
|
|
|
|
|
" -s,--server[=PATH] run as a server (use 'footclient' to start terminals).\n"
|
|
|
|
|
" Without PATH, $XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock will be used.\n"
|
|
|
|
|
" -H,--hold remain open after child process exits\n"
|
|
|
|
|
" -p,--print-pid=FILE|FD print PID to file or FD (only applicable in server mode)\n"
|
change default log level to WARNING
The default foot output looks like this, in Debian testing "bookworm"
at the time of writing:
anarcat@angela:pubpaste$ foot true
info: main.c:421: version: 1.13.1 +pgo +ime +graphemes -assertions
info: main.c:428: arch: Linux x86_64/64-bit
info: main.c:440: locale: fr_CA.UTF-8
info: config.c:3003: loading configuration from /home/anarcat/.config/foot/foot.ini
info: fcft.c:338: fcft: 3.1.5 +graphemes -runs +svg(nanosvg) -assertions
info: fcft.c:377: fontconfig: 2.13.1, freetype: 2.12.1, harfbuzz: 5.2.0
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=8.00pt/8px, dpi=75.00
info: wayland.c:1353: eDP-1: 2256x1504+0x0@60Hz 0x095F 13.32" scale=2 PPI=205x214 (physical) PPI=136x143 (logical), DPI=271.31
info: wayland.c:1509: requesting SSD decorations
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Bold.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Bold.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=24.00pt/32px, dpi=96.00
info: terminal.c:700: cell width=19, height=39
info: terminal.c:588: using 16 rendering threads
info: wayland.c:859: using SSD decorations
info: main.c:680: goodbye
anarcat@angela:pubpaste$
That's 17 lines of output that are *mostly* useless for most use
cases. I might understand having this output during the project's
startup, when it's helpful for diagnostics, but now Foot just mostly
works everywhere, and I've never had a use for any of that stuff in
the (arguably short) time I've been using Foot so far.
And if I do, there's the `--log-level` commandline option to tweak
this. At first, I looked at tweaking the log level through the config
file. But as explained in this issue:
https://codeberg.org/dnkl/foot/issues/1142
... there's a chicken and egg problem there that makes it hard to
implement and possibly confusing for users as well.
There's also the possibility for users to change the shortcut with
which they start foot, for example a `.desktop` file so that menu
systems that support those start foot properly. But that only works in
that environment, and not through the so many things that will just
call `foot` and hope it will do the right thing.
In my case, I have `foot` hardcoded in a lot of places now, between
sway and waybar, and this is only going to grow. Others have suggested
adding the flag to a $TERMINAL global variable, but that won't help
.desktop users.
So, instead of playing whack-a-mole with the log levels, just make it
so that, by default, foot is silent. This is actually one of the
[basics of UNIX philosophy][1]:
> Rule of Silence: When a program has nothing surprising to say, it
> should say nothing.
And yes, I am aware I am severely violating that principle by writing
a way too long commit log for a one-line patch, but there you go, I
figured it was good to document the why of this properly.
[1]: https://web.archive.org/web/20031102053334/http://www.faqs.org/docs/artu/ch01s06.html
2022-11-18 11:07:16 -05:00
|
|
|
" -d,--log-level={info|warning|error|none} log level (warning)\n"
|
2021-06-26 22:15:09 +01:00
|
|
|
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
|
2023-10-26 22:20:38 +02:00
|
|
|
" -S,--log-no-syslog disable syslog logging (only applicable in server mode)\n"
|
2021-09-18 23:40:40 +01:00
|
|
|
" -v,--version show the version number and quit\n"
|
|
|
|
|
" -e ignored (for compatibility with xterm -e)\n";
|
2021-09-18 19:44:04 +01:00
|
|
|
|
|
|
|
|
printf("Usage: %s [OPTIONS...]\n", prog_name);
|
|
|
|
|
printf("Usage: %s [OPTIONS...] command [ARGS...]\n", prog_name);
|
|
|
|
|
puts(options);
|
2019-11-01 20:34:32 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-19 07:25:05 +01:00
|
|
|
bool
|
|
|
|
|
locale_is_utf8(void)
|
|
|
|
|
{
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
static const char u8[] = u8"ö";
|
|
|
|
|
xassert(strlen(u8) == 2);
|
2019-12-19 07:25:05 +01:00
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
char32_t w;
|
|
|
|
|
if (mbrtoc32(&w, u8, 2, &(mbstate_t){0}) != 2)
|
2019-12-19 07:25:05 +01:00
|
|
|
return false;
|
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
return w == U'ö';
|
2019-12-19 07:25:05 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-01 20:34:32 +01:00
|
|
|
struct shutdown_context {
|
|
|
|
|
struct terminal **term;
|
|
|
|
|
int exit_code;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
term_shutdown_cb(void *data, int exit_code)
|
|
|
|
|
{
|
|
|
|
|
struct shutdown_context *ctx = data;
|
|
|
|
|
*ctx->term = NULL;
|
|
|
|
|
ctx->exit_code = exit_code;
|
2019-08-11 16:03:29 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-05 19:53:50 +01:00
|
|
|
static bool
|
|
|
|
|
print_pid(const char *pid_file, bool *unlink_at_exit)
|
|
|
|
|
{
|
|
|
|
|
LOG_DBG("printing PID to %s", pid_file);
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
char *end;
|
|
|
|
|
int pid_fd = strtoul(pid_file, &end, 10);
|
|
|
|
|
|
|
|
|
|
if (errno != 0 || *end != '\0') {
|
|
|
|
|
if ((pid_fd = open(pid_file,
|
|
|
|
|
O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC,
|
|
|
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
|
|
|
|
|
LOG_ERRNO("%s: failed to open", pid_file);
|
|
|
|
|
return false;
|
|
|
|
|
} else
|
|
|
|
|
*unlink_at_exit = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pid_fd >= 0) {
|
|
|
|
|
char pid[32];
|
2021-01-14 21:30:06 +00:00
|
|
|
size_t n = xsnprintf(pid, sizeof(pid), "%u\n", getpid());
|
2020-02-05 19:53:50 +01:00
|
|
|
|
2021-01-14 21:30:06 +00:00
|
|
|
ssize_t bytes = write(pid_fd, pid, n);
|
2020-02-05 19:53:50 +01:00
|
|
|
close(pid_fd);
|
|
|
|
|
|
|
|
|
|
if (bytes < 0) {
|
|
|
|
|
LOG_ERRNO("failed to write PID to FD=%u", pid_fd);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_DBG("wrote %zd bytes to FD=%d", bytes, pid_fd);
|
|
|
|
|
return true;
|
|
|
|
|
} else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 21:35:39 +01:00
|
|
|
static void
|
|
|
|
|
sanitize_signals(void)
|
|
|
|
|
{
|
|
|
|
|
sigset_t mask;
|
|
|
|
|
sigemptyset(&mask);
|
|
|
|
|
sigprocmask(SIG_SETMASK, &mask, NULL);
|
|
|
|
|
|
|
|
|
|
struct sigaction dfl = {.sa_handler = SIG_DFL};
|
|
|
|
|
sigemptyset(&dfl.sa_mask);
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i < SIGRTMAX; i++)
|
|
|
|
|
sigaction(i, &dfl, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-10 17:40:59 +00:00
|
|
|
enum {
|
|
|
|
|
PTY_OPTION = CHAR_MAX + 1,
|
2025-11-12 11:04:25 +01:00
|
|
|
TOPLEVEL_TAG_OPTION = CHAR_MAX + 2,
|
2021-12-10 17:40:59 +00:00
|
|
|
};
|
|
|
|
|
|
2019-06-12 20:08:54 +02:00
|
|
|
int
|
2019-07-03 09:46:13 +02:00
|
|
|
main(int argc, char *const *argv)
|
2019-06-12 20:08:54 +02:00
|
|
|
{
|
2021-04-30 22:47:16 +02:00
|
|
|
/* Custom exit code, to enable users to differentiate between foot
|
2023-10-03 14:11:55 +02:00
|
|
|
* itself failing, and the client application failing */
|
2021-05-01 10:46:40 +02:00
|
|
|
static const int foot_exit_failure = -26;
|
2021-04-30 22:47:16 +02:00
|
|
|
int ret = foot_exit_failure;
|
2019-06-12 20:08:54 +02:00
|
|
|
|
2022-02-02 21:35:39 +01:00
|
|
|
sanitize_signals();
|
|
|
|
|
|
2021-10-28 17:51:44 -07:00
|
|
|
/* XDG startup notifications */
|
|
|
|
|
const char *token = getenv("XDG_ACTIVATION_TOKEN");
|
|
|
|
|
unsetenv("XDG_ACTIVATION_TOKEN");
|
|
|
|
|
|
2019-09-26 18:41:39 +02:00
|
|
|
/* Startup notifications; we don't support it, but must ensure we
|
|
|
|
|
* don't pass this on to programs launched by us */
|
|
|
|
|
unsetenv("DESKTOP_STARTUP_ID");
|
|
|
|
|
|
2022-01-01 21:11:31 +01:00
|
|
|
const char *const prog_name = argc > 0 ? argv[0] : "<nullptr>";
|
2019-08-11 16:03:29 +02:00
|
|
|
|
2019-07-03 09:46:13 +02:00
|
|
|
static const struct option longopts[] = {
|
2020-09-08 19:17:29 +02:00
|
|
|
{"config", required_argument, NULL, 'c'},
|
|
|
|
|
{"check-config", no_argument, NULL, 'C'},
|
2021-06-11 04:40:08 -05:00
|
|
|
{"override", required_argument, NULL, 'o'},
|
2020-09-08 19:17:29 +02:00
|
|
|
{"term", required_argument, NULL, 't'},
|
|
|
|
|
{"title", required_argument, NULL, 'T'},
|
|
|
|
|
{"app-id", required_argument, NULL, 'a'},
|
2025-11-12 11:04:25 +01:00
|
|
|
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
|
2020-09-08 19:17:29 +02:00
|
|
|
{"login-shell", no_argument, NULL, 'L'},
|
2021-02-12 09:39:44 +01:00
|
|
|
{"working-directory", required_argument, NULL, 'D'},
|
2020-09-08 19:17:29 +02:00
|
|
|
{"font", required_argument, NULL, 'f'},
|
|
|
|
|
{"window-size-pixels", required_argument, NULL, 'w'},
|
|
|
|
|
{"window-size-chars", required_argument, NULL, 'W'},
|
|
|
|
|
{"server", optional_argument, NULL, 's'},
|
|
|
|
|
{"hold", no_argument, NULL, 'H'},
|
|
|
|
|
{"maximized", no_argument, NULL, 'm'},
|
|
|
|
|
{"fullscreen", no_argument, NULL, 'F'},
|
|
|
|
|
{"presentation-timings", no_argument, NULL, 'P'}, /* Undocumented */
|
2021-12-10 17:40:59 +00:00
|
|
|
{"pty", required_argument, NULL, PTY_OPTION},
|
2020-09-08 19:17:29 +02:00
|
|
|
{"print-pid", required_argument, NULL, 'p'},
|
2021-02-09 21:04:56 +01:00
|
|
|
{"log-level", required_argument, NULL, 'd'},
|
2020-09-08 19:17:29 +02:00
|
|
|
{"log-colorize", optional_argument, NULL, 'l'},
|
|
|
|
|
{"log-no-syslog", no_argument, NULL, 'S'},
|
|
|
|
|
{"version", no_argument, NULL, 'v'},
|
|
|
|
|
{"help", no_argument, NULL, 'h'},
|
|
|
|
|
{NULL, no_argument, NULL, 0},
|
2019-07-03 09:46:13 +02:00
|
|
|
};
|
|
|
|
|
|
2020-07-29 17:48:22 +02:00
|
|
|
bool check_config = false;
|
2019-12-17 19:08:43 +01:00
|
|
|
const char *conf_path = NULL;
|
2021-02-12 09:39:44 +01:00
|
|
|
const char *custom_cwd = NULL;
|
2021-12-10 17:40:59 +00:00
|
|
|
const char *pty_path = NULL;
|
2019-11-01 20:37:22 +01:00
|
|
|
bool as_server = false;
|
2019-12-17 19:08:43 +01:00
|
|
|
const char *conf_server_socket_path = NULL;
|
2019-12-31 15:39:40 +01:00
|
|
|
bool presentation_timings = false;
|
2020-02-03 19:58:32 +01:00
|
|
|
bool hold = false;
|
2020-02-05 19:53:50 +01:00
|
|
|
bool unlink_pid_file = false;
|
|
|
|
|
const char *pid_file = NULL;
|
change default log level to WARNING
The default foot output looks like this, in Debian testing "bookworm"
at the time of writing:
anarcat@angela:pubpaste$ foot true
info: main.c:421: version: 1.13.1 +pgo +ime +graphemes -assertions
info: main.c:428: arch: Linux x86_64/64-bit
info: main.c:440: locale: fr_CA.UTF-8
info: config.c:3003: loading configuration from /home/anarcat/.config/foot/foot.ini
info: fcft.c:338: fcft: 3.1.5 +graphemes -runs +svg(nanosvg) -assertions
info: fcft.c:377: fontconfig: 2.13.1, freetype: 2.12.1, harfbuzz: 5.2.0
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=8.00pt/8px, dpi=75.00
info: wayland.c:1353: eDP-1: 2256x1504+0x0@60Hz 0x095F 13.32" scale=2 PPI=205x214 (physical) PPI=136x143 (logical), DPI=271.31
info: wayland.c:1509: requesting SSD decorations
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Bold.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Bold.otf: size=24.00pt/32px, dpi=96.00
info: fcft.c:838: /home/anarcat/.local/share/fonts/Fira-4.202/otf/FiraMono-Regular.otf: size=24.00pt/32px, dpi=96.00
info: terminal.c:700: cell width=19, height=39
info: terminal.c:588: using 16 rendering threads
info: wayland.c:859: using SSD decorations
info: main.c:680: goodbye
anarcat@angela:pubpaste$
That's 17 lines of output that are *mostly* useless for most use
cases. I might understand having this output during the project's
startup, when it's helpful for diagnostics, but now Foot just mostly
works everywhere, and I've never had a use for any of that stuff in
the (arguably short) time I've been using Foot so far.
And if I do, there's the `--log-level` commandline option to tweak
this. At first, I looked at tweaking the log level through the config
file. But as explained in this issue:
https://codeberg.org/dnkl/foot/issues/1142
... there's a chicken and egg problem there that makes it hard to
implement and possibly confusing for users as well.
There's also the possibility for users to change the shortcut with
which they start foot, for example a `.desktop` file so that menu
systems that support those start foot properly. But that only works in
that environment, and not through the so many things that will just
call `foot` and hope it will do the right thing.
In my case, I have `foot` hardcoded in a lot of places now, between
sway and waybar, and this is only going to grow. Others have suggested
adding the flag to a $TERMINAL global variable, but that won't help
.desktop users.
So, instead of playing whack-a-mole with the log levels, just make it
so that, by default, foot is silent. This is actually one of the
[basics of UNIX philosophy][1]:
> Rule of Silence: When a program has nothing surprising to say, it
> should say nothing.
And yes, I am aware I am severely violating that principle by writing
a way too long commit log for a one-line patch, but there you go, I
figured it was good to document the why of this properly.
[1]: https://web.archive.org/web/20031102053334/http://www.faqs.org/docs/artu/ch01s06.html
2022-11-18 11:07:16 -05:00
|
|
|
enum log_class log_level = LOG_CLASS_WARNING;
|
2020-02-05 19:54:16 +01:00
|
|
|
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
|
|
|
|
|
bool log_syslog = true;
|
2020-09-08 19:17:29 +02:00
|
|
|
user_notifications_t user_notifications = tll_init();
|
2021-06-11 04:40:08 -05:00
|
|
|
config_override_t overrides = tll_init();
|
2019-11-01 20:37:22 +01:00
|
|
|
|
2019-07-03 09:46:13 +02:00
|
|
|
while (true) {
|
2021-09-18 23:40:40 +01:00
|
|
|
int c = getopt_long(argc, argv, "+c:Co:t:T:a:LD:f:w:W:s::HmFPp:d:l::Sveh", longopts, NULL);
|
2021-06-11 04:40:08 -05:00
|
|
|
|
2019-07-03 09:46:13 +02:00
|
|
|
if (c == -1)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
switch (c) {
|
2019-12-17 19:08:43 +01:00
|
|
|
case 'c':
|
|
|
|
|
conf_path = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2020-07-29 17:48:22 +02:00
|
|
|
case 'C':
|
|
|
|
|
check_config = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2021-06-11 04:40:08 -05:00
|
|
|
case 'o':
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_push_back(overrides, xstrdup(optarg));
|
2021-06-11 04:40:08 -05:00
|
|
|
break;
|
|
|
|
|
|
2019-07-18 14:34:45 +02:00
|
|
|
case 't':
|
2024-08-03 08:12:13 +01:00
|
|
|
tll_push_back(overrides, xstrjoin("term=", optarg));
|
2019-07-18 14:34:45 +02:00
|
|
|
break;
|
|
|
|
|
|
2020-02-20 18:34:23 +01:00
|
|
|
case 'L':
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_push_back(overrides, xstrdup("login-shell=yes"));
|
2020-02-20 18:34:23 +01:00
|
|
|
break;
|
|
|
|
|
|
2020-04-01 19:59:47 +02:00
|
|
|
case 'T':
|
2024-08-03 08:12:13 +01:00
|
|
|
tll_push_back(overrides, xstrjoin("title=", optarg));
|
2020-04-01 19:59:47 +02:00
|
|
|
break;
|
|
|
|
|
|
2020-04-01 18:40:51 +02:00
|
|
|
case 'a':
|
2024-08-03 08:12:13 +01:00
|
|
|
tll_push_back(overrides, xstrjoin("app-id=", optarg));
|
2020-04-01 18:40:51 +02:00
|
|
|
break;
|
|
|
|
|
|
2025-11-12 11:04:25 +01:00
|
|
|
case TOPLEVEL_TAG_OPTION:
|
|
|
|
|
tll_push_back(overrides, xstrjoin("toplevel-tag=", optarg));
|
|
|
|
|
break;
|
|
|
|
|
|
2021-02-13 10:48:31 +01:00
|
|
|
case 'D': {
|
|
|
|
|
struct stat st;
|
|
|
|
|
if (stat(optarg, &st) < 0 || !(st.st_mode & S_IFDIR)) {
|
|
|
|
|
fprintf(stderr, "error: %s: not a directory\n", optarg);
|
2021-04-30 22:47:16 +02:00
|
|
|
return ret;
|
2021-02-13 10:48:31 +01:00
|
|
|
}
|
2021-02-12 09:39:44 +01:00
|
|
|
custom_cwd = optarg;
|
|
|
|
|
break;
|
2021-02-13 10:48:31 +01:00
|
|
|
}
|
2021-02-12 09:39:44 +01:00
|
|
|
|
2023-07-31 16:26:17 +02:00
|
|
|
case 'f': {
|
2024-08-03 08:12:13 +01:00
|
|
|
char *font_override = xstrjoin("font=", optarg);
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_push_back(overrides, font_override);
|
2019-07-03 09:46:13 +02:00
|
|
|
break;
|
2023-07-31 16:26:17 +02:00
|
|
|
}
|
2019-07-03 09:46:13 +02:00
|
|
|
|
2020-09-08 19:17:29 +02:00
|
|
|
case 'w': {
|
2019-08-23 17:26:41 +02:00
|
|
|
unsigned width, height;
|
|
|
|
|
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
2020-09-08 19:17:29 +02:00
|
|
|
fprintf(stderr, "error: invalid window-size-pixels: %s\n", optarg);
|
2021-04-30 22:47:16 +02:00
|
|
|
return ret;
|
2019-08-23 17:26:41 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_push_back(
|
|
|
|
|
overrides, xasprintf("initial-window-size-pixels=%ux%u",
|
|
|
|
|
width, height));
|
2020-09-08 19:17:29 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'W': {
|
|
|
|
|
unsigned width, height;
|
|
|
|
|
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
|
|
|
|
fprintf(stderr, "error: invalid window-size-chars: %s\n", optarg);
|
2021-04-30 22:47:16 +02:00
|
|
|
return ret;
|
2020-09-08 19:17:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_push_back(
|
|
|
|
|
overrides, xasprintf("initial-window-size-chars=%ux%u",
|
|
|
|
|
width, height));
|
2019-08-23 17:26:41 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-01 20:37:22 +01:00
|
|
|
case 's':
|
|
|
|
|
as_server = true;
|
2019-12-17 19:08:43 +01:00
|
|
|
if (optarg != NULL)
|
|
|
|
|
conf_server_socket_path = optarg;
|
2019-11-01 20:37:22 +01:00
|
|
|
break;
|
|
|
|
|
|
2021-12-10 17:40:59 +00:00
|
|
|
case PTY_OPTION:
|
|
|
|
|
pty_path = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2020-02-05 19:53:50 +01:00
|
|
|
case 'P':
|
2019-12-31 15:39:40 +01:00
|
|
|
presentation_timings = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2020-02-03 19:58:32 +01:00
|
|
|
case 'H':
|
|
|
|
|
hold = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2020-03-26 19:47:00 +01:00
|
|
|
case 'm':
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_push_back(overrides, xstrdup("initial-window-mode=maximized"));
|
2020-03-26 19:47:00 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'F':
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_push_back(overrides, xstrdup("initial-window-mode=fullscreen"));
|
2020-03-26 19:47:00 +01:00
|
|
|
break;
|
|
|
|
|
|
2020-02-05 19:53:50 +01:00
|
|
|
case 'p':
|
|
|
|
|
pid_file = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2021-02-09 21:04:56 +01:00
|
|
|
case 'd': {
|
2021-02-11 11:08:18 +00:00
|
|
|
int lvl = log_level_from_string(optarg);
|
|
|
|
|
if (unlikely(lvl < 0)) {
|
2021-02-09 21:04:56 +01:00
|
|
|
fprintf(
|
2021-02-11 11:08:18 +00:00
|
|
|
stderr,
|
|
|
|
|
"-d,--log-level: %s: argument must be one of %s\n",
|
|
|
|
|
optarg,
|
|
|
|
|
log_level_string_hint());
|
2021-04-30 22:47:16 +02:00
|
|
|
return ret;
|
2021-02-09 21:04:56 +01:00
|
|
|
}
|
2021-02-11 11:08:18 +00:00
|
|
|
log_level = lvl;
|
2021-02-09 21:04:56 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-05 19:54:16 +01:00
|
|
|
case 'l':
|
2024-01-24 23:17:28 +00:00
|
|
|
if (optarg == NULL || streq(optarg, "auto"))
|
2020-02-05 19:54:16 +01:00
|
|
|
log_colorize = LOG_COLORIZE_AUTO;
|
2024-01-24 23:17:28 +00:00
|
|
|
else if (streq(optarg, "never"))
|
2020-02-05 19:54:16 +01:00
|
|
|
log_colorize = LOG_COLORIZE_NEVER;
|
2024-01-24 23:17:28 +00:00
|
|
|
else if (streq(optarg, "always"))
|
2020-02-05 19:54:16 +01:00
|
|
|
log_colorize = LOG_COLORIZE_ALWAYS;
|
|
|
|
|
else {
|
|
|
|
|
fprintf(stderr, "%s: argument must be one of 'never', 'always' or 'auto'\n", optarg);
|
2021-04-30 22:47:16 +02:00
|
|
|
return ret;
|
2020-02-05 19:54:16 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'S':
|
|
|
|
|
log_syslog = false;
|
|
|
|
|
break;
|
|
|
|
|
|
2019-08-11 16:03:29 +02:00
|
|
|
case 'v':
|
2025-03-14 20:15:11 +00:00
|
|
|
print_version_and_features("foot ");
|
2019-08-11 16:03:29 +02:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
|
2019-07-03 09:46:13 +02:00
|
|
|
case 'h':
|
2019-08-11 16:03:29 +02:00
|
|
|
print_usage(prog_name);
|
|
|
|
|
return EXIT_SUCCESS;
|
2019-07-03 09:46:13 +02:00
|
|
|
|
2021-09-18 23:40:40 +01:00
|
|
|
case 'e':
|
|
|
|
|
break;
|
|
|
|
|
|
2019-07-03 09:46:13 +02:00
|
|
|
case '?':
|
2021-04-30 22:47:16 +02:00
|
|
|
return ret;
|
2019-07-03 09:46:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-10 17:40:59 +00:00
|
|
|
if (as_server && pty_path) {
|
|
|
|
|
fputs("error: --pty is incompatible with server mode\n", stderr);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-05 19:54:16 +01:00
|
|
|
log_init(log_colorize, as_server && log_syslog,
|
2021-02-09 21:04:56 +01:00
|
|
|
as_server ? LOG_FACILITY_DAEMON : LOG_FACILITY_USER, log_level);
|
2019-12-17 19:07:28 +01:00
|
|
|
|
2022-01-01 21:11:31 +01:00
|
|
|
if (argc > 0) {
|
|
|
|
|
argc -= optind;
|
|
|
|
|
argv += optind;
|
|
|
|
|
}
|
2019-07-17 09:55:36 +02:00
|
|
|
|
2025-03-14 20:15:11 +00:00
|
|
|
LOG_INFO("%s", version_and_features);
|
2020-03-15 11:41:24 +01:00
|
|
|
|
2020-06-09 20:35:21 +02:00
|
|
|
{
|
|
|
|
|
struct utsname name;
|
|
|
|
|
if (uname(&name) < 0)
|
|
|
|
|
LOG_ERRNO("uname() failed");
|
|
|
|
|
else
|
2021-02-07 10:24:48 +01:00
|
|
|
LOG_INFO("arch: %s %s/%zu-bit",
|
|
|
|
|
name.sysname, name.machine, sizeof(void *) * 8);
|
2020-06-09 20:35:21 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-13 13:40:39 +01:00
|
|
|
srand(time(NULL));
|
|
|
|
|
|
2021-11-10 17:29:57 +00:00
|
|
|
const char *locale = setlocale(LC_CTYPE, "");
|
|
|
|
|
if (locale == NULL) {
|
2022-12-16 08:38:37 +01:00
|
|
|
/*
|
|
|
|
|
* If the user has configured an invalid locale, or a name of a locale
|
|
|
|
|
* that does not exist on this system, then the above call may return
|
|
|
|
|
* NULL. We should just continue with the fallback method below.
|
|
|
|
|
*/
|
2024-08-11 11:11:38 +02:00
|
|
|
LOG_ERR("setlocale() failed. The most common cause is that the "
|
|
|
|
|
"configured locale is not available, or has been misspelled");
|
2021-11-10 17:29:57 +00:00
|
|
|
}
|
main: present invalid locale errors as a user-notification
Foot does not support running under non-UTF8 locales. If we detect a
non-UTF8 locale, we log this and exit with an error.
However, it appears a fairly common situation is this:
user (knowingly or unknowingly) only configures his/hers locale in
e.g. the shell RC files. These aren’t sourced when the compositor is
started via a display manager.
Thus, compositor key binds will fail to launch, and the user typically
has no way of seeing foot’s output.
So, the user proceeds to start another terminal, and from that one
tries launching foot. And it works... (because the shell in the other
terminal sourced the locale configuration).
User is left confused and often don’t know how to debug.
This patch is somewhat hackish; in addition to logging the locale
error, it also pushes a user notification. For this to be visible, we
need to actually start a terminal window.
So, we ignore the configured shell, and we ignore any custom command
line, and instead spawns “/bin/sh -c ‘’”. This allows us to get
something running (that hopefully doesn’t produce too much output we
can’t decode due to the non-UTF8 locale). But, it will exit
immediately. So we also set the --hold flag.
This works, and may be a good enough “solution”. However, it only
works for standalone foot instances, not footclients.
2022-01-10 20:24:46 +01:00
|
|
|
|
2024-08-10 16:38:35 +02:00
|
|
|
LOG_INFO("locale: %s", locale != NULL ? locale : "<invalid>");
|
main: present invalid locale errors as a user-notification
Foot does not support running under non-UTF8 locales. If we detect a
non-UTF8 locale, we log this and exit with an error.
However, it appears a fairly common situation is this:
user (knowingly or unknowingly) only configures his/hers locale in
e.g. the shell RC files. These aren’t sourced when the compositor is
started via a display manager.
Thus, compositor key binds will fail to launch, and the user typically
has no way of seeing foot’s output.
So, the user proceeds to start another terminal, and from that one
tries launching foot. And it works... (because the shell in the other
terminal sourced the locale configuration).
User is left confused and often don’t know how to debug.
This patch is somewhat hackish; in addition to logging the locale
error, it also pushes a user notification. For this to be visible, we
need to actually start a terminal window.
So, we ignore the configured shell, and we ignore any custom command
line, and instead spawns “/bin/sh -c ‘’”. This allows us to get
something running (that hopefully doesn’t produce too much output we
can’t decode due to the non-UTF8 locale). But, it will exit
immediately. So we also set the --hold flag.
This works, and may be a good enough “solution”. However, it only
works for standalone foot instances, not footclients.
2022-01-10 20:24:46 +01:00
|
|
|
|
2024-08-10 16:38:35 +02:00
|
|
|
bool bad_locale = locale == NULL || !locale_is_utf8();
|
main: present invalid locale errors as a user-notification
Foot does not support running under non-UTF8 locales. If we detect a
non-UTF8 locale, we log this and exit with an error.
However, it appears a fairly common situation is this:
user (knowingly or unknowingly) only configures his/hers locale in
e.g. the shell RC files. These aren’t sourced when the compositor is
started via a display manager.
Thus, compositor key binds will fail to launch, and the user typically
has no way of seeing foot’s output.
So, the user proceeds to start another terminal, and from that one
tries launching foot. And it works... (because the shell in the other
terminal sourced the locale configuration).
User is left confused and often don’t know how to debug.
This patch is somewhat hackish; in addition to logging the locale
error, it also pushes a user notification. For this to be visible, we
need to actually start a terminal window.
So, we ignore the configured shell, and we ignore any custom command
line, and instead spawns “/bin/sh -c ‘’”. This allows us to get
something running (that hopefully doesn’t produce too much output we
can’t decode due to the non-UTF8 locale). But, it will exit
immediately. So we also set the --hold flag.
This works, and may be a good enough “solution”. However, it only
works for standalone foot instances, not footclients.
2022-01-10 20:24:46 +01:00
|
|
|
if (bad_locale) {
|
2022-01-12 15:53:26 +01:00
|
|
|
static const char fallback_locales[][12] = {
|
|
|
|
|
"C.UTF-8",
|
|
|
|
|
"en_US.UTF-8",
|
|
|
|
|
};
|
2024-08-10 16:38:35 +02:00
|
|
|
char *saved_locale = locale != NULL ? xstrdup(locale) : NULL;
|
2022-01-11 21:37:03 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Try to force an UTF-8 locale. If we succeed, launch the
|
2024-02-06 12:36:45 +01:00
|
|
|
* user's shell as usual, but add a user-notification saying
|
2022-01-11 21:37:03 +01:00
|
|
|
* the locale has been changed.
|
|
|
|
|
*/
|
2022-01-12 15:53:26 +01:00
|
|
|
for (size_t i = 0; i < ALEN(fallback_locales); i++) {
|
|
|
|
|
const char *const fallback_locale = fallback_locales[i];
|
|
|
|
|
|
|
|
|
|
if (setlocale(LC_CTYPE, fallback_locale) != NULL) {
|
2024-08-10 16:38:35 +02:00
|
|
|
if (saved_locale != NULL) {
|
|
|
|
|
LOG_WARN(
|
|
|
|
|
"'%s' is not a UTF-8 locale, falling back to '%s'",
|
|
|
|
|
saved_locale, fallback_locale);
|
|
|
|
|
|
|
|
|
|
user_notification_add_fmt(
|
|
|
|
|
&user_notifications, USER_NOTIFICATION_WARNING,
|
|
|
|
|
"'%s' is not a UTF-8 locale, falling back to '%s'",
|
|
|
|
|
saved_locale, fallback_locale);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
LOG_WARN(
|
|
|
|
|
"invalid locale, falling back to '%s'", fallback_locale);
|
|
|
|
|
user_notification_add_fmt(
|
|
|
|
|
&user_notifications, USER_NOTIFICATION_WARNING,
|
|
|
|
|
"invalid locale, falling back to '%s'", fallback_locale);
|
|
|
|
|
}
|
2022-01-12 18:59:15 +01:00
|
|
|
|
2022-01-12 15:53:26 +01:00
|
|
|
bad_locale = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-01-11 21:37:03 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-12 15:53:26 +01:00
|
|
|
if (bad_locale) {
|
2024-08-10 16:38:35 +02:00
|
|
|
if (saved_locale != NULL) {
|
|
|
|
|
LOG_ERR(
|
|
|
|
|
"'%s' is not a UTF-8 locale, and failed to find a fallback",
|
|
|
|
|
saved_locale);
|
|
|
|
|
|
|
|
|
|
user_notification_add_fmt(
|
|
|
|
|
&user_notifications, USER_NOTIFICATION_ERROR,
|
|
|
|
|
"'%s' is not a UTF-8 locale, and failed to find a fallback",
|
|
|
|
|
saved_locale);
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERR("invalid locale, and failed to find a fallback");
|
|
|
|
|
|
|
|
|
|
user_notification_add_fmt(
|
|
|
|
|
&user_notifications, USER_NOTIFICATION_ERROR,
|
|
|
|
|
"invalid locale, and failed to find a fallback");
|
|
|
|
|
}
|
2022-01-11 21:37:03 +01:00
|
|
|
}
|
2023-05-30 15:49:01 -04:00
|
|
|
free(saved_locale);
|
2020-10-09 19:45:26 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 19:08:43 +01:00
|
|
|
struct config conf = {NULL};
|
2021-12-22 20:21:46 +01:00
|
|
|
bool conf_successful = config_load(
|
2023-05-02 01:53:01 +10:00
|
|
|
&conf, conf_path, &user_notifications, &overrides, check_config, as_server);
|
2021-12-22 20:21:46 +01:00
|
|
|
|
2023-07-31 16:26:17 +02:00
|
|
|
tll_free_and_free(overrides, free);
|
2021-06-11 04:40:08 -05:00
|
|
|
if (!conf_successful) {
|
2022-04-12 13:01:56 +02:00
|
|
|
config_free(&conf);
|
2019-12-17 19:08:43 +01:00
|
|
|
return ret;
|
2020-03-09 20:04:25 +01:00
|
|
|
}
|
2019-12-17 19:08:43 +01:00
|
|
|
|
2020-07-29 17:48:22 +02:00
|
|
|
if (check_config) {
|
2022-04-12 13:01:56 +02:00
|
|
|
config_free(&conf);
|
2020-07-29 17:48:22 +02:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
_Static_assert((int)LOG_CLASS_ERROR == (int)FCFT_LOG_CLASS_ERROR,
|
|
|
|
|
"fcft log level enum offset");
|
|
|
|
|
_Static_assert((int)LOG_COLORIZE_ALWAYS == (int)FCFT_LOG_COLORIZE_ALWAYS,
|
|
|
|
|
"fcft colorize enum mismatch");
|
|
|
|
|
fcft_init(
|
|
|
|
|
(enum fcft_log_colorize)log_colorize,
|
|
|
|
|
as_server && log_syslog,
|
|
|
|
|
(enum fcft_log_class)log_level);
|
2020-09-13 17:59:56 +02:00
|
|
|
|
2019-12-17 19:08:43 +01:00
|
|
|
if (conf_server_socket_path != NULL) {
|
|
|
|
|
free(conf.server_socket_path);
|
2020-08-08 20:34:30 +01:00
|
|
|
conf.server_socket_path = xstrdup(conf_server_socket_path);
|
2019-12-17 19:08:43 +01:00
|
|
|
}
|
2019-12-31 15:39:40 +01:00
|
|
|
conf.presentation_timings = presentation_timings;
|
2020-02-03 19:58:32 +01:00
|
|
|
conf.hold_at_exit = hold;
|
2019-12-17 19:08:43 +01:00
|
|
|
|
2021-08-31 19:42:22 +02:00
|
|
|
if (conf.tweak.font_monospace_warn && conf.fonts[0].count > 0) {
|
|
|
|
|
check_if_font_is_monospaced(
|
|
|
|
|
conf.fonts[0].arr[0].pattern, &conf.notifications);
|
|
|
|
|
}
|
|
|
|
|
|
main: present invalid locale errors as a user-notification
Foot does not support running under non-UTF8 locales. If we detect a
non-UTF8 locale, we log this and exit with an error.
However, it appears a fairly common situation is this:
user (knowingly or unknowingly) only configures his/hers locale in
e.g. the shell RC files. These aren’t sourced when the compositor is
started via a display manager.
Thus, compositor key binds will fail to launch, and the user typically
has no way of seeing foot’s output.
So, the user proceeds to start another terminal, and from that one
tries launching foot. And it works... (because the shell in the other
terminal sourced the locale configuration).
User is left confused and often don’t know how to debug.
This patch is somewhat hackish; in addition to logging the locale
error, it also pushes a user notification. For this to be visible, we
need to actually start a terminal window.
So, we ignore the configured shell, and we ignore any custom command
line, and instead spawns “/bin/sh -c ‘’”. This allows us to get
something running (that hopefully doesn’t produce too much output we
can’t decode due to the non-UTF8 locale). But, it will exit
immediately. So we also set the --hold flag.
This works, and may be a good enough “solution”. However, it only
works for standalone foot instances, not footclients.
2022-01-10 20:24:46 +01:00
|
|
|
|
|
|
|
|
if (bad_locale) {
|
|
|
|
|
static char *const bad_locale_fake_argv[] = {"/bin/sh", "-c", "", NULL};
|
|
|
|
|
argc = 1;
|
|
|
|
|
argv = bad_locale_fake_argv;
|
|
|
|
|
conf.hold_at_exit = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-27 19:08:48 +01:00
|
|
|
struct fdm *fdm = NULL;
|
2020-05-21 20:15:10 +02:00
|
|
|
struct reaper *reaper = NULL;
|
key-binding: new API, for handling sets of key bindings
Up until now, our Wayland seats have been tracking key bindings. This
makes sense, since the seat’s keymap determines how the key bindings
are resolved.
However, tying bindings to the seat/keymap alone isn’t enough, since
we also depend on the current configuration (i.e. user settings) when
resolving a key binding.
This means configurations that doesn’t match the wayland object’s
configuration, currently don’t resolve key bindings correctly. This
applies to footclients where the user has overridden key bindings on
the command line (e.g. --override key-bindings.foo=bar).
Thus, to correctly resolve key bindings, each set of key bindings must
be tied *both* to a seat/keymap, *and* a configuration.
This patch introduces a key-binding manager, with an API to
add/remove/lookup, and load/unload keymaps from sets of key bindings.
In the API, sets are tied to a seat and terminal instance, since this
makes the most sense (we need to instantiate, or incref a set whenever
a new terminal instance is created). Internally, the set is tied to a
seat and the terminal’s configuration.
Sets are *added* when a new seat is added, and when a new terminal
instance is created. Since there can only be one instance of each
seat, sets are always removed when a seat is removed.
Terminals on the other hand can re-use the same configuration (and
typically do). Thus, sets ref-count the configuration. In other words,
when instantiating a new terminal, we may not have to instantiate a
new set of key bindings, but can often be incref:ed instead.
Whenever the keymap changes on a seat, all key bindings sets
associated with that seat reloads (re-resolves) their key bindings.
Closes #931
2022-04-17 15:39:51 +02:00
|
|
|
struct key_binding_manager *key_binding_manager = NULL;
|
2019-10-27 19:08:48 +01:00
|
|
|
struct wayland *wayl = NULL;
|
2020-01-04 19:49:26 +01:00
|
|
|
struct renderer *renderer = NULL;
|
2019-10-28 18:25:19 +01:00
|
|
|
struct terminal *term = NULL;
|
2019-11-01 20:37:22 +01:00
|
|
|
struct server *server = NULL;
|
2021-04-30 22:47:16 +02:00
|
|
|
struct shutdown_context shutdown_ctx = {.term = &term, .exit_code = foot_exit_failure};
|
2019-10-27 19:08:48 +01:00
|
|
|
|
2021-02-12 09:39:44 +01:00
|
|
|
const char *cwd = custom_cwd;
|
|
|
|
|
char *_cwd = NULL;
|
|
|
|
|
|
|
|
|
|
if (cwd == NULL) {
|
2019-12-21 19:57:28 +01:00
|
|
|
size_t buf_len = 1024;
|
|
|
|
|
do {
|
2021-02-12 09:39:44 +01:00
|
|
|
_cwd = xrealloc(_cwd, buf_len);
|
2025-01-22 19:38:11 +00:00
|
|
|
errno = 0;
|
2021-02-12 09:39:44 +01:00
|
|
|
if (getcwd(_cwd, buf_len) == NULL && errno != ERANGE) {
|
2020-02-20 18:46:45 +01:00
|
|
|
LOG_ERRNO("failed to get current working directory");
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2019-12-21 19:57:28 +01:00
|
|
|
buf_len *= 2;
|
|
|
|
|
} while (errno == ERANGE);
|
2021-02-12 09:39:44 +01:00
|
|
|
cwd = _cwd;
|
2019-12-21 19:57:28 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-26 19:09:33 +02:00
|
|
|
const char *pwd = getenv("PWD");
|
|
|
|
|
if (pwd != NULL) {
|
|
|
|
|
char *resolved_path_cwd = realpath(cwd, NULL);
|
|
|
|
|
char *resolved_path_pwd = realpath(pwd, NULL);
|
|
|
|
|
|
|
|
|
|
if (resolved_path_cwd != NULL &&
|
|
|
|
|
resolved_path_pwd != NULL &&
|
2024-01-24 23:17:28 +00:00
|
|
|
streq(resolved_path_cwd, resolved_path_pwd))
|
2022-09-26 19:09:33 +02:00
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The resolved path of $PWD matches the resolved path of
|
|
|
|
|
* the *actual* working directory - use $PWD.
|
|
|
|
|
*
|
|
|
|
|
* This makes a difference when $PWD refers to a symlink.
|
|
|
|
|
*/
|
|
|
|
|
cwd = pwd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(resolved_path_cwd);
|
|
|
|
|
free(resolved_path_pwd);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 20:48:02 +01:00
|
|
|
shm_set_max_pool_size(conf.tweak.max_shm_pool_size);
|
2025-10-04 09:29:56 +02:00
|
|
|
shm_set_min_stride_alignment(conf.tweak.min_stride_alignment);
|
2020-03-25 20:48:02 +01:00
|
|
|
|
2019-10-27 19:08:48 +01:00
|
|
|
if ((fdm = fdm_init()) == NULL)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2020-05-21 20:15:10 +02:00
|
|
|
if ((reaper = reaper_init(fdm)) == NULL)
|
|
|
|
|
goto out;
|
|
|
|
|
|
key-binding: new API, for handling sets of key bindings
Up until now, our Wayland seats have been tracking key bindings. This
makes sense, since the seat’s keymap determines how the key bindings
are resolved.
However, tying bindings to the seat/keymap alone isn’t enough, since
we also depend on the current configuration (i.e. user settings) when
resolving a key binding.
This means configurations that doesn’t match the wayland object’s
configuration, currently don’t resolve key bindings correctly. This
applies to footclients where the user has overridden key bindings on
the command line (e.g. --override key-bindings.foo=bar).
Thus, to correctly resolve key bindings, each set of key bindings must
be tied *both* to a seat/keymap, *and* a configuration.
This patch introduces a key-binding manager, with an API to
add/remove/lookup, and load/unload keymaps from sets of key bindings.
In the API, sets are tied to a seat and terminal instance, since this
makes the most sense (we need to instantiate, or incref a set whenever
a new terminal instance is created). Internally, the set is tied to a
seat and the terminal’s configuration.
Sets are *added* when a new seat is added, and when a new terminal
instance is created. Since there can only be one instance of each
seat, sets are always removed when a seat is removed.
Terminals on the other hand can re-use the same configuration (and
typically do). Thus, sets ref-count the configuration. In other words,
when instantiating a new terminal, we may not have to instantiate a
new set of key bindings, but can often be incref:ed instead.
Whenever the keymap changes on a seat, all key bindings sets
associated with that seat reloads (re-resolves) their key bindings.
Closes #931
2022-04-17 15:39:51 +02:00
|
|
|
if ((key_binding_manager = key_binding_manager_new()) == NULL)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2022-04-17 16:29:30 +02:00
|
|
|
if ((wayl = wayl_init(
|
|
|
|
|
fdm, key_binding_manager, conf.presentation_timings)) == NULL)
|
|
|
|
|
{
|
2019-10-27 19:08:48 +01:00
|
|
|
goto out;
|
2022-04-17 16:29:30 +02:00
|
|
|
}
|
2019-10-27 19:08:48 +01:00
|
|
|
|
2020-01-04 19:49:26 +01:00
|
|
|
if ((renderer = render_init(fdm, wayl)) == NULL)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2019-12-21 15:27:17 +01:00
|
|
|
if (!as_server && (term = term_init(
|
2021-12-10 17:40:59 +00:00
|
|
|
&conf, fdm, reaper, wayl, "foot", cwd, token, pty_path,
|
2022-04-11 12:19:40 +02:00
|
|
|
argc, argv, NULL,
|
2019-12-21 19:57:28 +01:00
|
|
|
&term_shutdown_cb, &shutdown_ctx)) == NULL) {
|
2019-11-01 20:34:32 +01:00
|
|
|
goto out;
|
2019-12-21 19:57:28 +01:00
|
|
|
}
|
2021-02-12 09:39:44 +01:00
|
|
|
free(_cwd);
|
|
|
|
|
_cwd = NULL;
|
2019-11-01 20:34:32 +01:00
|
|
|
|
2020-05-21 20:17:29 +02:00
|
|
|
if (as_server && (server = server_init(&conf, fdm, reaper, wayl)) == NULL)
|
2019-06-12 20:08:54 +02:00
|
|
|
goto out;
|
2019-08-12 21:49:17 +02:00
|
|
|
|
2021-02-10 16:21:56 +01:00
|
|
|
volatile sig_atomic_t aborted = false;
|
|
|
|
|
if (!fdm_signal_add(fdm, SIGINT, &fdm_sigint, (void *)&aborted) ||
|
|
|
|
|
!fdm_signal_add(fdm, SIGTERM, &fdm_sigint, (void *)&aborted))
|
|
|
|
|
{
|
2019-11-01 20:35:42 +01:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-30 12:23:39 +02:00
|
|
|
struct sigusr_context sigusr_context = {
|
|
|
|
|
.term = term,
|
|
|
|
|
.server = server,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!fdm_signal_add(fdm, SIGUSR1, &fdm_sigusr, &sigusr_context) ||
|
|
|
|
|
!fdm_signal_add(fdm, SIGUSR2, &fdm_sigusr, &sigusr_context))
|
2025-07-17 10:18:17 +02:00
|
|
|
{
|
2025-06-09 07:38:26 +02:00
|
|
|
goto out;
|
2025-07-17 10:18:17 +02:00
|
|
|
}
|
2025-06-09 07:38:26 +02:00
|
|
|
|
Explicitly initialize sigaction::sa_mask members with sigemptyset(3)
Not doing so before calling sigaction(3) is "undefined" according to
POSIX[1]:
> Applications shall call either sigemptyset() or sigfillset() at least
> once for each object of type sigset_t prior to any other use of that
> object. If such an object is not initialized in this way, but is
> nonetheless supplied as an argument to any of pthread_sigmask(),
> sigaction(), sigaddset(), sigdelset(), sigismember(), sigpending(),
> sigprocmask(), sigsuspend(), sigtimedwait(), sigwait(), or
> sigwaitinfo(), the results are undefined.
The use of designated initializers means that sa_mask members were
still being initialized, but sigset_t is an opaque type and implicit
initialization doesn't necessarily produce the same results as using
sigemptyset(3) (although it typically does on most implementations).
[1]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaddset.html
2022-02-12 12:04:57 +00:00
|
|
|
struct sigaction sig_ign = {.sa_handler = SIG_IGN};
|
|
|
|
|
sigemptyset(&sig_ign.sa_mask);
|
2021-12-05 15:25:26 +01:00
|
|
|
if (sigaction(SIGHUP, &sig_ign, NULL) < 0 ||
|
|
|
|
|
sigaction(SIGPIPE, &sig_ign, NULL) < 0)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERRNO("failed to ignore SIGHUP+SIGPIPE");
|
2019-11-03 13:23:49 +01:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-01 20:37:22 +01:00
|
|
|
if (as_server)
|
|
|
|
|
LOG_INFO("running as server; launch terminals by running footclient");
|
2019-10-27 19:21:36 +01:00
|
|
|
|
2020-02-05 19:53:50 +01:00
|
|
|
if (as_server && pid_file != NULL) {
|
|
|
|
|
if (!print_pid(pid_file, &unlink_pid_file))
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-16 22:40:51 +01:00
|
|
|
ret = EXIT_SUCCESS;
|
2020-11-26 18:23:28 +01:00
|
|
|
while (likely(!aborted && (as_server || tll_length(wayl->terms) > 0))) {
|
2022-02-16 22:40:51 +01:00
|
|
|
if (unlikely(!fdm_poll(fdm))) {
|
|
|
|
|
ret = foot_exit_failure;
|
2019-06-12 20:08:54 +02:00
|
|
|
break;
|
2022-02-16 22:40:51 +01:00
|
|
|
}
|
2019-10-27 11:46:18 +01:00
|
|
|
}
|
2019-07-21 19:14:19 +02:00
|
|
|
|
2019-10-27 11:46:18 +01:00
|
|
|
out:
|
2021-02-12 09:39:44 +01:00
|
|
|
free(_cwd);
|
2019-11-01 20:34:32 +01:00
|
|
|
server_destroy(server);
|
|
|
|
|
term_destroy(term);
|
2019-11-05 09:30:24 +01:00
|
|
|
|
|
|
|
|
shm_fini();
|
2020-01-04 19:49:26 +01:00
|
|
|
render_destroy(renderer);
|
2019-10-27 19:08:48 +01:00
|
|
|
wayl_destroy(wayl);
|
key-binding: new API, for handling sets of key bindings
Up until now, our Wayland seats have been tracking key bindings. This
makes sense, since the seat’s keymap determines how the key bindings
are resolved.
However, tying bindings to the seat/keymap alone isn’t enough, since
we also depend on the current configuration (i.e. user settings) when
resolving a key binding.
This means configurations that doesn’t match the wayland object’s
configuration, currently don’t resolve key bindings correctly. This
applies to footclients where the user has overridden key bindings on
the command line (e.g. --override key-bindings.foo=bar).
Thus, to correctly resolve key bindings, each set of key bindings must
be tied *both* to a seat/keymap, *and* a configuration.
This patch introduces a key-binding manager, with an API to
add/remove/lookup, and load/unload keymaps from sets of key bindings.
In the API, sets are tied to a seat and terminal instance, since this
makes the most sense (we need to instantiate, or incref a set whenever
a new terminal instance is created). Internally, the set is tied to a
seat and the terminal’s configuration.
Sets are *added* when a new seat is added, and when a new terminal
instance is created. Since there can only be one instance of each
seat, sets are always removed when a seat is removed.
Terminals on the other hand can re-use the same configuration (and
typically do). Thus, sets ref-count the configuration. In other words,
when instantiating a new terminal, we may not have to instantiate a
new set of key bindings, but can often be incref:ed instead.
Whenever the keymap changes on a seat, all key bindings sets
associated with that seat reloads (re-resolves) their key bindings.
Closes #931
2022-04-17 15:39:51 +02:00
|
|
|
key_binding_manager_destroy(key_binding_manager);
|
2020-05-21 20:15:10 +02:00
|
|
|
reaper_destroy(reaper);
|
2025-06-09 07:38:26 +02:00
|
|
|
fdm_signal_del(fdm, SIGUSR1);
|
2025-07-18 17:24:18 +02:00
|
|
|
fdm_signal_del(fdm, SIGUSR2);
|
2021-02-10 16:21:56 +01:00
|
|
|
fdm_signal_del(fdm, SIGTERM);
|
|
|
|
|
fdm_signal_del(fdm, SIGINT);
|
2019-10-27 11:46:18 +01:00
|
|
|
fdm_destroy(fdm);
|
2019-10-28 18:25:19 +01:00
|
|
|
|
2022-04-12 13:01:56 +02:00
|
|
|
config_free(&conf);
|
2019-12-19 07:25:05 +01:00
|
|
|
|
2020-02-05 19:53:50 +01:00
|
|
|
if (unlink_pid_file)
|
|
|
|
|
unlink(pid_file);
|
|
|
|
|
|
2019-12-19 07:25:05 +01:00
|
|
|
LOG_INFO("goodbye");
|
fcft: adapt to API changes in fcft-3.x
Fcft no longer uses wchar_t, but plain uint32_t to represent
codepoints.
Since we do a fair amount of string operations in foot, it still makes
sense to use something that actually _is_ a string (or character),
rather than an array of uint32_t.
For this reason, we switch out all wchar_t usage in foot to
char32_t. We also verify, at compile-time, that char32_t used
UTF-32 (which is what fcft expects).
Unfortunately, there are no string functions for char32_t. To avoid
having to re-implement all wcs*() functions, we add a small wrapper
layer of c32*() functions.
These wrapper functions take char32_t arguments, but then simply call
the corresponding wcs*() function.
For this to work, wcs*() must _also_ be UTF-32 compatible. We can
check for the presence of the __STDC_ISO_10646__ macro. If set,
wchar_t is at least 4 bytes and its internal representation is UTF-32.
FreeBSD does *not* define this macro, because its internal wchar_t
representation depends on the current locale. It _does_ use UTF-32
_if_ the current locale is UTF-8.
Since foot enforces UTF-8, we simply need to check if __FreeBSD__ is
defined.
Other fcft API changes:
* fcft_glyph_rasterize() -> fcft_codepoint_rasterize()
* font.space_advance has been removed
* ‘tags’ have been removed from fcft_grapheme_rasterize()
* ‘fcft_log_init()’ removed
* ‘fcft_init()’ and ‘fcft_fini()’ must be explicitly called
2021-08-21 14:50:42 +02:00
|
|
|
fcft_fini();
|
2019-11-20 19:43:31 +01:00
|
|
|
log_deinit();
|
2019-11-01 20:34:32 +01:00
|
|
|
return ret == EXIT_SUCCESS && !as_server ? shutdown_ctx.exit_code : ret;
|
2019-06-12 20:08:54 +02:00
|
|
|
}
|
osc: kitty notifications: cleanup and update to latest version of spec
* Don't store a list of unfinished notifications. Use a single one. If
the notification ID of the 'current' notification doesn't match the
previous, unfinished one, the 'current' notification replaces the
previous one, instead of updating it.
* Update xstrjoin() to take an optional delimiter (for example ','),
and use that when joining categories and 'alive IDs'.
* Rename ${action-arg} to ${action-argument}
* Update handling of the 'n' parameter (symbolic icon name); the spec
allows it to be used multiple times, and the terminal is supposed to
pick the first one it can resolve. Foot can't resolve icons at all,
neither can 'notify-send' or 'fyi' (which is what foot typically
executes to display a notification); it's the notification daemon that
resolves icons.
The spec _could_ be interpreted to mean the terminal should lookup
.desktop files, and use the value of the 'Icon' key from the first
matching .desktop files. But foot doesn't read .desktop files, and I
don't intend to implement XDG directory scanning and parsing of
.desktop files just to figure out which icon to use.
Instead, use a simple heuristics; use the *shortest* symbolic
names. The idea is pretty simple: plain icon names are typically
shorter than .desktop file IDs.
2024-08-02 08:07:13 +02:00
|
|
|
|
|
|
|
|
UNITTEST
|
|
|
|
|
{
|
2024-08-03 08:12:13 +01:00
|
|
|
char *s = xstrjoin("foo", "bar");
|
osc: kitty notifications: cleanup and update to latest version of spec
* Don't store a list of unfinished notifications. Use a single one. If
the notification ID of the 'current' notification doesn't match the
previous, unfinished one, the 'current' notification replaces the
previous one, instead of updating it.
* Update xstrjoin() to take an optional delimiter (for example ','),
and use that when joining categories and 'alive IDs'.
* Rename ${action-arg} to ${action-argument}
* Update handling of the 'n' parameter (symbolic icon name); the spec
allows it to be used multiple times, and the terminal is supposed to
pick the first one it can resolve. Foot can't resolve icons at all,
neither can 'notify-send' or 'fyi' (which is what foot typically
executes to display a notification); it's the notification daemon that
resolves icons.
The spec _could_ be interpreted to mean the terminal should lookup
.desktop files, and use the value of the 'Icon' key from the first
matching .desktop files. But foot doesn't read .desktop files, and I
don't intend to implement XDG directory scanning and parsing of
.desktop files just to figure out which icon to use.
Instead, use a simple heuristics; use the *shortest* symbolic
names. The idea is pretty simple: plain icon names are typically
shorter than .desktop file IDs.
2024-08-02 08:07:13 +02:00
|
|
|
xassert(streq(s, "foobar"));
|
|
|
|
|
free(s);
|
|
|
|
|
|
2024-08-03 08:12:13 +01:00
|
|
|
s = xstrjoin3("foo", " ", "bar");
|
osc: kitty notifications: cleanup and update to latest version of spec
* Don't store a list of unfinished notifications. Use a single one. If
the notification ID of the 'current' notification doesn't match the
previous, unfinished one, the 'current' notification replaces the
previous one, instead of updating it.
* Update xstrjoin() to take an optional delimiter (for example ','),
and use that when joining categories and 'alive IDs'.
* Rename ${action-arg} to ${action-argument}
* Update handling of the 'n' parameter (symbolic icon name); the spec
allows it to be used multiple times, and the terminal is supposed to
pick the first one it can resolve. Foot can't resolve icons at all,
neither can 'notify-send' or 'fyi' (which is what foot typically
executes to display a notification); it's the notification daemon that
resolves icons.
The spec _could_ be interpreted to mean the terminal should lookup
.desktop files, and use the value of the 'Icon' key from the first
matching .desktop files. But foot doesn't read .desktop files, and I
don't intend to implement XDG directory scanning and parsing of
.desktop files just to figure out which icon to use.
Instead, use a simple heuristics; use the *shortest* symbolic
names. The idea is pretty simple: plain icon names are typically
shorter than .desktop file IDs.
2024-08-02 08:07:13 +02:00
|
|
|
xassert(streq(s, "foo bar"));
|
|
|
|
|
free(s);
|
|
|
|
|
|
2024-08-03 08:12:13 +01:00
|
|
|
s = xstrjoin3("foo", ",", "bar");
|
osc: kitty notifications: cleanup and update to latest version of spec
* Don't store a list of unfinished notifications. Use a single one. If
the notification ID of the 'current' notification doesn't match the
previous, unfinished one, the 'current' notification replaces the
previous one, instead of updating it.
* Update xstrjoin() to take an optional delimiter (for example ','),
and use that when joining categories and 'alive IDs'.
* Rename ${action-arg} to ${action-argument}
* Update handling of the 'n' parameter (symbolic icon name); the spec
allows it to be used multiple times, and the terminal is supposed to
pick the first one it can resolve. Foot can't resolve icons at all,
neither can 'notify-send' or 'fyi' (which is what foot typically
executes to display a notification); it's the notification daemon that
resolves icons.
The spec _could_ be interpreted to mean the terminal should lookup
.desktop files, and use the value of the 'Icon' key from the first
matching .desktop files. But foot doesn't read .desktop files, and I
don't intend to implement XDG directory scanning and parsing of
.desktop files just to figure out which icon to use.
Instead, use a simple heuristics; use the *shortest* symbolic
names. The idea is pretty simple: plain icon names are typically
shorter than .desktop file IDs.
2024-08-02 08:07:13 +02:00
|
|
|
xassert(streq(s, "foo,bar"));
|
|
|
|
|
free(s);
|
2024-08-03 08:12:13 +01:00
|
|
|
|
|
|
|
|
s = xstrjoin3("foo", "bar", "baz");
|
|
|
|
|
xassert(streq(s, "foobarbaz"));
|
|
|
|
|
free(s);
|
osc: kitty notifications: cleanup and update to latest version of spec
* Don't store a list of unfinished notifications. Use a single one. If
the notification ID of the 'current' notification doesn't match the
previous, unfinished one, the 'current' notification replaces the
previous one, instead of updating it.
* Update xstrjoin() to take an optional delimiter (for example ','),
and use that when joining categories and 'alive IDs'.
* Rename ${action-arg} to ${action-argument}
* Update handling of the 'n' parameter (symbolic icon name); the spec
allows it to be used multiple times, and the terminal is supposed to
pick the first one it can resolve. Foot can't resolve icons at all,
neither can 'notify-send' or 'fyi' (which is what foot typically
executes to display a notification); it's the notification daemon that
resolves icons.
The spec _could_ be interpreted to mean the terminal should lookup
.desktop files, and use the value of the 'Icon' key from the first
matching .desktop files. But foot doesn't read .desktop files, and I
don't intend to implement XDG directory scanning and parsing of
.desktop files just to figure out which icon to use.
Instead, use a simple heuristics; use the *shortest* symbolic
names. The idea is pretty simple: plain icon names are typically
shorter than .desktop file IDs.
2024-08-02 08:07:13 +02:00
|
|
|
}
|