Instead of disabling content centering, delay the TIOCSWINSZ (a.k.a
delay sending the new dimensions to the client) by a small amount
while doing an interactive resize.
Non-interactive resizes are still immediate.
For now, force a resize when the user stops the interactive
resize. This ensures the client application receives the new
dimensions immediately.
It still works without the last, forced, resize, but there typically
be a small delay until the client application receives the final
dimensions.
Closes#301Closes#283
This is needed to apply content centering after an interactive resize,
as otherwise we’d just ignore the last configure event since the only
difference between that event and the next to last event is that the
is-resizing bit has been cleared. I.e. the window size is identical to
what we already have, and our resize code would thus ignore the event.
Before passing the pasted text to the decoder, we now replace \r\n,
and \n, with \r.
The URI decoder was looking for a \n, which meant we failed to split
up the list and instead pasted a single “multi-line” URI.
We failed to convert the byte-indices to cell indices, resulting in a
box cursor covering the entire pre-edit string.
Note that in addition to fixing the translation from byte index to
cell index, the rendered had to be updated to dirty one extra cell
from the original grid.
Without this, we left trailing cursors behind us when the user deleted
text from the pre-edit string.
When rendering the search input box, do the same ad-hoc workaround for
combining characters with a positive x-offset as we do when rendering
normal grid cells.
In this case, we don’t *know* when we’re dealing with combining
characters. But we can detect zero-width characters. For these, check
their glyph’s x-offset. If positive, adjust it like we do when
rendering combining glyphs in the main grid, to ensure the glyph is
positioned over the _previous_ character, not the next.
When ‘selection-target’ is set to ‘none’, selecting text does not copy
the text to _any_ clipboard.
This patch also refactors the value parsing to be data driven.
The freebsd/latest image is still FreeBSD-12, with clang-8. It
generate false positive warnings:
../../foot/search.c:357:21: error: suggest braces around initialization of subobject [-Werror,-Wmissing-braces]
mbstate_t ps = {0};
This fixes an out-of-range comparison in 32-bit builds:
client.c:289:19: error: result of comparison of constant 4294967296 with expression of type 'size_t' (aka 'unsigned int') is always false [-Werror,-Wtautological-constant-out-of-range-compare]
if (total_len >= 1llu << (8 * sizeof(uint32_t)) ||
~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ncurses on FreeBSD still uses termcap(5) while foot works fine with
xterm-256color sans status line and visible bell. Having more than
one ncurses version installed may break other applications.
Document -Dterminfo=false uses --term=xterm-256color by default
Base compiler on BSDs doesn't look where packages are installed to
avoid tainting build environment. When system fcft is installed to
the same prefix as wayland-client it passes CFLAGS that satisfy both
but when using subprojects/fcft there's a build error.
xdg-shell.c:33:10: fatal error: 'wayland-util.h' file not found
xdg-decoration-unstable-v1.c:28:10: fatal error: 'wayland-util.h' file not found
xdg-output-unstable-v1.c:28:10: fatal error: 'wayland-util.h' file not found
presentation-time.c:28:10: fatal error: 'wayland-util.h' file not found
primary-selection-unstable-v1.c:28:10: fatal error: 'wayland-util.h' file not found
text-input-unstable-v3.c:33:10: fatal error: 'wayland-util.h' file not found
In file included from ../../foot/grid.c:1:
In file included from ../../foot/grid.h:5:
In file included from ../../foot/terminal.h:19:
../../foot/wayland.h:8:10: fatal error: 'wayland-client.h' file not found
In file included from ../../foot/selection.c:1:
../../foot/selection.h:4:10: fatal error: 'wayland-client.h' file not found
epoll/timerfd are Linux-only but BSDs have a shim via kqueue.
libwayland on FreeBSD uses epoll-shim by default, so the build may
fail at linking instead of compilation stage.
csi.c:13:10: fatal error: 'sys/timerfd.h' file not found
#include <sys/timerfd.h>
^~~~~~~~~~~~~~~
selection.c:10:10: fatal error: 'sys/epoll.h' file not found
#include <sys/epoll.h>
^~~~~~~~~~~~~
terminal.c:15:10: fatal error: 'sys/epoll.h' file not found
#include <sys/epoll.h>
^~~~~~~~~~~~~
ld: error: undefined symbol: timerfd_create
>>> referenced by pgo.c:154 (pgo/pgo.c:154)
>>> pgo.p/pgo_pgo.c.o:(main)
>>> referenced by pgo.c:158 (pgo/pgo.c:158)
>>> pgo.p/pgo_pgo.c.o:(main)
>>> referenced by terminal.c:2022 (terminal.c:2022)
>>> terminal.c.o:(cursor_blink_rearm_timer) in archive libpgolib.a
>>> referenced 7 more times
ld: error: undefined symbol: epoll_shim_close
>>> referenced by pgo.c:160 (pgo/pgo.c:160)
>>> pgo.p/pgo_pgo.c.o:(main)
>>> referenced by pgo.c:258 (pgo/pgo.c:258)
>>> pgo.p/pgo_pgo.c.o:(main)
>>> referenced by pgo.c:277 (pgo/pgo.c:277)
>>> pgo.p/pgo_pgo.c.o:(main)
>>> referenced 14 more times
ld: error: undefined symbol: epoll_shim_read
>>> referenced by pgo.c:251 (pgo/pgo.c:251)
>>> pgo.p/pgo_pgo.c.o:(main)
>>> referenced by terminal.c:237 (terminal.c:237)
>>> terminal.c.o:(fdm_ptmx) in archive libpgolib.a
>>> referenced by terminal.c:363 (terminal.c:363)
>>> terminal.c.o:(fdm_blink) in archive libpgolib.a
>>> referenced 8 more times
ld: error: undefined symbol: timerfd_settime
>>> referenced by terminal.c:301 (terminal.c:301)
>>> terminal.c.o:(fdm_ptmx) in archive libpgolib.a
>>> referenced by terminal.c:309 (terminal.c:309)
>>> terminal.c.o:(fdm_ptmx) in archive libpgolib.a
>>> referenced by terminal.c:2041 (terminal.c:2041)
>>> terminal.c.o:(cursor_blink_rearm_timer) in archive libpgolib.a
>>> referenced 11 more times
ld: error: undefined symbol: timerfd_gettime
>>> referenced by selection.c:1165 (selection.c:1165)
>>> selection.c.o:(selection_start_scroll_timer) in archive libpgolib.a
foot uses a number of functions not in any POSIX version. On non-glibc
systems defining _POSIX_C_SOURCE usually hides non-compliant interfaces.
In file included from grid.c:1:
In file included from grid.h:4:
terminal.h:45:15: error: expected parameter declarator
static_assert(sizeof(struct attributes) == 8, "bad size");
^
terminal.h:45:15: error: expected ')'
terminal.h:45:14: note: to match this '('
static_assert(sizeof(struct attributes) == 8, "bad size");
^
terminal.h:45:1: error: type specifier missing, defaults to 'int' [-Werror,-Wimplicit-int]
static_assert(sizeof(struct attributes) == 8, "bad size");
^
terminal.h:55:15: error: expected parameter declarator
static_assert(sizeof(struct cell) == 12, "bad size");
^
terminal.h:55:15: error: expected ')'
terminal.h:55:14: note: to match this '('
static_assert(sizeof(struct cell) == 12, "bad size");
^
terminal.h:55:1: error: type specifier missing, defaults to 'int' [-Werror,-Wimplicit-int]
static_assert(sizeof(struct cell) == 12, "bad size");
^
grid.c:317:32: error: implicit declaration of function 'wcwidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
int width = max(1, wcwidth(wc));
^
grid.c:317:32: note: did you mean '__wcwidth'?
/usr/include/_ctype.h:161:1: note: '__wcwidth' declared here
__wcwidth(__ct_rune_t _c)
^
selection.c:1695:9: error: implicit declaration of function 'pipe2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (pipe2(fds, O_CLOEXEC) == -1) {
^
selection.c:1695:9: note: did you mean 'pipe'?
/usr/include/unistd.h:358:6: note: 'pipe' declared here
int pipe(int *);
^
selection.c:1842:9: error: implicit declaration of function 'pipe2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (pipe2(fds, O_CLOEXEC) == -1) {
^
selection.c:2129:9: error: implicit declaration of function 'pipe2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (pipe2(fds, O_CLOEXEC) == -1) {
^
vt.c:241:12: error: implicit declaration of function 'wcwidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
assert(wcwidth(c) == 1);
^
vt.c:241:12: note: did you mean '__wcwidth'?
/usr/include/_ctype.h:161:1: note: '__wcwidth' declared here
__wcwidth(__ct_rune_t _c)
^
vt.c:544:17: error: implicit declaration of function 'wcwidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
int width = wcwidth(wc);
^
csi.c:713:35: error: implicit declaration of function 'wcwidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
const int width = wcwidth(term->vt.last_printed);
^
csi.c:713:35: note: did you mean '__wcwidth'?
/usr/include/_ctype.h:161:1: note: '__wcwidth' declared here
__wcwidth(__ct_rune_t _c)
^
ime.c:169:25: error: implicit declaration of function 'wcwidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
int width = max(wcwidth(term->ime.preedit.text[i]), 1);
^
ime.c:169:25: note: did you mean '__wcwidth'?
/usr/include/_ctype.h:161:1: note: '__wcwidth' declared here
__wcwidth(__ct_rune_t _c)
^
quirks.c:81:22: error: implicit declaration of function 'strcasestr' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
is_kde = strcasestr(cur_desktop, "kde") != NULL;
^
quirks.c:81:53: error: comparison between pointer and integer ('int' and 'void *') [-Werror,-Wpointer-integer-compare]
is_kde = strcasestr(cur_desktop, "kde") != NULL;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~
config.c:89:15: error: expected ')'
static_assert(ALEN(binding_action_map) == BIND_ACTION_COUNT,
^
util.h:5:18: note: expanded from macro 'ALEN'
#define ALEN(v) (sizeof(v) / sizeof((v)[0]))
^
config.c:358:12: error: implicit declaration of function 'strcasecmp' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return strcasecmp(s, "on") == 0 ||
^
config.c:358:12: note: did you mean 'wcscasecmp'?
/usr/include/wchar.h:223:5: note: 'wcscasecmp' declared here
int wcscasecmp(const wchar_t *, const wchar_t *);
^
config.c:510:23: error: implicit declaration of function 'strcasecmp' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
bool center = strcasecmp(mode, "center") == 0;
^
config.c:1243:13: error: implicit declaration of function 'strcasecmp' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (strcasecmp(value, "none") == 0) {
^
config.c:1330:13: error: implicit declaration of function 'strcasecmp' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (strcasecmp(value, "none") == 0) {
^
config.c:1534:13: error: implicit declaration of function 'strcasecmp' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (strcasecmp(value, "none") == 0) {
^
spawn.c:20:9: error: implicit declaration of function 'pipe2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
^
spawn.c:20:9: note: did you mean 'pipe'?
/usr/include/unistd.h:358:6: note: 'pipe' declared here
int pipe(int *);
^
spawn.c:52:5: error: implicit declaration of function 'static_assert' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
static_assert(sizeof(_errno) == sizeof(errno), "errno size mismatch");
^
server.c:309:21: error: implicit declaration of function 'accept4' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
int client_fd = accept4(
^
server.c:309:21: note: did you mean 'accept'?
/usr/include/sys/socket.h:679:5: note: 'accept' declared here
int accept(int, struct sockaddr * __restrict, socklen_t * __restrict);
^
server.c:310:59: error: use of undeclared identifier 'SOCK_CLOEXEC'
server->fd, (struct sockaddr *)&addr, &addr_size, SOCK_CLOEXEC | SOCK_NONBLOCK);
^
server.c:310:74: error: use of undeclared identifier 'SOCK_NONBLOCK'
server->fd, (struct sockaddr *)&addr, &addr_size, SOCK_CLOEXEC | SOCK_NONBLOCK);
^
server.c:341:44: error: use of undeclared identifier 'SOCK_CLOEXEC'
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
^
server.c:341:59: error: use of undeclared identifier 'SOCK_NONBLOCK'
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
^
server.c:371:44: error: use of undeclared identifier 'SOCK_CLOEXEC'
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
^
server.c:371:59: error: use of undeclared identifier 'SOCK_NONBLOCK'
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
^
shm.c:138:26: error: use of undeclared identifier '_SC_PAGE_SIZE'
long n = sysconf(_SC_PAGE_SIZE);
^
shm.c:279:15: error: implicit declaration of function 'memfd_create' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
^
shm.c:279:15: note: did you mean 'timer_create'?
/usr/include/time.h:170:5: note: 'timer_create' declared here
int timer_create(clockid_t, struct sigevent *__restrict, timer_t *__restrict);
^
shm.c:279:60: error: use of undeclared identifier 'MFD_CLOEXEC'
pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
^
shm.c:279:74: error: use of undeclared identifier 'MFD_ALLOW_SEALING'
pool_fd = memfd_create("foot-wayland-shm-buffer-pool", MFD_CLOEXEC | MFD_ALLOW_SEALING);
^
shm.c:350:15: error: use of undeclared identifier 'F_SEAL_GROW'
F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
^
shm.c:350:29: error: use of undeclared identifier 'F_SEAL_SHRINK'
F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
^
shm.c:350:71: error: use of undeclared identifier 'F_SEAL_SEAL'
F_SEAL_GROW | F_SEAL_SHRINK | /*F_SEAL_FUTURE_WRITE |*/ F_SEAL_SEAL) < 0)
^
shm.c:349:24: error: use of undeclared identifier 'F_ADD_SEALS'
if (fcntl(pool_fd, F_ADD_SEALS,
^
slave.c:151:28: error: implicit declaration of function 'ptsname' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
const char *pts_name = ptsname(ptmx);
^
slave.c:151:28: note: did you mean 'ttyname'?
/usr/include/unistd.h:371:7: note: 'ttyname' declared here
char *ttyname(int);
^
slave.c:151:17: error: incompatible integer to pointer conversion initializing 'const char *' with an expression of type 'int' [-Werror,-Wint-conversion]
const char *pts_name = ptsname(ptmx);
^ ~~~~~~~~~~~~~
slave.c:153:9: error: implicit declaration of function 'grantpt' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (grantpt(ptmx) == -1) {
^
slave.c:157:9: error: implicit declaration of function 'unlockpt' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (unlockpt(ptmx) == -1) {
^
slave.c:252:9: error: implicit declaration of function 'pipe2' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
if (pipe2(fork_pipe, O_CLOEXEC) < 0) {
^
slave.c:252:9: note: did you mean 'pipe'?
/usr/include/unistd.h:358:6: note: 'pipe' declared here
int pipe(int *);
^
render.c:1166:28: error: implicit declaration of function 'wcwidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
int width = max(1, wcwidth(cell->wc));
^
render.c:1166:28: note: did you mean '__wcwidth'?
/usr/include/_ctype.h:161:1: note: '__wcwidth' declared here
__wcwidth(__ct_rune_t _c)
^
render.c:1932:9: error: implicit declaration of function 'gettimeofday' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
gettimeofday(&start_time, NULL);
^
render.c:2240:28: error: implicit declaration of function 'wcwidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
widths[i] = max(1, wcwidth(text[i]));
^
render.c:2243:32: error: implicit declaration of function 'wcswidth' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
const size_t total_cells = wcswidth(text, text_len);
^
render.c:2243:32: note: did you mean 'wcwidth'?
render.c:1166:28: note: 'wcwidth' declared here
int width = max(1, wcwidth(cell->wc));
^
util.h:7:27: note: expanded from macro 'max'
#define max(x, y) ((x) > (y) ? (x) : (y))
^
input.c:1540:9: error: implicit declaration of function 'gettimeofday' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
gettimeofday(&now, NULL);
^