Merge branch 'master' into releases/1.17

This commit is contained in:
Daniel Eklöf 2024-04-11 15:26:50 +02:00
commit 385fc0078f
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
19 changed files with 341 additions and 29 deletions

View file

@ -1,5 +1,6 @@
# Changelog
* [Unreleased](#unreleased)
* [1.17.0](#1-17-0)
* [1.16.2](#1-16-2)
* [1.16.1](#1-16-1)
@ -49,6 +50,39 @@
* [1.2.0](#1-2-0)
## Unreleased
### Added
* `cursor.unfocused-style=unchanged|hollow|none` to `foot.ini`. The
default is `hollow` ([#1582][1582]).
* New key binding: `quit` ([#1475][1475]).
[1582]: https://codeberg.org/dnkl/foot/issues/1582
[1475]: https://codeberg.org/dnkl/foot/issues/1475
### Changed
### Deprecated
### Removed
### Fixed
* Log-level not respected by syslog.
* Regression: terminal shutting down when the PTY is closed by the
client application, which may be earlier than when the client
application exits ([#1666][1666]).
* When closing the window, send `SIGHUP` to the client application,
before sending `SIGTERM`. The signal sequence is now `SIGHUP`, wait,
`SIGTERM`, wait `SIGKILL`.
* Crash when receiving a `DECRQSS` request with more than 2 bytes in
the `q` parameter.
[1666]: https://codeberg.org/dnkl/foot/issues/1666
### Security
### Contributors
## 1.17.0
### Added

83
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,83 @@
# Foot Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
Participants in the foot community are expected to uphold the described
standards not only in official community spaces (issue trackers, IRC channels,
etc.) but in all public spaces. The Code of Conduct however does acknowledge
that people are fallible and that it is possible to truely correct a past
pattern of unacceptable behavior. That is to say, the scope of the Code of
Conduct does not necessarily extend into the distant past.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior
may be reported to the community leaders responsible for enforcement
at [daniel@ekloef.se](mailto:daniel@ekloef.se). All complaints will
be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
The consequences for Code of Conduct violations will be decided upon and
enforced by community leaders. These may include a formal warning, a temporary
ban from community spaces, a permanent ban from community spaces, etc.
There are no hard and fast rules for exactly what behavior in which space will
result in what consequences, it is up to the community leaders to enforce the
Code of Conduct in a way that they believe best promotes a healthy community.
## Attribution
This Code of Conduct is adapted from the
[Contributor Covenant](https://www.contributor-covenant.org/),
version 2.1, available at
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.

View file

@ -37,6 +37,7 @@ The fast, lightweight and minimalistic Wayland terminal emulator.
1. [Programmatically checking if running in foot](#programmatically-checking-if-running-in-foot)
1. [XTGETTCAP](#xtgettcap)
1. [Credits](#Credits)
1. [Code of Conduct](#code-of-conduct)
1. [Bugs](#bugs)
1. [Contact](#contact)
1. [IRC](#irc)
@ -304,7 +305,7 @@ when starting your Wayland compositor (i.e. logging in to your
desktop), and then run `footclient` instead of `foot` whenever you
want to launch a new terminal.
Foot support socket activation, which means `foot --server` will only be
Foot supports socket activation, which means `foot --server` will only be
started the first time you'll run `footclient`. (systemd user units are
included, but it can work with other supervision suites).
@ -644,6 +645,11 @@ queried capabilities are **always** sent. No queries are ever dropped.
contributing foot's [logo](icons/hicolor/48x48/apps/foot.png).
# Code of Conduct
See [Code of Conduct](CODE_OF_CONDUCT.md)
# Bugs
Please report bugs to https://codeberg.org/dnkl/foot/issues

View file

@ -119,6 +119,7 @@ static const char *const binding_action_map[] = {
[BIND_ACTION_PROMPT_PREV] = "prompt-prev",
[BIND_ACTION_PROMPT_NEXT] = "prompt-next",
[BIND_ACTION_UNICODE_INPUT] = "unicode-input",
[BIND_ACTION_QUIT] = "quit",
/* Mouse-specific actions */
[BIND_ACTION_SCROLLBACK_UP_MOUSE] = "scrollback-up-mouse",
@ -1383,6 +1384,16 @@ parse_section_cursor(struct context *ctx)
(int *)&conf->cursor.style);
}
else if (streq(key, "unfocused-style")) {
_Static_assert(sizeof(conf->cursor.unfocused_style) == sizeof(int),
"enum is not 32-bit");
return value_to_enum(
ctx,
(const char *[]){"unchanged", "hollow", "none", NULL},
(int *)&conf->cursor.unfocused_style);
}
else if (streq(key, "blink"))
return value_to_bool(ctx, &conf->cursor.blink);
@ -3090,6 +3101,7 @@ config_load(struct config *conf, const char *conf_path,
.cursor = {
.style = CURSOR_BLOCK,
.unfocused_style = CURSOR_UNFOCUSED_HOLLOW,
.blink = false,
.color = {
.text = 0,

View file

@ -28,6 +28,11 @@ struct font_size_adjustment {
};
enum cursor_style { CURSOR_BLOCK, CURSOR_UNDERLINE, CURSOR_BEAM };
enum cursor_unfocused_style {
CURSOR_UNFOCUSED_UNCHANGED,
CURSOR_UNFOCUSED_HOLLOW,
CURSOR_UNFOCUSED_NONE
};
enum conf_size_type {CONF_SIZE_PX, CONF_SIZE_CELLS};
@ -256,6 +261,7 @@ struct config {
struct {
enum cursor_style style;
enum cursor_unfocused_style unfocused_style;
bool blink;
struct {
uint32_t text;

2
dcs.c
View file

@ -239,7 +239,7 @@ decrqss_put(struct terminal *term, uint8_t c)
return;
struct vt *vt = &term->vt;
if (vt->dcs.idx > 2)
if (vt->dcs.idx >= 2)
return;
vt->dcs.data[vt->dcs.idx++] = c;
}

View file

@ -500,6 +500,15 @@ applications can change these at runtime.
*beam* or *underline*. Note that this can be overridden by
applications. Default: _block_.
*unfocused-style*
Configures how the cursor is rendered when the terminal window is
unfocused. Possible values are:
- unchanged: render cursor in exactly the same way as when the
window has focus.
- hollow: render a block cursor, but hollowed out.
- none: do not display any cursor at all.
*blink*
Boolean. Enables blinking cursor. Note that this can be overridden
by applications. Default: _no_.
@ -916,6 +925,9 @@ e.g. *search-start=none*.
Default: _Control+Shift+u_.
*quit*
Quit foot. Default: _none_.
# SECTION: search-bindings
This section lets you override the default key bindings used in

View file

@ -193,6 +193,7 @@
# clipboard-paste=Control+v Control+Shift+v Control+y XF86Paste
# primary-paste=Shift+Insert
# unicode-input=none
# quit=none
# scrollback-up-page=Shift+Page_Up
# scrollback-up-half-page=none
# scrollback-up-line=none

View file

@ -444,6 +444,10 @@ execute_binding(struct seat *seat, struct terminal *term,
unicode_mode_activate(seat);
return true;
case BIND_ACTION_QUIT:
term_shutdown(term);
return true;
case BIND_ACTION_SELECT_BEGIN:
selection_start(
term, seat->mouse.col, seat->mouse.row, SELECTION_CHAR_WISE, false);

View file

@ -40,6 +40,7 @@ enum bind_action_normal {
BIND_ACTION_PROMPT_PREV,
BIND_ACTION_PROMPT_NEXT,
BIND_ACTION_UNICODE_INPUT,
BIND_ACTION_QUIT,
/* Mouse specific actions - i.e. they require a mouse coordinate */
BIND_ACTION_SCROLLBACK_UP_MOUSE,
@ -53,7 +54,7 @@ enum bind_action_normal {
BIND_ACTION_SELECT_QUOTE,
BIND_ACTION_SELECT_ROW,
BIND_ACTION_KEY_COUNT = BIND_ACTION_UNICODE_INPUT + 1,
BIND_ACTION_KEY_COUNT = BIND_ACTION_QUIT + 1,
BIND_ACTION_COUNT = BIND_ACTION_SELECT_ROW + 1,
};

3
log.c
View file

@ -105,6 +105,9 @@ _sys_log(enum log_class log_class, const char *module,
if (!do_syslog)
return;
if (log_class > log_level)
return;
/* Map our log level to syslog's level */
int level = log_level_map[log_class].syslog_equivalent;

View file

@ -305,8 +305,8 @@ color_brighten(const struct terminal *term, uint32_t color)
}
static void
draw_unfocused_block(const struct terminal *term, pixman_image_t *pix,
const pixman_color_t *color, int x, int y, int cell_cols)
draw_hollow_block(const struct terminal *term, pixman_image_t *pix,
const pixman_color_t *color, int x, int y, int cell_cols)
{
const int scale = (int)roundf(term->scale);
const int width = min(min(scale, term->cell_width), term->cell_height);
@ -429,10 +429,23 @@ draw_cursor(const struct terminal *term, const struct cell *cell,
switch (term->cursor_style) {
case CURSOR_BLOCK:
if (unlikely(!term->kbd_focus))
draw_unfocused_block(term, pix, &cursor_color, x, y, cols);
if (unlikely(!term->kbd_focus)) {
switch (term->conf->cursor.unfocused_style) {
case CURSOR_UNFOCUSED_UNCHANGED:
break;
else if (likely(term->cursor_blink.state == CURSOR_BLINK_ON)) {
case CURSOR_UNFOCUSED_HOLLOW:
draw_hollow_block(term, pix, fg, x, y, cols);
return;
case CURSOR_UNFOCUSED_NONE:
return;
}
}
if (likely(term->cursor_blink.state == CURSOR_BLINK_ON) ||
!term->kbd_focus)
{
*fg = text_color;
pixman_image_fill_rectangles(
PIXMAN_OP_SRC, pix, &cursor_color, 1,
@ -1513,7 +1526,7 @@ render_ime_preedit_for_seat(struct terminal *term, struct seat *seat,
/* Hollow cursor */
if (start >= 0 && end <= term->cols) {
int cols = end - start;
draw_unfocused_block(term, buf->pix[0], &cursor_color, x, y, cols);
draw_hollow_block(term, buf->pix[0], &cursor_color, x, y, cols);
}
term_ime_set_cursor_rect(
@ -3373,7 +3386,7 @@ render_search_box(struct terminal *term)
/* TODO: how do we handle a partially hidden rectangle? */
if (start >= 0 && end <= visible_cells) {
draw_unfocused_block(
draw_hollow_block(
term, buf->pix[0], &fg, x + start * term->cell_width, y, end - start);
}
term_ime_set_cursor_rect(term,

View file

@ -364,8 +364,20 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
del_utmp_record(term->conf, term->reaper, term->ptmx);
fdm_del(fdm, fd);
term->ptmx = -1;
if (!term->conf->hold_at_exit)
/*
* Normally, we do *not* want to shutdown when the PTY is
* closed. Instead, we want to wait for the client application
* to exit.
*
* However, when we're using a pre-existing PTY (the --pty
* option), there _is_ no client application. That is, foot
* does *not* fork+exec anything, and thus the only way to
* shutdown is to wait for the PTY to be closed.
*/
if (term->slave < 0 && !term->conf->hold_at_exit) {
term_shutdown(term);
}
}
return true;
@ -1527,10 +1539,36 @@ fdm_terminate_timeout(struct fdm *fdm, int fd, int events, void *data)
struct terminal *term = data;
xassert(!term->shutdown.client_has_terminated);
LOG_DBG("slave (PID=%u) has not terminated, sending SIGKILL (%d)",
term->slave, SIGKILL);
LOG_DBG("slave (PID=%u) has not terminated, sending %s (%d)",
term->slave,
term->shutdown.next_signal == SIGTERM ? "SIGTERM"
: term->shutdown.next_signal == SIGKILL ? "SIGKILL"
: "<unknown>",
term->shutdown.next_signal);
kill(-term->slave, term->shutdown.next_signal);
switch (term->shutdown.next_signal) {
case SIGTERM:
term->shutdown.next_signal = SIGKILL;
break;
case SIGKILL:
/* Disarm. Shouldn't be necessary, as we should be able to
shutdown completely after sending SIGKILL, before the next
timeout occurs). But lets play it safe... */
if (term->shutdown.terminate_timeout_fd >= 0) {
timerfd_settime(
term->shutdown.terminate_timeout_fd, 0,
&(const struct itimerspec){0}, NULL);
}
break;
default:
BUG("can only handle SIGTERM and SIGKILL");
return false;
}
kill(-term->slave, SIGKILL);
return true;
}
@ -1571,11 +1609,18 @@ term_shutdown(struct terminal *term)
term->shutdown.client_has_terminated = true;
} else {
LOG_DBG("initiating asynchronous terminate of slave; "
"sending SIGTERM to PID=%u", term->slave);
"sending SIGHUP to PID=%u", term->slave);
kill(-term->slave, SIGTERM);
kill(-term->slave, SIGHUP);
const struct itimerspec timeout = {.it_value = {.tv_sec = 60}};
/*
* Set up a timer, with an interval - on the first timeout
* we'll send SIGTERM. If the the client application still
* isn't terminating, we'll wait an additional interval,
* and then send SIGKILL.
*/
const struct itimerspec timeout = {.it_value = {.tv_sec = 30},
.it_interval = {.tv_sec = 30}};
int timeout_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (timeout_fd < 0 ||
@ -1590,6 +1635,7 @@ term_shutdown(struct terminal *term)
xassert(term->shutdown.terminate_timeout_fd < 0);
term->shutdown.terminate_timeout_fd = timeout_fd;
term->shutdown.next_signal = SIGTERM;
}
}
@ -1772,9 +1818,9 @@ term_destroy(struct terminal *term)
exit_status = term->shutdown.exit_status;
else {
LOG_DBG("initiating blocking terminate of slave; "
"sending SIGTERM to PID=%u", term->slave);
"sending SIGHUP to PID=%u", term->slave);
kill(-term->slave, SIGTERM);
kill(-term->slave, SIGHUP);
/*
* we've closed the ptxm, and sent SIGTERM to the client
@ -1795,7 +1841,12 @@ term_destroy(struct terminal *term)
struct sigaction action = {.sa_handler = &sig_alarm};
sigemptyset(&action.sa_mask);
sigaction(SIGALRM, &action, NULL);
alarm(60);
/* Wait, then send SIGTERM, wait again, then send SIGKILL */
int next_signal = SIGTERM;
alarm_raised = 0;
alarm(30);
while (true) {
int r = waitpid(term->slave, &exit_status, 0);
@ -1807,11 +1858,16 @@ term_destroy(struct terminal *term)
xassert(errno == EINTR);
if (alarm_raised) {
LOG_DBG(
"slave (PID=%u) has not terminate yet, "
"sending: SIGKILL (%d)", term->slave, SIGKILL);
LOG_DBG("slave (PID=%u) has not terminated yet, "
"sending: %s (%d)", term->slave,
next_signal == SIGTERM ? "SIGTERM" : "SIGKILL",
next_signal);
kill(-term->slave, SIGKILL);
kill(-term->slave, next_signal);
next_signal = SIGKILL;
alarm_raised = 0;
alarm(30);
}
}
}
@ -2125,7 +2181,7 @@ term_fractional_scaling(const struct terminal *term)
bool
term_preferred_buffer_scale(const struct terminal *term)
{
return term->wl->has_wl_compositor_v6;
return term->wl->has_wl_compositor_v6 && term->window->preferred_buffer_scale > 0;
}
bool

View file

@ -723,6 +723,7 @@ struct terminal {
bool client_has_terminated;
int terminate_timeout_fd;
int exit_status;
int next_signal;
void (*cb)(void *data, int exit_code);
void *cb_data;

View file

@ -635,6 +635,12 @@ test_section_cursor(void)
(const char *[]){"block", "beam", "underline"},
(int []){CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE},
(int *)&conf.cursor.style);
test_enum(
&ctx, &parse_section_cursor, "unfocused-style",
3,
(const char *[]){"unchanged", "hollow", "none"},
(int []){CURSOR_UNFOCUSED_UNCHANGED, CURSOR_UNFOCUSED_HOLLOW, CURSOR_UNFOCUSED_NONE},
(int *)&conf.cursor.unfocused_style);
test_boolean(&ctx, &parse_section_cursor, "blink", &conf.cursor.blink);
test_pt_or_px(&ctx, &parse_section_cursor, "beam-thickness",
&conf.cursor.beam_thickness);

25
themes/dracula-iterm Normal file
View file

@ -0,0 +1,25 @@
# -*- conf -*-
# Dracula iTerm2 variant
[cursor]
color=ffffff bbbbbb
[colors]
foreground=f8f8f2
background=1e1f29
regular0=000000 # black
regular1=ff5555 # red
regular2=50fa7b # green
regular3=f1fa8c # yellow
regular4=bd93f9 # blue
regular5=ff79c6 # magenta
regular6=8be9fd # cyan
regular7=bbbbbb # white
bright0=555555 # bright black
bright1=ff5555 # bright red
bright2=50fa7b # bright green
bright3=f1fa8c # bright yellow
bright4=bd93f9 # bright blue
bright5=ff79c6 # bright magenta
bright6=8be9fd # bright cyan
bright7=ffffff # bright white

31
themes/noirblaze Normal file
View file

@ -0,0 +1,31 @@
# -*- conf -*-
# noirblaze-kitty
# https://github.com/n1ghtmare/noirblaze-kitty
[cursor]
color=121212 ff0088
[colors]
foreground=d5d5d5
background=121212
# selection-foreground=121212
# selection-background=b0b0b0
regular0=121212 # black
regular1=ff0088 # red
regular2=00ff77 # green
regular3=ffffff # yellow
regular4=b0b0b0 # blue
regular5=7a7a7a # magenta
regular6=787878 # cyan
regular7=d5d5d5 # white
bright0=737373 # bright black
bright1=FD319E # bright red
bright2=FD319E # bright green
bright3=FDFDFD # bright yellow
bright4=BEBEBE # bright blue
bright5=939393 # bright magenta
bright6=919191 # bright cyan
bright7=f5f5f5 # bright white

22
themes/xterm Normal file
View file

@ -0,0 +1,22 @@
# -*- conf -*-
# The default palette of xterm.
[colors]
foreground=e5e5e5
background=000000
regular0=000000 # black
regular1=cd0000 # red
regular2=00cd00 # green
regular3=cdcd00 # yellow
regular4=0000ee # blue
regular5=cd00cd # magenta
regular6=00cdcd # cyan
regular7=e5e5e5 # white
bright0=7f7f7f # bright black
bright1=ff0000 # bright red
bright2=00ff00 # bright green
bright3=ffff00 # bright yellow
bright4=5c5cff # bright blue
bright5=ff00ff # bright magenta
bright6=00ffff # bright cyan
bright7=ffffff # bright white

View file

@ -1738,10 +1738,6 @@ wayl_win_init(struct terminal *term, const char *token)
win->fractional_scale, &fractional_scale_listener, win);
}
if (wayl->has_wl_compositor_v6) {
win->preferred_buffer_scale = 1;
}
win->xdg_surface = xdg_wm_base_get_xdg_surface(wayl->shell, win->surface.surf);
xdg_surface_add_listener(win->xdg_surface, &xdg_surface_listener, win);