Compare commits

..

No commits in common. "master" and "1.22.3" have entirely different histories.

147 changed files with 913 additions and 3043 deletions

View file

@ -29,7 +29,7 @@ body:
- type: input - type: input
id: compositor id: compositor
attributes: attributes:
label: Compositor Name and Version label: Compositor Version
description: "The name and version of your compositor" description: "The name and version of your compositor"
placeholder: "sway version 1.9" placeholder: "sway version 1.9"
validations: validations:

View file

@ -1,7 +1,7 @@
# -*- yaml -*- # -*- yaml -*-
steps: steps:
- name: pychecks - name: codespell
when: when:
- event: [manual, pull_request] - event: [manual, pull_request]
- event: [push, tag] - event: [push, tag]
@ -11,15 +11,10 @@ steps:
- apk add openssl - apk add openssl
- apk add python3 - apk add python3
- apk add py3-pip - apk add py3-pip
- python3 -m venv venv - python3 -m venv codespell-venv
- source venv/bin/activate - source codespell-venv/bin/activate
- python -m pip install --upgrade pip
- pip install codespell - pip install codespell
- pip install mypy - codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd
- pip install ruff
- codespell
- mypy
- ruff check
- deactivate - deactivate
- name: subprojects - name: subprojects

View file

@ -1,10 +1,5 @@
# Changelog # Changelog
* [Unreleased](#unreleased)
* [1.25.0](#1-25-0)
* [1.24.0](#1-24-0)
* [1.23.1](#1-23-1)
* [1.23.0](#1-23-0)
* [1.22.3](#1-22-3) * [1.22.3](#1-22-3)
* [1.22.2](#1-22-2) * [1.22.2](#1-22-2)
* [1.22.1](#1-22-1) * [1.22.1](#1-22-1)
@ -67,273 +62,6 @@
* [1.2.0](#1-2-0) * [1.2.0](#1-2-0)
## Unreleased
### Added
* `toplevel-tag` option (and `--toplevel-tag` command line options to
`foot` and `footclient`), allowing you to set a custom toplevel
tag. The compositor must implement the new `xdg-toplevel-tag-v1`
Wayland protocol ([#2212][2212]).
* `[colors-dark]` section to `foot.ini`. Replaces `[colors]`.
* `[colors-light]` section to `foot.ini`. Replaces `[colors2]`.
* `XTGETTCAP`: added `query-os-name`, returning the OS foot is
compiled for (e.g. _'Linux'_) ([#2209][2209]).
[2212]: https://codeberg.org/dnkl/foot/issues/2212
[2209]: https://codeberg.org/dnkl/foot/issues/2209
### Changed
* When enabling _"focus mode"_ (private mode 1004), foot now sends a
focus event immediately, to inform the application what the current
state is ([#2202][2202]).
* Scrollback search is now case sensitive when the search string
contains at least one upper case character.
* Mouse tracking in SGR pixel mode no longer emits negative column/row
pixel values ([#2226][2226]).
* Foot now always uses ARGB SHM surfaces. In earlier versions, XRGB
surfaces were used for opaque surfaces. Unfortunately, several
compositors had issues when foot switched between ARGB and XRGB
surfaces (for example when switching color theme, or toggling
fullscreen).
[2202]: https://codeberg.org/dnkl/foot/issues/2202
[2226]: https://codeberg.org/dnkl/foot/issues/2226
### Deprecated
* `[colors]` section in `foot.ini`. Use `[colors-dark]` instead.
* `[colors2]` section in `foot.ini`. Use `[colors-light]` instead.
### Removed
* `cursor.color` config option (deprecated in 1.23.0). Use
`colors-{dark,light}.cursor` instead.
### Fixed
* Search mode: composing keys not ignored.
* Crash when triple-clicking a soft-wrapped line and there is a quote
character in the last column.
* Crash when reverse-scrolling (terminfo capability `rin`) such that
the current viewport ends up outside the scrollback ([#2232][2232]).
* Regression: visual glitches in rare circumstances.
* Key release events for shortcuts being sent to the client
application (kitty keyboard protocol only) ([#2257][2257]).
* Crash when application emits sixel RA with a height of 0, a width >
0, and then starts writing sixel data ([#2267][2267]).
* Crash if shutting down terminal instance while a "pre-apply damage"
thread is running ([#2263][2263]).
[2232]: https://codeberg.org/dnkl/foot/issues/2232
[2257]: https://codeberg.org/dnkl/foot/issues/2257
[2267]: https://codeberg.org/dnkl/foot/issues/2267
[2263]: https://codeberg.org/dnkl/foot/issues/2263
### Security
### Contributors
## 1.25.0
### Added
* Performance increased and input latency decreased on compositors
that do not release SHM buffers immediately ([#2188][2188]).
* `colors{,2}.dim-blend-towards=black|white` option, allowing you to
select towards which color to blend when dimming text. Defaults to
`black` in `[colors]`, and `white` in `[colors2]` ([#2187][2187]).
[2188]: https://codeberg.org/dnkl/foot/issues/2188
[2187]: https://codeberg.org/dnkl/foot/issues/2187
### Changed
* SHM buffer sizes are now rounded up to nearest page size, and their
stride is always an even multiple of 256 bytes (by default,
configurable by setting `tweak.min-stride-alignment`). This allows
compositor to directly import foot's SHM buffers to the GPU, with
e.g. integrated graphics ([#2182][2182]).
* Jump label colors in the modus-operandi theme, for improved
readability.
[2182]: https://codeberg.org/dnkl/foot/issues/2182
### Fixed
* URL labels misplaces when URL contains double-width characters
([#2179][2179]).
* One space too much consumed when copying (or pipe:ing) contents with
tabs ([#2194][2194])
* Ensure we render a new frame when changing fullscreen state. Before,
this was automatically done if the window was also resized. But, it
is possible for a compositor to change an application's fullscreen
state without resizing the window.
[2179]: https://codeberg.org/dnkl/foot/issues/2179
[2194]: https://codeberg.org/dnkl/foot/issues/2194
### Contributors
* Charalampos Mitrodimas
* Matthias Heyman
## 1.24.0
### Added
* The `uppercase-regex-insert` option controls whether an uppercase hint
character will insert the selected text into the prompt in `regex-copy`
or `show-urls-copy` mode. It defaults to `true`. ([#2159][2159]).
[2159]: https://codeberg.org/dnkl/foot/issues/2159
### Changed
* The label letters are no longer sorted before being assigned to URLs
([#2140][2140]).
* Sending SIGUSR1/SIGUSR2 to a `foot --server` process now causes
newly spawned client instances to use the selected theme, instead of
the original one.
* SIGUSR1/SIGUSR2 can now be sent to `footclient` processes, to change
the theme of that particular instance ([#2156][2156]).
[2156]: https://codeberg.org/dnkl/foot/issues/2156
### Fixed
* Invalid configuration values overriding valid ones in surprising
ways.
* Bug where the libutempter utmp backend did not record logouts
correctly.
### Contributors
* Ryan Roden-Corrent
* Tobias Mock
## 1.23.1
### Changed
* URL labels are now assigned in reverse order, from bottom to
top. This ensures the **last** URL (which is often the one you are
interested in) is always assigned the same key ([#2140][2140]).
* Sending `SIGUSR1` no longer **toggles** between `[colors]` and
`[colors2]`, but explicitly changes to `[colors]`. `SIGUSR2` changes
to `[colors2]` ([#2144][2144]).
[2140]: https://codeberg.org/dnkl/foot/issues/2140
[2144]: https://codeberg.org/dnkl/foot/issues/2144
### Fixed
* 10-bit surfaces sometimes used instead of 16-bit.
* OSC-104/110/111/112/117/119 (reset colors) not taking the currently
active theme into account.
## 1.23.0
### Added
* `colors2` config section. This section duplicates the `colors`
section, and lets you define an alternative color theme.
* `key-bindings.color-theme-switch-1`,
`key-bindings.color-theme-switch-2` and
`key-bindings.color-theme-toggle` key bindings. These can be used to
switch between the primary and alternative color themes. They are
not bound by default.
* Sending `SIGUSR1` to the foot process now triggers a theme switch
(in server mode, **all** instances toggles their themes).
* Support for private mode 2031 - [_Dark and Light Mode
Detection_](https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
([#2025][2025])
* Added `initial-color-theme=1|2` config option. `1` uses colors from
the `[colors]` section, `2` uses `[colors2]`.
* Combined dark/light theme files for (dark variant is the default,
set `initial-color-theme=2` to use the light variant by default):
- gruvbox
- nvim
- paper-color
- selenized
- solarized
* `regex-copy`/`show-urls-copy` will copy and paste the selected text if the hint
is completed with an uppercase character ([#1975][1975]).
* `16-bit` to `tweak.surface-bit-depth`. Makes foot use 16-bit image
buffers. They provide the necessary color precision required by
`gamma-correct-blending=yes`.
* New cursor shapes, from `cursor-shape-v1` version 2.
* `center-when-fullscreen` and `center-when-maximized-and-fullscreen`
to the `pad` option. This allows you to configure when the grid is
centered in more detail ([#2111][2111]).
[2025]: https://codeberg.org/dnkl/foot/issues/2025
[1975]: https://codeberg.org/dnkl/foot/issues/1975
[2111]: https://codeberg.org/dnkl/foot/issues/2111
### Changed
* `cursor.color` moved to `colors.cursor`.
* OSC-11 without an alpha value will now restore the configured
(i.e. from `foot.ini`) alpha, rather than keeping whatever the
current alpha value is, unchanged.
* `gamma-correct-blending=yes` now defaults to `16-bit` image buffers,
instead of `10-bit`.
* Allow setting either selection background, or selection foreground,
only ([#1846][1846]).
* Drop required version of libxkbcommon from 1.8.0 back to 1.0.0
([#2103][2103]).
* OSC-52: an empty payload now clears the clipboard.
* DA (Device Attributes): include `52` in the reply, to indicate
OSC-52 support (when at least _copy_ has been enabled in
`security.osc52`).
[1846]: https://codeberg.org/dnkl/foot/issues/1846
[2103]: https://codeberg.org/dnkl/foot/issues/2103
### Deprecated
* `cursor.color` config option; use `colors.cursor` instead.
### Removed
* Subsurface unmap quirk for Sway. This was a workaround added in
1.12.1, for Sway issue [#6960][sway-6960].
### Fixed
* `REP`: wrong width of repeated multi-codepoint graphemes.
* Incorrect surface commit after a configure event, under certain
conditions ([#2105][2105]).
[2105]: https://codeberg.org/dnkl/foot/issues/2105
### Contributors
* Chen Mulong
* Kirill Primak
* Ryan Roden-Corrent
* tokyo4j
## 1.22.3 ## 1.22.3
### Added ### Added

View file

@ -53,7 +53,7 @@ decisions when appropriate.
Participants in the foot community are expected to uphold the described Participants in the foot community are expected to uphold the described
standards not only in official community spaces (issue trackers, IRC channels, standards not only in official community spaces (issue trackers, IRC channels,
etc.) but in all public spaces. The Code of Conduct however does acknowledge etc.) but in all public spaces. The Code of Conduct however does acknowledge
that people are fallible and that it is possible to truly correct a past 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 pattern of unacceptable behavior. That is to say, the scope of the Code of
Conduct does not necessarily extend into the distant past. Conduct does not necessarily extend into the distant past.

View file

@ -641,10 +641,6 @@ All replies are in `tigetstr()` format. That is, given the same
capability name, foot's reply is identical to what `tigetstr()` would capability name, foot's reply is identical to what `tigetstr()` would
have returned. have returned.
In addition to queries for terminfo entries, the `query-os-name` query
will be answered with a response of the form `uname=$(uname -s)`,
where `$(uname -s)` is the name of the OS foot was compiled for.
# Credits # Credits
@ -693,11 +689,8 @@ Every now and then I post foot related updates on
# Sponsoring/donations # Sponsoring/donations
* Liberapay: https://liberapay.com/dnkl
* GitHub Sponsors: https://github.com/sponsors/dnkl * GitHub Sponsors: https://github.com/sponsors/dnkl
[![Donate using Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/dnkl/donate)
# License # License

View file

@ -2,6 +2,7 @@
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include <fenv.h>
#include <errno.h> #include <errno.h>
#define LOG_MODULE "box-drawing" #define LOG_MODULE "box-drawing"

View file

@ -53,14 +53,6 @@ UNITTEST
xassert(c32cmp(U"b", U"a") > 0); xassert(c32cmp(U"b", U"a") > 0);
} }
UNITTEST
{
xassert(c32ncmp(U"foo", U"foot", 3) == 0);
xassert(c32ncmp(U"foot", U"FOOT", 4) > 0);
xassert(c32ncmp(U"a", U"b", 1) < 0);
xassert(c32ncmp(U"bb", U"aa", 2) > 0);
}
UNITTEST UNITTEST
{ {
char32_t copy[16]; char32_t copy[16];
@ -135,20 +127,6 @@ UNITTEST
xassert(c32cmp(dst, U"foobar12345678") == 0); xassert(c32cmp(dst, U"foobar12345678") == 0);
} }
UNITTEST
{
xassert(!isc32upper(U'a'));
xassert(isc32upper(U'A'));
xassert(!isc32upper(U'a'));
}
UNITTEST
{
xassert(hasc32upper(U"abc1A"));
xassert(!hasc32upper(U"abc1_aaa"));
xassert(!hasc32upper(U""));
}
UNITTEST UNITTEST
{ {
char32_t *c = xc32dup(U"foobar"); char32_t *c = xc32dup(U"foobar");

View file

@ -20,10 +20,6 @@ static inline int c32cmp(const char32_t *s1, const char32_t *s2) {
return wcscmp((const wchar_t *)s1, (const wchar_t *)s2); return wcscmp((const wchar_t *)s1, (const wchar_t *)s2);
} }
static inline int c32ncmp(const char32_t *s1, const char32_t *s2, size_t n) {
return wcsncmp((const wchar_t *)s1, (const wchar_t *)s2, n);
}
static inline char32_t *c32ncpy(char32_t *dst, const char32_t *src, size_t n) { static inline char32_t *c32ncpy(char32_t *dst, const char32_t *src, size_t n) {
return (char32_t *)wcsncpy((wchar_t *)dst, (const wchar_t *)src, n); return (char32_t *)wcsncpy((wchar_t *)dst, (const wchar_t *)src, n);
} }
@ -64,10 +60,6 @@ static inline char32_t toc32upper(char32_t c) {
return (char32_t)towupper((wint_t)c); return (char32_t)towupper((wint_t)c);
} }
static inline bool isc32upper(char32_t c32) {
return iswupper((wint_t)c32);
}
static inline bool isc32space(char32_t c32) { static inline bool isc32space(char32_t c32) {
return iswspace((wint_t)c32); return iswspace((wint_t)c32);
} }
@ -80,13 +72,6 @@ static inline bool isc32graph(char32_t c32) {
return iswgraph((wint_t)c32); return iswgraph((wint_t)c32);
} }
static inline bool hasc32upper(const char32_t *s) {
for (int i = 0; s[i] != '\0'; i++) {
if (isc32upper(s[i])) return true;
}
return false;
}
static inline int c32width(char32_t c) { static inline int c32width(char32_t c) {
#if defined(FOOT_GRAPHEME_CLUSTERING) #if defined(FOOT_GRAPHEME_CLUSTERING)
return utf8proc_charwidth((utf8proc_int32_t)c); return utf8proc_charwidth((utf8proc_int32_t)c);

View file

@ -29,17 +29,3 @@ struct client_data {
} __attribute__((packed)); } __attribute__((packed));
_Static_assert(sizeof(struct client_data) == 10, "protocol struct size error"); _Static_assert(sizeof(struct client_data) == 10, "protocol struct size error");
enum client_ipc_code {
FOOT_IPC_SIGUSR,
};
struct client_ipc_hdr {
enum client_ipc_code ipc_code;
uint8_t size;
} __attribute__((packed));
struct client_ipc_sigusr {
int signo;
} __attribute__((packed));

View file

@ -1,13 +1,12 @@
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
@ -34,20 +33,13 @@ struct string {
typedef tll(struct string) string_list_t; typedef tll(struct string) string_list_t;
static volatile sig_atomic_t aborted = 0; static volatile sig_atomic_t aborted = 0;
static volatile sig_atomic_t sigusr = 0;
static void static void
sigint_handler(int signo) sig_handler(int signo)
{ {
aborted = 1; aborted = 1;
} }
static void
sigusr_handler(int signo)
{
sigusr = signo;
}
static ssize_t static ssize_t
sendall(int sock, const void *_buf, size_t len) sendall(int sock, const void *_buf, size_t len)
{ {
@ -77,7 +69,6 @@ print_usage(const char *prog_name)
" -t,--term=TERM value to set the environment variable TERM to (" FOOT_DEFAULT_TERM ")\n" " -t,--term=TERM value to set the environment variable TERM to (" FOOT_DEFAULT_TERM ")\n"
" -T,--title=TITLE initial window title (foot)\n" " -T,--title=TITLE initial window title (foot)\n"
" -a,--app-id=ID window application ID (foot)\n" " -a,--app-id=ID window application ID (foot)\n"
" --toplevel-tag=TAG set a custom toplevel tag\n"
" -w,--window-size-pixels=WIDTHxHEIGHT initial width and height, in pixels\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" " -W,--window-size-chars=WIDTHxHEIGHT initial width and height, in characters\n"
" -m,--maximized start in maximized mode\n" " -m,--maximized start in maximized mode\n"
@ -139,10 +130,6 @@ send_string_list(int fd, const string_list_t *string_list)
return true; return true;
} }
enum {
TOPLEVEL_TAG_OPTION = CHAR_MAX + 1,
};
int int
main(int argc, char *const *argv) main(int argc, char *const *argv)
{ {
@ -157,7 +144,6 @@ main(int argc, char *const *argv)
{"term", required_argument, NULL, 't'}, {"term", required_argument, NULL, 't'},
{"title", required_argument, NULL, 'T'}, {"title", required_argument, NULL, 'T'},
{"app-id", required_argument, NULL, 'a'}, {"app-id", required_argument, NULL, 'a'},
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
{"window-size-pixels", required_argument, NULL, 'w'}, {"window-size-pixels", required_argument, NULL, 'w'},
{"window-size-chars", required_argument, NULL, 'W'}, {"window-size-chars", required_argument, NULL, 'W'},
{"maximized", no_argument, NULL, 'm'}, {"maximized", no_argument, NULL, 'm'},
@ -227,12 +213,6 @@ main(int argc, char *const *argv)
goto err; goto err;
break; break;
case TOPLEVEL_TAG_OPTION:
snprintf(buf, sizeof(buf), "toplevel-tag=%s", optarg);
if (!push_string(&overrides, buf, &total_len))
goto err;
break;
case 'L': case 'L':
if (!push_string(&overrides, "login-shell=yes", &total_len)) if (!push_string(&overrides, "login-shell=yes", &total_len))
goto err; goto err;
@ -527,63 +507,15 @@ main(int argc, char *const *argv)
if (!send_string_list(fd, &envp)) if (!send_string_list(fd, &envp))
goto err; goto err;
struct sigaction sa_int = {.sa_handler = &sigint_handler}; struct sigaction sa = {.sa_handler = &sig_handler};
struct sigaction sa_usr = {.sa_handler = &sigusr_handler}; sigemptyset(&sa.sa_mask);
sigemptyset(&sa_int.sa_mask); if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0) {
sigemptyset(&sa_usr.sa_mask);
if (sigaction(SIGINT, &sa_int, NULL) < 0 ||
sigaction(SIGTERM, &sa_int, NULL) < 0 ||
sigaction(SIGUSR1, &sa_usr, NULL) < 0 ||
sigaction(SIGUSR2, &sa_usr, NULL) < 0)
{
LOG_ERRNO("failed to register signal handlers"); LOG_ERRNO("failed to register signal handlers");
goto err; goto err;
} }
int exit_code; int exit_code;
ssize_t rcvd = -1; ssize_t rcvd = recv(fd, &exit_code, sizeof(exit_code), 0);
while (true) {
rcvd = recv(fd, &exit_code, sizeof(exit_code), 0);
const int got_sigusr = sigusr;
sigusr = 0;
if (rcvd < 0 && errno == EINTR) {
if (aborted)
break;
else if (got_sigusr != 0) {
LOG_DBG("sending sigusr %d to server", got_sigusr);
struct {
struct client_ipc_hdr hdr;
struct client_ipc_sigusr sigusr;
} ipc = {
.hdr = {
.ipc_code = FOOT_IPC_SIGUSR,
.size = sizeof(struct client_ipc_sigusr),
},
.sigusr = {
.signo = got_sigusr,
},
};
ssize_t count = send(fd, &ipc, sizeof(ipc), 0);
if (count < 0) {
LOG_ERRNO("failed to send SIGUSR IPC to server");
goto err;
} else if ((size_t)count != sizeof(ipc)) {
LOG_ERR("failed to send SIGUSR IPC to server");
goto err;
}
}
continue;
}
break;
}
if (rcvd == -1 && errno == EINTR) if (rcvd == -1 && errno == EINTR)
xassert(aborted); xassert(aborted);

View file

@ -6,7 +6,6 @@ _foot()
local cur prev flags word commands match previous_words i offset local cur prev flags word commands match previous_words i offset
flags=( flags=(
"--app-id" "--app-id"
"--toplevel-tag"
"--check-config" "--check-config"
"--config" "--config"
"--font" "--font"
@ -41,7 +40,7 @@ _foot()
for word in "${previous_words[@]}" ; do for word in "${previous_words[@]}" ; do
match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null) match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null)
if [[ ! -z "$match" ]] ; then if [[ ! -z "$match" ]] ; then
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--toplevel-tag|--config|--font|--log-level|--pty|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--config|--font|--log-level|--pty|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then
(( i++ )) (( i++ ))
continue continue
fi fi
@ -76,7 +75,7 @@ _foot()
COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;; COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;;
--log-colorize|-l) --log-colorize|-l)
COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;; COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;;
--app-id|--toplevel-tag|--help|--override|--pty|--title|--version|--window-size-chars|--window-size-pixels|--check-config|-[ahoTvWwC]) --app-id|--help|--override|--pty|--title|--version|--window-size-chars|--window-size-pixels|--check-config|-[ahoTvWwC])
# Don't autocomplete for these flags # Don't autocomplete for these flags
: ;; : ;;
*) *)

View file

@ -6,7 +6,6 @@ _footclient()
local cur prev flags word commands match previous_words i offset local cur prev flags word commands match previous_words i offset
flags=( flags=(
"--app-id" "--app-id"
"--toplevel-tag"
"--fullscreen" "--fullscreen"
"--help" "--help"
"--hold" "--hold"
@ -36,7 +35,7 @@ _footclient()
for word in "${previous_words[@]}" ; do for word in "${previous_words[@]}" ; do
match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null) match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null)
if [[ ! -z "$match" ]] ; then if [[ ! -z "$match" ]] ; then
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--toplevel-tag|--log-level|--server-socket|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--log-level|--server-socket|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; then
(( i++ )) (( i++ ))
continue continue
fi fi
@ -68,7 +67,7 @@ _footclient()
COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;; COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;;
--log-colorize|-l) --log-colorize|-l)
COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;; COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;;
--app-id|--toplevel-tag|--help|--override|--title|--version|--window-size-chars|--window-size-pixels|-[ahoTvWw]) --app-id|--help|--override|--title|--version|--window-size-chars|--window-size-pixels|-[ahoTvWw])
# Don't autocomplete for these flags # Don't autocomplete for these flags
: ;; : ;;
*) *)

View file

@ -6,7 +6,6 @@ complete -c foot -x -s f -l font -a "(fc-list : family | sed 's/,/
complete -c foot -x -s t -l term -a '(find /usr/share/terminfo -type f -printf "%f\n")' -d "value to set the environment variable TERM to (foot)" complete -c foot -x -s t -l term -a '(find /usr/share/terminfo -type f -printf "%f\n")' -d "value to set the environment variable TERM to (foot)"
complete -c foot -x -s T -l title -d "initial window title" complete -c foot -x -s T -l title -d "initial window title"
complete -c foot -x -s a -l app-id -d "value to set the app-id property on the Wayland window to (foot)" complete -c foot -x -s a -l app-id -d "value to set the app-id property on the Wayland window to (foot)"
complete -c foot -x -l toplevel-tag -d "value to set the toplevel-tag property on the Wayland window to"
complete -c foot -s m -l maximized -d "start in maximized mode" complete -c foot -s m -l maximized -d "start in maximized mode"
complete -c foot -s F -l fullscreen -d "start in fullscreen mode" complete -c foot -s F -l fullscreen -d "start in fullscreen mode"
complete -c foot -s L -l login-shell -d "start shell as a login shell" complete -c foot -s L -l login-shell -d "start shell as a login shell"

View file

@ -2,7 +2,6 @@ complete -c footclient -x -a "(__fish_complete_subcom
complete -c footclient -x -s t -l term -a '(find /usr/share/terminfo -type f -printf "%f\n")' -d "value to set the environment variable TERM to (foot)" complete -c footclient -x -s t -l term -a '(find /usr/share/terminfo -type f -printf "%f\n")' -d "value to set the environment variable TERM to (foot)"
complete -c footclient -x -s T -l title -d "initial window title" complete -c footclient -x -s T -l title -d "initial window title"
complete -c footclient -x -s a -l app-id -d "value to set the app-id property on the Wayland window to (foot)" complete -c footclient -x -s a -l app-id -d "value to set the app-id property on the Wayland window to (foot)"
complete -c footclient -x -l toplevel-tag -d "value to set the toplevel-tag property on the Wayland window to"
complete -c footclient -s m -l maximized -d "start in maximized mode" complete -c footclient -s m -l maximized -d "start in maximized mode"
complete -c footclient -s F -l fullscreen -d "start in fullscreen mode" complete -c footclient -s F -l fullscreen -d "start in fullscreen mode"
complete -c footclient -s L -l login-shell -d "start shell as a login shell" complete -c footclient -s L -l login-shell -d "start shell as a login shell"

View file

@ -9,7 +9,6 @@ _arguments \
'(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ '(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \
'(-T --title)'{-T,--title}'[initial window title]:()' \ '(-T --title)'{-T,--title}'[initial window title]:()' \
'(-a --app-id)'{-a,--app-id}'[value to set the app-id property on the Wayland window to (foot)]:()' \ '(-a --app-id)'{-a,--app-id}'[value to set the app-id property on the Wayland window to (foot)]:()' \
'--toplevel-tag=[value to set the toplevel-tag property on the Wayland window to]:()' \
'(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \ '(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \
'(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \ '(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \
'(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \ '(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \

View file

@ -5,7 +5,6 @@ _arguments \
'(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ '(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \
'(-T --title)'{-T,--title}'[initial window title]:()' \ '(-T --title)'{-T,--title}'[initial window title]:()' \
'(-a --app-id)'{-a,--app-id}'[value to set the app-id property on the Wayland window to (foot)]:()' \ '(-a --app-id)'{-a,--app-id}'[value to set the app-id property on the Wayland window to (foot)]:()' \
'--toplevel-tag=[value to set the toplevel-tag property on the Wayland window to]:()' \
'(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \ '(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \
'(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \ '(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \
'(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \ '(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \

338
config.c
View file

@ -142,11 +142,6 @@ static const char *const binding_action_map[] = {
[BIND_ACTION_QUIT] = "quit", [BIND_ACTION_QUIT] = "quit",
[BIND_ACTION_REGEX_LAUNCH] = "regex-launch", [BIND_ACTION_REGEX_LAUNCH] = "regex-launch",
[BIND_ACTION_REGEX_COPY] = "regex-copy", [BIND_ACTION_REGEX_COPY] = "regex-copy",
[BIND_ACTION_THEME_SWITCH_1] = "color-theme-switch-1",
[BIND_ACTION_THEME_SWITCH_2] = "color-theme-switch-2",
[BIND_ACTION_THEME_SWITCH_DARK] = "color-theme-switch-dark",
[BIND_ACTION_THEME_SWITCH_LIGHT] = "color-theme-switch-light",
[BIND_ACTION_THEME_TOGGLE] = "color-theme-toggle",
/* Mouse-specific actions */ /* Mouse-specific actions */
[BIND_ACTION_SCROLLBACK_UP_MOUSE] = "scrollback-up-mouse", [BIND_ACTION_SCROLLBACK_UP_MOUSE] = "scrollback-up-mouse",
@ -476,12 +471,8 @@ str_to_ulong(const char *s, int base, unsigned long *res)
errno = 0; errno = 0;
char *end = NULL; char *end = NULL;
unsigned long v = strtoul(s, &end, base); *res = strtoul(s, &end, base);
if (!(errno == 0 && *end == '\0')) return errno == 0 && *end == '\0';
return false;
*res = v;
return true;
} }
static bool NOINLINE static bool NOINLINE
@ -550,13 +541,12 @@ value_to_float(struct context *ctx, float *res)
errno = 0; errno = 0;
char *end = NULL; char *end = NULL;
float v = strtof(s, &end); *res = strtof(s, &end);
if (!(errno == 0 && *end == '\0')) { if (!(errno == 0 && *end == '\0')) {
LOG_CONTEXTUAL_ERR("invalid decimal value"); LOG_CONTEXTUAL_ERR("invalid decimal value");
return false; return false;
} }
*res = v;
return true; return true;
} }
@ -648,6 +638,7 @@ value_to_enum(struct context *ctx, const char **value_map, int *res)
valid_values[idx - 2] = '\0'; valid_values[idx - 2] = '\0';
LOG_CONTEXTUAL_ERR("not one of %s", valid_values); LOG_CONTEXTUAL_ERR("not one of %s", valid_values);
*res = -1;
return false; return false;
} }
@ -696,18 +687,14 @@ value_to_two_colors(struct context *ctx,
goto out; goto out;
} }
uint32_t a, b;
ctx->value = first_as_str; ctx->value = first_as_str;
if (!value_to_color(ctx, &a, allow_alpha)) if (!value_to_color(ctx, first, allow_alpha))
goto out; goto out;
ctx->value = second_as_str; ctx->value = second_as_str;
if (!value_to_color(ctx, &b, allow_alpha)) if (!value_to_color(ctx, second, allow_alpha))
goto out; goto out;
*first = a;
*second = b;
ret = true; ret = true;
out: out:
@ -925,9 +912,6 @@ parse_section_main(struct context *ctx)
else if (streq(key, "app-id")) else if (streq(key, "app-id"))
return value_to_str(ctx, &conf->app_id); return value_to_str(ctx, &conf->app_id);
else if (streq(key, "toplevel-tag"))
return value_to_str(ctx, &conf->toplevel_tag);
else if (streq(key, "initial-window-size-pixels")) { else if (streq(key, "initial-window-size-pixels")) {
if (!value_to_dimensions(ctx, &conf->size.width, &conf->size.height)) if (!value_to_dimensions(ctx, &conf->size.width, &conf->size.height))
return false; return false;
@ -946,34 +930,21 @@ parse_section_main(struct context *ctx)
else if (streq(key, "pad")) { else if (streq(key, "pad")) {
unsigned x, y; unsigned x, y;
char mode[64] = {0}; char mode[16] = {0};
int ret = sscanf(value, "%ux%u %63s", &x, &y, mode);
enum center_when center = CENTER_NEVER; int ret = sscanf(value, "%ux%u %15s", &x, &y, mode);
bool center = strcasecmp(mode, "center") == 0;
bool invalid_mode = !center && mode[0] != '\0';
if (ret == 3) { if ((ret != 2 && ret != 3) || invalid_mode) {
if (strcasecmp(mode, "center") == 0)
center = CENTER_ALWAYS;
else if (strcasecmp(mode, "center-when-fullscreen") == 0)
center = CENTER_FULLSCREEN;
else if (strcasecmp(mode, "center-when-maximized-and-fullscreen") == 0)
center = CENTER_MAXIMIZED_AND_FULLSCREEN;
else
center = CENTER_INVALID;
}
if ((ret != 2 && ret != 3) || center == CENTER_INVALID) {
LOG_CONTEXTUAL_ERR( LOG_CONTEXTUAL_ERR(
"invalid padding (must be in the form PAD_XxPAD_Y " "invalid padding (must be in the form PAD_XxPAD_Y [center])");
"[center|"
"center-when-fullscreen|"
"center-when-maximized-and-fullscreen])");
return false; return false;
} }
conf->pad_x = x; conf->pad_x = x;
conf->pad_y = y; conf->pad_y = y;
conf->center_when = ret == 2 ? CENTER_NEVER : center; conf->center = center;
return true; return true;
} }
@ -1115,50 +1086,6 @@ parse_section_main(struct context *ctx)
else if (streq(key, "gamma-correct-blending")) else if (streq(key, "gamma-correct-blending"))
return value_to_bool(ctx, &conf->gamma_correct); return value_to_bool(ctx, &conf->gamma_correct);
else if (streq(key, "initial-color-theme")) {
_Static_assert(
sizeof(conf->initial_color_theme) == sizeof(int),
"enum is not 32-bit");
if (!value_to_enum(ctx, (const char*[]){
"dark", "light", "1", "2", NULL},
(int *)&conf->initial_color_theme))
return false;
if (streq(ctx->value, "1")) {
LOG_WARN("%s:%d: [main].initial-color-theme=1 deprecated, "
"use [main].initial-color-theme=dark instead",
ctx->path, ctx->lineno);
user_notification_add(
&ctx->conf->notifications,
USER_NOTIFICATION_DEPRECATED,
xstrdup("[main].initial-color-theme=1: "
"use [main].initial-color-theme=dark instead"));
conf->initial_color_theme = COLOR_THEME_DARK;
}
else if (streq(ctx->value, "2")) {
LOG_WARN("%s:%d: [main].initial-color-theme=2 deprecated, "
"use [main].initial-color-theme=light instead",
ctx->path, ctx->lineno);
user_notification_add(
&ctx->conf->notifications,
USER_NOTIFICATION_DEPRECATED,
xstrdup("[main].initial-color-theme=2: "
"use [main].initial-color-theme=light instead"));
conf->initial_color_theme = COLOR_THEME_LIGHT;
}
return true;
}
else if (streq(key, "uppercase-regex-insert"))
return value_to_bool(ctx, &conf->uppercase_regex_insert);
else { else {
LOG_CONTEXTUAL_ERR("not a valid option: %s", key); LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
return false; return false;
@ -1402,9 +1329,10 @@ parse_section_regex(struct context *ctx)
} }
} }
static bool NOINLINE static bool
parse_color_theme(struct context *ctx, struct color_theme *theme) parse_section_colors(struct context *ctx)
{ {
struct config *conf = ctx->conf;
const char *key = ctx->key; const char *key = ctx->key;
size_t key_len = strlen(key); size_t key_len = strlen(key);
@ -1413,26 +1341,28 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
if (isdigit(key[0])) { if (isdigit(key[0])) {
unsigned long index; unsigned long index;
if (!str_to_ulong(key, 0, &index) || index >= ALEN(theme->table)) { if (!str_to_ulong(key, 0, &index) ||
index >= ALEN(conf->colors.table))
{
LOG_CONTEXTUAL_ERR( LOG_CONTEXTUAL_ERR(
"invalid color palette index: %s (not in range 0-%zu)", "invalid color palette index: %s (not in range 0-%zu)",
key, ALEN(theme->table)); key, ALEN(conf->colors.table));
return false; return false;
} }
color = &theme->table[index]; color = &conf->colors.table[index];
} }
else if (key_len == 8 && str_has_prefix(key, "regular") && last_digit < 8) else if (key_len == 8 && str_has_prefix(key, "regular") && last_digit < 8)
color = &theme->table[last_digit]; color = &conf->colors.table[last_digit];
else if (key_len == 7 && str_has_prefix(key, "bright") && last_digit < 8) else if (key_len == 7 && str_has_prefix(key, "bright") && last_digit < 8)
color = &theme->table[8 + last_digit]; color = &conf->colors.table[8 + last_digit];
else if (key_len == 4 && str_has_prefix(key, "dim") && last_digit < 8) { else if (key_len == 4 && str_has_prefix(key, "dim") && last_digit < 8) {
if (!value_to_color(ctx, &theme->dim[last_digit], false)) if (!value_to_color(ctx, &conf->colors.dim[last_digit], false))
return false; return false;
theme->use_custom.dim |= 1 << last_digit; conf->colors.use_custom.dim |= 1 << last_digit;
return true; return true;
} }
@ -1441,90 +1371,76 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
(key_len == 7 && key[5] == '1' && last_digit < 6))) (key_len == 7 && key[5] == '1' && last_digit < 6)))
{ {
size_t idx = key_len == 6 ? last_digit : 10 + last_digit; size_t idx = key_len == 6 ? last_digit : 10 + last_digit;
return value_to_color(ctx, &theme->sixel[idx], false); return value_to_color(ctx, &conf->colors.sixel[idx], false);
} }
else if (streq(key, "flash")) color = &theme->flash; else if (streq(key, "flash")) color = &conf->colors.flash;
else if (streq(key, "foreground")) color = &theme->fg; else if (streq(key, "foreground")) color = &conf->colors.fg;
else if (streq(key, "background")) color = &theme->bg; else if (streq(key, "background")) color = &conf->colors.bg;
else if (streq(key, "selection-foreground")) color = &theme->selection_fg; else if (streq(key, "selection-foreground")) color = &conf->colors.selection_fg;
else if (streq(key, "selection-background")) color = &theme->selection_bg; else if (streq(key, "selection-background")) color = &conf->colors.selection_bg;
else if (streq(key, "jump-labels")) { else if (streq(key, "jump-labels")) {
if (!value_to_two_colors( if (!value_to_two_colors(
ctx, ctx,
&theme->jump_label.fg, &conf->colors.jump_label.fg,
&theme->jump_label.bg, &conf->colors.jump_label.bg,
false)) false))
{ {
return false; return false;
} }
theme->use_custom.jump_label = true; conf->colors.use_custom.jump_label = true;
return true; return true;
} }
else if (streq(key, "scrollback-indicator")) { else if (streq(key, "scrollback-indicator")) {
if (!value_to_two_colors( if (!value_to_two_colors(
ctx, ctx,
&theme->scrollback_indicator.fg, &conf->colors.scrollback_indicator.fg,
&theme->scrollback_indicator.bg, &conf->colors.scrollback_indicator.bg,
false)) false))
{ {
return false; return false;
} }
theme->use_custom.scrollback_indicator = true; conf->colors.use_custom.scrollback_indicator = true;
return true; return true;
} }
else if (streq(key, "search-box-no-match")) { else if (streq(key, "search-box-no-match")) {
if (!value_to_two_colors( if (!value_to_two_colors(
ctx, ctx,
&theme->search_box.no_match.fg, &conf->colors.search_box.no_match.fg,
&theme->search_box.no_match.bg, &conf->colors.search_box.no_match.bg,
false)) false))
{ {
return false; return false;
} }
theme->use_custom.search_box_no_match = true; conf->colors.use_custom.search_box_no_match = true;
return true; return true;
} }
else if (streq(key, "search-box-match")) { else if (streq(key, "search-box-match")) {
if (!value_to_two_colors( if (!value_to_two_colors(
ctx, ctx,
&theme->search_box.match.fg, &conf->colors.search_box.match.fg,
&theme->search_box.match.bg, &conf->colors.search_box.match.bg,
false)) false))
{ {
return false; return false;
} }
theme->use_custom.search_box_match = true; conf->colors.use_custom.search_box_match = true;
return true;
}
else if (streq(key, "cursor")) {
if (!value_to_two_colors(
ctx,
&theme->cursor.text,
&theme->cursor.cursor,
false))
{
return false;
}
theme->use_custom.cursor = true;
return true; return true;
} }
else if (streq(key, "urls")) { else if (streq(key, "urls")) {
if (!value_to_color(ctx, &theme->url, false)) if (!value_to_color(ctx, &conf->colors.url, false))
return false; return false;
theme->use_custom.url = true; conf->colors.use_custom.url = true;
return true; return true;
} }
@ -1538,7 +1454,7 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
return false; return false;
} }
theme->alpha = alpha * 65535.; conf->colors.alpha = alpha * 65535.;
return true; return true;
} }
@ -1552,28 +1468,18 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
return false; return false;
} }
theme->flash_alpha = alpha * 65535.; conf->colors.flash_alpha = alpha * 65535.;
return true; return true;
} }
else if (streq(key, "alpha-mode")) { else if (strcmp(key, "alpha-mode") == 0) {
_Static_assert(sizeof(theme->alpha_mode) == sizeof(int), _Static_assert(sizeof(conf->colors.alpha_mode) == sizeof(int),
"enum is not 32-bit"); "enum is not 32-bit");
return value_to_enum( return value_to_enum(
ctx, ctx,
(const char *[]){"default", "matching", "all", NULL}, (const char *[]){"default", "matching", "all", NULL},
(int *)&theme->alpha_mode); (int *)&conf->colors.alpha_mode);
}
else if (streq(key, "dim-blend-towards")) {
_Static_assert(sizeof(theme->dim_blend_towards) == sizeof(int),
"enum is not 32-bit");
return value_to_enum(
ctx,
(const char *[]){"black", "white", NULL},
(int *)&theme->dim_blend_towards);
} }
else { else {
@ -1589,46 +1495,6 @@ parse_color_theme(struct context *ctx, struct color_theme *theme)
return true; return true;
} }
static bool
parse_section_colors_dark(struct context *ctx)
{
return parse_color_theme(ctx, &ctx->conf->colors_dark);
}
static bool
parse_section_colors_light(struct context *ctx)
{
return parse_color_theme(ctx, &ctx->conf->colors_light);
}
static bool
parse_section_colors(struct context *ctx)
{
LOG_WARN("%s:%d: [colors]: deprecated; use [colors-dark] instead",
ctx->path, ctx->lineno);
user_notification_add(
&ctx->conf->notifications,
USER_NOTIFICATION_DEPRECATED,
xstrdup("[colors]: use [colors-dark] instead"));
return parse_color_theme(ctx, &ctx->conf->colors_dark);
}
static bool
parse_section_colors2(struct context *ctx)
{
LOG_WARN("%s:%d: [colors2]: deprecated; use [colors-light] instead",
ctx->path, ctx->lineno);
user_notification_add(
&ctx->conf->notifications,
USER_NOTIFICATION_DEPRECATED,
xstrdup("[colors2]: use [colors-light] instead"));
return parse_color_theme(ctx, &ctx->conf->colors_light);
}
static bool static bool
parse_section_cursor(struct context *ctx) parse_section_cursor(struct context *ctx)
{ {
@ -1661,6 +1527,21 @@ parse_section_cursor(struct context *ctx)
else if (streq(key, "blink-rate")) else if (streq(key, "blink-rate"))
return value_to_uint32(ctx, 10, &conf->cursor.blink.rate_ms); return value_to_uint32(ctx, 10, &conf->cursor.blink.rate_ms);
else if (streq(key, "color")) {
if (!value_to_two_colors(
ctx,
&conf->cursor.color.text,
&conf->cursor.color.cursor,
false))
{
return false;
}
conf->cursor.color.text |= 1u << 31;
conf->cursor.color.cursor |= 1u << 31;
return true;
}
else if (streq(key, "beam-thickness")) else if (streq(key, "beam-thickness"))
return value_to_pt_or_px(ctx, &conf->cursor.beam_thickness); return value_to_pt_or_px(ctx, &conf->cursor.beam_thickness);
@ -2308,29 +2189,6 @@ parse_key_binding_section(struct context *ctx,
aux.regex_name = regex_name; aux.regex_name = regex_name;
} }
if (action_map == binding_action_map &&
action >= BIND_ACTION_THEME_SWITCH_1 &&
action <= BIND_ACTION_THEME_SWITCH_2)
{
const char *use_instead =
action_map[action == BIND_ACTION_THEME_SWITCH_1
? BIND_ACTION_THEME_SWITCH_DARK
: BIND_ACTION_THEME_SWITCH_LIGHT];
const char *notif = action == BIND_ACTION_THEME_SWITCH_1
? "[key-bindings].color-theme-switch-1: use [key-bindings].color-theme-switch-dark instead"
: "[key-bindings].color-theme-switch-2: use [key-bindings].color-theme-switch-light instead";
LOG_WARN("%s:%d: [key-bindings].%s: deprecated, use %s instead",
ctx->path, ctx->lineno,
action_map[action], use_instead);
user_notification_add(
&ctx->conf->notifications,
USER_NOTIFICATION_DEPRECATED,
xstrdup(notif));
}
if (!value_to_key_combos(ctx, action, &aux, bindings, KEY_BINDING)) { if (!value_to_key_combos(ctx, action, &aux, bindings, KEY_BINDING)) {
free_binding_aux(&aux); free_binding_aux(&aux);
return false; return false;
@ -2909,27 +2767,14 @@ parse_section_tweak(struct context *ctx)
else if (streq(key, "surface-bit-depth")) { else if (streq(key, "surface-bit-depth")) {
_Static_assert(sizeof(conf->tweak.surface_bit_depth) == sizeof(int), _Static_assert(sizeof(conf->tweak.surface_bit_depth) == sizeof(int),
"enum is not 32-bit"); "enum is not 32-bit");
#if defined(HAVE_PIXMAN_RGBA_16)
return value_to_enum(
ctx,
(const char *[]){"auto", "8-bit", "10-bit", "16-bit", NULL},
(int *)&conf->tweak.surface_bit_depth);
#else
return value_to_enum( return value_to_enum(
ctx, ctx,
(const char *[]){"auto", "8-bit", "10-bit", NULL}, (const char *[]){"auto", "8-bit", "10-bit", NULL},
(int *)&conf->tweak.surface_bit_depth); (int *)&conf->tweak.surface_bit_depth);
#endif
} }
else if (streq(key, "min-stride-alignment"))
return value_to_uint32(ctx, 10, &conf->tweak.min_stride_alignment);
else if (streq(key, "pre-apply-damage"))
return value_to_bool(ctx, &conf->tweak.preapply_damage);
else { else {
LOG_CONTEXTUAL_ERR("not a valid option: %s", key); LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
return false; return false;
@ -3021,8 +2866,7 @@ enum section {
SECTION_SCROLLBACK, SECTION_SCROLLBACK,
SECTION_URL, SECTION_URL,
SECTION_REGEX, SECTION_REGEX,
SECTION_COLORS_DARK, SECTION_COLORS,
SECTION_COLORS_LIGHT,
SECTION_CURSOR, SECTION_CURSOR,
SECTION_MOUSE, SECTION_MOUSE,
SECTION_CSD, SECTION_CSD,
@ -3034,11 +2878,6 @@ enum section {
SECTION_ENVIRONMENT, SECTION_ENVIRONMENT,
SECTION_TWEAK, SECTION_TWEAK,
SECTION_TOUCH, SECTION_TOUCH,
/* Deprecated */
SECTION_COLORS,
SECTION_COLORS2,
SECTION_COUNT, SECTION_COUNT,
}; };
@ -3057,8 +2896,7 @@ static const struct {
[SECTION_SCROLLBACK] = {&parse_section_scrollback, "scrollback"}, [SECTION_SCROLLBACK] = {&parse_section_scrollback, "scrollback"},
[SECTION_URL] = {&parse_section_url, "url"}, [SECTION_URL] = {&parse_section_url, "url"},
[SECTION_REGEX] = {&parse_section_regex, "regex", true}, [SECTION_REGEX] = {&parse_section_regex, "regex", true},
[SECTION_COLORS_DARK] = {&parse_section_colors_dark, "colors-dark"}, [SECTION_COLORS] = {&parse_section_colors, "colors"},
[SECTION_COLORS_LIGHT] = {&parse_section_colors_light, "colors-light"},
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"}, [SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
[SECTION_MOUSE] = {&parse_section_mouse, "mouse"}, [SECTION_MOUSE] = {&parse_section_mouse, "mouse"},
[SECTION_CSD] = {&parse_section_csd, "csd"}, [SECTION_CSD] = {&parse_section_csd, "csd"},
@ -3070,10 +2908,6 @@ static const struct {
[SECTION_ENVIRONMENT] = {&parse_section_environment, "environment"}, [SECTION_ENVIRONMENT] = {&parse_section_environment, "environment"},
[SECTION_TWEAK] = {&parse_section_tweak, "tweak"}, [SECTION_TWEAK] = {&parse_section_tweak, "tweak"},
[SECTION_TOUCH] = {&parse_section_touch, "touch"}, [SECTION_TOUCH] = {&parse_section_touch, "touch"},
/* Deprecated */
[SECTION_COLORS] = {&parse_section_colors, "colors"},
[SECTION_COLORS2] = {&parse_section_colors2, "colors2"},
}; };
static_assert(ALEN(section_info) == SECTION_COUNT, "section info array size mismatch"); static_assert(ALEN(section_info) == SECTION_COUNT, "section info array size mismatch");
@ -3446,7 +3280,6 @@ config_load(struct config *conf, const char *conf_path,
.shell = get_shell(), .shell = get_shell(),
.title = xstrdup("foot"), .title = xstrdup("foot"),
.app_id = (as_server ? xstrdup("footclient") : xstrdup("foot")), .app_id = (as_server ? xstrdup("footclient") : xstrdup("foot")),
.toplevel_tag = xstrdup(""),
.word_delimiters = xc32dup(U",│`|:\"'()[]{}<>"), .word_delimiters = xc32dup(U",│`|:\"'()[]{}<>"),
.size = { .size = {
.type = CONF_SIZE_PX, .type = CONF_SIZE_PX,
@ -3455,7 +3288,6 @@ config_load(struct config *conf, const char *conf_path,
}, },
.pad_x = 0, .pad_x = 0,
.pad_y = 0, .pad_y = 0,
.center_when = CENTER_MAXIMIZED_AND_FULLSCREEN,
.resize_by_cells = true, .resize_by_cells = true,
.resize_keep_grid = true, .resize_keep_grid = true,
.resize_delay_ms = 100, .resize_delay_ms = 100,
@ -3478,7 +3310,6 @@ config_load(struct config *conf, const char *conf_path,
.strikeout_thickness = {.pt = 0., .px = -1}, .strikeout_thickness = {.pt = 0., .px = -1},
.dpi_aware = false, .dpi_aware = false,
.gamma_correct = false, .gamma_correct = false,
.uppercase_regex_insert = true,
.security = { .security = {
.osc52 = OSC52_ENABLED, .osc52 = OSC52_ENABLED,
}, },
@ -3507,27 +3338,23 @@ config_load(struct config *conf, const char *conf_path,
}, },
.multiplier = 3., .multiplier = 3.,
}, },
.colors_dark = { .colors = {
.fg = default_foreground, .fg = default_foreground,
.bg = default_background, .bg = default_background,
.flash = 0x7f7f00, .flash = 0x7f7f00,
.flash_alpha = 0x7fff, .flash_alpha = 0x7fff,
.alpha = 0xffff, .alpha = 0xffff,
.alpha_mode = ALPHA_MODE_DEFAULT, .alpha_mode = ALPHA_MODE_DEFAULT,
.dim_blend_towards = DIM_BLEND_TOWARDS_BLACK,
.selection_fg = 0x80000000, /* Use default bg */ .selection_fg = 0x80000000, /* Use default bg */
.selection_bg = 0x80000000, /* Use default fg */ .selection_bg = 0x80000000, /* Use default fg */
.cursor = {
.text = 0,
.cursor = 0,
},
.use_custom = { .use_custom = {
.selection = false,
.jump_label = false, .jump_label = false,
.scrollback_indicator = false, .scrollback_indicator = false,
.url = false, .url = false,
}, },
}, },
.initial_color_theme = COLOR_THEME_DARK,
.cursor = { .cursor = {
.style = CURSOR_BLOCK, .style = CURSOR_BLOCK,
.unfocused_style = CURSOR_UNFOCUSED_HOLLOW, .unfocused_style = CURSOR_UNFOCUSED_HOLLOW,
@ -3535,6 +3362,10 @@ config_load(struct config *conf, const char *conf_path,
.enabled = false, .enabled = false,
.rate_ms = 500, .rate_ms = 500,
}, },
.color = {
.text = 0,
.cursor = 0,
},
.beam_thickness = {.pt = 1.5}, .beam_thickness = {.pt = 1.5},
.underline_thickness = {.pt = 0., .px = -1}, .underline_thickness = {.pt = 0., .px = -1},
}, },
@ -3589,8 +3420,6 @@ config_load(struct config *conf, const char *conf_path,
.font_monospace_warn = true, .font_monospace_warn = true,
.sixel = true, .sixel = true,
.surface_bit_depth = SHM_BITS_AUTO, .surface_bit_depth = SHM_BITS_AUTO,
.min_stride_alignment = 256,
.preapply_damage = true,
}, },
.touch = { .touch = {
@ -3607,11 +3436,8 @@ config_load(struct config *conf, const char *conf_path,
.notifications = tll_init(), .notifications = tll_init(),
}; };
memcpy(conf->colors_dark.table, default_color_table, sizeof(default_color_table)); memcpy(conf->colors.table, default_color_table, sizeof(default_color_table));
memcpy(conf->colors_dark.sixel, default_sixel_colors, sizeof(default_sixel_colors)); memcpy(conf->colors.sixel, default_sixel_colors, sizeof(default_sixel_colors));
memcpy(&conf->colors_light, &conf->colors_dark, sizeof(conf->colors_dark));
conf->colors_light.dim_blend_towards = DIM_BLEND_TOWARDS_WHITE;
parse_modifiers(XKB_MOD_NAME_SHIFT, 5, &conf->mouse.selection_override_modifiers); parse_modifiers(XKB_MOD_NAME_SHIFT, 5, &conf->mouse.selection_override_modifiers);
tokenize_cmdline( tokenize_cmdline(
@ -3715,6 +3541,10 @@ config_load(struct config *conf, const char *conf_path,
if (!config_override_apply(conf, overrides, errors_are_fatal)) if (!config_override_apply(conf, overrides, errors_are_fatal))
ret = !errors_are_fatal; ret = !errors_are_fatal;
conf->colors.use_custom.selection =
conf->colors.selection_fg >> 24 == 0 &&
conf->colors.selection_bg >> 24 == 0;
if (ret && conf->fonts[0].count == 0) { if (ret && conf->fonts[0].count == 0) {
struct config_font font; struct config_font font;
if (!config_font_parse("monospace", &font)) { if (!config_font_parse("monospace", &font)) {
@ -3899,7 +3729,6 @@ config_clone(const struct config *old)
conf->shell = xstrdup(old->shell); conf->shell = xstrdup(old->shell);
conf->title = xstrdup(old->title); conf->title = xstrdup(old->title);
conf->app_id = xstrdup(old->app_id); conf->app_id = xstrdup(old->app_id);
conf->toplevel_tag = xstrdup(old->toplevel_tag);
conf->word_delimiters = xc32dup(old->word_delimiters); conf->word_delimiters = xc32dup(old->word_delimiters);
conf->scrollback.indicator.text = xc32dup(old->scrollback.indicator.text); conf->scrollback.indicator.text = xc32dup(old->scrollback.indicator.text);
conf->server_socket_path = xstrdup(old->server_socket_path); conf->server_socket_path = xstrdup(old->server_socket_path);
@ -3999,7 +3828,6 @@ config_free(struct config *conf)
free(conf->shell); free(conf->shell);
free(conf->title); free(conf->title);
free(conf->app_id); free(conf->app_id);
free(conf->toplevel_tag);
free(conf->word_delimiters); free(conf->word_delimiters);
spawn_template_free(&conf->bell.command); spawn_template_free(&conf->bell.command);
free(conf->scrollback.indicator.text); free(conf->scrollback.indicator.text);
@ -4067,10 +3895,9 @@ config_font_parse(const char *pattern, struct config_font *font)
* both "size" and "pixelsize" being set, and we don't know * both "size" and "pixelsize" being set, and we don't know
* which one takes priority. * which one takes priority.
*/ */
FcConfig *fc_conf = FcConfigCreate();
FcPattern *pat_copy = FcPatternDuplicate(pat); FcPattern *pat_copy = FcPatternDuplicate(pat);
if (pat_copy == NULL || if (pat_copy == NULL ||
!FcConfigSubstitute(fc_conf, pat_copy, FcMatchPattern)) !FcConfigSubstitute(NULL, pat_copy, FcMatchPattern))
{ {
LOG_WARN("%s: failed to do config substitution", pattern); LOG_WARN("%s: failed to do config substitution", pattern);
} else { } else {
@ -4079,7 +3906,6 @@ config_font_parse(const char *pattern, struct config_font *font)
} }
FcPatternDestroy(pat_copy); FcPatternDestroy(pat_copy);
FcConfigDestroy(fc_conf);
if (have_pt_size != FcResultMatch && have_px_size != FcResultMatch) if (have_pt_size != FcResultMatch && have_px_size != FcResultMatch)
pt_size = 8.0; pt_size = 8.0;

146
config.h
View file

@ -131,89 +131,10 @@ struct custom_regex {
struct config_spawn_template launch; struct config_spawn_template launch;
}; };
struct color_theme {
uint32_t fg;
uint32_t bg;
uint32_t flash;
uint32_t flash_alpha;
uint32_t table[256];
uint16_t alpha;
uint32_t selection_fg;
uint32_t selection_bg;
uint32_t url;
uint32_t dim[8];
uint32_t sixel[16];
enum {
DIM_BLEND_TOWARDS_BLACK,
DIM_BLEND_TOWARDS_WHITE,
} dim_blend_towards;
enum {
ALPHA_MODE_DEFAULT,
ALPHA_MODE_MATCHING,
ALPHA_MODE_ALL
} alpha_mode;
struct {
uint32_t text;
uint32_t cursor;
} cursor;
struct {
uint32_t fg;
uint32_t bg;
} jump_label;
struct {
uint32_t fg;
uint32_t bg;
} scrollback_indicator;
struct {
struct {
uint32_t fg;
uint32_t bg;
} no_match;
struct {
uint32_t fg;
uint32_t bg;
} match;
} search_box;
struct {
bool cursor:1;
bool jump_label:1;
bool scrollback_indicator:1;
bool url:1;
bool search_box_no_match:1;
bool search_box_match:1;
uint8_t dim;
} use_custom;
};
enum which_color_theme {
COLOR_THEME_DARK,
COLOR_THEME_LIGHT,
COLOR_THEME_1, /* Deprecated */
COLOR_THEME_2, /* Deprecated */
};
enum shm_bit_depth { enum shm_bit_depth {
SHM_BITS_AUTO, SHM_BITS_AUTO,
SHM_BITS_8, SHM_BITS_8,
SHM_BITS_10, SHM_BITS_10
SHM_BITS_16,
};
enum center_when {
CENTER_INVALID,
CENTER_NEVER,
CENTER_FULLSCREEN,
CENTER_MAXIMIZED_AND_FULLSCREEN,
CENTER_ALWAYS,
}; };
struct config { struct config {
@ -221,7 +142,6 @@ struct config {
char *shell; char *shell;
char *title; char *title;
char *app_id; char *app_id;
char *toplevel_tag;
char32_t *word_delimiters; char32_t *word_delimiters;
bool login_shell; bool login_shell;
bool locked_title; bool locked_title;
@ -234,7 +154,7 @@ struct config {
unsigned pad_x; unsigned pad_x;
unsigned pad_y; unsigned pad_y;
enum center_when center_when; bool center;
bool resize_by_cells; bool resize_by_cells;
bool resize_keep_grid; bool resize_keep_grid;
@ -255,7 +175,6 @@ struct config {
bool dpi_aware; bool dpi_aware;
bool gamma_correct; bool gamma_correct;
bool uppercase_regex_insert;
struct config_font_list fonts[4]; struct config_font_list fonts[4];
struct font_size_adjustment font_size_adjustment; struct font_size_adjustment font_size_adjustment;
@ -329,9 +248,58 @@ struct config {
tll(struct custom_regex) custom_regexes; tll(struct custom_regex) custom_regexes;
struct color_theme colors_dark; struct {
struct color_theme colors_light; uint32_t fg;
enum which_color_theme initial_color_theme; uint32_t bg;
uint32_t flash;
uint32_t flash_alpha;
uint32_t table[256];
uint16_t alpha;
uint32_t selection_fg;
uint32_t selection_bg;
uint32_t url;
uint32_t dim[8];
uint32_t sixel[16];
enum {
ALPHA_MODE_DEFAULT,
ALPHA_MODE_MATCHING,
ALPHA_MODE_ALL
} alpha_mode;
struct {
uint32_t fg;
uint32_t bg;
} jump_label;
struct {
uint32_t fg;
uint32_t bg;
} scrollback_indicator;
struct {
struct {
uint32_t fg;
uint32_t bg;
} no_match;
struct {
uint32_t fg;
uint32_t bg;
} match;
} search_box;
struct {
bool selection:1;
bool jump_label:1;
bool scrollback_indicator:1;
bool url:1;
bool search_box_no_match:1;
bool search_box_match:1;
uint8_t dim;
} use_custom;
} colors;
struct { struct {
enum cursor_style style; enum cursor_style style;
@ -340,6 +308,10 @@ struct config {
bool enabled; bool enabled;
uint32_t rate_ms; uint32_t rate_ms;
} blink; } blink;
struct {
uint32_t text;
uint32_t cursor;
} color;
struct pt_or_px beam_thickness; struct pt_or_px beam_thickness;
struct pt_or_px underline_thickness; struct pt_or_px underline_thickness;
} cursor; } cursor;
@ -443,8 +415,6 @@ struct config {
bool font_monospace_warn; bool font_monospace_warn;
bool sixel; bool sixel;
enum shm_bit_depth surface_bit_depth; enum shm_bit_depth surface_bit_depth;
uint32_t min_stride_alignment;
bool preapply_damage;
} tweak; } tweak;
struct { struct {

78
csi.c
View file

@ -117,9 +117,9 @@ csi_sgr(struct terminal *term)
style > UNDERLINE_SINGLE; style > UNDERLINE_SINGLE;
break; break;
} }
} else
term->bits_affecting_ascii_printer.underline_style = false; term_update_ascii_printer(term);
term_update_ascii_printer(term); }
break; break;
} }
case 5: term->vt.attrs.blink = true; break; case 5: term->vt.attrs.blink = true; break;
@ -422,8 +422,6 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
case 1004: case 1004:
term->focus_events = enable; term->focus_events = enable;
if (enable)
term_to_slave(term, term->kbd_focus ? "\033[I" : "\033[O", 3);
break; break;
case 1005: case 1005:
@ -565,10 +563,6 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
#endif #endif
break; break;
case 2031:
term->report_theme_changes = enable;
break;
case 2048: case 2048:
if (enable) if (enable)
term_enable_size_notifications(term); term_enable_size_notifications(term);
@ -663,7 +657,6 @@ decrqm(const struct terminal *term, unsigned param)
case 2027: return term->conf->tweak.grapheme_width_method != GRAPHEME_WIDTH_DOUBLE case 2027: return term->conf->tweak.grapheme_width_method != GRAPHEME_WIDTH_DOUBLE
? DECRPM_PERMANENTLY_RESET ? DECRPM_PERMANENTLY_RESET
: decrpm(term->grapheme_shaping); : decrpm(term->grapheme_shaping);
case 2031: return decrpm(term->report_theme_changes);
case 2048: return decrpm(term->size_notifications); case 2048: return decrpm(term->size_notifications);
case 8452: return decrpm(term->sixel.cursor_right_of_graphics); case 8452: return decrpm(term->sixel.cursor_right_of_graphics);
case 737769: return decrpm(term_ime_is_enabled(term)); case 737769: return decrpm(term_ime_is_enabled(term));
@ -709,7 +702,6 @@ xtsave(struct terminal *term, unsigned param)
case 2004: term->xtsave.bracketed_paste = term->bracketed_paste; break; case 2004: term->xtsave.bracketed_paste = term->bracketed_paste; break;
case 2026: term->xtsave.app_sync_updates = term->render.app_sync_updates.enabled; break; case 2026: term->xtsave.app_sync_updates = term->render.app_sync_updates.enabled; break;
case 2027: term->xtsave.grapheme_shaping = term->grapheme_shaping; break; case 2027: term->xtsave.grapheme_shaping = term->grapheme_shaping; break;
case 2031: term->xtsave.report_theme_changes = term->report_theme_changes; break;
case 2048: term->xtsave.size_notifications = term->size_notifications; break; case 2048: term->xtsave.size_notifications = term->size_notifications; break;
case 8452: term->xtsave.sixel_cursor_right_of_graphics = term->sixel.cursor_right_of_graphics; break; case 8452: term->xtsave.sixel_cursor_right_of_graphics = term->sixel.cursor_right_of_graphics; break;
case 737769: term->xtsave.ime = term_ime_is_enabled(term); break; case 737769: term->xtsave.ime = term_ime_is_enabled(term); break;
@ -754,7 +746,6 @@ xtrestore(struct terminal *term, unsigned param)
case 2004: enable = term->xtsave.bracketed_paste; break; case 2004: enable = term->xtsave.bracketed_paste; break;
case 2026: enable = term->xtsave.app_sync_updates; break; case 2026: enable = term->xtsave.app_sync_updates; break;
case 2027: enable = term->xtsave.grapheme_shaping; break; case 2027: enable = term->xtsave.grapheme_shaping; break;
case 2031: enable = term->xtsave.report_theme_changes; break;
case 2048: enable = term->xtsave.size_notifications; break; case 2048: enable = term->xtsave.size_notifications; break;
case 8452: enable = term->xtsave.sixel_cursor_right_of_graphics; break; case 8452: enable = term->xtsave.sixel_cursor_right_of_graphics; break;
case 737769: enable = term->xtsave.ime; break; case 737769: enable = term->xtsave.ime; break;
@ -801,17 +792,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
int count = vt_param_get(term, 0, 1); int count = vt_param_get(term, 0, 1);
LOG_DBG("REP: '%lc' %d times", (wint_t)term->vt.last_printed, count); LOG_DBG("REP: '%lc' %d times", (wint_t)term->vt.last_printed, count);
int width; const int width = c32width(term->vt.last_printed);
if (term->vt.last_printed >= CELL_COMB_CHARS_LO) {
const struct composed *comp = composed_lookup(
term->composed, term->vt.last_printed - CELL_COMB_CHARS_LO);
xassert(comp != NULL);
width = comp->forced_width > 0 ? comp->forced_width : comp->width;
} else
width = c32width(term->vt.last_printed);
if (width > 0) { if (width > 0) {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
term_print(term, term->vt.last_printed, width, false); term_print(term, term->vt.last_printed, width, false);
@ -852,7 +833,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
* - 22 ANSI color, e.g., VT525. * - 22 ANSI color, e.g., VT525.
* - 28 Rectangular editing. * - 28 Rectangular editing.
* - 29 ANSI text locator (i.e., DEC Locator mode). * - 29 ANSI text locator (i.e., DEC Locator mode).
* - 52 Clipboard access
* *
* Note: we report ourselves as a VT220, mainly to be able * Note: we report ourselves as a VT220, mainly to be able
* to pass parameters, to indicate we support sixel, and * to pass parameters, to indicate we support sixel, and
@ -863,15 +843,13 @@ csi_dispatch(struct terminal *term, uint8_t final)
* *
* Note: tertiary DA responds with "FOOT". * Note: tertiary DA responds with "FOOT".
*/ */
char reply[32]; if (term->conf->tweak.sixel) {
static const char reply[] = "\033[?62;4;22;28c";
int len = snprintf( term_to_slave(term, reply, sizeof(reply) - 1);
reply, sizeof(reply), "\033[?62%s;22;28%sc", } else {
term->conf->tweak.sixel ? ";4" : "", static const char reply[] = "\033[?62;22;28c";
(term->conf->security.osc52 == OSC52_ENABLED || term_to_slave(term, reply, sizeof(reply) - 1);
term->conf->security.osc52 == OSC52_COPY_ENABLED ? ";52" : "")); }
term_to_slave(term, reply, len);
break; break;
} }
@ -1561,32 +1539,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
break; break;
} }
case 'n': {
const int param = vt_param_get(term, 0, 0);
switch (param) {
case 996: { /* Query current theme mode (see private mode 2031) */
/*
* 1 - dark mode
* 2 - light mode
*
* In foot, the themes aren't necessarily light/dark,
* but by convention, the primary theme is dark, and
* the alternative theme is light.
*/
char reply[16] = {0};
int chars = snprintf(
reply, sizeof(reply),
"\033[?997;%dn",
term->colors.active_theme == COLOR_THEME_DARK ? 1 : 2);
term_to_slave(term, reply, chars);
break;
}
}
break;
}
case 'p': { case 'p': {
/* /*
* Request status of ECMA-48/"ANSI" private mode (DECRQM * Request status of ECMA-48/"ANSI" private mode (DECRQM
@ -1644,10 +1596,10 @@ csi_dispatch(struct terminal *term, uint8_t final)
* 64 - vt520 * 64 - vt520
* 65 - vt525 * 65 - vt525
* *
* Param 2 - firmware version xterm uses its version * Param 2 - firmware version
* number. We do to, in the format "MAJORMINORPATCH", * xterm uses its version number. We use an xterm
* where all three version numbers are always two * version number too, since e.g. Emacs uses this to
* digits. So e.g. 1.25.0 is reported as 012500. * determine level of support.
* *
* We report ourselves as a VT220. This must be * We report ourselves as a VT220. This must be
* synchronized with the primary DA response. * synchronized with the primary DA response.

View file

@ -54,7 +54,7 @@ cursor_shape_to_server_shape(enum cursor_shape shape)
} }
enum wp_cursor_shape_device_v1_shape enum wp_cursor_shape_device_v1_shape
cursor_string_to_server_shape(const char *xcursor, int bound_version) cursor_string_to_server_shape(const char *xcursor)
{ {
if (xcursor == NULL) if (xcursor == NULL)
return 0; return 0;
@ -72,7 +72,7 @@ cursor_string_to_server_shape(const char *xcursor, int bound_version)
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT] = {"vertical-text"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT] = {"vertical-text"},
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS] = {"alias", "dnd-link"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS] = {"alias", "dnd-link"},
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY] = {"copy", "dnd-copy"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY] = {"copy", "dnd-copy"},
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE] = {"move", "dnd-move"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE] = {"move"}, /* dnd-move? */
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP] = {"no-drop", "dnd-no-drop"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP] = {"no-drop", "dnd-no-drop"},
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED] = {"not-allowed", "crossed_circle"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED] = {"not-allowed", "crossed_circle"},
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB] = {"grab", "hand1"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB] = {"grab", "hand1"},
@ -94,29 +94,9 @@ cursor_string_to_server_shape(const char *xcursor, int bound_version)
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL] = {"all-scroll", "fleur"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL] = {"all-scroll", "fleur"},
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN] = {"zoom-in"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN] = {"zoom-in"},
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT] = {"zoom-out"}, [WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT] = {"zoom-out"},
#if defined(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK_SINCE_VERSION) /* 1.42 */
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK] = {"dnd-ask"},
#endif
#if defined(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE_SINCE_VERSION) /* 1.42 */
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE] = {"all-resize"},
#endif
}; };
for (size_t i = 0; i < ALEN(table); i++) { for (size_t i = 0; i < ALEN(table); i++) {
#if defined(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK_SINCE_VERSION)
if (i == WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK &&
bound_version < WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DND_ASK_SINCE_VERSION)
{
continue;
}
#endif
#if defined(WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE_SINCE_VERSION)
if (i == WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE &&
bound_version < WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_RESIZE_SINCE_VERSION)
{
continue;
}
#endif
for (size_t j = 0; j < ALEN(table[i]); j++) { for (size_t j = 0; j < ALEN(table[i]); j++) {
if (table[i][j] != NULL && streq(xcursor, table[i][j])) { if (table[i][j] != NULL && streq(xcursor, table[i][j])) {
return i; return i;

View file

@ -26,4 +26,4 @@ const char *const *cursor_shape_to_string(enum cursor_shape shape);
enum wp_cursor_shape_device_v1_shape cursor_shape_to_server_shape( enum wp_cursor_shape_device_v1_shape cursor_shape_to_server_shape(
enum cursor_shape shape); enum cursor_shape shape);
enum wp_cursor_shape_device_v1_shape cursor_string_to_server_shape( enum wp_cursor_shape_device_v1_shape cursor_string_to_server_shape(
const char *xcursor, int bound_version); const char *xcursor);

View file

@ -337,9 +337,6 @@ that corresponds to one of the following modes:
| 2027 | 2027
: contour : contour
: Grapheme cluster processing : Grapheme cluster processing
| 2031
: contour
: Request color theme updates
| 2048 | 2048
: TODO : TODO
: In-band window resize notifications : In-band window resize notifications
@ -660,13 +657,6 @@ manipulation sequences. The generic format is:
: xterm : xterm
: Report the current entry on the palette stack, and the number of : Report the current entry on the palette stack, and the number of
palettes stored on the stack. palettes stored on the stack.
| \\E[ ? 996 n
: Query the current (color) theme mode
: contour
: The current color theme mode (light or dark) is reported as *CSI ?
997 ; 1|2 n*, where *1* means dark and *2* light. By convention, the
primary theme in foot is considered dark, and the alternative theme
light.
# OSC # OSC

View file

@ -67,11 +67,6 @@ the foot command line
Value to set the *app-id* property on the Wayland window Value to set the *app-id* property on the Wayland window
to. Default: _foot_ (normal mode), or _footclient_ (server mode). to. Default: _foot_ (normal mode), or _footclient_ (server mode).
*toplevel-tag*=_TAG_
Value to set the *toplevel-tag* property on the Wayland window
to. The compositor can use this value for session management,
window rules etc. Default: _not set_
*-m*,*--maximized* *-m*,*--maximized*
Start in maximized mode. If both *--maximized* and *--fullscreen* Start in maximized mode. If both *--maximized* and *--fullscreen*
are specified, the _last_ one takes precedence. are specified, the _last_ one takes precedence.
@ -257,6 +252,9 @@ These keyboard shortcuts affect the search selection:
*ctrl*+*shift*+*left* *ctrl*+*shift*+*left*
Extend current selection to the left to the last word boundary. Extend current selection to the left to the last word boundary.
*ctrl*+*shift*+*w*
Extend the current selection to the right to the last whitespace.
*shift*+*down* *shift*+*down*
Extend current selection down one line Extend current selection down one line
@ -691,21 +689,6 @@ variables may be defined in *foot.ini*(5).
In addition to the variables listed above, custom environment In addition to the variables listed above, custom environment
variables to unset may be defined in *foot.ini*(5). variables to unset may be defined in *foot.ini*(5).
# Signals
The following signals have special meaning in foot:
- SIGUSR1: switch to the dark color theme (*[colors-dark]*).
- SIGUSR2: switch to the light color theme (*[colors-light]*).
Note: you can send SIGUSR1/SIGUSR2 to a *foot --server* process too,
in which case all client instances will switch theme. Furthermore, all
future client instances will also use the selected theme.
You can also send SIGUSR1/SIGUSR2 to a footclient instance, see
*footclient*(1) for details.
# BUGS # BUGS
Please report bugs to https://codeberg.org/dnkl/foot/issues Please report bugs to https://codeberg.org/dnkl/foot/issues

View file

@ -24,7 +24,7 @@ commented out will usually be installed to */etc/xdg/foot/foot.ini*.
Options are set using KEY=VALUE pairs: Options are set using KEY=VALUE pairs:
*\[colors-dark\]*++ *\[colors\]*++
*background=000000*++ *background=000000*++
*foreground=ffffff* *foreground=ffffff*
@ -207,7 +207,7 @@ empty string to be set, but it must be quoted: *KEY=""*)
Compared to the default (disabled), bright glyphs on a dark Compared to the default (disabled), bright glyphs on a dark
background will appear thicker, and dark glyphs on a light background will appear thicker, and dark glyphs on a light
background will appear thinner. background will appear thinner.
FreeType can limit the effect of the latter, with a technique FreeType can limit the effect of the latter, with a technique
called stem darkening. It is only available for CFF fonts called stem darkening. It is only available for CFF fonts
(OpenType, .otf) and disabled by default (in FreeType). You can (OpenType, .otf) and disabled by default (in FreeType). You can
@ -221,23 +221,15 @@ empty string to be set, but it must be quoted: *KEY=""*)
font designer set the font weight based on incorrect rendering. font designer set the font weight based on incorrect rendering.
In order to represent colors faithfully, higher precision image In order to represent colors faithfully, higher precision image
buffers are required. By default, foot will use either 16-bit, or buffers are required. By default, foot will use 10-bit color
10-bit color channels, depending on availability, when channels, if available, when gamma-correct blending is
gamma-correct blending is enabled. However, the high precision enabled. However, the high precision buffers are slow; if you want
buffers are slow; if you want to use gamma-correct blending, but to use gamma-correct blending, but prefer speed (throughput and
prefer speed (throughput and input latency) over accurate colors, input latency) over accurate colors, you can force 8-bit color
you can force 8-bit color channels by setting channels by setting *tweak.surface-bit-depth=8-bit*.
*tweak.surface-bit-depth=8-bit*.
Default: _no_. Default: _no_.
*uppercase-regex-insert*
Boolean. When enabled, inputting an uppercase hint character in
*show-urls-copy* or *regex-copy* mode will insert the selected
text into the prompt in addition to copying it to the clipboard.
Default: _yes_
*box-drawings-uses-font-glyphs* *box-drawings-uses-font-glyphs*
Boolean. When disabled, foot generates box/line drawing characters Boolean. When disabled, foot generates box/line drawing characters
itself. The are several advantages to doing this instead of using itself. The are several advantages to doing this instead of using
@ -296,29 +288,18 @@ empty string to be set, but it must be quoted: *KEY=""*)
*pad* *pad*
Padding between border and glyphs, in pixels (subject to output Padding between border and glyphs, in pixels (subject to output
scaling), in the form scaling), in the form _XxY_.
```
_XxY_ [center | center-when-fullscreen | center-when-maximized-and-fullscreen]
```
This will add _at least_ X pixels on both the left and right This will add _at least_ X pixels on both the left and right
sides, and Y pixels on the top and bottom sides. sides, and Y pixels on the top and bottom sides. The grid content
will be anchored in the top left corner. I.e. if the window
manager forces an odd window size on foot, the additional pixels
will be added to the right and bottom sides.
When no centering is specified, the grid content is anchored to To instead center the grid content, append *center* (e.g. *pad=5x5
the top left corner. I.e. if the window manager forces an odd center*).
window size on foot, the additional pixels will be added to the
right and bottom sides.
If *center* is specified, the grid content is instead Default: _0x0_.
centered. This may cause "jumpiness" when resizing the window.
With *center-when-fullscreen* and
*center-when-maximized-and-fullscreen*, the grid is anchored to
the top left corner, unless the window is maximized, or
fullscreened.
Default: _0x0_ center-when-maximized-and-fullscreen.
*resize-delay-ms* *resize-delay-ms*
@ -370,19 +351,6 @@ empty string to be set, but it must be quoted: *KEY=""*)
Default: _yes_ Default: _yes_
*initial-color-theme*
Selects which color theme to use, *dark*, or *light*.
*dark* uses the colors defined in the *colors-dark* section, while
*light* uses the colors from the *colors-light* section.
Use the *color-theme-switch-dark*, *color-theme-switch-light* and
*color-theme-toggle* key bindings to switch between the two themes
at runtime, or send SIGUSR1/SIGUSR2 to the foot process (see
*foot*(1) for details).
Default: _1_
*initial-window-size-pixels* *initial-window-size-pixels*
Initial window width and height in _pixels_ (subject to output Initial window width and height in _pixels_ (subject to output
scaling), in the form _WIDTHxHEIGHT_. The height _includes_ the scaling), in the form _WIDTHxHEIGHT_. The height _includes_ the
@ -429,11 +397,6 @@ empty string to be set, but it must be quoted: *KEY=""*)
apply window management rules. Default: _foot_ (normal mode), or apply window management rules. Default: _foot_ (normal mode), or
_footclient_ (server mode). _footclient_ (server mode).
*toplevel-tag*
Value to set the *toplevel-tag* property on the Wayland window
to. The compositor can use this value for session management,
window rules etc. Default: _not set_
*bold-text-in-bright* *bold-text-in-bright*
Semi-boolean. When enabled, bold text is rendered in a brighter Semi-boolean. When enabled, bold text is rendered in a brighter
color (in addition to using a bold font). The color is brightened color (in addition to using a bold font). The color is brightened
@ -937,6 +900,15 @@ applications can change these at runtime.
enabled. Expressed in milliseconds between each blink. Default: enabled. Expressed in milliseconds between each blink. Default:
_500_. _500_.
*color*
Two space separated RRGGBB values (i.e. plain old 6-digit hex
values, without prefix) specifying the foreground (text) and
background (cursor) colors for the cursor.
Example: *ff0000 00ff00* (green cursor, red text)
Default: the regular foreground and background colors, reversed.
*beam-thickness* *beam-thickness*
Thickness (width) of the beam styled cursor. The value is in Thickness (width) of the beam styled cursor. The value is in
points, and its exact value thus depends on the monitor's DPI. To points, and its exact value thus depends on the monitor's DPI. To
@ -987,34 +959,16 @@ applications can change these at runtime.
Default: _400_. Default: _400_.
# SECTION: colors-dark, colors-light # SECTION: colors
These two sections controls the 16 ANSI colors, the default foreground This section controls the 16 ANSI colors, the default foreground and
and background colors, and the extended 256 color palette. Note that background colors, and the extended 256 color palette. Note that
applications can change these at runtime. applications can change these at runtime.
The colors are in RRGGBB format (i.e. plain old 6-digit hex values, The colors are in RRGGBB format (i.e. plain old 6-digit hex values,
without prefix). That is, they do *not* have an alpha component. You without prefix). That is, they do *not* have an alpha component. You
can configure the background transparency with the _alpha_ option. can configure the background transparency with the _alpha_ option.
*colors-dark* is intended to define a dark color theme, and
*colors-light* is intended to define a light color theme. You can
switch between them using the *color-theme-switch-dark*,
*color-theme-switch-light* and *color-theme-toggle* key bindings, or
by sending SIGUSR1/SIGUSR2 to the foot process.
The default theme used is *colors-dark*, unless
*initial-color-theme=light* has been set.
*cursor*
Two space separated RRGGBB values (i.e. plain old 6-digit hex
values, without prefix) specifying the foreground (text) and
background (cursor) colors for the cursor.
Example: *ff0000 00ff00* (green cursor, red text)
Default: the regular foreground and background colors, reversed.
*foreground* *foreground*
Default foreground color. This is the color used when no ANSI Default foreground color. This is the color used when no ANSI
color is being used. Default: _839496_. color is being used. Default: _839496_.
@ -1041,8 +995,7 @@ The default theme used is *colors-dark*, unless
a color value, and a "dim" attribute. a color value, and a "dim" attribute.
By default, foot implements this by blending the current color By default, foot implements this by blending the current color
with black or white, depending on what the *dim-blend-towards* with black. This is a generic approach that applies to both
option is set to . This is a generic approach that applies to both
colors from the 256-color palette, as well as 24-bit RGB colors. colors from the 256-color palette, as well as 24-bit RGB colors.
You can change this behavior by setting the *dimN* options. When You can change this behavior by setting the *dimN* options. When
@ -1097,17 +1050,10 @@ The default theme used is *colors-dark*, unless
Default: _default_ Default: _default_
*dim-blend-towards*
Which color to blend towards when "auto" dimming a color (see
*dim0*..*dim7* above). One of *black* or *white*. Blending towards
black makes the text darker, while blending towards white makes it
whiter (but still dimmer than normal text).
Default: _black_ (*colors-dark*), _white_ (*colors-light*)
*selection-foreground*, *selection-background* *selection-foreground*, *selection-background*
Foreground (text) and background color to use in selected Foreground (text) and background color to use in selected
text. Default: _inverse foreground/background_. text. Note that *both* options must be set, or the default will be
used. Default: _inverse foreground/background_.
*jump-labels* *jump-labels*
Two color values specifying the foreground (text) and background Two color values specifying the foreground (text) and background
@ -1383,8 +1329,7 @@ e.g. *search-start=none*.
*show-urls-copy* *show-urls-copy*
Enter URL mode, where all currently visible URLs are tagged with a Enter URL mode, where all currently visible URLs are tagged with a
jump label with a key sequence that will place the URL in the jump label with a key sequence that will place the URL in the
clipboard. If the hint is completed with an uppercase character, clipboard. Default: _none_.
the match will also be pasted. Default: _none_.
*regex-launch* *regex-launch*
Enter regex mode. This works exactly the same as URL mode; all Enter regex mode. This works exactly the same as URL mode; all
@ -1407,10 +1352,8 @@ e.g. *search-start=none*.
Default: _none_. Default: _none_.
*regex-copy* *regex-copy*
Same as *regex-launch*, but the match is placed in the clipboard, Same as *regex-copy*, but the match is placed in the clipboard,
instead of "launched", upon activation. If the hint is completed instead of "launched", upon activation. Default: _none_.
with an uppercase character, the match will also be pasted.
Default: _none_.
*prompt-prev* *prompt-prev*
Jump to the previous, currently not visible, prompt (requires Jump to the previous, currently not visible, prompt (requires
@ -1446,25 +1389,6 @@ e.g. *search-start=none*.
Default: _Control+Shift+u_. Default: _Control+Shift+u_.
*color-theme-switch-dark*, *color-theme-switch-dark*, *color-theme-toggle*
Switch between the dark color theme (defined in the *colors-dark*
section), and the light color theme (defined in the *colors-light*
section).
*color-theme-switch-dark* applies the dark color theme regardless
of which color theme is currently active.
*color-theme-switch-light* applies the light color theme
regardless of which color theme is currently active.
*color-theme-toggle* toggles between the primary and alternative
color themes.
Note: you can also send SIGUSR1/SIGUSR2 to the foot process to
change the theme (see *foot*(1) for details.)
Default: _none_
*quit* *quit*
Quit foot. Default: _none_. Quit foot. Default: _none_.
@ -2037,32 +1961,6 @@ any of these options.
Default: _512_. Maximum allowed: _2048_ (2GB). Default: _512_. Maximum allowed: _2048_ (2GB).
*min-stride-alignment*
This option controls the minimum stride alignment, in bytes, when
allocating SHM buffers.
In some circumstances, a compositor can import foot's SHM buffers
directly to the GPU, without copying the buffer to GPU memory
(typically on integrated graphics). Different drivers have
different requirements for this, and one of those requirements is
typically the stride alignment. At the time of writing, AMD GPUs
require 256-byte alignment.
Note that doing a direct import typically disables immediate
buffer release (if the compositor supports that), which means foot
has to double buffer. This adds a performance penalty in foot, but
the overall system performance should still be better.
If you are not using integrated graphics, or if the compositor
does not support GPU direct imports, this option has close to zero
impact. You can save a small amount of memory by setting this to
0.
Ultimately, it is up to the compositor to decide whether to do
immediate buffer releases, or try to optimize GPU imports.
Default: _256_
*sixel* *sixel*
Boolean. When enabled, foot will process sixel images. Default: Boolean. When enabled, foot will process sixel images. Default:
_yes_ _yes_
@ -2077,7 +1975,7 @@ any of these options.
*surface-bit-depth* *surface-bit-depth*
Selects which RGB bit depth to use for image buffers. One of Selects which RGB bit depth to use for image buffers. One of
*auto*, *8-bit*, *10-bit* or *16-bit*. *auto*, *8-bit*, or *10-bit*.
*auto* chooses bit depth depending on other settings, and *auto* chooses bit depth depending on other settings, and
availability. availability.
@ -2087,53 +1985,16 @@ any of these options.
*10-bit* uses 10 bits for each RGB channel, and 2 bits for the *10-bit* uses 10 bits for each RGB channel, and 2 bits for the
alpha channel. Thus, it provides higher precision color channels, alpha channel. Thus, it provides higher precision color channels,
but a lower precision alpha channel. but a lower precision alpha channel. It is the default when
*gamma-correct-blending=yes*, if supported by the compositor.
*16-bit* 16 bits for each color channel, alpha included. If Note that *10-bit* is much slower than *8-bit*; if you want to use
available, this is the default when *gamma-correct-blending=yes*. gamma-correct blending, and if you prefer speed (throughput and
input latency) over accurate colors, you can set
Note that both *10-bit* and *16-bit* are much slower than *8-bit*;
if you want to use gamma-correct blending, and if you prefer speed
(throughput and input latency) over accurate colors, you can set
*surface-bit-depth=8-bit* explicitly. *surface-bit-depth=8-bit* explicitly.
Default: _auto_ Default: _auto_
*pre-apply-damage*
Boolean. When enabled, foot will attempt to "pre-apply" the damage
from the last frame when foot is forced to double-buffer
(i.e. when the compositor does not release SHM buffers
immediately). All text after this assumes the compositor is not
releasing buffers immediately.
When this option is disabled, each time foot needs to render a
frame, it has to first copy over areas that changed in the last
frame (i.e. all changes between the last two frames). This is
basically a *memcpy*(3), which can be slow if the changed area is
large. It is also done on the main thread, which means foot cannot
do anything else at the same time; no other rendering, no VT
parsing. After the changes have been brought over to the new
frame, foot proceeds with rendering the cells that has changed
between the last frame and the new frame.
When this option is enabled, the changes between the last two frames
are brought over to what will become the next frame before foot
starts rendering the next frame. As soon as the compositor
releases the previous buffer (typically right after foot has
pushed a new frame), foot kicks off a thread that copies over the
changes to the newly released buffer. Since this is done in a
thread, foot can continue processing input at the same
time. Later, when it is time to render a new frame, the changes
have already been transferred, and foot can immediately start with
the actual rendering.
Thus, having this option enabled improves both performance
(copying the last two frames' changes is threaded), and improves
input latency (rending the next frame no longer has to first bring
over the changes between the last two frames).
Default: _yes_
# SEE ALSO # SEE ALSO
*foot*(1), *footclient*(1) *foot*(1), *footclient*(1)

View file

@ -33,11 +33,6 @@ terminal has terminated.
Value to set the *app-id* property on the Wayland window Value to set the *app-id* property on the Wayland window
to. Default: _foot_ (normal mode), or _footclient_ (server mode). to. Default: _foot_ (normal mode), or _footclient_ (server mode).
*toplevel-tag*=_TAG_
Value to set the *toplevel-tag* property on the Wayland window
to. The compositor can use this value for session management,
window rules etc. Default: _not set_
*-w*,*--window-size-pixels*=_WIDTHxHEIGHT_ *-w*,*--window-size-pixels*=_WIDTHxHEIGHT_
Set initial window width and height, in pixels. Default: _700x500_. Set initial window width and height, in pixels. Default: _700x500_.
@ -194,21 +189,6 @@ variables may be defined in *foot.ini*(5).
In addition to the variables listed above, custom environment In addition to the variables listed above, custom environment
variables to unset may be defined in *foot.ini*(5). variables to unset may be defined in *foot.ini*(5).
# Signals
The following signals have special meaning in footclient:
- SIGUSR1: switch to the dark color theme (*[colors-dark]*).
- SIGUSR2: switch to the light color theme (*[colors-light]*).
When sending SIGUSR1/SIGUSR2 to a footclient instance, the theme is
changed in that instance only. This is different from when you send
SIGUSR1/SIGUSR2 to the server process, where all instances change the
theme.
Note: for obvious reasons, this is not supported when footclient is
started with *--no-wait*.
# SEE ALSO # SEE ALSO
*foot*(1) *foot*(1)

View file

@ -256,8 +256,8 @@ extract_one(const struct terminal *term, const struct row *row,
} }
} }
if (next_tab_stop > col) xassert(next_tab_stop >= col);
ctx->tab_spaces_left = next_tab_stop - col - 1; ctx->tab_spaces_left = next_tab_stop - col;
} }
} }

30
fdm.c
View file

@ -18,18 +18,6 @@
#include "debug.h" #include "debug.h"
#include "xmalloc.h" #include "xmalloc.h"
#if !defined(SIGABBREV_NP)
#include <stdio.h>
static const char *
sigabbrev_np(int sig)
{
static char buf[16];
snprintf(buf, sizeof(buf), "<%d>", sig);
return buf;
}
#endif
struct fd_handler { struct fd_handler {
int fd; int fd;
int events; int events;
@ -125,8 +113,7 @@ fdm_destroy(struct fdm *fdm)
for (int i = 0; i < SIGRTMAX; i++) { for (int i = 0; i < SIGRTMAX; i++) {
if (fdm->signal_handlers[i].callback != NULL) if (fdm->signal_handlers[i].callback != NULL)
LOG_WARN("handler for signal %d (SIG%s) not removed", LOG_WARN("handler for signal %d not removed", i);
i, sigabbrev_np(i));
} }
if (tll_length(fdm->hooks_low) > 0 || if (tll_length(fdm->hooks_low) > 0 ||
@ -351,8 +338,7 @@ bool
fdm_signal_add(struct fdm *fdm, int signo, fdm_signal_handler_t handler, void *data) fdm_signal_add(struct fdm *fdm, int signo, fdm_signal_handler_t handler, void *data)
{ {
if (fdm->signal_handlers[signo].callback != NULL) { if (fdm->signal_handlers[signo].callback != NULL) {
LOG_ERR("signal %d (SIG%s) already has a handler", LOG_ERR("signal %d already has a handler", signo);
signo, sigabbrev_np(signo));
return false; return false;
} }
@ -361,16 +347,14 @@ fdm_signal_add(struct fdm *fdm, int signo, fdm_signal_handler_t handler, void *d
sigaddset(&mask, signo); sigaddset(&mask, signo);
if (sigprocmask(SIG_BLOCK, &mask, &original) < 0) { if (sigprocmask(SIG_BLOCK, &mask, &original) < 0) {
LOG_ERRNO("failed to block signal %d (SIG%s)", LOG_ERRNO("failed to block signal %d", signo);
signo, sigabbrev_np(signo));
return false; return false;
} }
struct sigaction action = {.sa_handler = &signal_handler}; struct sigaction action = {.sa_handler = &signal_handler};
sigemptyset(&action.sa_mask); sigemptyset(&action.sa_mask);
if (sigaction(signo, &action, NULL) < 0) { if (sigaction(signo, &action, NULL) < 0) {
LOG_ERRNO("failed to set signal handler for signal %d (SIG%s)", LOG_ERRNO("failed to set signal handler for signal %d", signo);
signo, sigabbrev_np(signo));
sigprocmask(SIG_SETMASK, &original, NULL); sigprocmask(SIG_SETMASK, &original, NULL);
return false; return false;
} }
@ -390,8 +374,7 @@ fdm_signal_del(struct fdm *fdm, int signo)
struct sigaction action = {.sa_handler = SIG_DFL}; struct sigaction action = {.sa_handler = SIG_DFL};
sigemptyset(&action.sa_mask); sigemptyset(&action.sa_mask);
if (sigaction(signo, &action, NULL) < 0) { if (sigaction(signo, &action, NULL) < 0) {
LOG_ERRNO("failed to restore signal handler for signal %d (SIG%s)", LOG_ERRNO("failed to restore signal handler for signal %d", signo);
signo, sigabbrev_np(signo));
return false; return false;
} }
@ -403,8 +386,7 @@ fdm_signal_del(struct fdm *fdm, int signo)
sigemptyset(&mask); sigemptyset(&mask);
sigaddset(&mask, signo); sigaddset(&mask, signo);
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) { if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) {
LOG_ERRNO("failed to unblock signal %d (SIG%s)", LOG_ERRNO("failed to unblock signal %d", signo);
signo, sigabbrev_np(signo));
return false; return false;
} }

View file

@ -22,12 +22,6 @@ const char version_and_features[] =
" -graphemes" " -graphemes"
#endif #endif
#if defined(HAVE_XDG_TOPLEVEL_TAG)
" +toplevel-tag"
#else
" -toplevel-tag"
#endif
#if !defined(NDEBUG) #if !defined(NDEBUG)
" +assertions" " +assertions"
#else #else

View file

@ -24,11 +24,10 @@
# dpi-aware=no # dpi-aware=no
# gamma-correct-blending=no # gamma-correct-blending=no
# initial-color-theme=dark
# initial-window-size-pixels=700x500 # Or, # initial-window-size-pixels=700x500 # Or,
# initial-window-size-chars=<COLSxROWS> # initial-window-size-chars=<COLSxROWS>
# initial-window-mode=windowed # initial-window-mode=windowed
# pad=0x0 center-when-maximized-and-fullscreen # pad=0x0 # optionally append 'center'
# resize-by-cells=yes # resize-by-cells=yes
# resize-keep-grid=yes # resize-keep-grid=yes
# resize-delay-ms=100 # resize-delay-ms=100
@ -40,8 +39,6 @@
# utmp-helper=/usr/lib/utempter/utempter # When utmp backend is libutempter (Linux) # utmp-helper=/usr/lib/utempter/utempter # When utmp backend is libutempter (Linux)
# utmp-helper=/usr/libexec/ulog-helper # When utmp backend is ulog (FreeBSD) # utmp-helper=/usr/libexec/ulog-helper # When utmp backend is ulog (FreeBSD)
# uppercase-regex-insert=yes
[environment] [environment]
# name=value # name=value
@ -89,6 +86,7 @@
[cursor] [cursor]
# style=block # style=block
# color=<inverse foreground/background>
# blink=no # blink=no
# blink-rate=500 # blink-rate=500
# beam-thickness=1.5 # beam-thickness=1.5
@ -101,7 +99,7 @@
[touch] [touch]
# long-press-delay=400 # long-press-delay=400
[colors-dark] [colors]
# alpha=1.0 # alpha=1.0
# alpha-mode=default # Can be `default`, `matching` or `all` # alpha-mode=default # Can be `default`, `matching` or `all`
# background=242424 # background=242424
@ -109,8 +107,6 @@
# flash=7f7f00 # flash=7f7f00
# flash-alpha=0.5 # flash-alpha=0.5
# cursor=<inverse foreground/background>
## Normal/regular colors (color palette 0-7) ## Normal/regular colors (color palette 0-7)
# regular0=242424 # black # regular0=242424 # black
# regular1=f62b5a # red # regular1=f62b5a # red
@ -132,7 +128,6 @@
# bright7=ffffff # bright white # bright7=ffffff # bright white
## dimmed colors (see foot.ini(5) man page) ## dimmed colors (see foot.ini(5) man page)
# dim-blend-towards=black
# dim0=<not set> # dim0=<not set>
# ... # ...
# dim7=<not-set> # dim7=<not-set>
@ -169,11 +164,6 @@
# search-box-match=<regular0> <regular3> # black-on-yellow # search-box-match=<regular0> <regular3> # black-on-yellow
# urls=<regular3> # urls=<regular3>
[colors-light]
# Alternative color theme, see man page foot.ini(5)
# Same builtin defaults as [color], except for:
# dim-blend-towards=white
[csd] [csd]
# preferred=server # preferred=server
# size=26 # size=26
@ -219,9 +209,6 @@
# prompt-prev=Control+Shift+z # prompt-prev=Control+Shift+z
# prompt-next=Control+Shift+x # prompt-next=Control+Shift+x
# unicode-input=Control+Shift+u # unicode-input=Control+Shift+u
# color-theme-switch-1=none
# color-theme-switch-2=none
# color-theme-toggle=none
# noop=none # noop=none
# quit=none # quit=none

78
input.c
View file

@ -40,7 +40,6 @@
#include "url-mode.h" #include "url-mode.h"
#include "util.h" #include "util.h"
#include "vt.h" #include "vt.h"
#include "xkbcommon-vmod.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "xsnprintf.h" #include "xsnprintf.h"
@ -120,14 +119,10 @@ execute_binding(struct seat *seat, struct terminal *term,
case BIND_ACTION_SCROLLBACK_UP_MOUSE: case BIND_ACTION_SCROLLBACK_UP_MOUSE:
if (term->grid == &term->alt) { if (term->grid == &term->alt) {
if (term->alt_scrolling) { if (term->alt_scrolling)
alternate_scroll(seat, amount, BTN_BACK); alternate_scroll(seat, amount, BTN_BACK);
return true; } else
} cmd_scrollback_up(term, amount);
} else {
cmd_scrollback_up(term, amount);
return true;
}
break; break;
case BIND_ACTION_SCROLLBACK_DOWN_PAGE: case BIND_ACTION_SCROLLBACK_DOWN_PAGE:
@ -153,14 +148,10 @@ execute_binding(struct seat *seat, struct terminal *term,
case BIND_ACTION_SCROLLBACK_DOWN_MOUSE: case BIND_ACTION_SCROLLBACK_DOWN_MOUSE:
if (term->grid == &term->alt) { if (term->grid == &term->alt) {
if (term->alt_scrolling) { if (term->alt_scrolling)
alternate_scroll(seat, amount, BTN_FORWARD); alternate_scroll(seat, amount, BTN_FORWARD);
return true; } else
}
} else {
cmd_scrollback_down(term, amount); cmd_scrollback_down(term, amount);
return true;
}
break; break;
case BIND_ACTION_SCROLLBACK_HOME: case BIND_ACTION_SCROLLBACK_HOME:
@ -493,20 +484,6 @@ execute_binding(struct seat *seat, struct terminal *term,
return true; return true;
case BIND_ACTION_THEME_SWITCH_1:
case BIND_ACTION_THEME_SWITCH_DARK:
term_theme_switch_to_dark(term);
return true;
case BIND_ACTION_THEME_SWITCH_2:
case BIND_ACTION_THEME_SWITCH_LIGHT:
term_theme_switch_to_light(term);
return true;
case BIND_ACTION_THEME_TOGGLE:
term_theme_toggle(term);
return true;
case BIND_ACTION_SELECT_BEGIN: case BIND_ACTION_SELECT_BEGIN:
selection_start( selection_start(
term, seat->mouse.col, seat->mouse.row, SELECTION_CHAR_WISE, false); term, seat->mouse.col, seat->mouse.row, SELECTION_CHAR_WISE, false);
@ -543,7 +520,7 @@ execute_binding(struct seat *seat, struct terminal *term,
case BIND_ACTION_SELECT_QUOTE: case BIND_ACTION_SELECT_QUOTE:
selection_start( selection_start(
term, seat->mouse.col, seat->mouse.row, SELECTION_QUOTE_WISE, false); term, seat->mouse.col, seat->mouse.row, SELECTION_QUOTE_WISE, false);
return true; break;
case BIND_ACTION_SELECT_ROW: case BIND_ACTION_SELECT_ROW:
selection_start( selection_start(
@ -586,20 +563,23 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
/* Verify keymap is in a format we understand */ /* Verify keymap is in a format we understand */
switch ((enum wl_keyboard_keymap_format)format) { switch ((enum wl_keyboard_keymap_format)format) {
case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP:
goto err; close(fd);
return;
case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1: case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1:
break; break;
default: default:
LOG_WARN("unrecognized keymap format: %u", format); LOG_WARN("unrecognized keymap format: %u", format);
goto err; close(fd);
return;
} }
char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (map_str == MAP_FAILED) { if (map_str == MAP_FAILED) {
LOG_ERRNO("failed to mmap keyboard keymap"); LOG_ERRNO("failed to mmap keyboard keymap");
goto err; close(fd);
return;
} }
while (map_str[size - 1] == '\0') while (map_str[size - 1] == '\0')
@ -612,8 +592,6 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
} }
munmap(map_str, size);
if (seat->kbd.xkb_keymap != NULL) { if (seat->kbd.xkb_keymap != NULL) {
seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap); seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap);
@ -694,10 +672,10 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN"); seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN");
} }
key_binding_load_keymap(wayl->key_binding_manager, seat); munmap(map_str, size);
err:
close(fd); close(fd);
key_binding_load_keymap(wayl->key_binding_manager, seat);
} }
static void static void
@ -1605,9 +1583,6 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
if (released) if (released)
stop_repeater(seat, key); stop_repeater(seat, key);
if (pressed)
seat->kbd.last_shortcut_sym = XKB_KEYSYM_MAX + 1;
bool should_repeat = bool should_repeat =
pressed && xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key); pressed && xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key);
@ -1709,7 +1684,6 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
if (bind->k.sym == raw_syms[i] && if (bind->k.sym == raw_syms[i] &&
execute_binding(seat, term, bind, serial, 1)) execute_binding(seat, term, bind, serial, 1))
{ {
seat->kbd.last_shortcut_sym = sym;
goto maybe_repeat; goto maybe_repeat;
} }
} }
@ -1723,7 +1697,6 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
bind->mods == (mods & ~consumed) && bind->mods == (mods & ~consumed) &&
execute_binding(seat, term, bind, serial, 1)) execute_binding(seat, term, bind, serial, 1))
{ {
seat->kbd.last_shortcut_sym = sym;
goto maybe_repeat; goto maybe_repeat;
} }
} }
@ -1739,31 +1712,12 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
if (code->item == key && if (code->item == key &&
execute_binding(seat, term, bind, serial, 1)) execute_binding(seat, term, bind, serial, 1))
{ {
seat->kbd.last_shortcut_sym = sym;
goto maybe_repeat; goto maybe_repeat;
} }
} }
} }
} }
if (released && seat->kbd.last_shortcut_sym == sym) {
/*
* Don't process a release event, if it corresponds to a
* triggered shortcut.
*
* 1. If we consumed a key (press) event, we shouldn't emit an
* escape for its release event.
* 2. Ignoring the incorrectness of doing so; this also caused
* us to reset the viewport.
*
* Background: if the kitty keyboard protocol was enabled,
* then the viewport was instantly reset to the bottom, after
* scrolling up.
*/
//seat->kbd.last_shortcut_sym = XKB_KEYSYM_MAX + 1;
goto maybe_repeat;
}
/* /*
* Keys generating escape sequences * Keys generating escape sequences
*/ */
@ -1911,7 +1865,7 @@ keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
UNITTEST UNITTEST
{ {
int chan[2]; int chan[2];
xassert(pipe2(chan, O_CLOEXEC) == 0); pipe2(chan, O_CLOEXEC);
xassert(chan[0] >= 0); xassert(chan[0] >= 0);
xassert(chan[1] >= 0); xassert(chan[1] >= 0);

View file

@ -11,7 +11,6 @@
#include "terminal.h" #include "terminal.h"
#include "util.h" #include "util.h"
#include "wayland.h" #include "wayland.h"
#include "xkbcommon-vmod.h"
#include "xmalloc.h" #include "xmalloc.h"
struct vmod_map { struct vmod_map {

View file

@ -43,11 +43,6 @@ enum bind_action_normal {
BIND_ACTION_QUIT, BIND_ACTION_QUIT,
BIND_ACTION_REGEX_LAUNCH, BIND_ACTION_REGEX_LAUNCH,
BIND_ACTION_REGEX_COPY, BIND_ACTION_REGEX_COPY,
BIND_ACTION_THEME_SWITCH_1,
BIND_ACTION_THEME_SWITCH_2,
BIND_ACTION_THEME_SWITCH_DARK,
BIND_ACTION_THEME_SWITCH_LIGHT,
BIND_ACTION_THEME_TOGGLE,
/* Mouse specific actions - i.e. they require a mouse coordinate */ /* Mouse specific actions - i.e. they require a mouse coordinate */
BIND_ACTION_SCROLLBACK_UP_MOUSE, BIND_ACTION_SCROLLBACK_UP_MOUSE,
@ -61,7 +56,7 @@ enum bind_action_normal {
BIND_ACTION_SELECT_QUOTE, BIND_ACTION_SELECT_QUOTE,
BIND_ACTION_SELECT_ROW, BIND_ACTION_SELECT_ROW,
BIND_ACTION_KEY_COUNT = BIND_ACTION_THEME_TOGGLE + 1, BIND_ACTION_KEY_COUNT = BIND_ACTION_REGEX_COPY + 1,
BIND_ACTION_COUNT = BIND_ACTION_SELECT_ROW + 1, BIND_ACTION_COUNT = BIND_ACTION_SELECT_ROW + 1,
}; };

48
main.c
View file

@ -45,33 +45,6 @@ fdm_sigint(struct fdm *fdm, int signo, void *data)
return true; return true;
} }
struct sigusr_context {
struct terminal *term;
struct server *server;
};
static bool
fdm_sigusr(struct fdm *fdm, int signo, void *data)
{
xassert(signo == SIGUSR1 || signo == SIGUSR2);
struct sigusr_context *ctx = data;
if (ctx->server != NULL) {
if (signo == SIGUSR1)
server_global_theme_switch_to_dark(ctx->server);
else
server_global_theme_switch_to_light(ctx->server);
} else {
if (signo == SIGUSR1)
term_theme_switch_to_dark(ctx->term);
else
term_theme_switch_to_light(ctx->term);
}
return true;
}
static void static void
print_usage(const char *prog_name) print_usage(const char *prog_name)
{ {
@ -84,7 +57,6 @@ print_usage(const char *prog_name)
" -t,--term=TERM value to set the environment variable TERM to (" FOOT_DEFAULT_TERM ")\n" " -t,--term=TERM value to set the environment variable TERM to (" FOOT_DEFAULT_TERM ")\n"
" -T,--title=TITLE initial window title (foot)\n" " -T,--title=TITLE initial window title (foot)\n"
" -a,--app-id=ID window application ID (foot)\n" " -a,--app-id=ID window application ID (foot)\n"
" --toplevel-tag=TAG set a custom toplevel tag\n"
" -m,--maximized start in maximized mode\n" " -m,--maximized start in maximized mode\n"
" -F,--fullscreen start in fullscreen mode\n" " -F,--fullscreen start in fullscreen mode\n"
" -L,--login-shell start shell as a login shell\n" " -L,--login-shell start shell as a login shell\n"
@ -186,7 +158,6 @@ sanitize_signals(void)
enum { enum {
PTY_OPTION = CHAR_MAX + 1, PTY_OPTION = CHAR_MAX + 1,
TOPLEVEL_TAG_OPTION = CHAR_MAX + 2,
}; };
int int
@ -216,7 +187,6 @@ main(int argc, char *const *argv)
{"term", required_argument, NULL, 't'}, {"term", required_argument, NULL, 't'},
{"title", required_argument, NULL, 'T'}, {"title", required_argument, NULL, 'T'},
{"app-id", required_argument, NULL, 'a'}, {"app-id", required_argument, NULL, 'a'},
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
{"login-shell", no_argument, NULL, 'L'}, {"login-shell", no_argument, NULL, 'L'},
{"working-directory", required_argument, NULL, 'D'}, {"working-directory", required_argument, NULL, 'D'},
{"font", required_argument, NULL, 'f'}, {"font", required_argument, NULL, 'f'},
@ -288,10 +258,6 @@ main(int argc, char *const *argv)
tll_push_back(overrides, xstrjoin("app-id=", optarg)); tll_push_back(overrides, xstrjoin("app-id=", optarg));
break; break;
case TOPLEVEL_TAG_OPTION:
tll_push_back(overrides, xstrjoin("toplevel-tag=", optarg));
break;
case 'D': { case 'D': {
struct stat st; struct stat st;
if (stat(optarg, &st) < 0 || !(st.st_mode & S_IFDIR)) { if (stat(optarg, &st) < 0 || !(st.st_mode & S_IFDIR)) {
@ -604,7 +570,6 @@ main(int argc, char *const *argv)
} }
shm_set_max_pool_size(conf.tweak.max_shm_pool_size); shm_set_max_pool_size(conf.tweak.max_shm_pool_size);
shm_set_min_stride_alignment(conf.tweak.min_stride_alignment);
if ((fdm = fdm_init()) == NULL) if ((fdm = fdm_init()) == NULL)
goto out; goto out;
@ -643,17 +608,6 @@ main(int argc, char *const *argv)
goto out; goto out;
} }
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))
{
goto out;
}
struct sigaction sig_ign = {.sa_handler = SIG_IGN}; struct sigaction sig_ign = {.sa_handler = SIG_IGN};
sigemptyset(&sig_ign.sa_mask); sigemptyset(&sig_ign.sa_mask);
if (sigaction(SIGHUP, &sig_ign, NULL) < 0 || if (sigaction(SIGHUP, &sig_ign, NULL) < 0 ||
@ -689,8 +643,6 @@ out:
wayl_destroy(wayl); wayl_destroy(wayl);
key_binding_manager_destroy(key_binding_manager); key_binding_manager_destroy(key_binding_manager);
reaper_destroy(reaper); reaper_destroy(reaper);
fdm_signal_del(fdm, SIGUSR1);
fdm_signal_del(fdm, SIGUSR2);
fdm_signal_del(fdm, SIGTERM); fdm_signal_del(fdm, SIGTERM);
fdm_signal_del(fdm, SIGINT); fdm_signal_del(fdm, SIGINT);
fdm_destroy(fdm); fdm_destroy(fdm);

View file

@ -1,5 +1,5 @@
project('foot', 'c', project('foot', 'c',
version: '1.25.0', version: '1.22.3',
license: 'MIT', license: 'MIT',
meson_version: '>=0.59.0', meson_version: '>=0.59.0',
default_options: [ default_options: [
@ -25,12 +25,6 @@ if cc.has_function('execvpe',
add_project_arguments('-DEXECVPE', language: 'c') add_project_arguments('-DEXECVPE', language: 'c')
endif endif
if cc.has_function('sigabbrev_np',
args: ['-D_GNU_SOURCE'],
prefix: '#include <string.h>')
add_project_arguments('-DSIGABBREV_NP', language: 'c')
endif
utmp_backend = get_option('utmp-backend') utmp_backend = get_option('utmp-backend')
if utmp_backend == 'auto' if utmp_backend == 'auto'
host_os = host_machine.system() host_os = host_machine.system()
@ -53,7 +47,7 @@ if utmp_backend == 'none'
elif utmp_backend == 'libutempter' elif utmp_backend == 'libutempter'
utmp_add = 'add' utmp_add = 'add'
utmp_del = 'del' utmp_del = 'del'
utmp_del_have_argument = false utmp_del_have_argument = true
if utmp_default_helper_path == 'auto' if utmp_default_helper_path == 'auto'
utmp_default_helper_path = join_paths('/usr', get_option('libdir'), 'utempter', 'utempter') utmp_default_helper_path = join_paths('/usr', get_option('libdir'), 'utempter', 'utempter')
endif endif
@ -143,7 +137,7 @@ wayland_protocols = dependency('wayland-protocols', version: '>=1.41',
default_options: ['tests=false']) default_options: ['tests=false'])
wayland_client = dependency('wayland-client') wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor') wayland_cursor = dependency('wayland-cursor')
xkb = dependency('xkbcommon', version: '>=1.0.0') xkb = dependency('xkbcommon', version: '>=1.8.0')
fontconfig = dependency('fontconfig') fontconfig = dependency('fontconfig')
utf8proc = dependency('libutf8proc', required: get_option('grapheme-clustering')) utf8proc = dependency('libutf8proc', required: get_option('grapheme-clustering'))
@ -151,10 +145,6 @@ if utf8proc.found()
add_project_arguments('-DFOOT_GRAPHEME_CLUSTERING=1', language: 'c') add_project_arguments('-DFOOT_GRAPHEME_CLUSTERING=1', language: 'c')
endif endif
if pixman.version().version_compare('>=0.46.0')
add_project_arguments('-DHAVE_PIXMAN_RGBA_16', language: 'c')
endif
tllist = dependency('tllist', version: '>=1.1.0', fallback: 'tllist') tllist = dependency('tllist', version: '>=1.1.0', fallback: 'tllist')
fcft = dependency('fcft', version: ['>=3.3.1', '<4.0.0'], fallback: 'fcft') fcft = dependency('fcft', version: ['>=3.3.1', '<4.0.0'], fallback: 'fcft')
@ -182,12 +172,7 @@ wl_proto_xml = [
wayland_protocols_datadir / 'staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml', wayland_protocols_datadir / 'staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml',
wayland_protocols_datadir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml', wayland_protocols_datadir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml',
wayland_protocols_datadir / 'staging/color-management/color-management-v1.xml', wayland_protocols_datadir / 'staging/color-management/color-management-v1.xml',
] ]
if (wayland_protocols.version().version_compare('>=1.43'))
wl_proto_xml += [wayland_protocols_datadir / 'staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml']
add_project_arguments('-DHAVE_XDG_TOPLEVEL_TAG=1', language: 'c')
endif
foreach prot : wl_proto_xml foreach prot : wl_proto_xml
wl_proto_headers += custom_target( wl_proto_headers += custom_target(
@ -330,7 +315,6 @@ executable(
'url-mode.c', 'url-mode.h', 'url-mode.c', 'url-mode.h',
'user-notification.c', 'user-notification.h', 'user-notification.c', 'user-notification.h',
'wayland.c', 'wayland.h', 'shm-formats.h', 'wayland.c', 'wayland.h', 'shm-formats.h',
'xkbcommon-vmod.h',
srgb_funcs, wl_proto_src + wl_proto_headers, version, srgb_funcs, wl_proto_src + wl_proto_headers, version,
dependencies: [math, threads, libepoll, pixman, wayland_client, wayland_cursor, xkb, fontconfig, utf8proc, dependencies: [math, threads, libepoll, pixman, wayland_client, wayland_cursor, xkb, fontconfig, utf8proc,
tllist, fcft], tllist, fcft],

View file

@ -114,7 +114,7 @@ consume_stdout(struct notification *notif, bool eof)
while (left > 0) { while (left > 0) {
line = data; line = data;
size_t len = left; size_t len = left;
char *eol = (char *)memchr(line, '\n', left); char *eol = memchr(line, '\n', left);
if (eol != NULL) { if (eol != NULL) {
*eol = '\0'; *eol = '\0';

119
osc.c
View file

@ -73,19 +73,16 @@ osc_to_clipboard(struct terminal *term, const char *target,
} }
char *decoded = base64_decode(base64_data, NULL); char *decoded = base64_decode(base64_data, NULL);
if (decoded == NULL || decoded[0] == '\0') { if (decoded == NULL) {
if (decoded == NULL) { if (errno == EINVAL)
if (errno == EINVAL) LOG_WARN("OSC: invalid clipboard data: %s", base64_data);
LOG_WARN("OSC: invalid clipboard data: %s", base64_data); else
else LOG_ERRNO("base64_decode() failed");
LOG_ERRNO("base64_decode() failed");
}
if (to_clipboard) if (to_clipboard)
selection_clipboard_unset(seat); selection_clipboard_unset(seat);
if (to_primary) if (to_primary)
selection_primary_unset(seat); selection_primary_unset(seat);
free(decoded);
return; return;
} }
@ -513,7 +510,7 @@ osc_uri(struct terminal *term, char *string)
key_value = strtok_r(NULL, ":", &ctx)) key_value = strtok_r(NULL, ":", &ctx))
{ {
const char *key = key_value; const char *key = key_value;
char *operator = (char *)strchr(key_value, '='); char *operator = strchr(key_value, '=');
if (operator == NULL) if (operator == NULL)
continue; continue;
@ -525,14 +522,12 @@ osc_uri(struct terminal *term, char *string)
id = sdbm_hash(value); id = sdbm_hash(value);
} }
LOG_DBG("OSC-8: URL=%s, id=%" PRIu64, uri, id);
if (uri[0] == '\0') { if (uri[0] == '\0')
LOG_DBG("OSC-8: close");
term_osc8_close(term); term_osc8_close(term);
} else { else
LOG_DBG("OSC-8: URL=%s, id=%" PRIu64, uri, id);
term_osc8_open(term, id, uri); term_osc8_open(term, id, uri);
}
} }
static void static void
@ -1460,20 +1455,15 @@ osc_dispatch(struct terminal *term)
case 11: case 11:
term->colors.bg = color; term->colors.bg = color;
if (!have_alpha) { if (have_alpha) {
alpha = term->colors.active_theme == COLOR_THEME_DARK const bool changed = term->colors.alpha != alpha;
? term->conf->colors_dark.alpha term->colors.alpha = alpha;
: term->conf->colors_light.alpha;
if (changed) {
wayl_win_alpha_changed(term->window);
term_font_subpixel_changed(term);
}
} }
const bool changed = term->colors.alpha != alpha;
term->colors.alpha = alpha;
if (changed) {
wayl_win_alpha_changed(term->window);
term_font_subpixel_changed(term);
}
term_damage_color(term, COLOR_DEFAULT, 0); term_damage_color(term, COLOR_DEFAULT, 0);
term_damage_margins(term); term_damage_margins(term);
break; break;
@ -1485,10 +1475,12 @@ osc_dispatch(struct terminal *term)
case 17: case 17:
term->colors.selection_bg = color; term->colors.selection_bg = color;
term->colors.use_custom_selection = true;
break; break;
case 19: case 19:
term->colors.selection_fg = color; term->colors.selection_fg = color;
term->colors.use_custom_selection = true;
break; break;
} }
@ -1517,14 +1509,10 @@ osc_dispatch(struct terminal *term)
case 104: { case 104: {
/* Reset Color Number 'c' (whole table if no parameter) */ /* Reset Color Number 'c' (whole table if no parameter) */
const struct color_theme *theme =
term->colors.active_theme == COLOR_THEME_DARK
? &term->conf->colors_dark
: &term->conf->colors_light;
if (string[0] == '\0') { if (string[0] == '\0') {
LOG_DBG("resetting all colors"); LOG_DBG("resetting all colors");
memcpy(term->colors.table, theme->table, sizeof(term->colors.table)); for (size_t i = 0; i < ALEN(term->colors.table); i++)
term->colors.table[i] = term->conf->colors.table[i];
term_damage_view(term); term_damage_view(term);
} }
@ -1546,7 +1534,7 @@ osc_dispatch(struct terminal *term)
} }
LOG_DBG("resetting color #%u", idx); LOG_DBG("resetting color #%u", idx);
term->colors.table[idx] = theme->table[idx]; term->colors.table[idx] = term->conf->colors.table[idx];
term_damage_color(term, COLOR_BASE256, idx); term_damage_color(term, COLOR_BASE256, idx);
} }
@ -1559,28 +1547,16 @@ osc_dispatch(struct terminal *term)
case 110: /* Reset default text foreground color */ case 110: /* Reset default text foreground color */
LOG_DBG("resetting foreground color"); LOG_DBG("resetting foreground color");
term->colors.fg = term->conf->colors.fg;
const struct color_theme *theme =
term->colors.active_theme == COLOR_THEME_DARK
? &term->conf->colors_dark
: &term->conf->colors_light;
term->colors.fg = theme->fg;
term_damage_color(term, COLOR_DEFAULT, 0); term_damage_color(term, COLOR_DEFAULT, 0);
break; break;
case 111: { /* Reset default text background color */ case 111: { /* Reset default text background color */
LOG_DBG("resetting background color"); LOG_DBG("resetting background color");
bool alpha_changed = term->colors.alpha != term->conf->colors.alpha;
const struct color_theme *theme = term->colors.bg = term->conf->colors.bg;
term->colors.active_theme == COLOR_THEME_DARK term->colors.alpha = term->conf->colors.alpha;
? &term->conf->colors_dark
: &term->conf->colors_light;
bool alpha_changed = term->colors.alpha != theme->alpha;
term->colors.bg = theme->bg;
term->colors.alpha = theme->alpha;
if (alpha_changed) { if (alpha_changed) {
wayl_win_alpha_changed(term->window); wayl_win_alpha_changed(term->window);
@ -1592,49 +1568,24 @@ osc_dispatch(struct terminal *term)
break; break;
} }
case 112: { case 112:
LOG_DBG("resetting cursor color"); LOG_DBG("resetting cursor color");
term->colors.cursor_fg = term->conf->cursor.color.text;
const struct color_theme *theme = term->colors.cursor_bg = term->conf->cursor.color.cursor;
term->colors.active_theme == COLOR_THEME_DARK
? &term->conf->colors_dark
: &term->conf->colors_light;
term->colors.cursor_fg = theme->cursor.text;
term->colors.cursor_bg = theme->cursor.cursor;
if (term->conf->colors_dark.use_custom.cursor) {
term->colors.cursor_fg |= 1u << 31;
term->colors.cursor_bg |= 1u << 31;
}
term_damage_cursor(term); term_damage_cursor(term);
break; break;
}
case 117: { case 117:
LOG_DBG("resetting selection background color"); LOG_DBG("resetting selection background color");
term->colors.selection_bg = term->conf->colors.selection_bg;
const struct color_theme *theme = term->colors.use_custom_selection = term->conf->colors.use_custom.selection;
term->colors.active_theme == COLOR_THEME_DARK
? &term->conf->colors_dark
: &term->conf->colors_light;
term->colors.selection_bg = theme->selection_bg;
break; break;
}
case 119: { case 119:
LOG_DBG("resetting selection foreground color"); LOG_DBG("resetting selection foreground color");
term->colors.selection_fg = term->conf->colors.selection_fg;
const struct color_theme *theme = term->colors.use_custom_selection = term->conf->colors.use_custom.selection;
term->colors.active_theme == COLOR_THEME_DARK
? &term->conf->colors_dark
: &term->conf->colors_light;
term->colors.selection_fg = theme->selection_fg;
break; break;
}
case 133: case 133:
/* /*

View file

@ -74,8 +74,6 @@ void render_refresh_icon(struct terminal *term) {}
void render_overlay(struct terminal *term) {} void render_overlay(struct terminal *term) {}
void render_buffer_release_callback(struct buffer *buf, void *data) {}
bool bool
render_xcursor_is_valid(const struct seat *seat, const char *cursor) render_xcursor_is_valid(const struct seat *seat, const char *cursor)
{ {
@ -208,8 +206,7 @@ enum shm_bit_depth shm_chain_bit_depth(const struct buffer_chain *chain) { retur
struct buffer_chain * struct buffer_chain *
shm_chain_new( shm_chain_new(
struct wayland *wayl, bool scrollable, size_t pix_instances, struct wayland *wayl, bool scrollable, size_t pix_instances,
enum shm_bit_depth desired_bit_depth, enum shm_bit_depth desired_bit_depth)
void (*release_cb)(struct buffer *buf, void *data), void *cb_data)
{ {
return NULL; return NULL;
} }

View file

@ -1,10 +0,0 @@
[tool.pyright]
strict = ['scripts']
[tool.mypy]
files = '$MYPY_CONFIG_FILE_DIR/scripts'
strict = true
[tool.codespell]
skip = 'pyproject.toml,./subprojects,./pkg,./src,./bld,foot.info,./unicode,./venv'
ignore-regex = 'terminfo capability `rin`|\* Simon Ser|\* \[zar\]\(https://codeberg.org/zar\)|iterm theme|iterm.toml|iterm/OneHalfDark.itermcolors'

View file

@ -67,7 +67,6 @@ quirk_weston_csd_off(struct terminal *term)
quirk_weston_subsurface_desync_off(term->window->csd.surface[i].sub); quirk_weston_subsurface_desync_off(term->window->csd.surface[i].sub);
} }
#if 0
static bool static bool
is_sway(void) is_sway(void)
{ {
@ -83,4 +82,13 @@ is_sway(void)
return is_sway; return is_sway;
} }
#endif
void
quirk_sway_subsurface_unmap(struct terminal *term)
{
return;
if (!is_sway())
return;
wl_surface_damage_buffer(term->window->surface.surf, 0, 0, INT32_MAX, INT32_MAX);
}

View file

@ -21,3 +21,5 @@ void quirk_weston_subsurface_desync_off(struct wl_subsurface *sub);
/* Shortcuts to call desync_{on,off} on all CSD subsurfaces */ /* Shortcuts to call desync_{on,off} on all CSD subsurfaces */
void quirk_weston_csd_on(struct terminal *term); void quirk_weston_csd_on(struct terminal *term);
void quirk_weston_csd_off(struct terminal *term); void quirk_weston_csd_off(struct terminal *term);
void quirk_sway_subsurface_unmap(struct terminal *term);

440
render.c
View file

@ -293,7 +293,7 @@ static inline uint32_t
color_dim(const struct terminal *term, uint32_t color) color_dim(const struct terminal *term, uint32_t color)
{ {
const struct config *conf = term->conf; const struct config *conf = term->conf;
const uint8_t custom_dim = conf->colors_dark.use_custom.dim; const uint8_t custom_dim = conf->colors.use_custom.dim;
if (unlikely(custom_dim != 0)) { if (unlikely(custom_dim != 0)) {
for (size_t i = 0; i < 8; i++) { for (size_t i = 0; i < 8; i++) {
@ -302,7 +302,7 @@ color_dim(const struct terminal *term, uint32_t color)
if (term->colors.table[0 + i] == color) { if (term->colors.table[0 + i] == color) {
/* "Regular" color, return the corresponding "dim" */ /* "Regular" color, return the corresponding "dim" */
return conf->colors_dark.dim[i]; return conf->colors.dim[i];
} }
else if (term->colors.table[8 + i] == color) { else if (term->colors.table[8 + i] == color) {
@ -312,14 +312,7 @@ color_dim(const struct terminal *term, uint32_t color)
} }
} }
const struct color_theme *theme = term->colors.active_theme == COLOR_THEME_DARK return color_blend_towards(color, 0x00000000, conf->dim.amount);
? &conf->colors_dark
: &conf->colors_light;
return color_blend_towards(
color,
theme->dim_blend_towards == DIM_BLEND_TOWARDS_BLACK ? 0x00000000 : 0x00ffffff,
conf->dim.amount);
} }
static inline uint32_t static inline uint32_t
@ -701,82 +694,58 @@ render_cell(struct terminal *term, pixman_image_t *pix,
const int x = term->margins.left + col * width; const int x = term->margins.left + col * width;
const int y = term->margins.top + row_no * height; const int y = term->margins.top + row_no * height;
bool is_selected = cell->attrs.selected;
uint32_t _fg = 0; uint32_t _fg = 0;
uint32_t _bg = 0; uint32_t _bg = 0;
uint16_t alpha = 0xffff; uint16_t alpha = 0xffff;
const bool is_selected = cell->attrs.selected;
/* Use cell specific color, if set, otherwise the default colors (possible reversed) */
switch (cell->attrs.fg_src) {
case COLOR_RGB:
_fg = cell->attrs.fg;
break;
case COLOR_BASE16:
case COLOR_BASE256:
xassert(cell->attrs.fg < ALEN(term->colors.table));
_fg = term->colors.table[cell->attrs.fg];
break;
case COLOR_DEFAULT:
_fg = term->reverse ? term->colors.bg : term->colors.fg;
break;
}
switch (cell->attrs.bg_src) {
case COLOR_RGB:
_bg = cell->attrs.bg;
break;
case COLOR_BASE16:
case COLOR_BASE256:
xassert(cell->attrs.bg < ALEN(term->colors.table));
_bg = term->colors.table[cell->attrs.bg];
break;
case COLOR_DEFAULT:
_bg = term->reverse ? term->colors.fg : term->colors.bg;
break;
}
if (unlikely(is_selected)) {
const uint32_t cell_fg = _fg;
const uint32_t cell_bg = _bg;
const bool custom_fg = term->colors.selection_fg >> 24 == 0;
const bool custom_bg = term->colors.selection_bg >> 24 == 0;
const bool custom_both = custom_fg && custom_bg;
if (custom_both) {
_fg = term->colors.selection_fg;
_bg = term->colors.selection_bg;
} else if (custom_bg) {
_bg = term->colors.selection_bg;
_fg = cell->attrs.reverse ? cell_bg : cell_fg;
} else if (custom_fg) {
_fg = term->colors.selection_fg;
_bg = cell->attrs.reverse ? cell_fg : cell_bg;
} else {
_bg = cell_fg;
_fg = cell_bg;
}
if (unlikely(_fg == _bg)) {
/* Invert bg when selected/highlighted text has same fg/bg */
_bg = ~_bg;
alpha = 0xffff;
}
if (is_selected && term->colors.use_custom_selection) {
_fg = term->colors.selection_fg;
_bg = term->colors.selection_bg;
} else { } else {
if (unlikely(cell->attrs.reverse)) { /* Use cell specific color, if set, otherwise the default colors (possible reversed) */
switch (cell->attrs.fg_src) {
case COLOR_RGB:
_fg = cell->attrs.fg;
break;
case COLOR_BASE16:
case COLOR_BASE256:
xassert(cell->attrs.fg < ALEN(term->colors.table));
_fg = term->colors.table[cell->attrs.fg];
break;
case COLOR_DEFAULT:
_fg = term->reverse ? term->colors.bg : term->colors.fg;
break;
}
switch (cell->attrs.bg_src) {
case COLOR_RGB:
_bg = cell->attrs.bg;
break;
case COLOR_BASE16:
case COLOR_BASE256:
xassert(cell->attrs.bg < ALEN(term->colors.table));
_bg = term->colors.table[cell->attrs.bg];
break;
case COLOR_DEFAULT:
_bg = term->reverse ? term->colors.fg : term->colors.bg;
break;
}
if (cell->attrs.reverse ^ is_selected) {
uint32_t swap = _fg; uint32_t swap = _fg;
_fg = _bg; _fg = _bg;
_bg = swap; _bg = swap;
} }
else if (!term->window->is_fullscreen && term->colors.alpha != 0xffff) { else if (!term->window->is_fullscreen && term->colors.alpha != 0xffff) {
switch (term->conf->colors_dark.alpha_mode) { switch (term->conf->colors.alpha_mode) {
case ALPHA_MODE_DEFAULT: { case ALPHA_MODE_DEFAULT: {
if (cell->attrs.bg_src == COLOR_DEFAULT) { if (cell->attrs.bg_src == COLOR_DEFAULT) {
alpha = term->colors.alpha; alpha = term->colors.alpha;
@ -837,6 +806,12 @@ render_cell(struct terminal *term, pixman_image_t *pix,
} }
} }
if (unlikely(is_selected && _fg == _bg)) {
/* Invert bg when selected/highlighted text has same fg/bg */
_bg = ~_bg;
alpha = 0xffff;
}
if (cell->attrs.dim) if (cell->attrs.dim)
_fg = color_dim(term, _fg); _fg = color_dim(term, _fg);
if (term->conf->bold_in_bright.enabled && cell->attrs.bold) if (term->conf->bold_in_bright.enabled && cell->attrs.bold)
@ -1175,8 +1150,8 @@ render_cell(struct terminal *term, pixman_image_t *pix,
if (unlikely(cell->attrs.url)) { if (unlikely(cell->attrs.url)) {
pixman_color_t url_color = color_hex_to_pixman( pixman_color_t url_color = color_hex_to_pixman(
term->conf->colors_dark.use_custom.url term->conf->colors.use_custom.url
? term->conf->colors_dark.url ? term->conf->colors.url
: term->colors.table[3], : term->colors.table[3],
gamma_correct); gamma_correct);
draw_underline(term, pix, font, &url_color, x, y, cell_cols); draw_underline(term, pix, font, &url_color, x, y, cell_cols);
@ -1977,6 +1952,10 @@ render_overlay(struct terminal *term)
wl_surface_commit(overlay->surface.surf); wl_surface_commit(overlay->surface.surf);
term->render.last_overlay_style = OVERLAY_NONE; term->render.last_overlay_style = OVERLAY_NONE;
term->render.last_overlay_buf = NULL; term->render.last_overlay_buf = NULL;
/* Work around Sway bug - unmapping a sub-surface does not
* damage the underlying surface */
quirk_sway_subsurface_unmap(term);
} }
return; return;
} }
@ -1991,8 +1970,8 @@ render_overlay(struct terminal *term)
case OVERLAY_FLASH: case OVERLAY_FLASH:
color = color_hex_to_pixman_with_alpha( color = color_hex_to_pixman_with_alpha(
term->conf->colors_dark.flash, term->conf->colors.flash,
term->conf->colors_dark.flash_alpha, term->conf->colors.flash_alpha,
wayl_do_linear_blending(term->wl, term->conf)); wayl_do_linear_blending(term->wl, term->conf));
break; break;
@ -2012,7 +1991,7 @@ render_overlay(struct terminal *term)
} }
struct buffer *buf = shm_get_buffer( struct buffer *buf = shm_get_buffer(
term->render.chains.overlay, term->width, term->height); term->render.chains.overlay, term->width, term->height, true);
pixman_image_set_clip_region32(buf->pix[0], NULL); pixman_image_set_clip_region32(buf->pix[0], NULL);
/* Bounding rectangle of damaged areas - for wl_surface_damage_buffer() */ /* Bounding rectangle of damaged areas - for wl_surface_damage_buffer() */
@ -2231,56 +2210,6 @@ render_worker_thread(void *_ctx)
case -2: case -2:
return 0; return 0;
case -3: {
if (term->conf->tweak.render_timer != RENDER_TIMER_NONE)
clock_gettime(CLOCK_MONOTONIC, &term->render.workers.preapplied_damage.start);
mtx_lock(&term->render.workers.preapplied_damage.lock);
buf = term->render.workers.preapplied_damage.buf;
xassert(buf != NULL);
if (likely(term->render.last_buf != NULL)) {
mtx_unlock(&term->render.workers.preapplied_damage.lock);
pixman_region32_t dmg;
pixman_region32_init(&dmg);
if (buf->age == 0)
; /* No need to do anything */
else if (buf->age == 1)
pixman_region32_copy(&dmg,
&term->render.last_buf->dirty[0]);
else
pixman_region32_init_rect(&dmg, 0, 0, buf->width,
buf->height);
pixman_image_set_clip_region32(buf->pix[my_id], &dmg);
pixman_image_composite32(PIXMAN_OP_SRC,
term->render.last_buf->pix[my_id],
NULL, buf->pix[my_id], 0, 0, 0, 0, 0,
0, buf->width, buf->height);
pixman_region32_fini(&dmg);
buf->age = 0;
shm_unref(term->render.last_buf);
shm_addref(buf);
term->render.last_buf = buf;
mtx_lock(&term->render.workers.preapplied_damage.lock);
}
term->render.workers.preapplied_damage.buf = NULL;
cnd_signal(&term->render.workers.preapplied_damage.cond);
mtx_unlock(&term->render.workers.preapplied_damage.lock);
if (term->conf->tweak.render_timer != RENDER_TIMER_NONE)
clock_gettime(CLOCK_MONOTONIC, &term->render.workers.preapplied_damage.stop);
frame_done = true;
break;
}
} }
} }
}; };
@ -2288,22 +2217,6 @@ render_worker_thread(void *_ctx)
return -1; return -1;
} }
void
render_wait_for_preapply_damage(struct terminal *term)
{
if (!term->render.preapply_last_frame_damage)
return;
if (term->render.workers.preapplied_damage.buf == NULL)
return;
mtx_lock(&term->render.workers.preapplied_damage.lock);
while (term->render.workers.preapplied_damage.buf != NULL) {
cnd_wait(&term->render.workers.preapplied_damage.cond,
&term->render.workers.preapplied_damage.lock);
}
mtx_unlock(&term->render.workers.preapplied_damage.lock);
}
struct csd_data struct csd_data
get_csd_data(const struct terminal *term, enum csd_surface surf_idx) get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
{ {
@ -2323,21 +2236,16 @@ get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
const int button_width = title_visible const int button_width = title_visible
? roundf(term->conf->csd.button_width * scale) : 0; ? roundf(term->conf->csd.button_width * scale) : 0;
int remaining_width = term->width; const int button_close_width = term->width >= 1 * button_width
? button_width : 0;
const int button_close_width = remaining_width >= button_width ? button_width : 0; const int button_maximize_width =
remaining_width -= button_close_width; term->width >= 2 * button_width && term->window->wm_capabilities.maximize
const int button_close_start = remaining_width; ? button_width : 0;
const int button_maximize_width = remaining_width >= button_width && const int button_minimize_width =
term->window->wm_capabilities.maximize ? button_width : 0; term->width >= 3 * button_width && term->window->wm_capabilities.minimize
remaining_width -= button_maximize_width; ? button_width : 0;
const int button_maximize_start = remaining_width;
const int button_minimize_width = remaining_width >= button_width &&
term->window->wm_capabilities.minimize ? button_width : 0;
remaining_width -= button_minimize_width;
const int button_minimize_start = remaining_width;
/* /*
* With fractional scaling, we must ensure the offset, when * With fractional scaling, we must ensure the offset, when
@ -2362,9 +2270,9 @@ get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
case CSD_SURF_BOTTOM: return (struct csd_data){-border_width, term->height, top_bottom_width, border_width}; case CSD_SURF_BOTTOM: return (struct csd_data){-border_width, term->height, top_bottom_width, border_width};
/* Positioned relative to CSD_SURF_TITLE */ /* Positioned relative to CSD_SURF_TITLE */
case CSD_SURF_MINIMIZE: return (struct csd_data){button_minimize_start, 0, button_minimize_width, title_height}; case CSD_SURF_MINIMIZE: return (struct csd_data){term->width - 3 * button_width, 0, button_minimize_width, title_height};
case CSD_SURF_MAXIMIZE: return (struct csd_data){button_maximize_start, 0, button_maximize_width, title_height}; case CSD_SURF_MAXIMIZE: return (struct csd_data){term->width - 2 * button_width, 0, button_maximize_width, title_height};
case CSD_SURF_CLOSE: return (struct csd_data){ button_close_start, 0, button_close_width, title_height}; case CSD_SURF_CLOSE: return (struct csd_data){term->width - 1 * button_width, 0, button_close_width, title_height};
case CSD_SURF_COUNT: case CSD_SURF_COUNT:
break; break;
@ -2510,10 +2418,10 @@ render_csd_title(struct terminal *term, const struct csd_data *info,
uint32_t bg = term->conf->csd.color.title_set uint32_t bg = term->conf->csd.color.title_set
? term->conf->csd.color.title ? term->conf->csd.color.title
: 0xffu << 24 | term->conf->colors_dark.fg; : 0xffu << 24 | term->conf->colors.fg;
uint32_t fg = term->conf->csd.color.buttons_set uint32_t fg = term->conf->csd.color.buttons_set
? term->conf->csd.color.buttons ? term->conf->csd.color.buttons
: term->conf->colors_dark.bg; : term->conf->colors.bg;
if (!term->visual_focus) { if (!term->visual_focus) {
bg = color_dim(term, bg); bg = color_dim(term, bg);
@ -2607,7 +2515,7 @@ render_csd_border(struct terminal *term, enum csd_surface surf_idx,
uint32_t _color = uint32_t _color =
conf->csd.color.border_set ? conf->csd.color.border : conf->csd.color.border_set ? conf->csd.color.border :
conf->csd.color.title_set ? conf->csd.color.title : conf->csd.color.title_set ? conf->csd.color.title :
0xffu << 24 | term->conf->colors_dark.fg; 0xffu << 24 | term->conf->colors.fg;
if (!term->visual_focus) if (!term->visual_focus)
_color = color_dim(term, _color); _color = color_dim(term, _color);
@ -2627,7 +2535,7 @@ static pixman_color_t
get_csd_button_fg_color(const struct terminal *term) get_csd_button_fg_color(const struct terminal *term)
{ {
const struct config *conf = term->conf; const struct config *conf = term->conf;
uint32_t _color = conf->colors_dark.bg; uint32_t _color = conf->colors.bg;
uint16_t alpha = 0xffff; uint16_t alpha = 0xffff;
if (conf->csd.color.buttons_set) { if (conf->csd.color.buttons_set) {
@ -2872,7 +2780,7 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx,
switch (surf_idx) { switch (surf_idx) {
case CSD_SURF_MINIMIZE: case CSD_SURF_MINIMIZE:
_color = term->conf->colors_dark.table[4]; /* blue */ _color = term->conf->colors.table[4]; /* blue */
is_set = term->conf->csd.color.minimize_set; is_set = term->conf->csd.color.minimize_set;
conf_color = &term->conf->csd.color.minimize; conf_color = &term->conf->csd.color.minimize;
is_active = term->active_surface == TERM_SURF_BUTTON_MINIMIZE && is_active = term->active_surface == TERM_SURF_BUTTON_MINIMIZE &&
@ -2880,7 +2788,7 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx,
break; break;
case CSD_SURF_MAXIMIZE: case CSD_SURF_MAXIMIZE:
_color = term->conf->colors_dark.table[2]; /* green */ _color = term->conf->colors.table[2]; /* green */
is_set = term->conf->csd.color.maximize_set; is_set = term->conf->csd.color.maximize_set;
conf_color = &term->conf->csd.color.maximize; conf_color = &term->conf->csd.color.maximize;
is_active = term->active_surface == TERM_SURF_BUTTON_MAXIMIZE && is_active = term->active_surface == TERM_SURF_BUTTON_MAXIMIZE &&
@ -2888,7 +2796,7 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx,
break; break;
case CSD_SURF_CLOSE: case CSD_SURF_CLOSE:
_color = term->conf->colors_dark.table[1]; /* red */ _color = term->conf->colors.table[1]; /* red */
is_set = term->conf->csd.color.close_set; is_set = term->conf->csd.color.close_set;
conf_color = &term->conf->csd.color.quit; conf_color = &term->conf->csd.color.quit;
is_active = term->active_surface == TERM_SURF_BUTTON_CLOSE && is_active = term->active_surface == TERM_SURF_BUTTON_CLOSE &&
@ -2970,7 +2878,7 @@ render_csd(struct terminal *term)
} }
struct buffer *bufs[CSD_SURF_COUNT]; struct buffer *bufs[CSD_SURF_COUNT];
shm_get_many(term->render.chains.csd, CSD_SURF_COUNT, widths, heights, bufs); shm_get_many(term->render.chains.csd, CSD_SURF_COUNT, widths, heights, bufs, true);
for (size_t i = CSD_SURF_LEFT; i <= CSD_SURF_BOTTOM; i++) for (size_t i = CSD_SURF_LEFT; i <= CSD_SURF_BOTTOM; i++)
render_csd_border(term, i, &infos[i], bufs[i]); render_csd_border(term, i, &infos[i], bufs[i]);
@ -2988,8 +2896,13 @@ render_scrollback_position(struct terminal *term)
struct wl_window *win = term->window; struct wl_window *win = term->window;
if (term->grid->view == term->grid->offset) { if (term->grid->view == term->grid->offset) {
if (win->scrollback_indicator.surface.surf != NULL) if (win->scrollback_indicator.surface.surf != NULL) {
wayl_win_subsurface_destroy(&win->scrollback_indicator); wayl_win_subsurface_destroy(&win->scrollback_indicator);
/* Work around Sway bug - unmapping a sub-surface does not damage
* the underlying surface */
quirk_sway_subsurface_unmap(term);
}
return; return;
} }
@ -3110,16 +3023,16 @@ render_scrollback_position(struct terminal *term)
} }
struct buffer_chain *chain = term->render.chains.scrollback_indicator; struct buffer_chain *chain = term->render.chains.scrollback_indicator;
struct buffer *buf = shm_get_buffer(chain, width, height); struct buffer *buf = shm_get_buffer(chain, width, height, false);
wl_subsurface_set_position( wl_subsurface_set_position(
win->scrollback_indicator.sub, roundf(x / scale), roundf(y / scale)); win->scrollback_indicator.sub, roundf(x / scale), roundf(y / scale));
uint32_t fg = term->colors.table[0]; uint32_t fg = term->colors.table[0];
uint32_t bg = term->colors.table[8 + 4]; uint32_t bg = term->colors.table[8 + 4];
if (term->conf->colors_dark.use_custom.scrollback_indicator) { if (term->conf->colors.use_custom.scrollback_indicator) {
fg = term->conf->colors_dark.scrollback_indicator.fg; fg = term->conf->colors.scrollback_indicator.fg;
bg = term->conf->colors_dark.scrollback_indicator.bg; bg = term->conf->colors.scrollback_indicator.bg;
} }
render_osd( render_osd(
@ -3153,7 +3066,7 @@ render_render_timer(struct terminal *term, struct timespec render_time)
height = roundf(scale * ceilf(height / scale)); height = roundf(scale * ceilf(height / scale));
struct buffer_chain *chain = term->render.chains.render_timer; struct buffer_chain *chain = term->render.chains.render_timer;
struct buffer *buf = shm_get_buffer(chain, width, height); struct buffer *buf = shm_get_buffer(chain, width, height, false);
wl_subsurface_set_position( wl_subsurface_set_position(
win->render_timer.sub, win->render_timer.sub,
@ -3186,6 +3099,14 @@ force_full_repaint(struct terminal *term, struct buffer *buf)
static void static void
reapply_old_damage(struct terminal *term, struct buffer *new, struct buffer *old) reapply_old_damage(struct terminal *term, struct buffer *new, struct buffer *old)
{ {
static int counter = 0;
static bool have_warned = false;
if (!have_warned && ++counter > 5) {
LOG_WARN("compositor is not releasing buffers immediately; "
"expect lower rendering performance");
have_warned = true;
}
if (new->age > 1) { if (new->age > 1) {
memcpy(new->data, old->data, new->height * new->stride); memcpy(new->data, old->data, new->height * new->stride);
return; return;
@ -3316,18 +3237,7 @@ grid_render(struct terminal *term)
if (term->shutdown.in_progress) if (term->shutdown.in_progress)
return; return;
struct timespec start_time; struct timespec start_time, start_double_buffering = {0}, stop_double_buffering = {0};
struct timespec start_wait_preapply = {0}, stop_wait_preapply = {0};
struct timespec start_double_buffering = {0}, stop_double_buffering = {0};
/* Might be a thread doing pre-applied damage */
if (unlikely(term->render.preapply_last_frame_damage &&
term->render.workers.preapplied_damage.buf != NULL))
{
clock_gettime(CLOCK_MONOTONIC, &start_wait_preapply);
render_wait_for_preapply_damage(term);
clock_gettime(CLOCK_MONOTONIC, &stop_wait_preapply);
}
if (term->conf->tweak.render_timer != RENDER_TIMER_NONE) if (term->conf->tweak.render_timer != RENDER_TIMER_NONE)
clock_gettime(CLOCK_MONOTONIC, &start_time); clock_gettime(CLOCK_MONOTONIC, &start_time);
@ -3336,14 +3246,15 @@ grid_render(struct terminal *term)
xassert(term->height > 0); xassert(term->height > 0);
struct buffer_chain *chain = term->render.chains.grid; struct buffer_chain *chain = term->render.chains.grid;
struct buffer *buf = shm_get_buffer(chain, term->width, term->height); bool use_alpha = !term->window->is_fullscreen &&
term->colors.alpha != 0xffff;
struct buffer *buf = shm_get_buffer(
chain, term->width, term->height, use_alpha);
/* Dirty old and current cursor cell, to ensure they're repainted */ /* Dirty old and current cursor cell, to ensure they're repainted */
dirty_old_cursor(term); dirty_old_cursor(term);
dirty_cursor(term); dirty_cursor(term);
LOG_DBG("buffer age: %u (%p)", buf->age, (void *)buf);
if (term->render.last_buf == NULL || if (term->render.last_buf == NULL ||
term->render.last_buf->width != buf->width || term->render.last_buf->width != buf->width ||
term->render.last_buf->height != buf->height || term->render.last_buf->height != buf->height ||
@ -3360,27 +3271,9 @@ grid_render(struct terminal *term)
xassert(term->render.last_buf->width == buf->width); xassert(term->render.last_buf->width == buf->width);
xassert(term->render.last_buf->height == buf->height); xassert(term->render.last_buf->height == buf->height);
if (++term->render.frames_since_last_immediate_release > 10) {
static bool have_warned = false;
if (!term->render.preapply_last_frame_damage &&
term->conf->tweak.preapply_damage &&
term->render.workers.count > 0)
{
LOG_INFO("enabling pre-applied frame damage");
term->render.preapply_last_frame_damage = true;
} else if (!have_warned && !term->render.preapply_last_frame_damage) {
LOG_WARN("compositor is not releasing buffers immediately; "
"expect lower rendering performance");
have_warned = true;
}
}
clock_gettime(CLOCK_MONOTONIC, &start_double_buffering); clock_gettime(CLOCK_MONOTONIC, &start_double_buffering);
reapply_old_damage(term, buf, term->render.last_buf); reapply_old_damage(term, buf, term->render.last_buf);
clock_gettime(CLOCK_MONOTONIC, &stop_double_buffering); clock_gettime(CLOCK_MONOTONIC, &stop_double_buffering);
} else if (!term->render.preapply_last_frame_damage) {
term->render.frames_since_last_immediate_release = 0;
} }
if (term->render.last_buf != NULL) { if (term->render.last_buf != NULL) {
@ -3608,40 +3501,27 @@ grid_render(struct terminal *term)
struct timespec end_time; struct timespec end_time;
clock_gettime(CLOCK_MONOTONIC, &end_time); clock_gettime(CLOCK_MONOTONIC, &end_time);
struct timespec wait_time;
timespec_sub(&stop_wait_preapply, &start_wait_preapply, &wait_time);
struct timespec render_time; struct timespec render_time;
timespec_sub(&end_time, &start_time, &render_time); timespec_sub(&end_time, &start_time, &render_time);
struct timespec double_buffering_time; struct timespec double_buffering_time;
timespec_sub(&stop_double_buffering, &start_double_buffering, &double_buffering_time); timespec_sub(&stop_double_buffering, &start_double_buffering, &double_buffering_time);
struct timespec preapply_damage;
timespec_sub(&term->render.workers.preapplied_damage.stop,
&term->render.workers.preapplied_damage.start,
&preapply_damage);
struct timespec total_render_time; struct timespec total_render_time;
timespec_add(&render_time, &double_buffering_time, &total_render_time); timespec_add(&render_time, &double_buffering_time, &total_render_time);
timespec_add(&wait_time, &total_render_time, &total_render_time);
switch (term->conf->tweak.render_timer) { switch (term->conf->tweak.render_timer) {
case RENDER_TIMER_LOG: case RENDER_TIMER_LOG:
case RENDER_TIMER_BOTH: case RENDER_TIMER_BOTH:
LOG_INFO( LOG_INFO(
"frame rendered in %lds %9ldns " "frame rendered in %lds %9ldns "
"(%lds %9ldns wait, %lds %9ldns rendering, %lds %9ldns double buffering) not included: %lds %ldns pre-apply damage", "(%lds %9ldns rendering, %lds %9ldns double buffering)",
(long)total_render_time.tv_sec, (long)total_render_time.tv_sec,
total_render_time.tv_nsec, total_render_time.tv_nsec,
(long)wait_time.tv_sec,
wait_time.tv_nsec,
(long)render_time.tv_sec, (long)render_time.tv_sec,
render_time.tv_nsec, render_time.tv_nsec,
(long)double_buffering_time.tv_sec, (long)double_buffering_time.tv_sec,
double_buffering_time.tv_nsec, double_buffering_time.tv_nsec);
(long)preapply_damage.tv_sec,
preapply_damage.tv_nsec);
break; break;
case RENDER_TIMER_OSD: case RENDER_TIMER_OSD:
@ -3784,7 +3664,7 @@ render_search_box(struct terminal *term)
size_t glyph_offset = term->render.search_glyph_offset; size_t glyph_offset = term->render.search_glyph_offset;
struct buffer_chain *chain = term->render.chains.search; struct buffer_chain *chain = term->render.chains.search;
struct buffer *buf = shm_get_buffer(chain, width, height); struct buffer *buf = shm_get_buffer(chain, width, height, true);
pixman_region32_t clip; pixman_region32_t clip;
pixman_region32_init_rect(&clip, 0, 0, width, height); pixman_region32_init_rect(&clip, 0, 0, width, height);
@ -3796,18 +3676,18 @@ render_search_box(struct terminal *term)
const bool is_match = term->search.match_len == text_len; const bool is_match = term->search.match_len == text_len;
const bool custom_colors = is_match const bool custom_colors = is_match
? term->conf->colors_dark.use_custom.search_box_match ? term->conf->colors.use_custom.search_box_match
: term->conf->colors_dark.use_custom.search_box_no_match; : term->conf->colors.use_custom.search_box_no_match;
/* Background - yellow on empty/match, red on mismatch (default) */ /* Background - yellow on empty/match, red on mismatch (default) */
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf); const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
const pixman_color_t color = color_hex_to_pixman( const pixman_color_t color = color_hex_to_pixman(
is_match is_match
? (custom_colors ? (custom_colors
? term->conf->colors_dark.search_box.match.bg ? term->conf->colors.search_box.match.bg
: term->colors.table[3]) : term->colors.table[3])
: (custom_colors : (custom_colors
? term->conf->colors_dark.search_box.no_match.bg ? term->conf->colors.search_box.no_match.bg
: term->colors.table[1]), : term->colors.table[1]),
gamma_correct); gamma_correct);
@ -3829,8 +3709,8 @@ render_search_box(struct terminal *term)
pixman_color_t fg = color_hex_to_pixman( pixman_color_t fg = color_hex_to_pixman(
custom_colors custom_colors
? (is_match ? (is_match
? term->conf->colors_dark.search_box.match.fg ? term->conf->colors.search_box.match.fg
: term->conf->colors_dark.search_box.no_match.fg) : term->conf->colors.search_box.no_match.fg)
: term->colors.table[0], : term->colors.table[0],
gamma_correct); gamma_correct);
@ -4249,13 +4129,13 @@ render_urls(struct terminal *term)
struct buffer_chain *chain = term->render.chains.url; struct buffer_chain *chain = term->render.chains.url;
struct buffer *bufs[render_count]; struct buffer *bufs[render_count];
shm_get_many(chain, render_count, widths, heights, bufs); shm_get_many(chain, render_count, widths, heights, bufs, false);
uint32_t fg = term->conf->colors_dark.use_custom.jump_label uint32_t fg = term->conf->colors.use_custom.jump_label
? term->conf->colors_dark.jump_label.fg ? term->conf->colors.jump_label.fg
: term->colors.table[0]; : term->colors.table[0];
uint32_t bg = term->conf->colors_dark.use_custom.jump_label uint32_t bg = term->conf->colors.use_custom.jump_label
? term->conf->colors_dark.jump_label.bg ? term->conf->colors.jump_label.bg
: term->colors.table[3]; : term->colors.table[3];
for (size_t i = 0; i < render_count; i++) { for (size_t i = 0; i < render_count; i++) {
@ -4401,7 +4281,6 @@ delayed_reflow_of_normal_grid(struct terminal *term)
term->interactive_resizing.old_hide_cursor = false; term->interactive_resizing.old_hide_cursor = false;
/* Invalidate render pointers */ /* Invalidate render pointers */
render_wait_for_preapply_damage(term);
shm_unref(term->render.last_buf); shm_unref(term->render.last_buf);
term->render.last_buf = NULL; term->render.last_buf = NULL;
term->render.last_cursor.row = NULL; term->render.last_cursor.row = NULL;
@ -4694,12 +4573,9 @@ render_resize(struct terminal *term, int width, int height, uint8_t opts)
const int total_x_pad = term->width - grid_width; const int total_x_pad = term->width - grid_width;
const int total_y_pad = term->height - grid_height; const int total_y_pad = term->height - grid_height;
const enum center_when center = term->conf->center_when; const bool centered_padding = term->conf->center
const bool centered_padding = || term->window->is_fullscreen
center == CENTER_ALWAYS || || term->window->is_maximized;
(center == CENTER_MAXIMIZED_AND_FULLSCREEN &&
(term->window->is_fullscreen || term->window->is_maximized)) ||
(center == CENTER_FULLSCREEN && term->window->is_fullscreen);
if (centered_padding && !term->window->is_resizing) { if (centered_padding && !term->window->is_resizing) {
term->margins.left = total_x_pad / 2; term->margins.left = total_x_pad / 2;
@ -4976,7 +4852,6 @@ damage_view:
tll_free(term->normal.scroll_damage); tll_free(term->normal.scroll_damage);
tll_free(term->alt.scroll_damage); tll_free(term->alt.scroll_damage);
render_wait_for_preapply_damage(term);
shm_unref(term->render.last_buf); shm_unref(term->render.last_buf);
term->render.last_buf = NULL; term->render.last_buf = NULL;
term_damage_view(term); term_damage_view(term);
@ -5031,9 +4906,8 @@ render_xcursor_update(struct seat *seat)
const enum wp_cursor_shape_device_v1_shape custom_shape = const enum wp_cursor_shape_device_v1_shape custom_shape =
(shape == CURSOR_SHAPE_CUSTOM && xcursor != NULL (shape == CURSOR_SHAPE_CUSTOM && xcursor != NULL
? cursor_string_to_server_shape( ? cursor_string_to_server_shape(xcursor)
xcursor, seat->wayl->shape_manager_version) : 0);
: 0);
if (shape != CURSOR_SHAPE_CUSTOM || custom_shape != 0) { if (shape != CURSOR_SHAPE_CUSTOM || custom_shape != 0) {
xassert(custom_shape == 0 || shape == CURSOR_SHAPE_CUSTOM); xassert(custom_shape == 0 || shape == CURSOR_SHAPE_CUSTOM);
@ -5375,77 +5249,3 @@ render_xcursor_set(struct seat *seat, struct terminal *term,
seat->pointer.xcursor_pending = true; seat->pointer.xcursor_pending = true;
return true; return true;
} }
void
render_buffer_release_callback(struct buffer *buf, void *data)
{
/*
* Called from shm.c when a buffer is released
*
* We use it to pre-apply last-frame's damage to it, when we're
* forced to double buffer (compositor doesn't release buffers
* immediately).
*
* The timeline is thus:
* 1. We render and push a new frame
* 2. Some (hopefully short) time after that, the compositor releases the previous buffer
* 3. We're called, and kick off the thread that copies the changes from (1) to the just freed buffer
* 4. Time passes....
* 5. The compositor calls our frame callback, signalling to us that it's time to start rendering the next frame
* 6. Hopefully, our thread is already done with copying the changes, otherwise we stall, waiting for it
* 7. We render the frame as if the compositor does immediate releases.
*
* What's the gain? Reduced latency, by applying the previous
* frame's damage as soon as possible, we shorten the time it
* takes to render the frame after the frame callback.
*
* This means the compositor can, in theory, push the frame
* callback closer to the vblank deadline, and thus reduce input
* latency. Not all compositors (most, in fact?) don't adapt like
* this, unfortunately. But some allows the user to manually
* configure the deadline.
*/
struct terminal *term = data;
if (likely(buf->age != 1))
return;
if (likely(!term->render.preapply_last_frame_damage))
return;
if (term->render.last_buf == NULL)
return;
if (term->render.last_buf->age != 0)
return;
if (buf->width != term->render.last_buf->width)
return;
if (buf->height != term->render.last_buf->height)
return;
xassert(term->render.workers.count > 0);
xassert(term->render.last_buf != NULL);
xassert(term->render.last_buf->age == 0);
xassert(term->render.last_buf != buf);
mtx_lock(&term->render.workers.preapplied_damage.lock);
if (term->render.workers.preapplied_damage.buf != NULL) {
mtx_unlock(&term->render.workers.preapplied_damage.lock);
return;
}
xassert(term->render.workers.preapplied_damage.buf == NULL);
term->render.workers.preapplied_damage.buf = buf;
term->render.workers.preapplied_damage.start = (struct timespec){0};
term->render.workers.preapplied_damage.stop = (struct timespec){0};
mtx_unlock(&term->render.workers.preapplied_damage.lock);
mtx_lock(&term->render.workers.lock);
sem_post(&term->render.workers.start);
xassert(tll_length(term->render.workers.queue) == 0);
tll_push_back(term->render.workers.queue, -3);
mtx_unlock(&term->render.workers.lock);
}

View file

@ -47,6 +47,3 @@ struct csd_data {
}; };
struct csd_data get_csd_data(const struct terminal *term, enum csd_surface surf_idx); struct csd_data get_csd_data(const struct terminal *term, enum csd_surface surf_idx);
void render_buffer_release_callback(struct buffer *buf, void *data);
void render_wait_for_preapply_damage(struct terminal *term);

View file

@ -11,7 +11,7 @@ import termios
from datetime import datetime from datetime import datetime
def main() -> None: def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('files', type=argparse.FileType('rb'), nargs='+') parser.add_argument('files', type=argparse.FileType('rb'), nargs='+')
parser.add_argument('--iterations', type=int, default=20) parser.add_argument('--iterations', type=int, default=20)
@ -24,12 +24,12 @@ def main() -> None:
termios.TIOCGWINSZ, termios.TIOCGWINSZ,
struct.pack('HHHH', 0, 0, 0, 0))) struct.pack('HHHH', 0, 0, 0, 0)))
times: dict[str, list[float]] = {name: [] for name in [f.name for f in args.files]} times = {name: [] for name in [f.name for f in args.files]}
for f in args.files: for f in args.files:
bench_bytes = f.read() bench_bytes = f.read()
for _ in range(args.iterations): for i in range(args.iterations):
start = datetime.now() start = datetime.now()
sys.stdout.buffer.write(bench_bytes) sys.stdout.buffer.write(bench_bytes)
stop = datetime.now() stop = datetime.now()
@ -48,4 +48,4 @@ def main() -> None:
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

View file

@ -8,8 +8,6 @@ import struct
import sys import sys
import termios import termios
from typing import Any
class ColorVariant(enum.IntEnum): class ColorVariant(enum.IntEnum):
NONE = enum.auto() NONE = enum.auto()
@ -19,7 +17,7 @@ class ColorVariant(enum.IntEnum):
RGB = enum.auto() RGB = enum.auto()
def main() -> None: def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
'out', type=argparse.FileType(mode='w'), nargs='?', help='name of output file') 'out', type=argparse.FileType(mode='w'), nargs='?', help='name of output file')
@ -40,16 +38,10 @@ def main() -> None:
opts = parser.parse_args() opts = parser.parse_args()
out = opts.out if opts.out is not None else sys.stdout out = opts.out if opts.out is not None else sys.stdout
lines: int | None = None
cols: int | None = None
width: int | None = None
height: int | None = None
if opts.rows is None or opts.cols is None: if opts.rows is None or opts.cols is None:
try: try:
def dummy(*args: Any) -> None: def dummy(*args):
"""Need a handler installed for sigwait() to trigger.""" """Need a handler installed for sigwait() to trigger."""
_ = args
pass pass
signal.signal(signal.SIGWINCH, dummy) signal.signal(signal.SIGWINCH, dummy)
@ -61,9 +53,6 @@ def main() -> None:
termios.TIOCGWINSZ, termios.TIOCGWINSZ,
struct.pack('HHHH', 0, 0, 0, 0))) struct.pack('HHHH', 0, 0, 0, 0)))
assert width is not None
assert height is not None
if width > 0 and height > 0: if width > 0 and height > 0:
break break
@ -82,11 +71,9 @@ def main() -> None:
if opts.rows is not None: if opts.rows is not None:
lines = opts.rows lines = opts.rows
assert lines is not None
height = 15 * lines # PGO helper binary hardcodes cell height to 15px height = 15 * lines # PGO helper binary hardcodes cell height to 15px
if opts.cols is not None: if opts.cols is not None:
cols = opts.cols cols = opts.cols
assert cols is not None
width = 8 * cols # PGO help binary hardcodes cell width to 8px width = 8 * cols # PGO help binary hardcodes cell width to 8px
if lines is None or cols is None or height is None or width is None: if lines is None or cols is None or height is None or width is None:
@ -203,8 +190,8 @@ def main() -> None:
# The sixel 'alphabet' # The sixel 'alphabet'
sixels = '?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' sixels = '?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
last_pos: tuple[int, int] | None = None last_pos = None
last_size: tuple[int, int] = 0, 0 last_size = None
for _ in range(20): for _ in range(20):
if last_pos is not None and random.randrange(2): if last_pos is not None and random.randrange(2):
@ -267,4 +254,4 @@ def main() -> None:
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

View file

@ -1,12 +1,14 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import os
import re import re
import sys
from typing import Dict, Union
class Capability: class Capability:
def __init__(self, name: str, value: bool | int | str): def __init__(self, name: str, value: Union[bool, int, str]):
self._name = name self._name = name
self._value = value self._value = value
@ -15,37 +17,25 @@ class Capability:
return self._name return self._name
@property @property
def value(self) -> bool | int | str: def value(self) -> Union[bool, int, str]:
return self._value return self._value
def __lt__(self, other: object) -> bool: def __lt__(self, other):
if not isinstance(other, Capability):
return NotImplemented
return self._name < other._name return self._name < other._name
def __le__(self, other: object) -> bool: def __le__(self, other):
if not isinstance(other, Capability):
return NotImplemented
return self._name <= other._name return self._name <= other._name
def __eq__(self, other: object) -> bool: def __eq__(self, other):
if not isinstance(other, Capability):
return NotImplemented
return self._name == other._name return self._name == other._name
def __ne__(self, other: object) -> bool: def __ne__(self, other):
if not isinstance(other, Capability): return self._name != other._name
return NotImplemented
return bool(self._name != other._name)
def __gt__(self, other: object) -> bool: def __gt__(self, other):
if not isinstance(other, Capability): return self._name > other._name
return NotImplemented
return bool(self._name > other._name)
def __ge__(self, other: object) -> bool: def __ge__(self, other):
if not isinstance(other, Capability):
return NotImplemented
return self._name >= other._name return self._name >= other._name
@ -63,7 +53,7 @@ class StringCapability(Capability):
# see terminfo(5) for valid escape sequences # see terminfo(5) for valid escape sequences
# Control characters # Control characters
def translate_ctrl_chr(m: re.Match[str]) -> str: def translate_ctrl_chr(m):
ctrl = m.group(1) ctrl = m.group(1)
if ctrl == '?': if ctrl == '?':
return '\\x7f' return '\\x7f'
@ -95,7 +85,7 @@ class Fragment:
def __init__(self, name: str, description: str): def __init__(self, name: str, description: str):
self._name = name self._name = name
self._description = description self._description = description
self._caps = dict[str, Capability]() self._caps = {}
@property @property
def name(self) -> str: def name(self) -> str:
@ -106,18 +96,18 @@ class Fragment:
return self._description return self._description
@property @property
def caps(self) -> dict[str, Capability]: def caps(self) -> Dict[str, Capability]:
return self._caps return self._caps
def add_capability(self, cap: Capability) -> None: def add_capability(self, cap: Capability):
assert cap.name not in self._caps assert cap.name not in self._caps
self._caps[cap.name] = cap self._caps[cap.name] = cap
def del_capability(self, name: str) -> None: def del_capability(self, name: str):
del self._caps[name] del self._caps[name]
def main() -> None: def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('source_entry_name') parser.add_argument('source_entry_name')
parser.add_argument('source', type=argparse.FileType('r')) parser.add_argument('source', type=argparse.FileType('r'))
@ -130,15 +120,15 @@ def main() -> None:
source = opts.source source = opts.source
target = opts.target target = opts.target
lines = list[str]() lines = []
for line in source.readlines(): for l in source.readlines():
line = line.strip() l = l.strip()
if line.startswith('#'): if l.startswith('#'):
continue continue
lines.append(line) lines.append(l)
fragments = dict[str, Fragment]() fragments = {}
cur_fragment: Fragment | None = None cur_fragment = None
for m in re.finditer( for m in re.finditer(
r'(?P<name>(?P<entry_name>[-+\w@]+)\|(?P<entry_desc>.+?),)|' r'(?P<name>(?P<entry_name>[-+\w@]+)\|(?P<entry_desc>.+?),)|'
@ -157,20 +147,17 @@ def main() -> None:
elif m.group('bool_cap') is not None: elif m.group('bool_cap') is not None:
name = m.group('bool_name') name = m.group('bool_name')
assert cur_fragment is not None
cur_fragment.add_capability(BoolCapability(name)) cur_fragment.add_capability(BoolCapability(name))
elif m.group('int_cap') is not None: elif m.group('int_cap') is not None:
name = m.group('int_name') name = m.group('int_name')
int_value = int(m.group('int_val'), 0) value = int(m.group('int_val'), 0)
assert cur_fragment is not None cur_fragment.add_capability(IntCapability(name, value))
cur_fragment.add_capability(IntCapability(name, int_value))
elif m.group('str_cap') is not None: elif m.group('str_cap') is not None:
name = m.group('str_name') name = m.group('str_name')
str_value = m.group('str_val') value = m.group('str_val')
assert cur_fragment is not None cur_fragment.add_capability(StringCapability(name, value))
cur_fragment.add_capability(StringCapability(name, str_value))
else: else:
assert False assert False
@ -179,9 +166,6 @@ def main() -> None:
for frag in fragments.values(): for frag in fragments.values():
for cap in frag.caps.values(): for cap in frag.caps.values():
if cap.name == 'use': if cap.name == 'use':
assert isinstance(cap, StringCapability)
assert isinstance(cap.value, str)
use_frag = fragments[cap.value] use_frag = fragments[cap.value]
for use_cap in use_frag.caps.values(): for use_cap in use_frag.caps.values():
frag.add_capability(use_cap) frag.add_capability(use_cap)
@ -201,9 +185,8 @@ def main() -> None:
entry.add_capability(StringCapability('TN', target_entry_name)) entry.add_capability(StringCapability('TN', target_entry_name))
entry.add_capability(StringCapability('name', target_entry_name)) entry.add_capability(StringCapability('name', target_entry_name))
entry.add_capability(IntCapability('RGB', 8)) # 8 bits per channel entry.add_capability(IntCapability('RGB', 8)) # 8 bits per channel
entry.add_capability(StringCapability('query-os-name', os.uname().sysname))
terminfo_parts = list[str]() terminfo_parts = []
for cap in sorted(entry.caps.values()): for cap in sorted(entry.caps.values()):
name = cap.name name = cap.name
value = str(cap.value) value = str(cap.value)
@ -227,4 +210,4 @@ def main() -> None:
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

View file

@ -1,10 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import sys
class Codepoint: class Codepoint:
def __init__(self, start: int, end: None | int = None): def __init__(self, start: int, end: None|int = None):
self.start = start self.start = start
self.end = start if end is None else end self.end = start if end is None else end
self.vs15 = False self.vs15 = False
@ -14,7 +15,7 @@ class Codepoint:
return f'{self.start:x}-{self.end:x}, vs15={self.vs15}, vs16={self.vs16}' return f'{self.start:x}-{self.end:x}, vs15={self.vs15}, vs16={self.vs16}'
def main() -> None: def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('input', type=argparse.FileType('r')) parser.add_argument('input', type=argparse.FileType('r'))
parser.add_argument('output', type=argparse.FileType('w')) parser.add_argument('output', type=argparse.FileType('w'))
@ -99,4 +100,4 @@ def main() -> None:
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

View file

@ -2,6 +2,7 @@
import argparse import argparse
import math import math
import sys
# Note: we use a pure gamma 2.2 function, rather than the piece-wise # Note: we use a pure gamma 2.2 function, rather than the piece-wise
@ -16,7 +17,7 @@ def linear_to_srgb(f: float) -> float:
return math.pow(f, 1 / 2.2) return math.pow(f, 1 / 2.2)
def main() -> None: def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('c_output', type=argparse.FileType('w')) parser.add_argument('c_output', type=argparse.FileType('w'))
parser.add_argument('h_output', type=argparse.FileType('w')) parser.add_argument('h_output', type=argparse.FileType('w'))
@ -67,4 +68,4 @@ def main() -> None:
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

View file

@ -283,13 +283,8 @@ matches_cell(const struct terminal *term, const struct cell *cell, size_t search
if (composed == NULL && base == 0 && term->search.buf[search_ofs] == U' ') if (composed == NULL && base == 0 && term->search.buf[search_ofs] == U' ')
return 1; return 1;
if (hasc32upper(term->search.buf)) { if (c32ncasecmp(&base, &term->search.buf[search_ofs], 1) != 0)
if (c32ncmp(&base, &term->search.buf[search_ofs], 1) != 0) return -1;
return -1;
} else {
if (c32ncasecmp(&base, &term->search.buf[search_ofs], 1) != 0)
return -1;
}
if (composed != NULL) { if (composed != NULL) {
if (search_ofs + composed->count > term->search.len) if (search_ofs + composed->count > term->search.len)
@ -1484,8 +1479,7 @@ search_input(struct seat *seat, struct terminal *term,
count = xkb_compose_state_get_utf8( count = xkb_compose_state_get_utf8(
seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf)); seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
xkb_compose_state_reset(seat->kbd.xkb_compose_state); xkb_compose_state_reset(seat->kbd.xkb_compose_state);
} else if (compose_status == XKB_COMPOSE_CANCELLED || } else if (compose_status == XKB_COMPOSE_CANCELLED) {
compose_status == XKB_COMPOSE_COMPOSING) {
count = 0; count = 0;
} else { } else {
count = xkb_state_key_get_utf8( count = xkb_state_key_get_utf8(

View file

@ -19,7 +19,6 @@
#include "char32.h" #include "char32.h"
#include "commands.h" #include "commands.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "extract.h" #include "extract.h"
#include "grid.h" #include "grid.h"
#include "misc.h" #include "misc.h"
@ -559,15 +558,9 @@ selection_find_quote_left(struct terminal *term, struct coord *pos,
if (*quote_char == '\0' ? (wc == '"' || wc == '\'') if (*quote_char == '\0' ? (wc == '"' || wc == '\'')
: wc == *quote_char) : wc == *quote_char)
{ {
xassert(next_col + 1 <= term->cols); pos->row = next_row;
if (next_col + 1 == term->cols) { pos->col = next_col + 1;
xassert(next_row < pos->row); xassert(pos->col < term->cols);
pos->row = next_row + 1;
pos->col = 0;
} else {
pos->row = next_row;
pos->col = next_col + 1;
}
*quote_char = wc; *quote_char = wc;
return true; return true;

View file

@ -30,7 +30,7 @@ struct client;
struct terminal_instance; struct terminal_instance;
struct server { struct server {
struct config *conf; const struct config *conf;
struct fdm *fdm; struct fdm *fdm;
struct reaper *reaper; struct reaper *reaper;
struct wayland *wayl; struct wayland *wayl;
@ -156,61 +156,10 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
xassert(events & EPOLLIN); xassert(events & EPOLLIN);
if (client->instance != NULL) { if (client->instance != NULL) {
struct client_ipc_hdr ipc_hdr; uint8_t dummy[128];
ssize_t count = read(fd, &ipc_hdr, sizeof(ipc_hdr)); ssize_t count = read(fd, dummy, sizeof(dummy));
LOG_WARN("client unexpectedly sent %zd bytes", count);
if (count != sizeof(ipc_hdr)) { return true; /* TODO: shutdown instead? */
LOG_WARN("client unexpectedly sent %zd bytes", count);
return true; /* TODO: shutdown instead? */
}
switch (ipc_hdr.ipc_code) {
case FOOT_IPC_SIGUSR: {
xassert(ipc_hdr.size == sizeof(struct client_ipc_sigusr));
struct client_ipc_sigusr sigusr;
count = read(fd, &sigusr, sizeof(sigusr));
if (count < 0) {
LOG_ERRNO("failed to read SIGUSR IPC data from client");
return true; /* TODO: shutdown instead? */
}
if ((size_t)count != sizeof(sigusr)) {
LOG_ERR("failed to read SIGUSR IPC data from client");
return true; /* TODO: shutdown instead? */
}
switch (sigusr.signo) {
case SIGUSR1:
term_theme_switch_to_dark(client->instance->terminal);
break;
case SIGUSR2:
term_theme_switch_to_light(client->instance->terminal);
break;
default:
LOG_ERR(
"client sent bad SIGUSR number: %d "
"(expected SIGUSR1=%d or SIGUSR2=%d)",
sigusr.signo, SIGUSR1, SIGUSR2);
break;
}
return true;
}
default:
LOG_WARN(
"client sent unrecognized IPC (0x%04x), ignoring %hhu bytes",
ipc_hdr.ipc_code, ipc_hdr.size);
/* TODO: slightly broken, since not all data is guaranteed
to be readable yet */
uint8_t dummy[ipc_hdr.size];
(void)!!read(fd, dummy, ipc_hdr.size);
return true;
}
} }
if (client->buffer.data == NULL) { if (client->buffer.data == NULL) {
@ -556,7 +505,7 @@ prepare_socket(int fd)
} }
struct server * struct server *
server_init(struct config *conf, struct fdm *fdm, struct reaper *reaper, server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
struct wayland *wayl) struct wayland *wayl)
{ {
int fd; int fd;
@ -668,23 +617,3 @@ server_destroy(struct server *server)
unlink(server->sock_path); unlink(server->sock_path);
free(server); free(server);
} }
void
server_global_theme_switch_to_dark(struct server *server)
{
server->conf->initial_color_theme = COLOR_THEME_DARK;
tll_foreach(server->clients, it)
term_theme_switch_to_dark(it->item->instance->terminal);
tll_foreach(server->terminals, it)
term_theme_switch_to_dark(it->item->terminal);
}
void
server_global_theme_switch_to_light(struct server *server)
{
server->conf->initial_color_theme = COLOR_THEME_LIGHT;
tll_foreach(server->clients, it)
term_theme_switch_to_light(it->item->instance->terminal);
tll_foreach(server->terminals, it)
term_theme_switch_to_light(it->item->terminal);
}

View file

@ -6,9 +6,6 @@
#include "wayland.h" #include "wayland.h"
struct server; struct server;
struct server *server_init(struct config *conf, struct fdm *fdm, struct server *server_init(const struct config *conf, struct fdm *fdm,
struct reaper *reaper, struct wayland *wayl); struct reaper *reaper, struct wayland *wayl);
void server_destroy(struct server *server); void server_destroy(struct server *server);
void server_global_theme_switch_to_dark(struct server *server);
void server_global_theme_switch_to_light(struct server *server);

156
shm.c
View file

@ -13,6 +13,7 @@
#include <pixman.h> #include <pixman.h>
#include <fcft/stride.h>
#include <tllist.h> #include <tllist.h>
#define LOG_MODULE "shm" #define LOG_MODULE "shm"
@ -20,7 +21,6 @@
#include "log.h" #include "log.h"
#include "debug.h" #include "debug.h"
#include "macros.h" #include "macros.h"
#include "stride.h"
#include "xmalloc.h" #include "xmalloc.h"
#if !defined(MAP_UNINITIALIZED) #if !defined(MAP_UNINITIALIZED)
@ -61,8 +61,6 @@ static off_t max_pool_size = 512 * 1024 * 1024;
static bool can_punch_hole = false; static bool can_punch_hole = false;
static bool can_punch_hole_initialized = false; static bool can_punch_hole_initialized = false;
static size_t min_stride_alignment = 0;
struct buffer_pool { struct buffer_pool {
int fd; /* memfd */ int fd; /* memfd */
struct wl_shm_pool *wl_pool; struct wl_shm_pool *wl_pool;
@ -84,11 +82,9 @@ struct buffer_private {
struct buffer_pool *pool; struct buffer_pool *pool;
off_t offset; /* Offset into memfd where data begins */ off_t offset; /* Offset into memfd where data begins */
size_t size; size_t size;
bool with_alpha;
bool scrollable; bool scrollable;
void (*release_cb)(struct buffer *buf, void *data);
void *cb_data;
}; };
struct buffer_chain { struct buffer_chain {
@ -97,11 +93,11 @@ struct buffer_chain {
size_t pix_instances; size_t pix_instances;
bool scrollable; bool scrollable;
pixman_format_code_t pixman_fmt; pixman_format_code_t pixman_fmt_without_alpha;
enum wl_shm_format shm_format; enum wl_shm_format shm_format_without_alpha;
void (*release_cb)(struct buffer *buf, void *data); pixman_format_code_t pixman_fmt_with_alpha;
void *cb_data; enum wl_shm_format shm_format_with_alpha;
}; };
static tll(struct buffer_private *) deferred; static tll(struct buffer_private *) deferred;
@ -117,12 +113,6 @@ shm_set_max_pool_size(off_t _max_pool_size)
max_pool_size = _max_pool_size; max_pool_size = _max_pool_size;
} }
void
shm_set_min_stride_alignment(size_t _min_stride_alignment)
{
min_stride_alignment = _min_stride_alignment;
}
static void static void
buffer_destroy_dont_close(struct buffer *buf) buffer_destroy_dont_close(struct buffer *buf)
{ {
@ -234,10 +224,6 @@ buffer_release(void *data, struct wl_buffer *wl_buffer)
xassert(found); xassert(found);
if (!found) if (!found)
LOG_WARN("deferred delete: buffer not on the 'deferred' list"); LOG_WARN("deferred delete: buffer not on the 'deferred' list");
} else {
if (buffer->release_cb != NULL) {
buffer->release_cb(&buffer->public, buffer->cb_data);
}
} }
} }
@ -245,6 +231,7 @@ static const struct wl_buffer_listener buffer_listener = {
.release = &buffer_release, .release = &buffer_release,
}; };
#if __SIZEOF_POINTER__ == 8
static size_t static size_t
page_size(void) page_size(void)
{ {
@ -261,6 +248,7 @@ page_size(void)
xassert(size > 0); xassert(size > 0);
return size; return size;
} }
#endif
static bool static bool
instantiate_offset(struct buffer_private *buf, off_t new_offset) instantiate_offset(struct buffer_private *buf, off_t new_offset)
@ -281,7 +269,9 @@ instantiate_offset(struct buffer_private *buf, off_t new_offset)
wl_buf = wl_shm_pool_create_buffer( wl_buf = wl_shm_pool_create_buffer(
pool->wl_pool, new_offset, pool->wl_pool, new_offset,
buf->public.width, buf->public.height, buf->public.stride, buf->public.width, buf->public.height, buf->public.stride,
buf->chain->shm_format); buf->with_alpha
? buf->chain->shm_format_with_alpha
: buf->chain->shm_format_without_alpha);
if (wl_buf == NULL) { if (wl_buf == NULL) {
LOG_ERR("failed to create SHM buffer"); LOG_ERR("failed to create SHM buffer");
@ -291,7 +281,9 @@ instantiate_offset(struct buffer_private *buf, off_t new_offset)
/* One pixman image for each worker thread (do we really need multiple?) */ /* One pixman image for each worker thread (do we really need multiple?) */
for (size_t i = 0; i < buf->public.pix_instances; i++) { for (size_t i = 0; i < buf->public.pix_instances; i++) {
pix[i] = pixman_image_create_bits_no_clear( pix[i] = pixman_image_create_bits_no_clear(
buf->chain->pixman_fmt, buf->with_alpha
? buf->chain->pixman_fmt_with_alpha
: buf->chain->pixman_fmt_without_alpha,
buf->public.width, buf->public.height, buf->public.width, buf->public.height,
(uint32_t *)mmapped, buf->public.stride); (uint32_t *)mmapped, buf->public.stride);
@ -326,7 +318,8 @@ err:
static void NOINLINE static void NOINLINE
get_new_buffers(struct buffer_chain *chain, size_t count, get_new_buffers(struct buffer_chain *chain, size_t count,
int widths[static count], int heights[static count], int widths[static count], int heights[static count],
struct buffer *bufs[static count], bool immediate_purge) struct buffer *bufs[static count], bool with_alpha,
bool immediate_purge)
{ {
xassert(count == 1 || !chain->scrollable); xassert(count == 1 || !chain->scrollable);
/* /*
@ -345,14 +338,7 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
size_t total_size = 0; size_t total_size = 0;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
stride[i] = stride_for_format_and_width( stride[i] = stride_for_format_and_width(
chain->pixman_fmt, widths[i]); with_alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8, widths[i]);
if (min_stride_alignment > 0) {
const size_t m = min_stride_alignment;
stride[i] = (stride[i] + m - 1) / m * m;
}
xassert(min_stride_alignment == 0 || stride[i] % min_stride_alignment == 0);
sizes[i] = stride[i] * heights[i]; sizes[i] = stride[i] * heights[i];
total_size += sizes[i]; total_size += sizes[i];
} }
@ -394,11 +380,9 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
goto err; goto err;
} }
const size_t page_sz = page_size();
#if __SIZEOF_POINTER__ == 8 #if __SIZEOF_POINTER__ == 8
off_t offset = chain->scrollable && max_pool_size > 0 off_t offset = chain->scrollable && max_pool_size > 0
? (max_pool_size / 4) & ~(page_sz - 1) ? (max_pool_size / 4) & ~(page_size() - 1)
: 0; : 0;
off_t memfd_size = chain->scrollable && max_pool_size > 0 off_t memfd_size = chain->scrollable && max_pool_size > 0
? max_pool_size ? max_pool_size
@ -408,8 +392,7 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
off_t memfd_size = total_size; off_t memfd_size = total_size;
#endif #endif
/* Page align */ xassert(chain->scrollable || (offset == 0 && memfd_size == total_size));
memfd_size = (memfd_size + page_sz - 1) & ~(page_sz - 1);
LOG_DBG("memfd-size: %lu, initial offset: %lu", memfd_size, offset); LOG_DBG("memfd-size: %lu, initial offset: %lu", memfd_size, offset);
@ -441,9 +424,6 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
memfd_size = total_size; memfd_size = total_size;
chain->scrollable = false; chain->scrollable = false;
/* Page align */
memfd_size = (memfd_size + page_sz - 1) & ~(page_sz - 1);
if (ftruncate(pool_fd, memfd_size) < 0) { if (ftruncate(pool_fd, memfd_size) < 0) {
LOG_ERRNO("failed to set size of SHM backing memory file"); LOG_ERRNO("failed to set size of SHM backing memory file");
goto err; goto err;
@ -509,12 +489,11 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
.chain = chain, .chain = chain,
.ref_count = immediate_purge ? 0 : 1, .ref_count = immediate_purge ? 0 : 1,
.busy = true, .busy = true,
.with_alpha = with_alpha,
.pool = pool, .pool = pool,
.offset = 0, .offset = 0,
.size = sizes[i], .size = sizes[i],
.scrollable = chain->scrollable, .scrollable = chain->scrollable,
.release_cb = chain->release_cb,
.cb_data = chain->cb_data,
}; };
if (!instantiate_offset(buf, offset)) { if (!instantiate_offset(buf, offset)) {
@ -580,13 +559,13 @@ shm_did_not_use_buf(struct buffer *_buf)
void void
shm_get_many(struct buffer_chain *chain, size_t count, shm_get_many(struct buffer_chain *chain, size_t count,
int widths[static count], int heights[static count], int widths[static count], int heights[static count],
struct buffer *bufs[static count]) struct buffer *bufs[static count], bool with_alpha)
{ {
get_new_buffers(chain, count, widths, heights, bufs, true); get_new_buffers(chain, count, widths, heights, bufs, with_alpha, true);
} }
struct buffer * struct buffer *
shm_get_buffer(struct buffer_chain *chain, int width, int height) shm_get_buffer(struct buffer_chain *chain, int width, int height, bool with_alpha)
{ {
LOG_DBG( LOG_DBG(
"chain=%p: looking for a reusable %dx%d buffer " "chain=%p: looking for a reusable %dx%d buffer "
@ -597,7 +576,9 @@ shm_get_buffer(struct buffer_chain *chain, int width, int height)
tll_foreach(chain->bufs, it) { tll_foreach(chain->bufs, it) {
struct buffer_private *buf = it->item; struct buffer_private *buf = it->item;
if (buf->public.width != width || buf->public.height != height) { if (buf->public.width != width || buf->public.height != height ||
with_alpha != buf->with_alpha)
{
LOG_DBG("purging mismatching buffer %p", (void *)buf); LOG_DBG("purging mismatching buffer %p", (void *)buf);
if (buffer_unref_no_remove_from_chain(buf)) if (buffer_unref_no_remove_from_chain(buf))
tll_remove(chain->bufs, it); tll_remove(chain->bufs, it);
@ -613,9 +594,9 @@ shm_get_buffer(struct buffer_chain *chain, int width, int height)
else else
#endif #endif
{ {
if (cached == NULL) { if (cached == NULL)
cached = buf; cached = buf;
} else { else {
/* We have multiple buffers eligible for /* We have multiple buffers eligible for
* reuse. Pick the "youngest" one, and mark the * reuse. Pick the "youngest" one, and mark the
* other one for purging */ * other one for purging */
@ -648,7 +629,7 @@ shm_get_buffer(struct buffer_chain *chain, int width, int height)
} }
struct buffer *ret; struct buffer *ret;
get_new_buffers(chain, 1, &width, &height, &ret, false); get_new_buffers(chain, 1, &width, &height, &ret, with_alpha, false);
return ret; return ret;
} }
@ -991,43 +972,23 @@ shm_unref(struct buffer *_buf)
struct buffer_chain * struct buffer_chain *
shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances, shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
enum shm_bit_depth desired_bit_depth, enum shm_bit_depth desired_bit_depth)
void (*release_cb)(struct buffer *buf, void *data), void *cb_data)
{ {
pixman_format_code_t pixman_fmt = PIXMAN_a8r8g8b8; pixman_format_code_t pixman_fmt_without_alpha = PIXMAN_x8r8g8b8;
enum wl_shm_format shm_fmt = WL_SHM_FORMAT_ARGB8888; enum wl_shm_format shm_fmt_without_alpha = WL_SHM_FORMAT_XRGB8888;
pixman_format_code_t pixman_fmt_with_alpha = PIXMAN_a8r8g8b8;
enum wl_shm_format shm_fmt_with_alpha = WL_SHM_FORMAT_ARGB8888;
static bool have_logged = false; static bool have_logged = false;
static bool have_logged_10_fallback = false;
#if defined(HAVE_PIXMAN_RGBA_16) if (desired_bit_depth == SHM_BITS_10) {
static bool have_logged_16_fallback = false; if (wayl->shm_have_argb2101010 && wayl->shm_have_xrgb2101010) {
pixman_fmt_without_alpha = PIXMAN_x2r10g10b10;
shm_fmt_without_alpha = WL_SHM_FORMAT_XRGB2101010;
if (desired_bit_depth == SHM_BITS_16) { pixman_fmt_with_alpha = PIXMAN_a2r10g10b10;
if (wayl->shm_have_abgr161616) { shm_fmt_with_alpha = WL_SHM_FORMAT_ARGB2101010;
pixman_fmt = PIXMAN_a16b16g16r16;
shm_fmt = WL_SHM_FORMAT_ABGR16161616;
if (!have_logged) {
have_logged = true;
LOG_INFO("using 16-bit BGR surfaces");
}
} else {
if (!have_logged_16_fallback) {
have_logged_16_fallback = true;
LOG_WARN(
"16-bit surfaces requested, but compositor does not "
"implement ABGR161616+XBGR161616");
}
}
}
#endif
if (desired_bit_depth >= SHM_BITS_10 && pixman_fmt == PIXMAN_a8r8g8b8) {
if (wayl->shm_have_argb2101010) {
pixman_fmt = PIXMAN_a2r10g10b10;
shm_fmt = WL_SHM_FORMAT_ARGB2101010;
if (!have_logged) { if (!have_logged) {
have_logged = true; have_logged = true;
@ -1035,9 +996,12 @@ shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
} }
} }
else if (wayl->shm_have_abgr2101010) { else if (wayl->shm_have_abgr2101010 && wayl->shm_have_xbgr2101010) {
pixman_fmt = PIXMAN_a2b10g10r10; pixman_fmt_without_alpha = PIXMAN_x2b10g10r10;
shm_fmt = WL_SHM_FORMAT_ABGR2101010; shm_fmt_without_alpha = WL_SHM_FORMAT_XBGR2101010;
pixman_fmt_with_alpha = PIXMAN_a2b10g10r10;
shm_fmt_with_alpha = WL_SHM_FORMAT_ABGR2101010;
if (!have_logged) { if (!have_logged) {
have_logged = true; have_logged = true;
@ -1046,13 +1010,13 @@ shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
} }
else { else {
if (!have_logged_10_fallback) { if (!have_logged) {
have_logged_10_fallback = true; have_logged = true;
LOG_WARN( LOG_WARN(
"10-bit surfaces requested, but compositor does not " "10-bit surfaces requested, but compositor does not "
"implement ARGB2101010+XRGB2101010, or " "implement ARGB2101010+XRGB2101010, or "
"ABGR2101010+XBGR2101010"); "ABGR2101010+XBGR2101010. Falling back to 8-bit surfaces");
} }
} }
} else { } else {
@ -1069,11 +1033,11 @@ shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
.pix_instances = pix_instances, .pix_instances = pix_instances,
.scrollable = scrollable, .scrollable = scrollable,
.pixman_fmt = pixman_fmt, .pixman_fmt_without_alpha = pixman_fmt_without_alpha,
.shm_format = shm_fmt, .shm_format_without_alpha = shm_fmt_without_alpha,
.release_cb = release_cb, .pixman_fmt_with_alpha = pixman_fmt_with_alpha,
.cb_data = cb_data, .shm_format_with_alpha = shm_fmt_with_alpha,
}; };
return chain; return chain;
} }
@ -1097,13 +1061,9 @@ shm_chain_free(struct buffer_chain *chain)
enum shm_bit_depth enum shm_bit_depth
shm_chain_bit_depth(const struct buffer_chain *chain) shm_chain_bit_depth(const struct buffer_chain *chain)
{ {
const pixman_format_code_t fmt = chain->pixman_fmt; const pixman_format_code_t fmt = chain->pixman_fmt_with_alpha;
return fmt == PIXMAN_a8r8g8b8 return (fmt == PIXMAN_a2r10g10b10 || fmt == PIXMAN_a2b10g10r10)
? SHM_BITS_8 ? SHM_BITS_10
#if defined(HAVE_PIXMAN_RGBA_16) : SHM_BITS_8;
: fmt == PIXMAN_a16b16g16r16
? SHM_BITS_16
#endif
: SHM_BITS_10;
} }

11
shm.h
View file

@ -42,16 +42,12 @@ struct buffer {
}; };
void shm_fini(void); void shm_fini(void);
/* TODO: combine into shm_init() */
void shm_set_max_pool_size(off_t max_pool_size); void shm_set_max_pool_size(off_t max_pool_size);
void shm_set_min_stride_alignment(size_t min_stride_alignment);
struct buffer_chain; struct buffer_chain;
struct buffer_chain *shm_chain_new( struct buffer_chain *shm_chain_new(
struct wayland *wayl, bool scrollable, size_t pix_instances, struct wayland *wayl, bool scrollable, size_t pix_instances,
enum shm_bit_depth desired_bit_depth, enum shm_bit_depth desired_bit_depth);
void (*release_cb)(struct buffer *buf, void *data), void *cb_data);
void shm_chain_free(struct buffer_chain *chain); void shm_chain_free(struct buffer_chain *chain);
enum shm_bit_depth shm_chain_bit_depth(const struct buffer_chain *chain); enum shm_bit_depth shm_chain_bit_depth(const struct buffer_chain *chain);
@ -65,7 +61,8 @@ enum shm_bit_depth shm_chain_bit_depth(const struct buffer_chain *chain);
* *
* A newly allocated buffer has an age of 1234. * A newly allocated buffer has an age of 1234.
*/ */
struct buffer *shm_get_buffer(struct buffer_chain *chain, int width, int height); struct buffer *shm_get_buffer(
struct buffer_chain *chain, int width, int height, bool with_alpha);
/* /*
* Returns many buffers, described by 'info', all sharing the same SHM * Returns many buffers, described by 'info', all sharing the same SHM
* buffer pool. * buffer pool.
@ -83,7 +80,7 @@ struct buffer *shm_get_buffer(struct buffer_chain *chain, int width, int height)
void shm_get_many( void shm_get_many(
struct buffer_chain *chain, size_t count, struct buffer_chain *chain, size_t count,
int widths[static count], int heights[static count], int widths[static count], int heights[static count],
struct buffer *bufs[static count]); struct buffer *bufs[static count], bool with_alpha);
void shm_did_not_use_buf(struct buffer *buf); void shm_did_not_use_buf(struct buffer *buf);

26
sixel.c
View file

@ -113,31 +113,20 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
term->sixel.linear_blending = wayl_do_linear_blending(term->wl, term->conf); term->sixel.linear_blending = wayl_do_linear_blending(term->wl, term->conf);
term->sixel.pixman_fmt = PIXMAN_a8r8g8b8; term->sixel.pixman_fmt = PIXMAN_a8r8g8b8;
/* if (term->conf->tweak.surface_bit_depth == SHM_BITS_10) {
* Use higher-precision sixel surfaces if we're using if (term->wl->shm_have_argb2101010 && term->wl->shm_have_xrgb2101010) {
* higher-precision window surfaces.
*
* This is to a) get more accurate colors when doing gamma-correct
* blending, and b) use the same pixman format as the main
* surfaces, for (hopefully) better performance.
*
* For now, don't support 16-bit surfaces (too much sixel logic
* that assumes 32-bit pixels).
*/
if (shm_chain_bit_depth(term->render.chains.grid) >= SHM_BITS_10) {
if (term->wl->shm_have_argb2101010) {
term->sixel.use_10bit = true; term->sixel.use_10bit = true;
term->sixel.pixman_fmt = PIXMAN_a2r10g10b10; term->sixel.pixman_fmt = PIXMAN_a2r10g10b10;
} }
else if (term->wl->shm_have_abgr2101010) { else if (term->wl->shm_have_abgr2101010 && term->wl->shm_have_xbgr2101010) {
term->sixel.use_10bit = true; term->sixel.use_10bit = true;
term->sixel.pixman_fmt = PIXMAN_a2b10g10r10; term->sixel.pixman_fmt = PIXMAN_a2b10g10r10;
} }
} }
const size_t active_palette_entries = min( const size_t active_palette_entries = min(
ALEN(term->conf->colors_dark.sixel), term->sixel.palette_size); ALEN(term->conf->colors.sixel), term->sixel.palette_size);
if (term->sixel.use_private_palette) { if (term->sixel.use_private_palette) {
xassert(term->sixel.private_palette == NULL); xassert(term->sixel.private_palette == NULL);
@ -145,7 +134,7 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
term->sixel.palette_size, sizeof(term->sixel.private_palette[0])); term->sixel.palette_size, sizeof(term->sixel.private_palette[0]));
memcpy( memcpy(
term->sixel.private_palette, term->conf->colors_dark.sixel, term->sixel.private_palette, term->conf->colors.sixel,
active_palette_entries * sizeof(term->sixel.private_palette[0])); active_palette_entries * sizeof(term->sixel.private_palette[0]));
if (term->sixel.linear_blending || term->sixel.use_10bit) { if (term->sixel.linear_blending || term->sixel.use_10bit) {
@ -164,7 +153,7 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
term->sixel.palette_size, sizeof(term->sixel.shared_palette[0])); term->sixel.palette_size, sizeof(term->sixel.shared_palette[0]));
memcpy( memcpy(
term->sixel.shared_palette, term->conf->colors_dark.sixel, term->sixel.shared_palette, term->conf->colors.sixel,
active_palette_entries * sizeof(term->sixel.shared_palette[0])); active_palette_entries * sizeof(term->sixel.shared_palette[0]));
if (term->sixel.linear_blending || term->sixel.use_10bit) { if (term->sixel.linear_blending || term->sixel.use_10bit) {
@ -1559,9 +1548,6 @@ resize(struct terminal *term, int new_width_mutable, int new_height_mutable)
new_height_mutable = term->sixel.max_height; new_height_mutable = term->sixel.max_height;
} }
if (unlikely(new_height_mutable == 0)) {
new_height_mutable = 6 * term->sixel.pan;
}
uint32_t *old_data = term->sixel.image.data; uint32_t *old_data = term->sixel.image.data;
const int old_width = term->sixel.image.width; const int old_width = term->sixel.image.width;

50
slave.c
View file

@ -436,54 +436,8 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
add_to_env(&custom_env, "COLORTERM", "truecolor"); add_to_env(&custom_env, "COLORTERM", "truecolor");
add_to_env(&custom_env, "PWD", cwd); add_to_env(&custom_env, "PWD", cwd);
del_from_env(&custom_env, "TERM_PROGRAM"); /* Wezterm, Ghostty */ del_from_env(&custom_env, "TERM_PROGRAM");
del_from_env(&custom_env, "TERM_PROGRAM_VERSION"); /* Wezterm, Ghostty */ del_from_env(&custom_env, "TERM_PROGRAM_VERSION");
del_from_env(&custom_env, "TERMINAL_NAME"); /* Contour */
del_from_env(&custom_env, "TERMINAL_VERSION_STRING"); /* Contour */
del_from_env(&custom_env, "TERMINAL_VERSION_TRIPLE"); /* Contour */
/* XTerm specific */
del_from_env(&custom_env, "XTERM_SHELL");
del_from_env(&custom_env, "XTERM_VERSION");
del_from_env(&custom_env, "XTERM_LOCALE");
/* Mlterm specific */
del_from_env(&custom_env, "MLTERM");
/* Zutty specific */
del_from_env(&custom_env, "ZUTTY_VERSION");
/* Ghostty specific */
del_from_env(&custom_env, "GHOSTTY_BIN_DIR");
del_from_env(&custom_env, "GHOSTTY_SHELL_INTEGRATION_NO_SUDO");
del_from_env(&custom_env, "GHOSTTY_RESOURCES_DIR");
/* Kitty specific */
del_from_env(&custom_env, "KITTY_WINDOW_ID");
del_from_env(&custom_env, "KITTY_PID");
del_from_env(&custom_env, "KITTY_PUBLIC_KEY");
del_from_env(&custom_env, "KITTY_INSTALLATION_DIR");
/* Contour specific */
del_from_env(&custom_env, "CONTOUR_PROFILE");
/* Wezterm specific */
del_from_env(&custom_env, "WEZTERM_PANE");
del_from_env(&custom_env, "WEZTERM_EXECUTABLE");
del_from_env(&custom_env, "WEZTERM_CONFIG_FILE");
del_from_env(&custom_env, "WEZTERM_EXECUTABLE_DIR");
del_from_env(&custom_env, "WEZTERM_UNIX_SOCKET");
del_from_env(&custom_env, "WEZTERM_CONFIG_DIR");
/* Alacritty specific */
del_from_env(&custom_env, "ALACRITTY_LOG");
del_from_env(&custom_env, "ALACRITTY_WINDOW_ID");
del_from_env(&custom_env, "ALACRITTY_SOCKET");
/* VTE, gnome-terminal, kgx etc */
del_from_env(&custom_env, "VTE_VERSION");
del_from_env(&custom_env, "GNOME_TERMINAL_SERVICE");
del_from_env(&custom_env, "GNOME_TERMINAL_SCREEN");
#if defined(FOOT_TERMINFO_PATH) #if defined(FOOT_TERMINFO_PATH)
add_to_env(&custom_env, "TERMINFO", FOOT_TERMINFO_PATH); add_to_env(&custom_env, "TERMINFO", FOOT_TERMINFO_PATH);

View file

@ -199,7 +199,7 @@ add_utmp_record(const struct config *conf, struct reaper *reaper, int ptmx)
return true; return true;
char *const argv[] = {conf->utmp_helper_path, UTMP_ADD, getenv("WAYLAND_DISPLAY"), NULL}; char *const argv[] = {conf->utmp_helper_path, UTMP_ADD, getenv("WAYLAND_DISPLAY"), NULL};
return spawn(reaper, NULL, argv, ptmx, -1, -1, NULL, NULL, NULL) >= 0; return spawn(reaper, NULL, argv, ptmx, ptmx, -1, NULL, NULL, NULL) >= 0;
#else #else
return true; return true;
#endif #endif
@ -223,7 +223,7 @@ del_utmp_record(const struct config *conf, struct reaper *reaper, int ptmx)
; ;
char *const argv[] = {conf->utmp_helper_path, UTMP_DEL, del_argument, NULL}; char *const argv[] = {conf->utmp_helper_path, UTMP_DEL, del_argument, NULL};
return spawn(reaper, NULL, argv, ptmx, -1, -1, NULL, NULL, NULL) >= 0; return spawn(reaper, NULL, argv, ptmx, ptmx, -1, NULL, NULL, NULL) >= 0;
#else #else
return true; return true;
#endif #endif
@ -719,9 +719,6 @@ initialize_render_workers(struct terminal *term)
goto err_sem_destroy; goto err_sem_destroy;
} }
mtx_init(&term->render.workers.preapplied_damage.lock, mtx_plain);
cnd_init(&term->render.workers.preapplied_damage.cond);
term->render.workers.threads = xcalloc( term->render.workers.threads = xcalloc(
term->render.workers.count, sizeof(term->render.workers.threads[0])); term->render.workers.count, sizeof(term->render.workers.threads[0]));
@ -1085,11 +1082,7 @@ reload_fonts(struct terminal *term, bool resize_grid)
* an a2r10g0b10 type of surface, since we need more than 2 * an a2r10g0b10 type of surface, since we need more than 2
* bits for alpha. * bits for alpha.
*/ */
#if defined(HAVE_PIXMAN_RGBA_16)
options->color_glyphs.format = PIXMAN_a16b16g16r16;
#else
options->color_glyphs.format = PIXMAN_rgba_float; options->color_glyphs.format = PIXMAN_rgba_float;
#endif
} }
struct fcft_font *fonts[4]; struct fcft_font *fonts[4];
@ -1266,17 +1259,9 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
const enum shm_bit_depth desired_bit_depth = const enum shm_bit_depth desired_bit_depth =
conf->tweak.surface_bit_depth == SHM_BITS_AUTO conf->tweak.surface_bit_depth == SHM_BITS_AUTO
? wayl_do_linear_blending(wayl, conf) ? SHM_BITS_16 : SHM_BITS_8 ? wayl_do_linear_blending(wayl, conf) ? SHM_BITS_10 : SHM_BITS_8
: conf->tweak.surface_bit_depth; : conf->tweak.surface_bit_depth;
const struct color_theme *theme = NULL;
switch (conf->initial_color_theme) {
case COLOR_THEME_DARK: theme = &conf->colors_dark; break;
case COLOR_THEME_LIGHT: theme = &conf->colors_light; break;
case COLOR_THEME_1: BUG("COLOR_THEME_1 should not be used"); break;
case COLOR_THEME_2: BUG("COLOR_THEME_2 should not be used"); break;
}
/* Initialize configure-based terminal attributes */ /* Initialize configure-based terminal attributes */
*term = (struct terminal) { *term = (struct terminal) {
.fdm = fdm, .fdm = fdm,
@ -1294,7 +1279,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
}, },
.font_dpi = 0., .font_dpi = 0.,
.font_dpi_before_unmap = -1., .font_dpi_before_unmap = -1.,
.font_subpixel = (theme->alpha == 0xffff /* Can't do subpixel rendering on transparent background */ .font_subpixel = (conf->colors.alpha == 0xffff /* Can't do subpixel rendering on transparent background */
? FCFT_SUBPIXEL_DEFAULT ? FCFT_SUBPIXEL_DEFAULT
: FCFT_SUBPIXEL_NONE), : FCFT_SUBPIXEL_NONE),
.cursor_keys_mode = CURSOR_KEYS_NORMAL, .cursor_keys_mode = CURSOR_KEYS_NORMAL,
@ -1310,14 +1295,14 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.state = 0, /* STATE_GROUND */ .state = 0, /* STATE_GROUND */
}, },
.colors = { .colors = {
.fg = theme->fg, .fg = conf->colors.fg,
.bg = theme->bg, .bg = conf->colors.bg,
.alpha = theme->alpha, .alpha = conf->colors.alpha,
.cursor_fg = (theme->use_custom.cursor ? 1u << 31 : 0) | theme->cursor.text, .cursor_fg = conf->cursor.color.text,
.cursor_bg = (theme->use_custom.cursor ? 1u << 31 : 0) | theme->cursor.cursor, .cursor_bg = conf->cursor.color.cursor,
.selection_fg = theme->selection_fg, .selection_fg = conf->colors.selection_fg,
.selection_bg = theme->selection_bg, .selection_bg = conf->colors.selection_bg,
.active_theme = conf->initial_color_theme, .use_custom_selection = conf->colors.use_custom.selection,
}, },
.color_stack = { .color_stack = {
.stack = NULL, .stack = NULL,
@ -1361,13 +1346,13 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.render = { .render = {
.chains = { .chains = {
.grid = shm_chain_new(wayl, true, 1 + conf->render_worker_count, .grid = shm_chain_new(wayl, true, 1 + conf->render_worker_count,
desired_bit_depth, &render_buffer_release_callback, term), desired_bit_depth),
.search = shm_chain_new(wayl, false, 1 ,desired_bit_depth, NULL, NULL), .search = shm_chain_new(wayl, false, 1 ,desired_bit_depth),
.scrollback_indicator = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL), .scrollback_indicator = shm_chain_new(wayl, false, 1, desired_bit_depth),
.render_timer = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL), .render_timer = shm_chain_new(wayl, false, 1, desired_bit_depth),
.url = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL), .url = shm_chain_new(wayl, false, 1, desired_bit_depth),
.csd = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL), .csd = shm_chain_new(wayl, false, 1, desired_bit_depth),
.overlay = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL), .overlay = shm_chain_new(wayl, false, 1, desired_bit_depth),
}, },
.scrollback_lines = conf->scrollback.lines, .scrollback_lines = conf->scrollback.lines,
.app_sync_updates.timer_fd = app_sync_updates_fd, .app_sync_updates.timer_fd = app_sync_updates_fd,
@ -1414,7 +1399,6 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
pixman_region32_init(&term->render.last_overlay_clip); pixman_region32_init(&term->render.last_overlay_clip);
term_update_ascii_printer(term); term_update_ascii_printer(term);
memcpy(term->colors.table, theme->table, sizeof(term->colors.table));
for (size_t i = 0; i < 4; i++) { for (size_t i = 0; i < 4; i++) {
const struct config_font_list *font_list = &conf->fonts[i]; const struct config_font_list *font_list = &conf->fonts[i];
@ -1449,6 +1433,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
xassert(tll_length(term->wl->monitors) > 0); xassert(tll_length(term->wl->monitors) > 0);
term->scale = tll_front(term->wl->monitors).scale; term->scale = tll_front(term->wl->monitors).scale;
memcpy(term->colors.table, term->conf->colors.table, sizeof(term->colors.table));
/* Initialize the Wayland window backend */ /* Initialize the Wayland window backend */
if ((term->window = wayl_win_init(term, token)) == NULL) if ((term->window = wayl_win_init(term, token)) == NULL)
goto err; goto err;
@ -1898,8 +1884,6 @@ term_destroy(struct terminal *term)
} }
} }
free(term->render.workers.threads); free(term->render.workers.threads);
mtx_destroy(&term->render.workers.preapplied_damage.lock);
cnd_destroy(&term->render.workers.preapplied_damage.cond);
mtx_destroy(&term->render.workers.lock); mtx_destroy(&term->render.workers.lock);
sem_destroy(&term->render.workers.start); sem_destroy(&term->render.workers.start);
sem_destroy(&term->render.workers.done); sem_destroy(&term->render.workers.done);
@ -2080,19 +2064,6 @@ erase_line(struct terminal *term, struct row *row)
row->shell_integration.cmd_end = -1; row->shell_integration.cmd_end = -1;
} }
static void
term_theme_apply(struct terminal *term, const struct color_theme *theme)
{
term->colors.fg = theme->fg;
term->colors.bg = theme->bg;
term->colors.alpha = theme->alpha;
term->colors.cursor_fg = (theme->use_custom.cursor ? 1u << 31 : 0) | theme->cursor.text;
term->colors.cursor_bg = (theme->use_custom.cursor ? 1u << 31 : 0) | theme->cursor.cursor;
term->colors.selection_fg = theme->selection_fg;
term->colors.selection_bg = theme->selection_bg;
memcpy(term->colors.table, theme->table, sizeof(term->colors.table));
}
void void
term_reset(struct terminal *term, bool hard) term_reset(struct terminal *term, bool hard)
{ {
@ -2176,20 +2147,19 @@ term_reset(struct terminal *term, bool hard)
if (!hard) if (!hard)
return; return;
const struct color_theme *theme = NULL;
switch (term->conf->initial_color_theme) {
case COLOR_THEME_DARK: theme = &term->conf->colors_dark; break;
case COLOR_THEME_LIGHT: theme = &term->conf->colors_light; break;
case COLOR_THEME_1: BUG("COLOR_THEME_1 should not be used"); break;
case COLOR_THEME_2: BUG("COLOR_THEME_2 should not be used"); break;
}
term->flash.active = false; term->flash.active = false;
term->blink.state = BLINK_ON; term->blink.state = BLINK_ON;
fdm_del(term->fdm, term->blink.fd); term->blink.fd = -1; fdm_del(term->fdm, term->blink.fd); term->blink.fd = -1;
term_theme_apply(term, theme); term->colors.fg = term->conf->colors.fg;
term->colors.active_theme = term->conf->initial_color_theme; term->colors.bg = term->conf->colors.bg;
term->colors.alpha = term->conf->colors.alpha;
term->colors.cursor_fg = term->conf->cursor.color.text;
term->colors.cursor_bg = term->conf->cursor.color.cursor;
term->colors.selection_fg = term->conf->colors.selection_fg;
term->colors.selection_bg = term->conf->colors.selection_bg;
term->colors.use_custom_selection = term->conf->colors.use_custom.selection;
memcpy(term->colors.table, term->conf->colors.table,
sizeof(term->colors.table));
free(term->color_stack.stack); free(term->color_stack.stack);
term->color_stack.stack = NULL; term->color_stack.stack = NULL;
term->color_stack.size = 0; term->color_stack.size = 0;
@ -2790,11 +2760,13 @@ UNITTEST
}, },
.kind = SELECTION_NONE, .kind = SELECTION_NONE,
.auto_scroll = { .auto_scroll = {
.fd = -1, .fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK),
}, },
}, },
}; };
xassert(term.selection.auto_scroll.fd >= 0);
#define populate_scrollback() do { \ #define populate_scrollback() do { \
for (int i = 0; i < scrollback_rows; i++) { \ for (int i = 0; i < scrollback_rows; i++) { \
if (term.normal.rows[i] == NULL) { \ if (term.normal.rows[i] == NULL) { \
@ -2884,7 +2856,7 @@ UNITTEST
/* Cleanup */ /* Cleanup */
tll_free(term.normal.sixel_images); tll_free(term.normal.sixel_images);
xassert(term.selection.auto_scroll.fd == -1); close(term.selection.auto_scroll.fd);
for (int i = 0; i < scrollback_rows; i++) for (int i = 0; i < scrollback_rows; i++)
grid_row_free(term.normal.rows[i]); grid_row_free(term.normal.rows[i]);
free(term.normal.rows); free(term.normal.rows);
@ -3169,17 +3141,11 @@ term_scroll_reverse_partial(struct terminal *term,
sixel_scroll_down(term, rows); sixel_scroll_down(term, rows);
const bool view_follows = term->grid->view == term->grid->offset; bool view_follows = term->grid->view == term->grid->offset;
term->grid->offset -= rows; term->grid->offset -= rows;
term->grid->offset += term->grid->num_rows; term->grid->offset += term->grid->num_rows;
term->grid->offset &= term->grid->num_rows - 1; term->grid->offset &= term->grid->num_rows - 1;
/* How many lines from the scrollback start is the current viewport? */
const int view_sb_start_distance = grid_row_abs_to_sb(
term->grid, term->rows, term->grid->view);
const int offset_sb_start_distance = grid_row_abs_to_sb(
term->grid, term->rows, term->grid->offset);
xassert(term->grid->offset >= 0); xassert(term->grid->offset >= 0);
xassert(term->grid->offset < term->grid->num_rows); xassert(term->grid->offset < term->grid->num_rows);
@ -3187,11 +3153,6 @@ term_scroll_reverse_partial(struct terminal *term,
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows); term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
selection_view_up(term, term->grid->offset); selection_view_up(term, term->grid->offset);
term->grid->view = term->grid->offset; term->grid->view = term->grid->offset;
} else if (unlikely(view_sb_start_distance > offset_sb_start_distance)) {
/* Part of current view is being scrolled out */
int new_view = term->grid->offset;
selection_view_up(term, new_view);
term->grid->view = new_view;
} }
/* Bottom non-scrolling region */ /* Bottom non-scrolling region */
@ -3208,16 +3169,11 @@ term_scroll_reverse_partial(struct terminal *term,
erase_line(term, row); erase_line(term, row);
} }
if (unlikely(view_sb_start_distance > offset_sb_start_distance))
term_damage_view(term);
term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row); term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row);
#if defined(_DEBUG) #if defined(_DEBUG)
for (int r = 0; r < term->rows; r++) for (int r = 0; r < term->rows; r++)
xassert(grid_row(term->grid, r) != NULL); xassert(grid_row(term->grid, r) != NULL);
for (int r = 0; r < term->rows; r++)
xassert(grid_row_in_view(term->grid, r) != NULL);
#endif #endif
} }
@ -3424,13 +3380,10 @@ report_mouse_click(struct terminal *term, int encoded_button, int row, int col,
encoded_button, col + 1, row + 1, release ? 'm' : 'M'); encoded_button, col + 1, row + 1, release ? 'm' : 'M');
break; break;
case MOUSE_SGR_PIXELS: { case MOUSE_SGR_PIXELS:
const int bounded_col = max(col_pixels, 0);
const int bounded_row = max(row_pixels, 0);
snprintf(response, sizeof(response), "\033[<%d;%d;%d%c", snprintf(response, sizeof(response), "\033[<%d;%d;%d%c",
encoded_button, bounded_col + 1, bounded_row + 1, release ? 'm' : 'M'); encoded_button, col_pixels + 1, row_pixels + 1, release ? 'm' : 'M');
break; break;
}
case MOUSE_URXVT: case MOUSE_URXVT:
snprintf(response, sizeof(response), "\033[%d;%d;%dM", snprintf(response, sizeof(response), "\033[%d;%d;%dM",
@ -3611,9 +3564,7 @@ term_xcursor_update_for_seat(struct terminal *term, struct seat *seat)
if (seat->pointer.hidden) if (seat->pointer.hidden)
shape = CURSOR_SHAPE_HIDDEN; shape = CURSOR_SHAPE_HIDDEN;
else if (cursor_string_to_server_shape( else if (cursor_string_to_server_shape(term->mouse_user_cursor) != 0 ||
term->mouse_user_cursor,
term->wl->shape_manager_version) != 0 ||
render_xcursor_is_valid(seat, term->mouse_user_cursor)) render_xcursor_is_valid(seat, term->mouse_user_cursor))
{ {
shape = CURSOR_SHAPE_CUSTOM; shape = CURSOR_SHAPE_CUSTOM;
@ -4033,11 +3984,9 @@ term_print(struct terminal *term, char32_t wc, int width, bool insert_mode_disab
cell->wc = term->vt.last_printed = wc; cell->wc = term->vt.last_printed = wc;
cell->attrs = term->vt.attrs; cell->attrs = term->vt.attrs;
if (unlikely(term->vt.osc8.uri != NULL)) { if (term->vt.osc8.uri != NULL) {
for (int i = 0; i < width && (col + i) < term->cols; i++) { grid_row_uri_range_put(
grid_row_uri_range_put( row, col, term->vt.osc8.uri, term->vt.osc8.id);
row, col + i, term->vt.osc8.uri, term->vt.osc8.id);
}
switch (term->conf->url.osc8_underline) { switch (term->conf->url.osc8_underline) {
case OSC8_UNDERLINE_ALWAYS: case OSC8_UNDERLINE_ALWAYS:
@ -4744,68 +4693,3 @@ term_send_size_notification(struct terminal *term)
term->rows, term->cols, height, width); term->rows, term->cols, height, width);
term_to_slave(term, buf, n); term_to_slave(term, buf, n);
} }
void
term_theme_switch_to_dark(struct terminal *term)
{
if (term->colors.active_theme == COLOR_THEME_DARK)
return;
term_theme_apply(term, &term->conf->colors_dark);
term->colors.active_theme = COLOR_THEME_DARK;
wayl_win_alpha_changed(term->window);
term_font_subpixel_changed(term);
if (term->report_theme_changes)
term_to_slave(term, "\033[?997;1n", 9);
term_damage_view(term);
term_damage_margins(term);
render_refresh(term);
}
void
term_theme_switch_to_light(struct terminal *term)
{
if (term->colors.active_theme == COLOR_THEME_LIGHT)
return;
term_theme_apply(term, &term->conf->colors_light);
term->colors.active_theme = COLOR_THEME_LIGHT;
wayl_win_alpha_changed(term->window);
term_font_subpixel_changed(term);
if (term->report_theme_changes)
term_to_slave(term, "\033[?997;2n", 9);
term_damage_view(term);
term_damage_margins(term);
render_refresh(term);
}
void
term_theme_toggle(struct terminal *term)
{
if (term->colors.active_theme == COLOR_THEME_DARK) {
term_theme_apply(term, &term->conf->colors_light);
term->colors.active_theme = COLOR_THEME_LIGHT;
if (term->report_theme_changes)
term_to_slave(term, "\033[?997;2n", 9);
} else {
term_theme_apply(term, &term->conf->colors_dark);
term->colors.active_theme = COLOR_THEME_DARK;
if (term->report_theme_changes)
term_to_slave(term, "\033[?997;1n", 9);
}
wayl_win_alpha_changed(term->window);
term_font_subpixel_changed(term);
term_damage_view(term);
term_damage_margins(term);
render_refresh(term);
}

View file

@ -404,7 +404,7 @@ struct colors {
uint32_t cursor_bg; /* cursor color */ uint32_t cursor_bg; /* cursor color */
uint32_t selection_fg; uint32_t selection_fg;
uint32_t selection_bg; uint32_t selection_bg;
enum which_color_theme active_theme; bool use_custom_selection;
}; };
struct terminal { struct terminal {
@ -517,7 +517,6 @@ struct terminal {
bool num_lock_modifier; bool num_lock_modifier;
bool bell_action_enabled; bool bell_action_enabled;
bool report_theme_changes;
/* Saved DECSET modes - we save the SET state */ /* Saved DECSET modes - we save the SET state */
struct { struct {
@ -548,7 +547,6 @@ struct terminal {
bool ime:1; bool ime:1;
bool app_sync_updates:1; bool app_sync_updates:1;
bool grapheme_shaping:1; bool grapheme_shaping:1;
bool report_theme_changes:1;
bool size_notifications:1; bool size_notifications:1;
@ -706,14 +704,6 @@ struct terminal {
tll(int) queue; tll(int) queue;
thrd_t *threads; thrd_t *threads;
struct buffer *buf; struct buffer *buf;
struct {
mtx_t lock;
cnd_t cond;
struct buffer *buf;
struct timespec start;
struct timespec stop;
} preapplied_damage;
} workers; } workers;
/* Last rendered cursor position */ /* Last rendered cursor position */
@ -724,8 +714,6 @@ struct terminal {
} last_cursor; } last_cursor;
struct buffer *last_buf; /* Buffer we rendered to last time */ struct buffer *last_buf; /* Buffer we rendered to last time */
size_t frames_since_last_immediate_release;
bool preapply_last_frame_damage;
enum overlay_style last_overlay_style; enum overlay_style last_overlay_style;
struct buffer *last_overlay_buf; struct buffer *last_overlay_buf;
@ -994,10 +982,6 @@ void term_enable_size_notifications(struct terminal *term);
void term_disable_size_notifications(struct terminal *term); void term_disable_size_notifications(struct terminal *term);
void term_send_size_notification(struct terminal *term); void term_send_size_notification(struct terminal *term);
void term_theme_switch_to_dark(struct terminal *term);
void term_theme_switch_to_light(struct terminal *term);
void term_theme_toggle(struct terminal *term);
static inline void term_reset_grapheme_state(struct terminal *term) static inline void term_reset_grapheme_state(struct terminal *term)
{ {
#if defined(FOOT_GRAPHEME_CLUSTERING) #if defined(FOOT_GRAPHEME_CLUSTERING)

View file

@ -399,16 +399,6 @@ test_color(struct context *ctx, bool (*parse_fun)(struct context *ctx),
BUG("[%s].%s=%s: failed to parse", BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value); ctx->section, ctx->key, ctx->value);
} }
uint32_t color = input[i].color;
if (alpha_allowed && strlen(input[i].option_string) == 6)
color |= 0xff000000;
if (*ptr != color) {
BUG("[%s].%s=%s: expected 0x%08x, got 0x%08x",
ctx->section, ctx->key, ctx->value,
color, *ptr);
}
} }
} }
} }
@ -455,18 +445,6 @@ test_two_colors(struct context *ctx, bool (*parse_fun)(struct context *ctx),
BUG("[%s].%s=%s: failed to parse", BUG("[%s].%s=%s: failed to parse",
ctx->section, ctx->key, ctx->value); ctx->section, ctx->key, ctx->value);
} }
if (*ptr1 != input[i].color1) {
BUG("[%s].%s=%s: expected 0x%08x, got 0x%08x",
ctx->section, ctx->key, ctx->value,
input[i].color1, *ptr1);
}
if (*ptr2 != input[i].color2) {
BUG("[%s].%s=%s: expected 0x%08x, got 0x%08x",
ctx->section, ctx->key, ctx->value,
input[i].color2, *ptr2);
}
} }
} }
} }
@ -482,7 +460,6 @@ test_section_main(void)
test_string(&ctx, &parse_section_main, "shell", &conf.shell); test_string(&ctx, &parse_section_main, "shell", &conf.shell);
test_string(&ctx, &parse_section_main, "term", &conf.term); test_string(&ctx, &parse_section_main, "term", &conf.term);
test_string(&ctx, &parse_section_main, "app-id", &conf.app_id); test_string(&ctx, &parse_section_main, "app-id", &conf.app_id);
test_string(&ctx, &parse_section_main, "toplevel-tag", &conf.toplevel_tag);
test_string(&ctx, &parse_section_main, "utmp-helper", &conf.utmp_helper_path); test_string(&ctx, &parse_section_main, "utmp-helper", &conf.utmp_helper_path);
test_c32string(&ctx, &parse_section_main, "word-delimiters", &conf.word_delimiters); test_c32string(&ctx, &parse_section_main, "word-delimiters", &conf.word_delimiters);
@ -492,7 +469,6 @@ test_section_main(void)
test_boolean(&ctx, &parse_section_main, "locked-title", &conf.locked_title); test_boolean(&ctx, &parse_section_main, "locked-title", &conf.locked_title);
test_boolean(&ctx, &parse_section_main, "dpi-aware", &conf.dpi_aware); test_boolean(&ctx, &parse_section_main, "dpi-aware", &conf.dpi_aware);
test_boolean(&ctx, &parse_section_main, "gamma-correct-blending", &conf.gamma_correct); test_boolean(&ctx, &parse_section_main, "gamma-correct-blending", &conf.gamma_correct);
test_boolean(&ctx, &parse_section_main, "uppercase-regex-insert", &conf.uppercase_regex_insert);
test_pt_or_px(&ctx, &parse_section_main, "font-size-adjustment", &conf.font_size_adjustment.pt_or_px); /* TODO: test N% values too */ test_pt_or_px(&ctx, &parse_section_main, "font-size-adjustment", &conf.font_size_adjustment.pt_or_px); /* TODO: test N% values too */
test_pt_or_px(&ctx, &parse_section_main, "line-height", &conf.line_height); test_pt_or_px(&ctx, &parse_section_main, "line-height", &conf.line_height);
@ -521,14 +497,6 @@ test_section_main(void)
(int []){STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN}, (int []){STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN},
(int *)&conf.startup_mode); (int *)&conf.startup_mode);
test_enum(
&ctx, &parse_section_main, "initial-color-theme",
2,
(const char *[]){"dark", "light", "1", "2"},
(int []){COLOR_THEME_DARK, COLOR_THEME_LIGHT,
COLOR_THEME_DARK, COLOR_THEME_LIGHT},
(int *)&conf.initial_color_theme);
/* TODO: font (custom) */ /* TODO: font (custom) */
/* TODO: include (custom) */ /* TODO: include (custom) */
/* TODO: bold-text-in-bright (enum/boolean) */ /* TODO: bold-text-in-bright (enum/boolean) */
@ -703,157 +671,69 @@ test_section_touch(void)
} }
static void static void
test_section_colors_dark(void) test_section_colors(void)
{ {
struct config conf = {0}; struct config conf = {0};
struct context ctx = { struct context ctx = {
.conf = &conf, .section = "colors-dark", .path = "unittest"}; .conf = &conf, .section = "colors", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_colors, "invalid-key"); test_invalid_key(&ctx, &parse_section_colors, "invalid-key");
test_color(&ctx, &parse_section_colors_dark, "foreground", false, &conf.colors_dark.fg); test_color(&ctx, &parse_section_colors, "foreground", false, &conf.colors.fg);
test_color(&ctx, &parse_section_colors_dark, "background", false, &conf.colors_dark.bg); test_color(&ctx, &parse_section_colors, "background", false, &conf.colors.bg);
test_color(&ctx, &parse_section_colors_dark, "regular0", false, &conf.colors_dark.table[0]); test_color(&ctx, &parse_section_colors, "regular0", false, &conf.colors.table[0]);
test_color(&ctx, &parse_section_colors_dark, "regular1", false, &conf.colors_dark.table[1]); test_color(&ctx, &parse_section_colors, "regular1", false, &conf.colors.table[1]);
test_color(&ctx, &parse_section_colors_dark, "regular2", false, &conf.colors_dark.table[2]); test_color(&ctx, &parse_section_colors, "regular2", false, &conf.colors.table[2]);
test_color(&ctx, &parse_section_colors_dark, "regular3", false, &conf.colors_dark.table[3]); test_color(&ctx, &parse_section_colors, "regular3", false, &conf.colors.table[3]);
test_color(&ctx, &parse_section_colors_dark, "regular4", false, &conf.colors_dark.table[4]); test_color(&ctx, &parse_section_colors, "regular4", false, &conf.colors.table[4]);
test_color(&ctx, &parse_section_colors_dark, "regular5", false, &conf.colors_dark.table[5]); test_color(&ctx, &parse_section_colors, "regular5", false, &conf.colors.table[5]);
test_color(&ctx, &parse_section_colors_dark, "regular6", false, &conf.colors_dark.table[6]); test_color(&ctx, &parse_section_colors, "regular6", false, &conf.colors.table[6]);
test_color(&ctx, &parse_section_colors_dark, "regular7", false, &conf.colors_dark.table[7]); test_color(&ctx, &parse_section_colors, "regular7", false, &conf.colors.table[7]);
test_color(&ctx, &parse_section_colors_dark, "bright0", false, &conf.colors_dark.table[8]); test_color(&ctx, &parse_section_colors, "bright0", false, &conf.colors.table[8]);
test_color(&ctx, &parse_section_colors_dark, "bright1", false, &conf.colors_dark.table[9]); test_color(&ctx, &parse_section_colors, "bright1", false, &conf.colors.table[9]);
test_color(&ctx, &parse_section_colors_dark, "bright2", false, &conf.colors_dark.table[10]); test_color(&ctx, &parse_section_colors, "bright2", false, &conf.colors.table[10]);
test_color(&ctx, &parse_section_colors_dark, "bright3", false, &conf.colors_dark.table[11]); test_color(&ctx, &parse_section_colors, "bright3", false, &conf.colors.table[11]);
test_color(&ctx, &parse_section_colors_dark, "bright4", false, &conf.colors_dark.table[12]); test_color(&ctx, &parse_section_colors, "bright4", false, &conf.colors.table[12]);
test_color(&ctx, &parse_section_colors_dark, "bright5", false, &conf.colors_dark.table[13]); test_color(&ctx, &parse_section_colors, "bright5", false, &conf.colors.table[13]);
test_color(&ctx, &parse_section_colors_dark, "bright6", false, &conf.colors_dark.table[14]); test_color(&ctx, &parse_section_colors, "bright6", false, &conf.colors.table[14]);
test_color(&ctx, &parse_section_colors_dark, "bright7", false, &conf.colors_dark.table[15]); test_color(&ctx, &parse_section_colors, "bright7", false, &conf.colors.table[15]);
test_color(&ctx, &parse_section_colors_dark, "dim0", false, &conf.colors_dark.dim[0]); test_color(&ctx, &parse_section_colors, "dim0", false, &conf.colors.dim[0]);
test_color(&ctx, &parse_section_colors_dark, "dim1", false, &conf.colors_dark.dim[1]); test_color(&ctx, &parse_section_colors, "dim1", false, &conf.colors.dim[1]);
test_color(&ctx, &parse_section_colors_dark, "dim2", false, &conf.colors_dark.dim[2]); test_color(&ctx, &parse_section_colors, "dim2", false, &conf.colors.dim[2]);
test_color(&ctx, &parse_section_colors_dark, "dim3", false, &conf.colors_dark.dim[3]); test_color(&ctx, &parse_section_colors, "dim3", false, &conf.colors.dim[3]);
test_color(&ctx, &parse_section_colors_dark, "dim4", false, &conf.colors_dark.dim[4]); test_color(&ctx, &parse_section_colors, "dim4", false, &conf.colors.dim[4]);
test_color(&ctx, &parse_section_colors_dark, "dim5", false, &conf.colors_dark.dim[5]); test_color(&ctx, &parse_section_colors, "dim5", false, &conf.colors.dim[5]);
test_color(&ctx, &parse_section_colors_dark, "dim6", false, &conf.colors_dark.dim[6]); test_color(&ctx, &parse_section_colors, "dim6", false, &conf.colors.dim[6]);
test_color(&ctx, &parse_section_colors_dark, "dim7", false, &conf.colors_dark.dim[7]); test_color(&ctx, &parse_section_colors, "dim7", false, &conf.colors.dim[7]);
test_color(&ctx, &parse_section_colors_dark, "selection-foreground", false, &conf.colors_dark.selection_fg); test_color(&ctx, &parse_section_colors, "selection-foreground", false, &conf.colors.selection_fg);
test_color(&ctx, &parse_section_colors_dark, "selection-background", false, &conf.colors_dark.selection_bg); test_color(&ctx, &parse_section_colors, "selection-background", false, &conf.colors.selection_bg);
test_color(&ctx, &parse_section_colors_dark, "urls", false, &conf.colors_dark.url); test_color(&ctx, &parse_section_colors, "urls", false, &conf.colors.url);
test_two_colors(&ctx, &parse_section_colors_dark, "jump-labels", false, test_two_colors(&ctx, &parse_section_colors, "jump-labels", false,
&conf.colors_dark.jump_label.fg, &conf.colors.jump_label.fg,
&conf.colors_dark.jump_label.bg); &conf.colors.jump_label.bg);
test_two_colors(&ctx, &parse_section_colors_dark, "scrollback-indicator", false, test_two_colors(&ctx, &parse_section_colors, "scrollback-indicator", false,
&conf.colors_dark.scrollback_indicator.fg, &conf.colors.scrollback_indicator.fg,
&conf.colors_dark.scrollback_indicator.bg); &conf.colors.scrollback_indicator.bg);
test_two_colors(&ctx, &parse_section_colors_dark, "search-box-no-match", false, test_two_colors(&ctx, &parse_section_colors, "search-box-no-match", false,
&conf.colors_dark.search_box.no_match.fg, &conf.colors.search_box.no_match.fg,
&conf.colors_dark.search_box.no_match.bg); &conf.colors.search_box.no_match.bg);
test_two_colors(&ctx, &parse_section_colors_dark, "search-box-match", false, test_two_colors(&ctx, &parse_section_colors, "search-box-match", false,
&conf.colors_dark.search_box.match.fg, &conf.colors.search_box.match.fg,
&conf.colors_dark.search_box.match.bg); &conf.colors.search_box.match.bg);
test_two_colors(&ctx, &parse_section_colors_dark, "cursor", false, test_enum(&ctx, &parse_section_colors, "alpha-mode", 3,
&conf.colors_dark.cursor.text,
&conf.colors_dark.cursor.cursor);
test_enum(&ctx, &parse_section_colors_dark, "alpha-mode", 3,
(const char *[]){"default", "matching", "all"}, (const char *[]){"default", "matching", "all"},
(int []){ALPHA_MODE_DEFAULT, ALPHA_MODE_MATCHING, ALPHA_MODE_ALL}, (int []){ALPHA_MODE_DEFAULT, ALPHA_MODE_MATCHING, ALPHA_MODE_ALL},
(int *)&conf.colors_dark.alpha_mode); (int *)&conf.colors.alpha_mode);
test_enum(&ctx, &parse_section_colors_dark, "dim-blend-towards", 2,
(const char *[]){"black", "white"},
(int []){DIM_BLEND_TOWARDS_BLACK, DIM_BLEND_TOWARDS_WHITE},
(int *)&conf.colors_dark.dim_blend_towards);
for (size_t i = 0; i < 255; i++) { for (size_t i = 0; i < 255; i++) {
char key_name[4]; char key_name[4];
sprintf(key_name, "%zu", i); sprintf(key_name, "%zu", i);
test_color(&ctx, &parse_section_colors_dark, key_name, false, test_color(&ctx, &parse_section_colors, key_name, false,
&conf.colors_dark.table[i]); &conf.colors.table[i]);
} }
test_invalid_key(&ctx, &parse_section_colors_dark, "256"); test_invalid_key(&ctx, &parse_section_colors, "256");
/* TODO: alpha (float in range 0-1, converted to uint16_t) */
config_free(&conf);
}
static void
test_section_colors_light(void)
{
struct config conf = {0};
struct context ctx = {
.conf = &conf, .section = "colors-light", .path = "unittest"};
test_invalid_key(&ctx, &parse_section_colors, "invalid-key");
test_color(&ctx, &parse_section_colors_light, "foreground", false, &conf.colors_light.fg);
test_color(&ctx, &parse_section_colors_light, "background", false, &conf.colors_light.bg);
test_color(&ctx, &parse_section_colors_light, "regular0", false, &conf.colors_light.table[0]);
test_color(&ctx, &parse_section_colors_light, "regular1", false, &conf.colors_light.table[1]);
test_color(&ctx, &parse_section_colors_light, "regular2", false, &conf.colors_light.table[2]);
test_color(&ctx, &parse_section_colors_light, "regular3", false, &conf.colors_light.table[3]);
test_color(&ctx, &parse_section_colors_light, "regular4", false, &conf.colors_light.table[4]);
test_color(&ctx, &parse_section_colors_light, "regular5", false, &conf.colors_light.table[5]);
test_color(&ctx, &parse_section_colors_light, "regular6", false, &conf.colors_light.table[6]);
test_color(&ctx, &parse_section_colors_light, "regular7", false, &conf.colors_light.table[7]);
test_color(&ctx, &parse_section_colors_light, "bright0", false, &conf.colors_light.table[8]);
test_color(&ctx, &parse_section_colors_light, "bright1", false, &conf.colors_light.table[9]);
test_color(&ctx, &parse_section_colors_light, "bright2", false, &conf.colors_light.table[10]);
test_color(&ctx, &parse_section_colors_light, "bright3", false, &conf.colors_light.table[11]);
test_color(&ctx, &parse_section_colors_light, "bright4", false, &conf.colors_light.table[12]);
test_color(&ctx, &parse_section_colors_light, "bright5", false, &conf.colors_light.table[13]);
test_color(&ctx, &parse_section_colors_light, "bright6", false, &conf.colors_light.table[14]);
test_color(&ctx, &parse_section_colors_light, "bright7", false, &conf.colors_light.table[15]);
test_color(&ctx, &parse_section_colors_light, "dim0", false, &conf.colors_light.dim[0]);
test_color(&ctx, &parse_section_colors_light, "dim1", false, &conf.colors_light.dim[1]);
test_color(&ctx, &parse_section_colors_light, "dim2", false, &conf.colors_light.dim[2]);
test_color(&ctx, &parse_section_colors_light, "dim3", false, &conf.colors_light.dim[3]);
test_color(&ctx, &parse_section_colors_light, "dim4", false, &conf.colors_light.dim[4]);
test_color(&ctx, &parse_section_colors_light, "dim5", false, &conf.colors_light.dim[5]);
test_color(&ctx, &parse_section_colors_light, "dim6", false, &conf.colors_light.dim[6]);
test_color(&ctx, &parse_section_colors_light, "dim7", false, &conf.colors_light.dim[7]);
test_color(&ctx, &parse_section_colors_light, "selection-foreground", false, &conf.colors_light.selection_fg);
test_color(&ctx, &parse_section_colors_light, "selection-background", false, &conf.colors_light.selection_bg);
test_color(&ctx, &parse_section_colors_light, "urls", false, &conf.colors_light.url);
test_two_colors(&ctx, &parse_section_colors_light, "jump-labels", false,
&conf.colors_light.jump_label.fg,
&conf.colors_light.jump_label.bg);
test_two_colors(&ctx, &parse_section_colors_light, "scrollback-indicator", false,
&conf.colors_light.scrollback_indicator.fg,
&conf.colors_light.scrollback_indicator.bg);
test_two_colors(&ctx, &parse_section_colors_light, "search-box-no-match", false,
&conf.colors_light.search_box.no_match.fg,
&conf.colors_light.search_box.no_match.bg);
test_two_colors(&ctx, &parse_section_colors_light, "search-box-match", false,
&conf.colors_light.search_box.match.fg,
&conf.colors_light.search_box.match.bg);
test_two_colors(&ctx, &parse_section_colors_light, "cursor", false,
&conf.colors_light.cursor.text,
&conf.colors_light.cursor.cursor);
test_enum(&ctx, &parse_section_colors_light, "alpha-mode", 3,
(const char *[]){"default", "matching", "all"},
(int []){ALPHA_MODE_DEFAULT, ALPHA_MODE_MATCHING, ALPHA_MODE_ALL},
(int *)&conf.colors_light.alpha_mode);
test_enum(&ctx, &parse_section_colors_light, "dim-blend-towards", 2,
(const char *[]){"black", "white"},
(int []){DIM_BLEND_TOWARDS_BLACK, DIM_BLEND_TOWARDS_WHITE},
(int *)&conf.colors_light.dim_blend_towards);
for (size_t i = 0; i < 255; i++) {
char key_name[4];
sprintf(key_name, "%zu", i);
test_color(&ctx, &parse_section_colors_light, key_name, false,
&conf.colors_light.table[i]);
}
test_invalid_key(&ctx, &parse_section_colors_light, "256");
/* TODO: alpha (float in range 0-1, converted to uint16_t) */ /* TODO: alpha (float in range 0-1, converted to uint16_t) */
@ -1506,9 +1386,6 @@ test_section_tweak(void)
test_float(&ctx, &parse_section_tweak, "bold-text-in-bright-amount", test_float(&ctx, &parse_section_tweak, "bold-text-in-bright-amount",
&conf.bold_in_bright.amount); &conf.bold_in_bright.amount);
test_uint32(&ctx, &parse_section_tweak, "min-stride-alignment",
&conf.tweak.min_stride_alignment);
#if 0 /* Must be equal to, or less than INT32_MAX */ #if 0 /* Must be equal to, or less than INT32_MAX */
test_uint32(&ctx, &parse_section_tweak, "max-shm-pool-size-mb", test_uint32(&ctx, &parse_section_tweak, "max-shm-pool-size-mb",
&conf.tweak.max_shm_pool_size); &conf.tweak.max_shm_pool_size);
@ -1531,8 +1408,7 @@ main(int argc, const char *const *argv)
test_section_cursor(); test_section_cursor();
test_section_mouse(); test_section_mouse();
test_section_touch(); test_section_touch();
test_section_colors_dark(); test_section_colors();
test_section_colors_light();
test_section_csd(); test_section_csd();
test_section_key_bindings(); test_section_key_bindings();
test_section_key_bindings_collisions(); test_section_key_bindings_collisions();

View file

@ -1,8 +1,10 @@
# -*- conf -*- # -*- conf -*-
# Aero root theme # Aero root theme
[colors-dark] [cursor]
cursor=1a1a1a 9fd5f5 color=1a1a1a 9fd5f5
[colors]
foreground=dedeef foreground=dedeef
background=1a1a1a background=1a1a1a

View file

@ -1,8 +1,10 @@
# -*- conf -*- # -*- conf -*-
# Alacritty # Alacritty
[colors-dark] [cursor]
cursor = 181818 56d8c9 color = 181818 56d8c9
[colors]
background= 181818 background= 181818
foreground= d8d8d8 foreground= d8d8d8

View file

@ -1,8 +1,10 @@
# -*- conf -*- # -*- conf -*-
# https://github.com/romainl/Apprentice # https://github.com/romainl/Apprentice
[colors-dark] [cursor]
cursor=262626 6c6c6c color=262626 6c6c6c
[colors]
foreground=bcbcbc foreground=bcbcbc
background=262626 background=262626
regular0=1c1c1c regular0=1c1c1c

View file

@ -2,8 +2,10 @@
# theme: Ayu Mirage # theme: Ayu Mirage
# description: a theme based on Ayu Mirage for Sublime Text (original: https://github.com/dempfi/ayu) # description: a theme based on Ayu Mirage for Sublime Text (original: https://github.com/dempfi/ayu)
[colors-dark] [cursor]
cursor = ffcc66 665a44 color = ffcc66 665a44
[colors]
foreground = cccac2 foreground = cccac2
background = 242936 background = 242936

View file

@ -1,7 +1,7 @@
# _*_ conf _*_ # _*_ conf _*_
# Catppuccin Frappe # Catppuccin Frappe
[colors-dark] [colors]
foreground=c6d0f5 foreground=c6d0f5
background=303446 background=303446
@ -23,11 +23,6 @@ bright5=f4b8e4
bright6=81c8be bright6=81c8be
bright7=a5adce bright7=a5adce
cursor=232634 f2d5cf
16=ef9f76
17=f2d5cf
selection-foreground=c6d0f5 selection-foreground=c6d0f5
selection-background=4f5369 selection-background=4f5369

View file

@ -1,10 +1,7 @@
# _*_ conf _*_ # _*_ conf _*_
# Catppuccin Latte # Catppuccin Latte
[main] [colors]
initial-color-theme=light
[colors-light]
foreground=4c4f69 foreground=4c4f69
background=eff1f5 background=eff1f5
@ -26,11 +23,6 @@ bright5=ea76cb
bright6=179299 bright6=179299
bright7=bcc0cc bright7=bcc0cc
cursor=eff1f5 dc8a78
16=fe640b
17=dc8a78
selection-foreground=4c4f69 selection-foreground=4c4f69
selection-background=ccced7 selection-background=ccced7

View file

@ -1,7 +1,7 @@
# _*_ conf _*_ # _*_ conf _*_
# Catppuccin Macchiato # Catppuccin Macchiato
[colors-dark] [colors]
foreground=cad3f5 foreground=cad3f5
background=24273a background=24273a
@ -23,11 +23,6 @@ bright5=f5bde6
bright6=8bd5ca bright6=8bd5ca
bright7=a5adcb bright7=a5adcb
cursor=181926 f4dbd6
16=f5a97f
17=f4dbd6
selection-foreground=cad3f5 selection-foreground=cad3f5
selection-background=454a5f selection-background=454a5f

View file

@ -1,7 +1,7 @@
# _*_ conf _*_ # _*_ conf _*_
# Catppuccin Mocha # Catppuccin Mocha
[colors-dark] [colors]
foreground=cdd6f4 foreground=cdd6f4
background=1e1e2e background=1e1e2e
@ -23,11 +23,6 @@ bright5=f5c2e7
bright6=94e2d5 bright6=94e2d5
bright7=a6adc8 bright7=a6adc8
cursor=11111b f5e0dc
16=fab387
17=f5e0dc
selection-foreground=cdd6f4 selection-foreground=cdd6f4
selection-background=414356 selection-background=414356

View file

@ -3,8 +3,10 @@
# author: ayushnix (https://sr.ht/~ayushnix) # author: ayushnix (https://sr.ht/~ayushnix)
# description: A dark theme with bright cyberpunk colors (WCAG AAA compliant) # description: A dark theme with bright cyberpunk colors (WCAG AAA compliant)
[colors-dark] [cursor]
cursor = 181818 cdcdcd color = 181818 cdcdcd
[colors]
foreground = cdcdcd foreground = cdcdcd
background = 181818 background = 181818
regular0 = 181818 regular0 = 181818

View file

@ -1,8 +1,10 @@
# -*- conf -*- # -*- conf -*-
# Derp # Derp
[colors-dark] [cursor]
cursor=000000 ffffff color=000000 ffffff
[colors]
foreground=ffffff foreground=ffffff
background=000000 background=000000
regular0=111111 regular0=111111

View file

@ -2,8 +2,10 @@
# Deus # Deus
# Color palette based on: https://github.com/ajmwagar/vim-deus # Color palette based on: https://github.com/ajmwagar/vim-deus
[colors-dark] [cursor]
cursor=2c323b eaeaea color=2c323b eaeaea
[colors]
background=2c323b background=2c323b
foreground=eaeaea foreground=eaeaea
regular0=242a32 regular0=242a32

View file

@ -1,8 +1,10 @@
# -*- conf -*- # -*- conf -*-
# Dracula # Dracula
[colors-dark] [cursor]
cursor=282a36 f8f8f2 color=282a36 f8f8f2
[colors]
foreground=f8f8f2 foreground=f8f8f2
background=282a36 background=282a36
regular0=000000 # black regular0=000000 # black

View file

@ -1,8 +1,10 @@
# -*- conf -*- # -*- conf -*-
# Dracula iTerm2 variant # Dracula iTerm2 variant
[colors-dark] [cursor]
cursor=ffffff bbbbbb color=ffffff bbbbbb
[colors]
foreground=f8f8f2 foreground=f8f8f2
background=1e1f29 background=1e1f29
regular0=000000 # black regular0=000000 # black

View file

@ -5,11 +5,10 @@
# text and the white background. # text and the white background.
# author: Eugen Rahaian <eugen@rah.ro> # author: Eugen Rahaian <eugen@rah.ro>
[main] [cursor]
initial-color-theme=light color=ffffff 515151
[colors-light] [colors]
cursor=ffffff 515151
background= ffffff background= ffffff
foreground= 000000 foreground= 000000

View file

@ -1,42 +0,0 @@
# -*- conf -*-
# Gruvbox
[colors-dark]
background=282828
foreground=ebdbb2
regular0=282828
regular1=cc241d
regular2=98971a
regular3=d79921
regular4=458588
regular5=b16286
regular6=689d6a
regular7=a89984
bright0=928374
bright1=fb4934
bright2=b8bb26
bright3=fabd2f
bright4=83a598
bright5=d3869b
bright6=8ec07c
bright7=ebdbb2
[colors-light]
background=fbf1c7
foreground=3c3836
regular0=fbf1c7
regular1=cc241d
regular2=98971a
regular3=d79921
regular4=458588
regular5=b16286
regular6=689d6a
regular7=7c6f64
bright0=928374
bright1=9d0006
bright2=79740e
bright3=b57614
bright4=076678
bright5=8f3f71
bright6=427b58
bright7=3c3836

View file

@ -1,7 +1,7 @@
# -*- conf -*- # -*- conf -*-
# Gruvbox # Gruvbox
[colors-dark] [colors]
background=282828 background=282828
foreground=ebdbb2 foreground=ebdbb2
regular0=282828 regular0=282828

View file

@ -1,10 +1,7 @@
# -*- conf -*- # -*- conf -*-
# Gruvbox - Light # Gruvbox - Light
[main] [colors]
initial-color-theme=light
[colors-light]
background=fbf1c7 background=fbf1c7
foreground=3c3836 foreground=3c3836
regular0=fbf1c7 regular0=fbf1c7

View file

@ -1,7 +1,8 @@
# -*- conf -*- # -*- conf -*-
[cursor]
color=141414 c9c9c9
[colors-dark] [colors]
cursor=141414 c9c9c9
foreground=c9c9c9 foreground=c9c9c9
background=141414 background=141414
regular0=191918 # black regular0=191918 # black

View file

@ -2,7 +2,7 @@
# this foot theme is based on alacritty iterm theme: # this foot theme is based on alacritty iterm theme:
# https://github.com/alacritty/alacritty-theme/blob/master/themes/iterm.toml # https://github.com/alacritty/alacritty-theme/blob/master/themes/iterm.toml
[colors-dark] [colors]
foreground=fffbf6 foreground=fffbf6
background=101421 background=101421

View file

@ -2,8 +2,10 @@
# JetBrains Darcula # JetBrains Darcula
# Palette based on the same theme from https://github.com/dexpota/kitty-themes # Palette based on the same theme from https://github.com/dexpota/kitty-themes
[colors-dark] [cursor]
cursor=202020 ffffff color=202020 ffffff
[colors]
background=202020 background=202020
foreground=adadad foreground=adadad
regular0=000000 # black regular0=000000 # black

View file

@ -1,7 +1,9 @@
# -*- conf -*- # -*- conf -*-
[colors-dark] [cursor]
cursor=111111 cccccc color=111111 cccccc
[colors]
foreground=dddddd foreground=dddddd
background=000000 background=000000
regular0=000000 # black regular0=000000 # black

View file

@ -2,11 +2,10 @@
# Material Amber # Material Amber
# Based on material.io guidelines with Amber 50 background # Based on material.io guidelines with Amber 50 background
[main] [cursor]
initial-color-theme=light color=fff8e1 21201d
[colors-light] [colors]
cursor=fff8e1 21201d
foreground = 21201d foreground = 21201d
background = fff8e1 background = fff8e1

View file

@ -2,7 +2,7 @@
# Material # Material
# From https://github.com/MartinSeeler/iterm2-material-design # From https://github.com/MartinSeeler/iterm2-material-design
[colors-dark] [colors]
foreground=ECEFF1 foreground=ECEFF1
background=263238 background=263238
regular0=546E7A # black regular0=546E7A # black

View file

@ -3,11 +3,7 @@
# modus-operandi # modus-operandi
# See: https://protesilaos.com/emacs/modus-themes # See: https://protesilaos.com/emacs/modus-themes
# #
[colors]
[main]
initial-color-theme=light
[colors-light]
background=ffffff background=ffffff
foreground=000000 foreground=000000
regular0=000000 regular0=000000
@ -26,5 +22,3 @@ bright4=2544bb
bright5=5317ac bright5=5317ac
bright6=005a5f bright6=005a5f
bright7=ffffff bright7=ffffff
jump-labels=dce0e8 0000ff

View file

@ -4,7 +4,7 @@
# See: https://protesilaos.com/emacs/modus-themes # See: https://protesilaos.com/emacs/modus-themes
# #
[colors-dark] [colors]
background=000000 background=000000
foreground=ffffff foreground=ffffff
regular0=000000 regular0=000000

View file

@ -1,25 +0,0 @@
# -*- conf -*-
#
# modus-vivendi-tinted
# See: https://protesilaos.com/emacs/modus-themes
#
[colors-dark]
background=0d0e1c
foreground=ffffff
regular0=000000
regular1=ff5f59
regular2=44bc44
regular3=d0bc00
regular4=2fafff
regular5=feacd0
regular6=00d3d0
regular7=a6a6a6
bright0=595959
bright1=ff6b55
bright2=ff6b55
bright3=fec43f
bright4=fec43f
bright5=b6a0ff
bright6=6ae4b9
bright7=777777

View file

@ -2,7 +2,7 @@
# Molokai # Molokai
# Based on zhou13's at https://github.com/zhou13/molokai-terminal/blob/master/xterm/Xresources # Based on zhou13's at https://github.com/zhou13/molokai-terminal/blob/master/xterm/Xresources
[colors-dark] [colors]
background=1B1D1E background=1B1D1E
foreground=CCCCCC foreground=CCCCCC
regular0=1B1D1E regular0=1B1D1E

View file

@ -1,7 +1,7 @@
# -*- conf -*- # -*- conf -*-
# Monokai Pro # Monokai Pro
[colors-dark] [colors]
background=2D2A2E background=2D2A2E
foreground=FCFCFA foreground=FCFCFA
regular0=403E41 regular0=403E41

View file

@ -2,8 +2,10 @@
# moonfly # moonfly
# Based on https://github.com/bluz71/vim-moonfly-colors # Based on https://github.com/bluz71/vim-moonfly-colors
[colors-dark] [cursor]
cursor = 080808 9e9e9e color = 080808 9e9e9e
[colors]
foreground = b2b2b2 foreground = b2b2b2
background = 080808 background = 080808

View file

@ -6,7 +6,7 @@
# https://xcolors.net/neon # https://xcolors.net/neon
# #
[colors-dark] [colors]
foreground=f8f8f8 foreground=f8f8f8
background=171717 background=171717
regular0=171717 regular0=171717

View file

@ -1,8 +1,10 @@
# _*_ conf _*_ # _*_ conf _*_
# Night Owl # Night Owl
[colors-dark] [cursor]
cursor=011627 80a4c2 color=011627 80a4c2
[colors]
foreground=d6deeb foreground=d6deeb
background=011627 background=011627

View file

@ -2,8 +2,10 @@
# nightfly # nightfly
# Based on https://github.com/bluz71/vim-nightfly-guicolors # Based on https://github.com/bluz71/vim-nightfly-guicolors
[colors-dark] [cursor]
cursor = 080808 9ca1aa color = 080808 9ca1aa
[colors]
foreground = acb4c2 foreground = acb4c2
background = 011627 background = 011627

View file

@ -3,8 +3,10 @@
# https://github.com/n1ghtmare/noirblaze-kitty # https://github.com/n1ghtmare/noirblaze-kitty
[colors-dark] [cursor]
cursor=121212 ff0088 color=121212 ff0088
[colors]
foreground=d5d5d5 foreground=d5d5d5
background=121212 background=121212

View file

@ -6,8 +6,10 @@
# this specific foot theme is based on nord-alacritty: # this specific foot theme is based on nord-alacritty:
# https://github.com/arcticicestudio/nord-alacritty/blob/develop/src/nord.yml # https://github.com/arcticicestudio/nord-alacritty/blob/develop/src/nord.yml
[colors-dark] [cursor]
cursor = 2e3440 d8dee9 color = 2e3440 d8dee9
[colors]
foreground = d8dee9 foreground = d8dee9
background = 2e3440 background = 2e3440

View file

@ -1,8 +1,10 @@
# -*- conf -*- # -*- conf -*-
# Nordiq # Nordiq
[colors-dark] [cursor]
cursor=eeeeee 9f515a color=eeeeee 9f515a
[colors]
foreground=dbdee9 foreground=dbdee9
background=0e1420 background=0e1420
regular0=5b6272 regular0=5b6272

View file

@ -1,56 +0,0 @@
# -*- conf -*-
# Neovim Dark theme
# Uses the dark color palette from the default Neovim color scheme
# See: https://github.com/neovim/neovim/blob/fb6c059dc55c8d594102937be4dd70f5ff51614a/src/nvim/highlight_group.c#L419
[colors-dark]
cursor=14161b e0e2ea # NvimDarkGrey2 NvimLightGrey2
foreground=e0e2ea # NvimLightGrey2
background=14161b # NvimDarkGrey2
selection-foreground=e0e2ea # NvimLightGrey2
selection-background=4f5258 # NvimDarkGrey4
regular0=07080d # NvimDarkGrey1
regular1=ffc0b9 # NvimLightRed
regular2=b3f6c0 # NvimLightGreen
regular3=fce094 # NvimLightYellow
regular4=a6dbff # NvimLightBlue
regular5=ffcaff # NvimLightMagenta
regular6=8cf8f7 # NvimLightCyan
regular7=c4c6cd # NvimLightGrey3
bright0=2c2e33 # NvimDarkGrey3
bright1=ffc0b9 # NvimLightRed
bright2=b3f6c0 # NvimLightGreen
bright3=fce094 # NvimLightYellow
bright4=a6dbff # NvimLightBlue
bright5=ffcaff # NvimLightMagenta
bright6=8cf8f7 # NvimLightCyan
bright7=eef1f8 # NvimLightGrey1
[colors-light]
cursor=e0e2ea 14161b # NvimLightGrey2 NvimDarkGrey2
foreground=14161b # NvimDarkGrey2
background=e0e2ea # NvimLightGrey2
selection-foreground=14161b # NvimDarkGrey2
selection-background=9b9ea4 # NvimLightGrey4
regular0=eef1f8 # NvimLightGrey1
regular1=590008 # NvimDarkRed
regular2=005523 # NvimDarkGreen
regular3=6b5300 # NvimDarkYellow
regular4=004c73 # NvimDarkBlue
regular5=470045 # NvimDarkMagenta
regular6=007373 # NvimDarkCyan
regular7=2c2e33 # NvimDarkGrey3
bright0=c4c6cd # NvimLightGrey3
bright1=590008 # NvimDarkRed
bright2=005523 # NvimDarkGreen
bright3=6b5300 # NvimDarkYellow
bright4=004c73 # NvimDarkBlue
bright5=470045 # NvimDarkMagenta
bright6=007373 # NvimDarkCyan
bright7=07080d # NvimDarkGrey1

View file

@ -3,8 +3,10 @@
# Uses the dark color palette from the default Neovim color scheme # Uses the dark color palette from the default Neovim color scheme
# See: https://github.com/neovim/neovim/blob/fb6c059dc55c8d594102937be4dd70f5ff51614a/src/nvim/highlight_group.c#L419 # See: https://github.com/neovim/neovim/blob/fb6c059dc55c8d594102937be4dd70f5ff51614a/src/nvim/highlight_group.c#L419
[colors-dark] [cursor]
cursor=14161b e0e2ea # NvimDarkGrey2 NvimLightGrey2 color=14161b e0e2ea # NvimDarkGrey2 NvimLightGrey2
[colors]
foreground=e0e2ea # NvimLightGrey2 foreground=e0e2ea # NvimLightGrey2
background=14161b # NvimDarkGrey2 background=14161b # NvimDarkGrey2

View file

@ -3,11 +3,10 @@
# Uses the light color palette from the default Neovim color scheme # Uses the light color palette from the default Neovim color scheme
# See: https://github.com/neovim/neovim/blob/fb6c059dc55c8d594102937be4dd70f5ff51614a/src/nvim/highlight_group.c#L334 # See: https://github.com/neovim/neovim/blob/fb6c059dc55c8d594102937be4dd70f5ff51614a/src/nvim/highlight_group.c#L334
[main] [cursor]
initial-color-theme=light color=e0e2ea 14161b # NvimLightGrey2 NvimDarkGrey2
[colors-light] [colors]
cursor=e0e2ea 14161b # NvimLightGrey2 NvimDarkGrey2
foreground=14161b # NvimDarkGrey2 foreground=14161b # NvimDarkGrey2
background=e0e2ea # NvimLightGrey2 background=e0e2ea # NvimLightGrey2

View file

@ -1,8 +1,10 @@
# OneDark # OneDark
# Palette based on the same theme from https://github.com/dexpota/kitty-themes # Palette based on the same theme from https://github.com/dexpota/kitty-themes
[colors-dark] [cursor]
cursor=111111 cccccc color=111111 cccccc
[colors]
foreground=979eab foreground=979eab
background=282c34 background=282c34
regular0=282c34 # black regular0=282c34 # black

View file

@ -7,8 +7,10 @@
# + cursor colors from: # + cursor colors from:
# https://github.com/sonph/onehalf/blob/master/iterm/OneHalfDark.itermcolors # https://github.com/sonph/onehalf/blob/master/iterm/OneHalfDark.itermcolors
[colors-dark] [cursor]
cursor=dcdfe4 a3b3cc color=dcdfe4 a3b3cc
[colors]
foreground=dcdfe4 foreground=dcdfe4
background=282c34 background=282c34
regular0=282c34 # black regular0=282c34 # black

View file

@ -1,7 +1,7 @@
# -*- conf -*- # -*- conf -*-
# http://panda.siamak.me/ # http://panda.siamak.me/
[colors-dark] [colors]
# alpha=1.0 # alpha=1.0
background=1D1E20 background=1D1E20
foreground=F0F0F0 foreground=F0F0F0

View file

@ -1,49 +0,0 @@
# -*- conf -*-
# PaperColorDark
# Palette based on https://github.com/NLKNguyen/papercolor-theme
[colors-dark]
cursor=1c1c1c eeeeee
background=1c1c1c
foreground=eeeeee
regular0=1c1c1c # black
regular1=af005f # red
regular2=5faf00 # green
regular3=d7af5f # yellow
regular4=5fafd7 # blue
regular5=808080 # magenta
regular6=d7875f # cyan
regular7=d0d0d0 # white
bright0=bcbcbc # bright black
bright1=5faf5f # bright red
bright2=afd700 # bright green
bright3=af87d7 # bright yellow
bright4=ffaf00 # bright blue
bright5=ff5faf # bright magenta
bright6=00afaf # bright cyan
bright7=5f8787 # bright white
# selection-foreground=1c1c1c
# selection-background=af87d7
[colors-light]
cursor=eeeeee 444444
background=eeeeee
foreground=444444
regular0=eeeeee # black
regular1=af0000 # red
regular2=008700 # green
regular3=5f8700 # yellow
regular4=0087af # blue
regular5=878787 # magenta
regular6=005f87 # cyan
regular7=764e37 # white
bright0=bcbcbc # bright black
bright1=d70000 # bright red
bright2=d70087 # bright green
bright3=8700af # bright yellow
bright4=d75f00 # bright blue
bright5=d75f00 # bright magenta
bright6=4c7a5d # bright cyan
bright7=005faf # bright white
# selection-foreground=eeeeee
# selection-background=0087af

Some files were not shown because too many files have changed in this diff Show more