mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
Compare commits
152 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c291194a4e | ||
|
|
0bf193ef81 | ||
|
|
6fbb9b7d3b | ||
|
|
3a2eb80d83 | ||
|
|
e2a989785a | ||
|
|
b78cc92322 | ||
|
|
42e04c5c87 | ||
|
|
53e8fbbdec | ||
|
|
bb6968c284 | ||
|
|
41679e64a8 | ||
|
|
b3cb180e44 | ||
|
|
ee682abac8 | ||
|
|
6ab2e2d9eb | ||
|
|
bbebe0f330 | ||
|
|
cb1e152d99 | ||
|
|
ca278398b1 | ||
|
|
4cb17f5ae6 | ||
|
|
aa26676c43 | ||
|
|
1caba0d993 | ||
|
|
cf2b390f6e | ||
|
|
4e96780eef | ||
|
|
15ebc433ba | ||
|
|
6e533231b0 | ||
|
|
ac6d7660dd | ||
|
|
65bd79b77d | ||
|
|
55f8388694 | ||
|
|
be19ca2b20 | ||
|
|
fc9625678f | ||
|
|
c9abab0807 | ||
|
|
5cb8ff2e9c | ||
|
|
1fce0e69f5 | ||
|
|
9728ada028 | ||
|
|
143f220527 | ||
|
|
5ae4955e83 | ||
|
|
71de0c45bc | ||
|
|
19466a21d8 | ||
|
|
5587604469 | ||
|
|
82e75851e4 | ||
|
|
e114a5f02f | ||
|
|
b44a62724c | ||
|
|
dc5a921d2c | ||
|
|
612adda384 | ||
|
|
dbf18ba444 | ||
|
|
96605bf52f | ||
|
|
7ed36c1033 | ||
|
|
371837ef7b | ||
|
|
e308a4733e | ||
|
|
fd88c6c61c | ||
|
|
299186a654 | ||
|
|
bb314425ef | ||
|
|
e43ea3676f | ||
|
|
bd994eda1c | ||
|
|
fac3994154 | ||
|
|
80951ab7a6 | ||
|
|
1dfa86c93a | ||
|
|
44a674edb8 | ||
|
|
c34f063307 | ||
|
|
363477fa0d | ||
|
|
fa0fd2f50f | ||
|
|
f715f3b55f | ||
|
|
efc39097e5 | ||
|
|
65528f455d | ||
|
|
1d9ac3f611 | ||
|
|
298196365c | ||
|
|
f0e36e35cb | ||
|
|
ed7652db50 | ||
|
|
72d9a13c0c | ||
|
|
b13a8f12d2 | ||
|
|
70d99a8051 | ||
|
|
b1b2162416 | ||
|
|
3b8d59f476 | ||
|
|
6eedc88d70 | ||
|
|
7636f264a8 | ||
|
|
83303bd2a4 | ||
|
|
f873aa904d | ||
|
|
86d63f08ba | ||
|
|
8814b5f080 | ||
|
|
43620935a1 | ||
|
|
95e8b18c12 | ||
|
|
5a01dbc234 | ||
|
|
fcde74a181 | ||
|
|
42be74214a | ||
|
|
21db6a6cdc | ||
|
|
7ab43ebf74 | ||
|
|
57ae3bb89c | ||
|
|
01387f9593 | ||
|
|
cc290fa9b0 | ||
|
|
692b22cbbb | ||
|
|
9b6a9db98a | ||
|
|
d62bff1440 | ||
|
|
e72e08625d | ||
|
|
693aefa96a | ||
|
|
aa579acd6e | ||
|
|
968bc05c32 | ||
|
|
499f019dea | ||
|
|
d9675a7140 | ||
|
|
33eefa7b45 | ||
|
|
7347f4beb1 | ||
|
|
eeaecba723 | ||
|
|
5a84f8d841 | ||
|
|
5621829bb0 | ||
|
|
664cdcc65c | ||
|
|
d266599881 | ||
|
|
456ac5d79f | ||
|
|
3e1e3ea38c | ||
|
|
8bd39b32cd | ||
|
|
ebd1614316 | ||
|
|
9b0d5e7c96 | ||
|
|
073b637d45 | ||
|
|
c037836bbd | ||
|
|
c6db0bed42 | ||
|
|
970e13db8d | ||
|
|
7354b94f73 | ||
|
|
5080e271c2 | ||
|
|
237db6e771 | ||
|
|
0ea572dc63 | ||
|
|
183fd96aba | ||
|
|
85c81042d2 | ||
|
|
acea863fbe | ||
|
|
2a8948a3f3 | ||
|
|
7ced397089 | ||
|
|
9ff0151055 | ||
|
|
e5a0755451 | ||
|
|
b07ce56321 | ||
|
|
1dc8354534 | ||
|
|
99954534e1 | ||
|
|
513e91c33a | ||
|
|
fc293bad5e | ||
|
|
172f67a8df | ||
|
|
ce424e0990 | ||
|
|
1ea20b1b70 | ||
|
|
eb79a27900 | ||
|
|
d7b48d3924 | ||
|
|
97910a5cba | ||
|
|
d20fbc6807 | ||
|
|
4d70bb7b42 | ||
|
|
8273514d3c | ||
|
|
d3e45791bd | ||
|
|
6a1c3b89c2 | ||
|
|
1dc14a3001 | ||
|
|
537092e643 | ||
|
|
bc5b716668 | ||
|
|
10e7f29149 | ||
|
|
6bc91b5e28 | ||
|
|
1423babc35 | ||
|
|
01c43f1644 | ||
|
|
b24a9a59b9 | ||
|
|
5406ae3355 | ||
|
|
624c383a1f | ||
|
|
a7276d9dff | ||
|
|
79f6b4b1de | ||
|
|
fea9f5579f |
147 changed files with 3159 additions and 991 deletions
|
|
@ -29,7 +29,7 @@ body:
|
|||
- type: input
|
||||
id: compositor
|
||||
attributes:
|
||||
label: Compositor Version
|
||||
label: Compositor Name and Version
|
||||
description: "The name and version of your compositor"
|
||||
placeholder: "sway version 1.9"
|
||||
validations:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- yaml -*-
|
||||
|
||||
steps:
|
||||
- name: codespell
|
||||
- name: pychecks
|
||||
when:
|
||||
- event: [manual, pull_request]
|
||||
- event: [push, tag]
|
||||
|
|
@ -11,10 +11,15 @@ steps:
|
|||
- apk add openssl
|
||||
- apk add python3
|
||||
- apk add py3-pip
|
||||
- python3 -m venv codespell-venv
|
||||
- source codespell-venv/bin/activate
|
||||
- python3 -m venv venv
|
||||
- source venv/bin/activate
|
||||
- python -m pip install --upgrade pip
|
||||
- pip install codespell
|
||||
- codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd
|
||||
- pip install mypy
|
||||
- pip install ruff
|
||||
- codespell
|
||||
- mypy
|
||||
- ruff check
|
||||
- deactivate
|
||||
|
||||
- name: subprojects
|
||||
|
|
|
|||
315
CHANGELOG.md
315
CHANGELOG.md
|
|
@ -1,5 +1,12 @@
|
|||
# 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.2](#1-22-2)
|
||||
* [1.22.1](#1-22-1)
|
||||
* [1.22.0](#1-22-0)
|
||||
* [1.21.0](#1-21-0)
|
||||
|
|
@ -60,6 +67,314 @@
|
|||
* [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
|
||||
|
||||
### Added
|
||||
|
||||
* `auto` to the `tweak.surface-bit-depth` option.
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
* `gamma-correct-blending` now defaults to `no` instead of `yes`.
|
||||
* `tweak.surface-bit-depth` default value changed to `auto`; uses
|
||||
10-bit surfaces when `gamma-correct-blending=yes`, and 8-bit
|
||||
surfaces otherwise.
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
* Inaccurate colors when `gamma-correct-blending=yes` ([#2082][2082]).
|
||||
|
||||
[2082]: https://codeberg.org/dnkl/foot/issues/2082
|
||||
|
||||
|
||||
## 1.22.2
|
||||
|
||||
### Changed
|
||||
|
||||
* `gamma-correct-blending=yes` now uses a pure gamma 2.2 transfer
|
||||
function, instead of the piece-wise sRGB transfer function, to match
|
||||
what compositors do.
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
* Wrong colors when `gamma-correct-blending=yes` (the default when
|
||||
there is compositor support). Note that some colors will still be
|
||||
off by a **very** small amount, due to loss of precision when
|
||||
converting to a linear color space. ([#2035][2035]).
|
||||
|
||||
[2035]: https://codeberg.org/dnkl/foot/issues/2035
|
||||
|
||||
|
||||
## 1.22.1
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ decisions when appropriate.
|
|||
Participants in the foot community are expected to uphold the described
|
||||
standards not only in official community spaces (issue trackers, IRC channels,
|
||||
etc.) but in all public spaces. The Code of Conduct however does acknowledge
|
||||
that people are fallible and that it is possible to truely correct a past
|
||||
that people are fallible and that it is possible to truly correct a past
|
||||
pattern of unacceptable behavior. That is to say, the scope of the Code of
|
||||
Conduct does not necessarily extend into the distant past.
|
||||
|
||||
|
|
|
|||
|
|
@ -641,6 +641,10 @@ All replies are in `tigetstr()` format. That is, given the same
|
|||
capability name, foot's reply is identical to what `tigetstr()` would
|
||||
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
|
||||
|
||||
|
|
@ -689,8 +693,11 @@ Every now and then I post foot related updates on
|
|||
|
||||
# Sponsoring/donations
|
||||
|
||||
* Liberapay: https://liberapay.com/dnkl
|
||||
* GitHub Sponsors: https://github.com/sponsors/dnkl
|
||||
|
||||
[](https://liberapay.com/dnkl/donate)
|
||||
|
||||
|
||||
# License
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <fenv.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define LOG_MODULE "box-drawing"
|
||||
|
|
|
|||
22
char32.c
22
char32.c
|
|
@ -53,6 +53,14 @@ UNITTEST
|
|||
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
|
||||
{
|
||||
char32_t copy[16];
|
||||
|
|
@ -127,6 +135,20 @@ UNITTEST
|
|||
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
|
||||
{
|
||||
char32_t *c = xc32dup(U"foobar");
|
||||
|
|
|
|||
15
char32.h
15
char32.h
|
|
@ -20,6 +20,10 @@ static inline int c32cmp(const char32_t *s1, const char32_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) {
|
||||
return (char32_t *)wcsncpy((wchar_t *)dst, (const wchar_t *)src, n);
|
||||
}
|
||||
|
|
@ -60,6 +64,10 @@ static inline char32_t toc32upper(char32_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) {
|
||||
return iswspace((wint_t)c32);
|
||||
}
|
||||
|
|
@ -72,6 +80,13 @@ static inline bool isc32graph(char32_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) {
|
||||
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
||||
return utf8proc_charwidth((utf8proc_int32_t)c);
|
||||
|
|
|
|||
|
|
@ -29,3 +29,17 @@ struct client_data {
|
|||
} __attribute__((packed));
|
||||
|
||||
_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));
|
||||
|
|
|
|||
94
client.c
94
client.c
|
|
@ -1,12 +1,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#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 <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
|
@ -33,13 +34,20 @@ struct string {
|
|||
typedef tll(struct string) string_list_t;
|
||||
|
||||
static volatile sig_atomic_t aborted = 0;
|
||||
static volatile sig_atomic_t sigusr = 0;
|
||||
|
||||
static void
|
||||
sig_handler(int signo)
|
||||
sigint_handler(int signo)
|
||||
{
|
||||
aborted = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
sigusr_handler(int signo)
|
||||
{
|
||||
sigusr = signo;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
sendall(int sock, const void *_buf, size_t len)
|
||||
{
|
||||
|
|
@ -69,6 +77,7 @@ print_usage(const char *prog_name)
|
|||
" -t,--term=TERM value to set the environment variable TERM to (" FOOT_DEFAULT_TERM ")\n"
|
||||
" -T,--title=TITLE initial window title (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-chars=WIDTHxHEIGHT initial width and height, in characters\n"
|
||||
" -m,--maximized start in maximized mode\n"
|
||||
|
|
@ -130,6 +139,10 @@ send_string_list(int fd, const string_list_t *string_list)
|
|||
return true;
|
||||
}
|
||||
|
||||
enum {
|
||||
TOPLEVEL_TAG_OPTION = CHAR_MAX + 1,
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *const *argv)
|
||||
{
|
||||
|
|
@ -144,6 +157,7 @@ main(int argc, char *const *argv)
|
|||
{"term", required_argument, NULL, 't'},
|
||||
{"title", required_argument, NULL, 'T'},
|
||||
{"app-id", required_argument, NULL, 'a'},
|
||||
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
|
||||
{"window-size-pixels", required_argument, NULL, 'w'},
|
||||
{"window-size-chars", required_argument, NULL, 'W'},
|
||||
{"maximized", no_argument, NULL, 'm'},
|
||||
|
|
@ -213,6 +227,12 @@ main(int argc, char *const *argv)
|
|||
goto err;
|
||||
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':
|
||||
if (!push_string(&overrides, "login-shell=yes", &total_len))
|
||||
goto err;
|
||||
|
|
@ -507,15 +527,63 @@ main(int argc, char *const *argv)
|
|||
if (!send_string_list(fd, &envp))
|
||||
goto err;
|
||||
|
||||
struct sigaction sa = {.sa_handler = &sig_handler};
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0) {
|
||||
struct sigaction sa_int = {.sa_handler = &sigint_handler};
|
||||
struct sigaction sa_usr = {.sa_handler = &sigusr_handler};
|
||||
sigemptyset(&sa_int.sa_mask);
|
||||
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");
|
||||
goto err;
|
||||
}
|
||||
|
||||
int exit_code;
|
||||
ssize_t rcvd = recv(fd, &exit_code, sizeof(exit_code), 0);
|
||||
ssize_t rcvd = -1;
|
||||
|
||||
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)
|
||||
xassert(aborted);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ _foot()
|
|||
local cur prev flags word commands match previous_words i offset
|
||||
flags=(
|
||||
"--app-id"
|
||||
"--toplevel-tag"
|
||||
"--check-config"
|
||||
"--config"
|
||||
"--font"
|
||||
|
|
@ -40,7 +41,7 @@ _foot()
|
|||
for word in "${previous_words[@]}" ; do
|
||||
match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null)
|
||||
if [[ ! -z "$match" ]] ; then
|
||||
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--config|--font|--log-level|--pty|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; 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
|
||||
(( i++ ))
|
||||
continue
|
||||
fi
|
||||
|
|
@ -75,7 +76,7 @@ _foot()
|
|||
COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;;
|
||||
--log-colorize|-l)
|
||||
COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;;
|
||||
--app-id|--help|--override|--pty|--title|--version|--window-size-chars|--window-size-pixels|--check-config|-[ahoTvWwC])
|
||||
--app-id|--toplevel-tag|--help|--override|--pty|--title|--version|--window-size-chars|--window-size-pixels|--check-config|-[ahoTvWwC])
|
||||
# Don't autocomplete for these flags
|
||||
: ;;
|
||||
*)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ _footclient()
|
|||
local cur prev flags word commands match previous_words i offset
|
||||
flags=(
|
||||
"--app-id"
|
||||
"--toplevel-tag"
|
||||
"--fullscreen"
|
||||
"--help"
|
||||
"--hold"
|
||||
|
|
@ -35,7 +36,7 @@ _footclient()
|
|||
for word in "${previous_words[@]}" ; do
|
||||
match=$(printf "$commands" | grep -Fx "$word" 2>/dev/null)
|
||||
if [[ ! -z "$match" ]] ; then
|
||||
if [[ ${COMP_WORDS[i-1]} =~ ^(--app-id|--log-level|--server-socket|--term|--title|--window-size-pixels|--window-size-chars|--working-directory)$ ]] ; 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
|
||||
(( i++ ))
|
||||
continue
|
||||
fi
|
||||
|
|
@ -67,7 +68,7 @@ _footclient()
|
|||
COMPREPLY=( $(compgen -W "none error warning info" -- ${cur}) ) ;;
|
||||
--log-colorize|-l)
|
||||
COMPREPLY=( $(compgen -W "never always auto" -- ${cur}) ) ;;
|
||||
--app-id|--help|--override|--title|--version|--window-size-chars|--window-size-pixels|-[ahoTvWw])
|
||||
--app-id|--toplevel-tag|--help|--override|--title|--version|--window-size-chars|--window-size-pixels|-[ahoTvWw])
|
||||
# Don't autocomplete for these flags
|
||||
: ;;
|
||||
*)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ 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 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 -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 F -l fullscreen -d "start in fullscreen mode"
|
||||
complete -c foot -s L -l login-shell -d "start shell as a login shell"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ 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 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 -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 F -l fullscreen -d "start in fullscreen mode"
|
||||
complete -c footclient -s L -l login-shell -d "start shell as a login shell"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ _arguments \
|
|||
'(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \
|
||||
'(-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)]:()' \
|
||||
'--toplevel-tag=[value to set the toplevel-tag property on the Wayland window to]:()' \
|
||||
'(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \
|
||||
'(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \
|
||||
'(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ _arguments \
|
|||
'(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \
|
||||
'(-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)]:()' \
|
||||
'--toplevel-tag=[value to set the toplevel-tag property on the Wayland window to]:()' \
|
||||
'(-m --maximized)'{-m,--maximized}'[start in maximized mode]' \
|
||||
'(-F --fullscreen)'{-F,--fullscreen}'[start in fullscreen mode]' \
|
||||
'(-L --login-shell)'{-L,--login-shell}'[start shell as a login shell]' \
|
||||
|
|
|
|||
349
config.c
349
config.c
|
|
@ -142,6 +142,11 @@ static const char *const binding_action_map[] = {
|
|||
[BIND_ACTION_QUIT] = "quit",
|
||||
[BIND_ACTION_REGEX_LAUNCH] = "regex-launch",
|
||||
[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 */
|
||||
[BIND_ACTION_SCROLLBACK_UP_MOUSE] = "scrollback-up-mouse",
|
||||
|
|
@ -471,8 +476,12 @@ str_to_ulong(const char *s, int base, unsigned long *res)
|
|||
errno = 0;
|
||||
char *end = NULL;
|
||||
|
||||
*res = strtoul(s, &end, base);
|
||||
return errno == 0 && *end == '\0';
|
||||
unsigned long v = strtoul(s, &end, base);
|
||||
if (!(errno == 0 && *end == '\0'))
|
||||
return false;
|
||||
|
||||
*res = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool NOINLINE
|
||||
|
|
@ -541,12 +550,13 @@ value_to_float(struct context *ctx, float *res)
|
|||
errno = 0;
|
||||
char *end = NULL;
|
||||
|
||||
*res = strtof(s, &end);
|
||||
float v = strtof(s, &end);
|
||||
if (!(errno == 0 && *end == '\0')) {
|
||||
LOG_CONTEXTUAL_ERR("invalid decimal value");
|
||||
return false;
|
||||
}
|
||||
|
||||
*res = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -638,7 +648,6 @@ value_to_enum(struct context *ctx, const char **value_map, int *res)
|
|||
valid_values[idx - 2] = '\0';
|
||||
|
||||
LOG_CONTEXTUAL_ERR("not one of %s", valid_values);
|
||||
*res = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -687,14 +696,18 @@ value_to_two_colors(struct context *ctx,
|
|||
goto out;
|
||||
}
|
||||
|
||||
uint32_t a, b;
|
||||
|
||||
ctx->value = first_as_str;
|
||||
if (!value_to_color(ctx, first, allow_alpha))
|
||||
if (!value_to_color(ctx, &a, allow_alpha))
|
||||
goto out;
|
||||
|
||||
ctx->value = second_as_str;
|
||||
if (!value_to_color(ctx, second, allow_alpha))
|
||||
if (!value_to_color(ctx, &b, allow_alpha))
|
||||
goto out;
|
||||
|
||||
*first = a;
|
||||
*second = b;
|
||||
ret = true;
|
||||
|
||||
out:
|
||||
|
|
@ -912,6 +925,9 @@ parse_section_main(struct context *ctx)
|
|||
else if (streq(key, "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")) {
|
||||
if (!value_to_dimensions(ctx, &conf->size.width, &conf->size.height))
|
||||
return false;
|
||||
|
|
@ -930,21 +946,34 @@ parse_section_main(struct context *ctx)
|
|||
|
||||
else if (streq(key, "pad")) {
|
||||
unsigned x, y;
|
||||
char mode[16] = {0};
|
||||
char mode[64] = {0};
|
||||
int ret = sscanf(value, "%ux%u %63s", &x, &y, mode);
|
||||
|
||||
int ret = sscanf(value, "%ux%u %15s", &x, &y, mode);
|
||||
bool center = strcasecmp(mode, "center") == 0;
|
||||
bool invalid_mode = !center && mode[0] != '\0';
|
||||
enum center_when center = CENTER_NEVER;
|
||||
|
||||
if ((ret != 2 && ret != 3) || invalid_mode) {
|
||||
if (ret == 3) {
|
||||
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(
|
||||
"invalid padding (must be in the form PAD_XxPAD_Y [center])");
|
||||
"invalid padding (must be in the form PAD_XxPAD_Y "
|
||||
"[center|"
|
||||
"center-when-fullscreen|"
|
||||
"center-when-maximized-and-fullscreen])");
|
||||
return false;
|
||||
}
|
||||
|
||||
conf->pad_x = x;
|
||||
conf->pad_y = y;
|
||||
conf->center = center;
|
||||
conf->center_when = ret == 2 ? CENTER_NEVER : center;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1083,18 +1112,53 @@ parse_section_main(struct context *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
else if (streq(key, "gamma-correct-blending")) {
|
||||
bool gamma_correct;
|
||||
if (!value_to_bool(ctx, &gamma_correct))
|
||||
else if (streq(key, "gamma-correct-blending"))
|
||||
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;
|
||||
|
||||
conf->gamma_correct =
|
||||
gamma_correct
|
||||
? GAMMA_CORRECT_ENABLED
|
||||
: GAMMA_CORRECT_DISABLED;
|
||||
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 {
|
||||
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
||||
return false;
|
||||
|
|
@ -1338,10 +1402,9 @@ parse_section_regex(struct context *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_section_colors(struct context *ctx)
|
||||
static bool NOINLINE
|
||||
parse_color_theme(struct context *ctx, struct color_theme *theme)
|
||||
{
|
||||
struct config *conf = ctx->conf;
|
||||
const char *key = ctx->key;
|
||||
|
||||
size_t key_len = strlen(key);
|
||||
|
|
@ -1350,28 +1413,26 @@ parse_section_colors(struct context *ctx)
|
|||
|
||||
if (isdigit(key[0])) {
|
||||
unsigned long index;
|
||||
if (!str_to_ulong(key, 0, &index) ||
|
||||
index >= ALEN(conf->colors.table))
|
||||
{
|
||||
if (!str_to_ulong(key, 0, &index) || index >= ALEN(theme->table)) {
|
||||
LOG_CONTEXTUAL_ERR(
|
||||
"invalid color palette index: %s (not in range 0-%zu)",
|
||||
key, ALEN(conf->colors.table));
|
||||
key, ALEN(theme->table));
|
||||
return false;
|
||||
}
|
||||
color = &conf->colors.table[index];
|
||||
color = &theme->table[index];
|
||||
}
|
||||
|
||||
else if (key_len == 8 && str_has_prefix(key, "regular") && last_digit < 8)
|
||||
color = &conf->colors.table[last_digit];
|
||||
color = &theme->table[last_digit];
|
||||
|
||||
else if (key_len == 7 && str_has_prefix(key, "bright") && last_digit < 8)
|
||||
color = &conf->colors.table[8 + last_digit];
|
||||
color = &theme->table[8 + last_digit];
|
||||
|
||||
else if (key_len == 4 && str_has_prefix(key, "dim") && last_digit < 8) {
|
||||
if (!value_to_color(ctx, &conf->colors.dim[last_digit], false))
|
||||
if (!value_to_color(ctx, &theme->dim[last_digit], false))
|
||||
return false;
|
||||
|
||||
conf->colors.use_custom.dim |= 1 << last_digit;
|
||||
theme->use_custom.dim |= 1 << last_digit;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1380,76 +1441,90 @@ parse_section_colors(struct context *ctx)
|
|||
(key_len == 7 && key[5] == '1' && last_digit < 6)))
|
||||
{
|
||||
size_t idx = key_len == 6 ? last_digit : 10 + last_digit;
|
||||
return value_to_color(ctx, &conf->colors.sixel[idx], false);
|
||||
return value_to_color(ctx, &theme->sixel[idx], false);
|
||||
}
|
||||
|
||||
else if (streq(key, "flash")) color = &conf->colors.flash;
|
||||
else if (streq(key, "foreground")) color = &conf->colors.fg;
|
||||
else if (streq(key, "background")) color = &conf->colors.bg;
|
||||
else if (streq(key, "selection-foreground")) color = &conf->colors.selection_fg;
|
||||
else if (streq(key, "selection-background")) color = &conf->colors.selection_bg;
|
||||
else if (streq(key, "flash")) color = &theme->flash;
|
||||
else if (streq(key, "foreground")) color = &theme->fg;
|
||||
else if (streq(key, "background")) color = &theme->bg;
|
||||
else if (streq(key, "selection-foreground")) color = &theme->selection_fg;
|
||||
else if (streq(key, "selection-background")) color = &theme->selection_bg;
|
||||
|
||||
else if (streq(key, "jump-labels")) {
|
||||
if (!value_to_two_colors(
|
||||
ctx,
|
||||
&conf->colors.jump_label.fg,
|
||||
&conf->colors.jump_label.bg,
|
||||
&theme->jump_label.fg,
|
||||
&theme->jump_label.bg,
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
conf->colors.use_custom.jump_label = true;
|
||||
theme->use_custom.jump_label = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (streq(key, "scrollback-indicator")) {
|
||||
if (!value_to_two_colors(
|
||||
ctx,
|
||||
&conf->colors.scrollback_indicator.fg,
|
||||
&conf->colors.scrollback_indicator.bg,
|
||||
&theme->scrollback_indicator.fg,
|
||||
&theme->scrollback_indicator.bg,
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
conf->colors.use_custom.scrollback_indicator = true;
|
||||
theme->use_custom.scrollback_indicator = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (streq(key, "search-box-no-match")) {
|
||||
if (!value_to_two_colors(
|
||||
ctx,
|
||||
&conf->colors.search_box.no_match.fg,
|
||||
&conf->colors.search_box.no_match.bg,
|
||||
&theme->search_box.no_match.fg,
|
||||
&theme->search_box.no_match.bg,
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
conf->colors.use_custom.search_box_no_match = true;
|
||||
theme->use_custom.search_box_no_match = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (streq(key, "search-box-match")) {
|
||||
if (!value_to_two_colors(
|
||||
ctx,
|
||||
&conf->colors.search_box.match.fg,
|
||||
&conf->colors.search_box.match.bg,
|
||||
&theme->search_box.match.fg,
|
||||
&theme->search_box.match.bg,
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
conf->colors.use_custom.search_box_match = true;
|
||||
theme->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;
|
||||
}
|
||||
|
||||
else if (streq(key, "urls")) {
|
||||
if (!value_to_color(ctx, &conf->colors.url, false))
|
||||
if (!value_to_color(ctx, &theme->url, false))
|
||||
return false;
|
||||
|
||||
conf->colors.use_custom.url = true;
|
||||
theme->use_custom.url = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1463,7 +1538,7 @@ parse_section_colors(struct context *ctx)
|
|||
return false;
|
||||
}
|
||||
|
||||
conf->colors.alpha = alpha * 65535.;
|
||||
theme->alpha = alpha * 65535.;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1477,18 +1552,28 @@ parse_section_colors(struct context *ctx)
|
|||
return false;
|
||||
}
|
||||
|
||||
conf->colors.flash_alpha = alpha * 65535.;
|
||||
theme->flash_alpha = alpha * 65535.;
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (strcmp(key, "alpha-mode") == 0) {
|
||||
_Static_assert(sizeof(conf->colors.alpha_mode) == sizeof(int),
|
||||
else if (streq(key, "alpha-mode")) {
|
||||
_Static_assert(sizeof(theme->alpha_mode) == sizeof(int),
|
||||
"enum is not 32-bit");
|
||||
|
||||
return value_to_enum(
|
||||
ctx,
|
||||
(const char *[]){"default", "matching", "all", NULL},
|
||||
(int *)&conf->colors.alpha_mode);
|
||||
(int *)&theme->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 {
|
||||
|
|
@ -1504,6 +1589,46 @@ parse_section_colors(struct context *ctx)
|
|||
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
|
||||
parse_section_cursor(struct context *ctx)
|
||||
{
|
||||
|
|
@ -1536,21 +1661,6 @@ parse_section_cursor(struct context *ctx)
|
|||
else if (streq(key, "blink-rate"))
|
||||
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"))
|
||||
return value_to_pt_or_px(ctx, &conf->cursor.beam_thickness);
|
||||
|
||||
|
|
@ -2198,6 +2308,29 @@ parse_key_binding_section(struct context *ctx,
|
|||
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)) {
|
||||
free_binding_aux(&aux);
|
||||
return false;
|
||||
|
|
@ -2776,14 +2909,27 @@ parse_section_tweak(struct context *ctx)
|
|||
|
||||
else if (streq(key, "surface-bit-depth")) {
|
||||
_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 *[]){"8-bit", "10-bit", NULL},
|
||||
(const char *[]){"auto", "8-bit", "10-bit", "16-bit", NULL},
|
||||
(int *)&conf->tweak.surface_bit_depth);
|
||||
#else
|
||||
return value_to_enum(
|
||||
ctx,
|
||||
(const char *[]){"auto", "8-bit", "10-bit", NULL},
|
||||
(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 {
|
||||
LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
|
||||
return false;
|
||||
|
|
@ -2875,7 +3021,8 @@ enum section {
|
|||
SECTION_SCROLLBACK,
|
||||
SECTION_URL,
|
||||
SECTION_REGEX,
|
||||
SECTION_COLORS,
|
||||
SECTION_COLORS_DARK,
|
||||
SECTION_COLORS_LIGHT,
|
||||
SECTION_CURSOR,
|
||||
SECTION_MOUSE,
|
||||
SECTION_CSD,
|
||||
|
|
@ -2887,6 +3034,11 @@ enum section {
|
|||
SECTION_ENVIRONMENT,
|
||||
SECTION_TWEAK,
|
||||
SECTION_TOUCH,
|
||||
|
||||
/* Deprecated */
|
||||
SECTION_COLORS,
|
||||
SECTION_COLORS2,
|
||||
|
||||
SECTION_COUNT,
|
||||
};
|
||||
|
||||
|
|
@ -2905,7 +3057,8 @@ static const struct {
|
|||
[SECTION_SCROLLBACK] = {&parse_section_scrollback, "scrollback"},
|
||||
[SECTION_URL] = {&parse_section_url, "url"},
|
||||
[SECTION_REGEX] = {&parse_section_regex, "regex", true},
|
||||
[SECTION_COLORS] = {&parse_section_colors, "colors"},
|
||||
[SECTION_COLORS_DARK] = {&parse_section_colors_dark, "colors-dark"},
|
||||
[SECTION_COLORS_LIGHT] = {&parse_section_colors_light, "colors-light"},
|
||||
[SECTION_CURSOR] = {&parse_section_cursor, "cursor"},
|
||||
[SECTION_MOUSE] = {&parse_section_mouse, "mouse"},
|
||||
[SECTION_CSD] = {&parse_section_csd, "csd"},
|
||||
|
|
@ -2917,6 +3070,10 @@ static const struct {
|
|||
[SECTION_ENVIRONMENT] = {&parse_section_environment, "environment"},
|
||||
[SECTION_TWEAK] = {&parse_section_tweak, "tweak"},
|
||||
[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");
|
||||
|
|
@ -3289,6 +3446,7 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.shell = get_shell(),
|
||||
.title = xstrdup("foot"),
|
||||
.app_id = (as_server ? xstrdup("footclient") : xstrdup("foot")),
|
||||
.toplevel_tag = xstrdup(""),
|
||||
.word_delimiters = xc32dup(U",│`|:\"'()[]{}<>"),
|
||||
.size = {
|
||||
.type = CONF_SIZE_PX,
|
||||
|
|
@ -3297,6 +3455,7 @@ config_load(struct config *conf, const char *conf_path,
|
|||
},
|
||||
.pad_x = 0,
|
||||
.pad_y = 0,
|
||||
.center_when = CENTER_MAXIMIZED_AND_FULLSCREEN,
|
||||
.resize_by_cells = true,
|
||||
.resize_keep_grid = true,
|
||||
.resize_delay_ms = 100,
|
||||
|
|
@ -3318,7 +3477,8 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.underline_thickness = {.pt = 0., .px = -1},
|
||||
.strikeout_thickness = {.pt = 0., .px = -1},
|
||||
.dpi_aware = false,
|
||||
.gamma_correct = GAMMA_CORRECT_AUTO,
|
||||
.gamma_correct = false,
|
||||
.uppercase_regex_insert = true,
|
||||
.security = {
|
||||
.osc52 = OSC52_ENABLED,
|
||||
},
|
||||
|
|
@ -3347,23 +3507,27 @@ config_load(struct config *conf, const char *conf_path,
|
|||
},
|
||||
.multiplier = 3.,
|
||||
},
|
||||
.colors = {
|
||||
.colors_dark = {
|
||||
.fg = default_foreground,
|
||||
.bg = default_background,
|
||||
.flash = 0x7f7f00,
|
||||
.flash_alpha = 0x7fff,
|
||||
.alpha = 0xffff,
|
||||
.alpha_mode = ALPHA_MODE_DEFAULT,
|
||||
.dim_blend_towards = DIM_BLEND_TOWARDS_BLACK,
|
||||
.selection_fg = 0x80000000, /* Use default bg */
|
||||
.selection_bg = 0x80000000, /* Use default fg */
|
||||
.cursor = {
|
||||
.text = 0,
|
||||
.cursor = 0,
|
||||
},
|
||||
.use_custom = {
|
||||
.selection = false,
|
||||
.jump_label = false,
|
||||
.scrollback_indicator = false,
|
||||
.url = false,
|
||||
},
|
||||
},
|
||||
|
||||
.initial_color_theme = COLOR_THEME_DARK,
|
||||
.cursor = {
|
||||
.style = CURSOR_BLOCK,
|
||||
.unfocused_style = CURSOR_UNFOCUSED_HOLLOW,
|
||||
|
|
@ -3371,10 +3535,6 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.enabled = false,
|
||||
.rate_ms = 500,
|
||||
},
|
||||
.color = {
|
||||
.text = 0,
|
||||
.cursor = 0,
|
||||
},
|
||||
.beam_thickness = {.pt = 1.5},
|
||||
.underline_thickness = {.pt = 0., .px = -1},
|
||||
},
|
||||
|
|
@ -3428,7 +3588,9 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.box_drawing_solid_shades = true,
|
||||
.font_monospace_warn = true,
|
||||
.sixel = true,
|
||||
.surface_bit_depth = 8,
|
||||
.surface_bit_depth = SHM_BITS_AUTO,
|
||||
.min_stride_alignment = 256,
|
||||
.preapply_damage = true,
|
||||
},
|
||||
|
||||
.touch = {
|
||||
|
|
@ -3445,8 +3607,11 @@ config_load(struct config *conf, const char *conf_path,
|
|||
.notifications = tll_init(),
|
||||
};
|
||||
|
||||
memcpy(conf->colors.table, default_color_table, sizeof(default_color_table));
|
||||
memcpy(conf->colors.sixel, default_sixel_colors, sizeof(default_sixel_colors));
|
||||
memcpy(conf->colors_dark.table, default_color_table, sizeof(default_color_table));
|
||||
memcpy(conf->colors_dark.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);
|
||||
|
||||
tokenize_cmdline(
|
||||
|
|
@ -3550,10 +3715,6 @@ config_load(struct config *conf, const char *conf_path,
|
|||
if (!config_override_apply(conf, overrides, 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) {
|
||||
struct config_font font;
|
||||
if (!config_font_parse("monospace", &font)) {
|
||||
|
|
@ -3738,6 +3899,7 @@ config_clone(const struct config *old)
|
|||
conf->shell = xstrdup(old->shell);
|
||||
conf->title = xstrdup(old->title);
|
||||
conf->app_id = xstrdup(old->app_id);
|
||||
conf->toplevel_tag = xstrdup(old->toplevel_tag);
|
||||
conf->word_delimiters = xc32dup(old->word_delimiters);
|
||||
conf->scrollback.indicator.text = xc32dup(old->scrollback.indicator.text);
|
||||
conf->server_socket_path = xstrdup(old->server_socket_path);
|
||||
|
|
@ -3837,6 +3999,7 @@ config_free(struct config *conf)
|
|||
free(conf->shell);
|
||||
free(conf->title);
|
||||
free(conf->app_id);
|
||||
free(conf->toplevel_tag);
|
||||
free(conf->word_delimiters);
|
||||
spawn_template_free(&conf->bell.command);
|
||||
free(conf->scrollback.indicator.text);
|
||||
|
|
@ -3904,9 +4067,10 @@ config_font_parse(const char *pattern, struct config_font *font)
|
|||
* both "size" and "pixelsize" being set, and we don't know
|
||||
* which one takes priority.
|
||||
*/
|
||||
FcConfig *fc_conf = FcConfigCreate();
|
||||
FcPattern *pat_copy = FcPatternDuplicate(pat);
|
||||
if (pat_copy == NULL ||
|
||||
!FcConfigSubstitute(NULL, pat_copy, FcMatchPattern))
|
||||
!FcConfigSubstitute(fc_conf, pat_copy, FcMatchPattern))
|
||||
{
|
||||
LOG_WARN("%s: failed to do config substitution", pattern);
|
||||
} else {
|
||||
|
|
@ -3915,6 +4079,7 @@ config_font_parse(const char *pattern, struct config_font *font)
|
|||
}
|
||||
|
||||
FcPatternDestroy(pat_copy);
|
||||
FcConfigDestroy(fc_conf);
|
||||
|
||||
if (have_pt_size != FcResultMatch && have_px_size != FcResultMatch)
|
||||
pt_size = 8.0;
|
||||
|
|
|
|||
156
config.h
156
config.h
|
|
@ -131,11 +131,97 @@ struct custom_regex {
|
|||
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 {
|
||||
SHM_BITS_AUTO,
|
||||
SHM_BITS_8,
|
||||
SHM_BITS_10,
|
||||
SHM_BITS_16,
|
||||
};
|
||||
|
||||
enum center_when {
|
||||
CENTER_INVALID,
|
||||
CENTER_NEVER,
|
||||
CENTER_FULLSCREEN,
|
||||
CENTER_MAXIMIZED_AND_FULLSCREEN,
|
||||
CENTER_ALWAYS,
|
||||
};
|
||||
|
||||
struct config {
|
||||
char *term;
|
||||
char *shell;
|
||||
char *title;
|
||||
char *app_id;
|
||||
char *toplevel_tag;
|
||||
char32_t *word_delimiters;
|
||||
bool login_shell;
|
||||
bool locked_title;
|
||||
|
|
@ -148,7 +234,7 @@ struct config {
|
|||
|
||||
unsigned pad_x;
|
||||
unsigned pad_y;
|
||||
bool center;
|
||||
enum center_when center_when;
|
||||
|
||||
bool resize_by_cells;
|
||||
bool resize_keep_grid;
|
||||
|
|
@ -168,9 +254,8 @@ struct config {
|
|||
enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode;
|
||||
|
||||
bool dpi_aware;
|
||||
enum {GAMMA_CORRECT_DISABLED,
|
||||
GAMMA_CORRECT_ENABLED,
|
||||
GAMMA_CORRECT_AUTO} gamma_correct;
|
||||
bool gamma_correct;
|
||||
bool uppercase_regex_insert;
|
||||
struct config_font_list fonts[4];
|
||||
struct font_size_adjustment font_size_adjustment;
|
||||
|
||||
|
|
@ -244,58 +329,9 @@ struct config {
|
|||
|
||||
tll(struct custom_regex) custom_regexes;
|
||||
|
||||
struct {
|
||||
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 {
|
||||
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 color_theme colors_dark;
|
||||
struct color_theme colors_light;
|
||||
enum which_color_theme initial_color_theme;
|
||||
|
||||
struct {
|
||||
enum cursor_style style;
|
||||
|
|
@ -304,10 +340,6 @@ struct config {
|
|||
bool enabled;
|
||||
uint32_t rate_ms;
|
||||
} blink;
|
||||
struct {
|
||||
uint32_t text;
|
||||
uint32_t cursor;
|
||||
} color;
|
||||
struct pt_or_px beam_thickness;
|
||||
struct pt_or_px underline_thickness;
|
||||
} cursor;
|
||||
|
|
@ -410,7 +442,9 @@ struct config {
|
|||
bool box_drawing_solid_shades;
|
||||
bool font_monospace_warn;
|
||||
bool sixel;
|
||||
enum { SHM_8_BIT, SHM_10_BIT } surface_bit_depth;
|
||||
enum shm_bit_depth surface_bit_depth;
|
||||
uint32_t min_stride_alignment;
|
||||
bool preapply_damage;
|
||||
} tweak;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
78
csi.c
78
csi.c
|
|
@ -117,9 +117,9 @@ csi_sgr(struct terminal *term)
|
|||
style > UNDERLINE_SINGLE;
|
||||
break;
|
||||
}
|
||||
|
||||
term_update_ascii_printer(term);
|
||||
}
|
||||
} else
|
||||
term->bits_affecting_ascii_printer.underline_style = false;
|
||||
term_update_ascii_printer(term);
|
||||
break;
|
||||
}
|
||||
case 5: term->vt.attrs.blink = true; break;
|
||||
|
|
@ -422,6 +422,8 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
|
|||
|
||||
case 1004:
|
||||
term->focus_events = enable;
|
||||
if (enable)
|
||||
term_to_slave(term, term->kbd_focus ? "\033[I" : "\033[O", 3);
|
||||
break;
|
||||
|
||||
case 1005:
|
||||
|
|
@ -563,6 +565,10 @@ decset_decrst(struct terminal *term, unsigned param, bool enable)
|
|||
#endif
|
||||
break;
|
||||
|
||||
case 2031:
|
||||
term->report_theme_changes = enable;
|
||||
break;
|
||||
|
||||
case 2048:
|
||||
if (enable)
|
||||
term_enable_size_notifications(term);
|
||||
|
|
@ -657,6 +663,7 @@ decrqm(const struct terminal *term, unsigned param)
|
|||
case 2027: return term->conf->tweak.grapheme_width_method != GRAPHEME_WIDTH_DOUBLE
|
||||
? DECRPM_PERMANENTLY_RESET
|
||||
: decrpm(term->grapheme_shaping);
|
||||
case 2031: return decrpm(term->report_theme_changes);
|
||||
case 2048: return decrpm(term->size_notifications);
|
||||
case 8452: return decrpm(term->sixel.cursor_right_of_graphics);
|
||||
case 737769: return decrpm(term_ime_is_enabled(term));
|
||||
|
|
@ -702,6 +709,7 @@ xtsave(struct terminal *term, unsigned param)
|
|||
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 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 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;
|
||||
|
|
@ -746,6 +754,7 @@ xtrestore(struct terminal *term, unsigned param)
|
|||
case 2004: enable = term->xtsave.bracketed_paste; break;
|
||||
case 2026: enable = term->xtsave.app_sync_updates; 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 8452: enable = term->xtsave.sixel_cursor_right_of_graphics; break;
|
||||
case 737769: enable = term->xtsave.ime; break;
|
||||
|
|
@ -792,7 +801,17 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
int count = vt_param_get(term, 0, 1);
|
||||
LOG_DBG("REP: '%lc' %d times", (wint_t)term->vt.last_printed, count);
|
||||
|
||||
const int width = c32width(term->vt.last_printed);
|
||||
int width;
|
||||
|
||||
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) {
|
||||
for (int i = 0; i < count; i++)
|
||||
term_print(term, term->vt.last_printed, width, false);
|
||||
|
|
@ -833,6 +852,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
* - 22 ANSI color, e.g., VT525.
|
||||
* - 28 Rectangular editing.
|
||||
* - 29 ANSI text locator (i.e., DEC Locator mode).
|
||||
* - 52 Clipboard access
|
||||
*
|
||||
* Note: we report ourselves as a VT220, mainly to be able
|
||||
* to pass parameters, to indicate we support sixel, and
|
||||
|
|
@ -843,13 +863,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
*
|
||||
* Note: tertiary DA responds with "FOOT".
|
||||
*/
|
||||
if (term->conf->tweak.sixel) {
|
||||
static const char reply[] = "\033[?62;4;22;28c";
|
||||
term_to_slave(term, reply, sizeof(reply) - 1);
|
||||
} else {
|
||||
static const char reply[] = "\033[?62;22;28c";
|
||||
term_to_slave(term, reply, sizeof(reply) - 1);
|
||||
}
|
||||
char reply[32];
|
||||
|
||||
int len = snprintf(
|
||||
reply, sizeof(reply), "\033[?62%s;22;28%sc",
|
||||
term->conf->tweak.sixel ? ";4" : "",
|
||||
(term->conf->security.osc52 == OSC52_ENABLED ||
|
||||
term->conf->security.osc52 == OSC52_COPY_ENABLED ? ";52" : ""));
|
||||
|
||||
term_to_slave(term, reply, len);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1539,6 +1561,32 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
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': {
|
||||
/*
|
||||
* Request status of ECMA-48/"ANSI" private mode (DECRQM
|
||||
|
|
@ -1596,10 +1644,10 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
* 64 - vt520
|
||||
* 65 - vt525
|
||||
*
|
||||
* Param 2 - firmware version
|
||||
* xterm uses its version number. We use an xterm
|
||||
* version number too, since e.g. Emacs uses this to
|
||||
* determine level of support.
|
||||
* Param 2 - firmware version xterm uses its version
|
||||
* number. We do to, in the format "MAJORMINORPATCH",
|
||||
* where all three version numbers are always two
|
||||
* digits. So e.g. 1.25.0 is reported as 012500.
|
||||
*
|
||||
* We report ourselves as a VT220. This must be
|
||||
* synchronized with the primary DA response.
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ cursor_shape_to_server_shape(enum cursor_shape shape)
|
|||
}
|
||||
|
||||
enum wp_cursor_shape_device_v1_shape
|
||||
cursor_string_to_server_shape(const char *xcursor)
|
||||
cursor_string_to_server_shape(const char *xcursor, int bound_version)
|
||||
{
|
||||
if (xcursor == NULL)
|
||||
return 0;
|
||||
|
|
@ -72,7 +72,7 @@ cursor_string_to_server_shape(const char *xcursor)
|
|||
[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_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_NOT_ALLOWED] = {"not-allowed", "crossed_circle"},
|
||||
[WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB] = {"grab", "hand1"},
|
||||
|
|
@ -94,9 +94,29 @@ cursor_string_to_server_shape(const char *xcursor)
|
|||
[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_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++) {
|
||||
#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++) {
|
||||
if (table[i][j] != NULL && streq(xcursor, table[i][j])) {
|
||||
return i;
|
||||
|
|
|
|||
|
|
@ -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 cursor_shape shape);
|
||||
enum wp_cursor_shape_device_v1_shape cursor_string_to_server_shape(
|
||||
const char *xcursor);
|
||||
const char *xcursor, int bound_version);
|
||||
|
|
|
|||
|
|
@ -337,6 +337,9 @@ that corresponds to one of the following modes:
|
|||
| 2027
|
||||
: contour
|
||||
: Grapheme cluster processing
|
||||
| 2031
|
||||
: contour
|
||||
: Request color theme updates
|
||||
| 2048
|
||||
: TODO
|
||||
: In-band window resize notifications
|
||||
|
|
@ -657,6 +660,13 @@ manipulation sequences. The generic format is:
|
|||
: xterm
|
||||
: Report the current entry on the palette stack, and the number of
|
||||
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
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ the foot command line
|
|||
Value to set the *app-id* property on the Wayland window
|
||||
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*
|
||||
Start in maximized mode. If both *--maximized* and *--fullscreen*
|
||||
are specified, the _last_ one takes precedence.
|
||||
|
|
@ -252,9 +257,6 @@ These keyboard shortcuts affect the search selection:
|
|||
*ctrl*+*shift*+*left*
|
||||
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*
|
||||
Extend current selection down one line
|
||||
|
||||
|
|
@ -689,6 +691,21 @@ variables may be defined in *foot.ini*(5).
|
|||
In addition to the variables listed above, custom environment
|
||||
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
|
||||
|
||||
Please report bugs to https://codeberg.org/dnkl/foot/issues
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ commented out will usually be installed to */etc/xdg/foot/foot.ini*.
|
|||
|
||||
Options are set using KEY=VALUE pairs:
|
||||
|
||||
*\[colors\]*++
|
||||
*\[colors-dark\]*++
|
||||
*background=000000*++
|
||||
*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
|
||||
background will appear thicker, and dark glyphs on a light
|
||||
background will appear thinner.
|
||||
|
||||
|
||||
FreeType can limit the effect of the latter, with a technique
|
||||
called stem darkening. It is only available for CFF fonts
|
||||
(OpenType, .otf) and disabled by default (in FreeType). You can
|
||||
|
|
@ -220,13 +220,23 @@ empty string to be set, but it must be quoted: *KEY=""*)
|
|||
than intended when rendered with gamma-correct blending, since the
|
||||
font designer set the font weight based on incorrect rendering.
|
||||
|
||||
Note that some colors (especially dark ones) will look a bit
|
||||
off. The reason for this is loss of color precision, due to foot
|
||||
using 8-bit surfaces (i.e. each color channel is 8 bits). The
|
||||
amount of errors can be reduced by using 10-bit surfaces; see
|
||||
*tweak.surface-bit-depth*.
|
||||
In order to represent colors faithfully, higher precision image
|
||||
buffers are required. By default, foot will use either 16-bit, or
|
||||
10-bit color channels, depending on availability, when
|
||||
gamma-correct blending is enabled. However, the high precision
|
||||
buffers are slow; if you want to use gamma-correct blending, but
|
||||
prefer speed (throughput and input latency) over accurate colors,
|
||||
you can force 8-bit color channels by setting
|
||||
*tweak.surface-bit-depth=8-bit*.
|
||||
|
||||
Default: enabled when compositor support is available
|
||||
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*
|
||||
Boolean. When disabled, foot generates box/line drawing characters
|
||||
|
|
@ -286,18 +296,29 @@ empty string to be set, but it must be quoted: *KEY=""*)
|
|||
|
||||
*pad*
|
||||
Padding between border and glyphs, in pixels (subject to output
|
||||
scaling), in the form _XxY_.
|
||||
scaling), in the form
|
||||
|
||||
```
|
||||
_XxY_ [center | center-when-fullscreen | center-when-maximized-and-fullscreen]
|
||||
```
|
||||
|
||||
This will add _at least_ X pixels on both the left and right
|
||||
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.
|
||||
sides, and Y pixels on the top and bottom sides.
|
||||
|
||||
To instead center the grid content, append *center* (e.g. *pad=5x5
|
||||
center*).
|
||||
When no centering is specified, the grid content is anchored to
|
||||
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.
|
||||
|
||||
Default: _0x0_.
|
||||
If *center* is specified, the grid content is instead
|
||||
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*
|
||||
|
||||
|
|
@ -349,6 +370,19 @@ empty string to be set, but it must be quoted: *KEY=""*)
|
|||
|
||||
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 width and height in _pixels_ (subject to output
|
||||
scaling), in the form _WIDTHxHEIGHT_. The height _includes_ the
|
||||
|
|
@ -395,6 +429,11 @@ empty string to be set, but it must be quoted: *KEY=""*)
|
|||
apply window management rules. Default: _foot_ (normal mode), or
|
||||
_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*
|
||||
Semi-boolean. When enabled, bold text is rendered in a brighter
|
||||
color (in addition to using a bold font). The color is brightened
|
||||
|
|
@ -898,15 +937,6 @@ applications can change these at runtime.
|
|||
enabled. Expressed in milliseconds between each blink. Default:
|
||||
_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*
|
||||
Thickness (width) of the beam styled cursor. The value is in
|
||||
points, and its exact value thus depends on the monitor's DPI. To
|
||||
|
|
@ -957,16 +987,34 @@ applications can change these at runtime.
|
|||
|
||||
Default: _400_.
|
||||
|
||||
# SECTION: colors
|
||||
# SECTION: colors-dark, colors-light
|
||||
|
||||
This section controls the 16 ANSI colors, the default foreground and
|
||||
background colors, and the extended 256 color palette. Note that
|
||||
These two sections controls the 16 ANSI colors, the default foreground
|
||||
and background colors, and the extended 256 color palette. Note that
|
||||
applications can change these at runtime.
|
||||
|
||||
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
|
||||
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*
|
||||
Default foreground color. This is the color used when no ANSI
|
||||
color is being used. Default: _839496_.
|
||||
|
|
@ -993,7 +1041,8 @@ can configure the background transparency with the _alpha_ option.
|
|||
a color value, and a "dim" attribute.
|
||||
|
||||
By default, foot implements this by blending the current color
|
||||
with black. This is a generic approach that applies to both
|
||||
with black or white, depending on what the *dim-blend-towards*
|
||||
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.
|
||||
|
||||
You can change this behavior by setting the *dimN* options. When
|
||||
|
|
@ -1048,10 +1097,17 @@ can configure the background transparency with the _alpha_ option.
|
|||
|
||||
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*
|
||||
Foreground (text) and background color to use in selected
|
||||
text. Note that *both* options must be set, or the default will be
|
||||
used. Default: _inverse foreground/background_.
|
||||
text. Default: _inverse foreground/background_.
|
||||
|
||||
*jump-labels*
|
||||
Two color values specifying the foreground (text) and background
|
||||
|
|
@ -1327,7 +1383,8 @@ e.g. *search-start=none*.
|
|||
*show-urls-copy*
|
||||
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
|
||||
clipboard. Default: _none_.
|
||||
clipboard. If the hint is completed with an uppercase character,
|
||||
the match will also be pasted. Default: _none_.
|
||||
|
||||
*regex-launch*
|
||||
Enter regex mode. This works exactly the same as URL mode; all
|
||||
|
|
@ -1350,8 +1407,10 @@ e.g. *search-start=none*.
|
|||
Default: _none_.
|
||||
|
||||
*regex-copy*
|
||||
Same as *regex-copy*, but the match is placed in the clipboard,
|
||||
instead of "launched", upon activation. Default: _none_.
|
||||
Same as *regex-launch*, but the match is placed in the clipboard,
|
||||
instead of "launched", upon activation. If the hint is completed
|
||||
with an uppercase character, the match will also be pasted.
|
||||
Default: _none_.
|
||||
|
||||
*prompt-prev*
|
||||
Jump to the previous, currently not visible, prompt (requires
|
||||
|
|
@ -1387,6 +1446,25 @@ e.g. *search-start=none*.
|
|||
|
||||
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 foot. Default: _none_.
|
||||
|
||||
|
|
@ -1959,6 +2037,32 @@ any of these options.
|
|||
|
||||
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*
|
||||
Boolean. When enabled, foot will process sixel images. Default:
|
||||
_yes_
|
||||
|
|
@ -1973,23 +2077,62 @@ any of these options.
|
|||
|
||||
*surface-bit-depth*
|
||||
Selects which RGB bit depth to use for image buffers. One of
|
||||
*8-bit*, or *10-bit*.
|
||||
*auto*, *8-bit*, *10-bit* or *16-bit*.
|
||||
|
||||
The default, *8-bit*, uses 8 bits for all channels, alpha
|
||||
included. When *gamma-correct-blending* is disabled, this is the
|
||||
best option.
|
||||
*auto* chooses bit depth depending on other settings, and
|
||||
availability.
|
||||
|
||||
When *gamma-correct-blending* is enabled, you may want to enable
|
||||
10-bit surfaces, as that improves color precision. Be aware
|
||||
however, that in this mode, the alpha channel is only 2 bits
|
||||
instead of 8 bits. Thus, if you are using a transparent
|
||||
background, you may want to use the default, *8-bit*, even if you
|
||||
have gamma-correct blending enabled.
|
||||
*8-bit*, uses 8 bits for each color channel, alpha included. This
|
||||
is the default when *gamma-correct-blending=no*.
|
||||
|
||||
You should also note that 10-bit surface is much slower. This will
|
||||
increase input latency and decrease rendering throughput.
|
||||
*10-bit* uses 10 bits for each RGB channel, and 2 bits for the
|
||||
alpha channel. Thus, it provides higher precision color channels,
|
||||
but a lower precision alpha channel.
|
||||
|
||||
Default: _8-bit_
|
||||
*16-bit* 16 bits for each color channel, alpha included. If
|
||||
available, this is the default when *gamma-correct-blending=yes*.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ terminal has terminated.
|
|||
Value to set the *app-id* property on the Wayland window
|
||||
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_
|
||||
Set initial window width and height, in pixels. Default: _700x500_.
|
||||
|
||||
|
|
@ -189,6 +194,21 @@ variables may be defined in *foot.ini*(5).
|
|||
In addition to the variables listed above, custom environment
|
||||
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
|
||||
|
||||
*foot*(1)
|
||||
|
|
|
|||
|
|
@ -256,8 +256,8 @@ extract_one(const struct terminal *term, const struct row *row,
|
|||
}
|
||||
}
|
||||
|
||||
xassert(next_tab_stop >= col);
|
||||
ctx->tab_spaces_left = next_tab_stop - col;
|
||||
if (next_tab_stop > col)
|
||||
ctx->tab_spaces_left = next_tab_stop - col - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
30
fdm.c
30
fdm.c
|
|
@ -18,6 +18,18 @@
|
|||
#include "debug.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 {
|
||||
int fd;
|
||||
int events;
|
||||
|
|
@ -113,7 +125,8 @@ fdm_destroy(struct fdm *fdm)
|
|||
|
||||
for (int i = 0; i < SIGRTMAX; i++) {
|
||||
if (fdm->signal_handlers[i].callback != NULL)
|
||||
LOG_WARN("handler for signal %d not removed", i);
|
||||
LOG_WARN("handler for signal %d (SIG%s) not removed",
|
||||
i, sigabbrev_np(i));
|
||||
}
|
||||
|
||||
if (tll_length(fdm->hooks_low) > 0 ||
|
||||
|
|
@ -338,7 +351,8 @@ bool
|
|||
fdm_signal_add(struct fdm *fdm, int signo, fdm_signal_handler_t handler, void *data)
|
||||
{
|
||||
if (fdm->signal_handlers[signo].callback != NULL) {
|
||||
LOG_ERR("signal %d already has a handler", signo);
|
||||
LOG_ERR("signal %d (SIG%s) already has a handler",
|
||||
signo, sigabbrev_np(signo));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -347,14 +361,16 @@ fdm_signal_add(struct fdm *fdm, int signo, fdm_signal_handler_t handler, void *d
|
|||
sigaddset(&mask, signo);
|
||||
|
||||
if (sigprocmask(SIG_BLOCK, &mask, &original) < 0) {
|
||||
LOG_ERRNO("failed to block signal %d", signo);
|
||||
LOG_ERRNO("failed to block signal %d (SIG%s)",
|
||||
signo, sigabbrev_np(signo));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sigaction action = {.sa_handler = &signal_handler};
|
||||
sigemptyset(&action.sa_mask);
|
||||
if (sigaction(signo, &action, NULL) < 0) {
|
||||
LOG_ERRNO("failed to set signal handler for signal %d", signo);
|
||||
LOG_ERRNO("failed to set signal handler for signal %d (SIG%s)",
|
||||
signo, sigabbrev_np(signo));
|
||||
sigprocmask(SIG_SETMASK, &original, NULL);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -374,7 +390,8 @@ fdm_signal_del(struct fdm *fdm, int signo)
|
|||
struct sigaction action = {.sa_handler = SIG_DFL};
|
||||
sigemptyset(&action.sa_mask);
|
||||
if (sigaction(signo, &action, NULL) < 0) {
|
||||
LOG_ERRNO("failed to restore signal handler for signal %d", signo);
|
||||
LOG_ERRNO("failed to restore signal handler for signal %d (SIG%s)",
|
||||
signo, sigabbrev_np(signo));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +403,8 @@ fdm_signal_del(struct fdm *fdm, int signo)
|
|||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signo);
|
||||
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) {
|
||||
LOG_ERRNO("failed to unblock signal %d", signo);
|
||||
LOG_ERRNO("failed to unblock signal %d (SIG%s)",
|
||||
signo, sigabbrev_np(signo));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ const char version_and_features[] =
|
|||
" -graphemes"
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_XDG_TOPLEVEL_TAG)
|
||||
" +toplevel-tag"
|
||||
#else
|
||||
" -toplevel-tag"
|
||||
#endif
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
" +assertions"
|
||||
#else
|
||||
|
|
|
|||
20
foot.ini
20
foot.ini
|
|
@ -22,11 +22,13 @@
|
|||
# strikeout-thickness=<font strikeout thickness>
|
||||
# box-drawings-uses-font-glyphs=no
|
||||
# dpi-aware=no
|
||||
# gamma-correct-blending=no
|
||||
|
||||
# initial-color-theme=dark
|
||||
# initial-window-size-pixels=700x500 # Or,
|
||||
# initial-window-size-chars=<COLSxROWS>
|
||||
# initial-window-mode=windowed
|
||||
# pad=0x0 # optionally append 'center'
|
||||
# pad=0x0 center-when-maximized-and-fullscreen
|
||||
# resize-by-cells=yes
|
||||
# resize-keep-grid=yes
|
||||
# resize-delay-ms=100
|
||||
|
|
@ -38,6 +40,8 @@
|
|||
# utmp-helper=/usr/lib/utempter/utempter # When utmp backend is ‘libutempter’ (Linux)
|
||||
# utmp-helper=/usr/libexec/ulog-helper # When utmp backend is ‘ulog’ (FreeBSD)
|
||||
|
||||
# uppercase-regex-insert=yes
|
||||
|
||||
[environment]
|
||||
# name=value
|
||||
|
||||
|
|
@ -85,7 +89,6 @@
|
|||
|
||||
[cursor]
|
||||
# style=block
|
||||
# color=<inverse foreground/background>
|
||||
# blink=no
|
||||
# blink-rate=500
|
||||
# beam-thickness=1.5
|
||||
|
|
@ -98,7 +101,7 @@
|
|||
[touch]
|
||||
# long-press-delay=400
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
# alpha=1.0
|
||||
# alpha-mode=default # Can be `default`, `matching` or `all`
|
||||
# background=242424
|
||||
|
|
@ -106,6 +109,8 @@
|
|||
# flash=7f7f00
|
||||
# flash-alpha=0.5
|
||||
|
||||
# cursor=<inverse foreground/background>
|
||||
|
||||
## Normal/regular colors (color palette 0-7)
|
||||
# regular0=242424 # black
|
||||
# regular1=f62b5a # red
|
||||
|
|
@ -127,6 +132,7 @@
|
|||
# bright7=ffffff # bright white
|
||||
|
||||
## dimmed colors (see foot.ini(5) man page)
|
||||
# dim-blend-towards=black
|
||||
# dim0=<not set>
|
||||
# ...
|
||||
# dim7=<not-set>
|
||||
|
|
@ -163,6 +169,11 @@
|
|||
# search-box-match=<regular0> <regular3> # black-on-yellow
|
||||
# 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]
|
||||
# preferred=server
|
||||
# size=26
|
||||
|
|
@ -208,6 +219,9 @@
|
|||
# prompt-prev=Control+Shift+z
|
||||
# prompt-next=Control+Shift+x
|
||||
# unicode-input=Control+Shift+u
|
||||
# color-theme-switch-1=none
|
||||
# color-theme-switch-2=none
|
||||
# color-theme-toggle=none
|
||||
# noop=none
|
||||
# quit=none
|
||||
|
||||
|
|
|
|||
78
input.c
78
input.c
|
|
@ -40,6 +40,7 @@
|
|||
#include "url-mode.h"
|
||||
#include "util.h"
|
||||
#include "vt.h"
|
||||
#include "xkbcommon-vmod.h"
|
||||
#include "xmalloc.h"
|
||||
#include "xsnprintf.h"
|
||||
|
||||
|
|
@ -119,10 +120,14 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
|
||||
case BIND_ACTION_SCROLLBACK_UP_MOUSE:
|
||||
if (term->grid == &term->alt) {
|
||||
if (term->alt_scrolling)
|
||||
if (term->alt_scrolling) {
|
||||
alternate_scroll(seat, amount, BTN_BACK);
|
||||
} else
|
||||
cmd_scrollback_up(term, amount);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
cmd_scrollback_up(term, amount);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SCROLLBACK_DOWN_PAGE:
|
||||
|
|
@ -148,10 +153,14 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
|
||||
case BIND_ACTION_SCROLLBACK_DOWN_MOUSE:
|
||||
if (term->grid == &term->alt) {
|
||||
if (term->alt_scrolling)
|
||||
if (term->alt_scrolling) {
|
||||
alternate_scroll(seat, amount, BTN_FORWARD);
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
cmd_scrollback_down(term, amount);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SCROLLBACK_HOME:
|
||||
|
|
@ -484,6 +493,20 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
|
||||
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:
|
||||
selection_start(
|
||||
term, seat->mouse.col, seat->mouse.row, SELECTION_CHAR_WISE, false);
|
||||
|
|
@ -520,7 +543,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
case BIND_ACTION_SELECT_QUOTE:
|
||||
selection_start(
|
||||
term, seat->mouse.col, seat->mouse.row, SELECTION_QUOTE_WISE, false);
|
||||
break;
|
||||
return true;
|
||||
|
||||
case BIND_ACTION_SELECT_ROW:
|
||||
selection_start(
|
||||
|
|
@ -563,23 +586,20 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
|||
/* Verify keymap is in a format we understand */
|
||||
switch ((enum wl_keyboard_keymap_format)format) {
|
||||
case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP:
|
||||
close(fd);
|
||||
return;
|
||||
goto err;
|
||||
|
||||
case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1:
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WARN("unrecognized keymap format: %u", format);
|
||||
close(fd);
|
||||
return;
|
||||
goto err;
|
||||
}
|
||||
|
||||
char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (map_str == MAP_FAILED) {
|
||||
LOG_ERRNO("failed to mmap keyboard keymap");
|
||||
close(fd);
|
||||
return;
|
||||
goto err;
|
||||
}
|
||||
|
||||
while (map_str[size - 1] == '\0')
|
||||
|
|
@ -592,6 +612,8 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
|||
|
||||
}
|
||||
|
||||
munmap(map_str, size);
|
||||
|
||||
if (seat->kbd.xkb_keymap != NULL) {
|
||||
seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap);
|
||||
|
||||
|
|
@ -672,10 +694,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");
|
||||
}
|
||||
|
||||
munmap(map_str, size);
|
||||
close(fd);
|
||||
|
||||
key_binding_load_keymap(wayl->key_binding_manager, seat);
|
||||
|
||||
err:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1583,6 +1605,9 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
|||
if (released)
|
||||
stop_repeater(seat, key);
|
||||
|
||||
if (pressed)
|
||||
seat->kbd.last_shortcut_sym = XKB_KEYSYM_MAX + 1;
|
||||
|
||||
bool should_repeat =
|
||||
pressed && xkb_keymap_key_repeats(seat->kbd.xkb_keymap, key);
|
||||
|
||||
|
|
@ -1684,6 +1709,7 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
|||
if (bind->k.sym == raw_syms[i] &&
|
||||
execute_binding(seat, term, bind, serial, 1))
|
||||
{
|
||||
seat->kbd.last_shortcut_sym = sym;
|
||||
goto maybe_repeat;
|
||||
}
|
||||
}
|
||||
|
|
@ -1697,6 +1723,7 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
|||
bind->mods == (mods & ~consumed) &&
|
||||
execute_binding(seat, term, bind, serial, 1))
|
||||
{
|
||||
seat->kbd.last_shortcut_sym = sym;
|
||||
goto maybe_repeat;
|
||||
}
|
||||
}
|
||||
|
|
@ -1712,12 +1739,31 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
|||
if (code->item == key &&
|
||||
execute_binding(seat, term, bind, serial, 1))
|
||||
{
|
||||
seat->kbd.last_shortcut_sym = sym;
|
||||
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
|
||||
*/
|
||||
|
|
@ -1865,7 +1911,7 @@ keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
UNITTEST
|
||||
{
|
||||
int chan[2];
|
||||
pipe2(chan, O_CLOEXEC);
|
||||
xassert(pipe2(chan, O_CLOEXEC) == 0);
|
||||
|
||||
xassert(chan[0] >= 0);
|
||||
xassert(chan[1] >= 0);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "terminal.h"
|
||||
#include "util.h"
|
||||
#include "wayland.h"
|
||||
#include "xkbcommon-vmod.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
struct vmod_map {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ enum bind_action_normal {
|
|||
BIND_ACTION_QUIT,
|
||||
BIND_ACTION_REGEX_LAUNCH,
|
||||
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 */
|
||||
BIND_ACTION_SCROLLBACK_UP_MOUSE,
|
||||
|
|
@ -56,7 +61,7 @@ enum bind_action_normal {
|
|||
BIND_ACTION_SELECT_QUOTE,
|
||||
BIND_ACTION_SELECT_ROW,
|
||||
|
||||
BIND_ACTION_KEY_COUNT = BIND_ACTION_REGEX_COPY + 1,
|
||||
BIND_ACTION_KEY_COUNT = BIND_ACTION_THEME_TOGGLE + 1,
|
||||
BIND_ACTION_COUNT = BIND_ACTION_SELECT_ROW + 1,
|
||||
};
|
||||
|
||||
|
|
|
|||
48
main.c
48
main.c
|
|
@ -45,6 +45,33 @@ fdm_sigint(struct fdm *fdm, int signo, void *data)
|
|||
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
|
||||
print_usage(const char *prog_name)
|
||||
{
|
||||
|
|
@ -57,6 +84,7 @@ print_usage(const char *prog_name)
|
|||
" -t,--term=TERM value to set the environment variable TERM to (" FOOT_DEFAULT_TERM ")\n"
|
||||
" -T,--title=TITLE initial window title (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"
|
||||
" -F,--fullscreen start in fullscreen mode\n"
|
||||
" -L,--login-shell start shell as a login shell\n"
|
||||
|
|
@ -158,6 +186,7 @@ sanitize_signals(void)
|
|||
|
||||
enum {
|
||||
PTY_OPTION = CHAR_MAX + 1,
|
||||
TOPLEVEL_TAG_OPTION = CHAR_MAX + 2,
|
||||
};
|
||||
|
||||
int
|
||||
|
|
@ -187,6 +216,7 @@ main(int argc, char *const *argv)
|
|||
{"term", required_argument, NULL, 't'},
|
||||
{"title", required_argument, NULL, 'T'},
|
||||
{"app-id", required_argument, NULL, 'a'},
|
||||
{"toplevel-tag", required_argument, NULL, TOPLEVEL_TAG_OPTION},
|
||||
{"login-shell", no_argument, NULL, 'L'},
|
||||
{"working-directory", required_argument, NULL, 'D'},
|
||||
{"font", required_argument, NULL, 'f'},
|
||||
|
|
@ -258,6 +288,10 @@ main(int argc, char *const *argv)
|
|||
tll_push_back(overrides, xstrjoin("app-id=", optarg));
|
||||
break;
|
||||
|
||||
case TOPLEVEL_TAG_OPTION:
|
||||
tll_push_back(overrides, xstrjoin("toplevel-tag=", optarg));
|
||||
break;
|
||||
|
||||
case 'D': {
|
||||
struct stat st;
|
||||
if (stat(optarg, &st) < 0 || !(st.st_mode & S_IFDIR)) {
|
||||
|
|
@ -570,6 +604,7 @@ main(int argc, char *const *argv)
|
|||
}
|
||||
|
||||
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)
|
||||
goto out;
|
||||
|
|
@ -608,6 +643,17 @@ main(int argc, char *const *argv)
|
|||
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};
|
||||
sigemptyset(&sig_ign.sa_mask);
|
||||
if (sigaction(SIGHUP, &sig_ign, NULL) < 0 ||
|
||||
|
|
@ -643,6 +689,8 @@ out:
|
|||
wayl_destroy(wayl);
|
||||
key_binding_manager_destroy(key_binding_manager);
|
||||
reaper_destroy(reaper);
|
||||
fdm_signal_del(fdm, SIGUSR1);
|
||||
fdm_signal_del(fdm, SIGUSR2);
|
||||
fdm_signal_del(fdm, SIGTERM);
|
||||
fdm_signal_del(fdm, SIGINT);
|
||||
fdm_destroy(fdm);
|
||||
|
|
|
|||
24
meson.build
24
meson.build
|
|
@ -1,5 +1,5 @@
|
|||
project('foot', 'c',
|
||||
version: '1.22.1',
|
||||
version: '1.25.0',
|
||||
license: 'MIT',
|
||||
meson_version: '>=0.59.0',
|
||||
default_options: [
|
||||
|
|
@ -25,6 +25,12 @@ if cc.has_function('execvpe',
|
|||
add_project_arguments('-DEXECVPE', language: 'c')
|
||||
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')
|
||||
if utmp_backend == 'auto'
|
||||
host_os = host_machine.system()
|
||||
|
|
@ -47,7 +53,7 @@ if utmp_backend == 'none'
|
|||
elif utmp_backend == 'libutempter'
|
||||
utmp_add = 'add'
|
||||
utmp_del = 'del'
|
||||
utmp_del_have_argument = true
|
||||
utmp_del_have_argument = false
|
||||
if utmp_default_helper_path == 'auto'
|
||||
utmp_default_helper_path = join_paths('/usr', get_option('libdir'), 'utempter', 'utempter')
|
||||
endif
|
||||
|
|
@ -137,7 +143,7 @@ wayland_protocols = dependency('wayland-protocols', version: '>=1.41',
|
|||
default_options: ['tests=false'])
|
||||
wayland_client = dependency('wayland-client')
|
||||
wayland_cursor = dependency('wayland-cursor')
|
||||
xkb = dependency('xkbcommon', version: '>=1.8.0')
|
||||
xkb = dependency('xkbcommon', version: '>=1.0.0')
|
||||
fontconfig = dependency('fontconfig')
|
||||
utf8proc = dependency('libutf8proc', required: get_option('grapheme-clustering'))
|
||||
|
||||
|
|
@ -145,6 +151,10 @@ if utf8proc.found()
|
|||
add_project_arguments('-DFOOT_GRAPHEME_CLUSTERING=1', language: 'c')
|
||||
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')
|
||||
fcft = dependency('fcft', version: ['>=3.3.1', '<4.0.0'], fallback: 'fcft')
|
||||
|
||||
|
|
@ -172,7 +182,12 @@ wl_proto_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/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
|
||||
wl_proto_headers += custom_target(
|
||||
|
|
@ -315,6 +330,7 @@ executable(
|
|||
'url-mode.c', 'url-mode.h',
|
||||
'user-notification.c', 'user-notification.h',
|
||||
'wayland.c', 'wayland.h', 'shm-formats.h',
|
||||
'xkbcommon-vmod.h',
|
||||
srgb_funcs, wl_proto_src + wl_proto_headers, version,
|
||||
dependencies: [math, threads, libepoll, pixman, wayland_client, wayland_cursor, xkb, fontconfig, utf8proc,
|
||||
tllist, fcft],
|
||||
|
|
|
|||
2
notify.c
2
notify.c
|
|
@ -114,7 +114,7 @@ consume_stdout(struct notification *notif, bool eof)
|
|||
while (left > 0) {
|
||||
line = data;
|
||||
size_t len = left;
|
||||
char *eol = memchr(line, '\n', left);
|
||||
char *eol = (char *)memchr(line, '\n', left);
|
||||
|
||||
if (eol != NULL) {
|
||||
*eol = '\0';
|
||||
|
|
|
|||
123
osc.c
123
osc.c
|
|
@ -73,16 +73,19 @@ osc_to_clipboard(struct terminal *term, const char *target,
|
|||
}
|
||||
|
||||
char *decoded = base64_decode(base64_data, NULL);
|
||||
if (decoded == NULL) {
|
||||
if (errno == EINVAL)
|
||||
LOG_WARN("OSC: invalid clipboard data: %s", base64_data);
|
||||
else
|
||||
LOG_ERRNO("base64_decode() failed");
|
||||
if (decoded == NULL || decoded[0] == '\0') {
|
||||
if (decoded == NULL) {
|
||||
if (errno == EINVAL)
|
||||
LOG_WARN("OSC: invalid clipboard data: %s", base64_data);
|
||||
else
|
||||
LOG_ERRNO("base64_decode() failed");
|
||||
}
|
||||
|
||||
if (to_clipboard)
|
||||
selection_clipboard_unset(seat);
|
||||
if (to_primary)
|
||||
selection_primary_unset(seat);
|
||||
free(decoded);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +513,7 @@ osc_uri(struct terminal *term, char *string)
|
|||
key_value = strtok_r(NULL, ":", &ctx))
|
||||
{
|
||||
const char *key = key_value;
|
||||
char *operator = strchr(key_value, '=');
|
||||
char *operator = (char *)strchr(key_value, '=');
|
||||
|
||||
if (operator == NULL)
|
||||
continue;
|
||||
|
|
@ -522,12 +525,14 @@ osc_uri(struct terminal *term, char *string)
|
|||
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);
|
||||
else
|
||||
} else {
|
||||
LOG_DBG("OSC-8: URL=%s, id=%" PRIu64, uri, id);
|
||||
term_osc8_open(term, id, uri);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1455,15 +1460,20 @@ osc_dispatch(struct terminal *term)
|
|||
|
||||
case 11:
|
||||
term->colors.bg = color;
|
||||
if (have_alpha) {
|
||||
const bool changed = term->colors.alpha != alpha;
|
||||
term->colors.alpha = alpha;
|
||||
|
||||
if (changed) {
|
||||
wayl_win_alpha_changed(term->window);
|
||||
term_font_subpixel_changed(term);
|
||||
}
|
||||
if (!have_alpha) {
|
||||
alpha = term->colors.active_theme == COLOR_THEME_DARK
|
||||
? term->conf->colors_dark.alpha
|
||||
: term->conf->colors_light.alpha;
|
||||
}
|
||||
|
||||
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_margins(term);
|
||||
break;
|
||||
|
|
@ -1475,12 +1485,10 @@ osc_dispatch(struct terminal *term)
|
|||
|
||||
case 17:
|
||||
term->colors.selection_bg = color;
|
||||
term->colors.use_custom_selection = true;
|
||||
break;
|
||||
|
||||
case 19:
|
||||
term->colors.selection_fg = color;
|
||||
term->colors.use_custom_selection = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1509,10 +1517,14 @@ osc_dispatch(struct terminal *term)
|
|||
case 104: {
|
||||
/* 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') {
|
||||
LOG_DBG("resetting all colors");
|
||||
for (size_t i = 0; i < ALEN(term->colors.table); i++)
|
||||
term->colors.table[i] = term->conf->colors.table[i];
|
||||
memcpy(term->colors.table, theme->table, sizeof(term->colors.table));
|
||||
term_damage_view(term);
|
||||
}
|
||||
|
||||
|
|
@ -1534,7 +1546,7 @@ osc_dispatch(struct terminal *term)
|
|||
}
|
||||
|
||||
LOG_DBG("resetting color #%u", idx);
|
||||
term->colors.table[idx] = term->conf->colors.table[idx];
|
||||
term->colors.table[idx] = theme->table[idx];
|
||||
term_damage_color(term, COLOR_BASE256, idx);
|
||||
}
|
||||
|
||||
|
|
@ -1547,16 +1559,28 @@ osc_dispatch(struct terminal *term)
|
|||
|
||||
case 110: /* Reset default text 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);
|
||||
break;
|
||||
|
||||
case 111: { /* Reset default text background color */
|
||||
LOG_DBG("resetting background color");
|
||||
bool alpha_changed = term->colors.alpha != term->conf->colors.alpha;
|
||||
|
||||
term->colors.bg = term->conf->colors.bg;
|
||||
term->colors.alpha = term->conf->colors.alpha;
|
||||
const struct color_theme *theme =
|
||||
term->colors.active_theme == COLOR_THEME_DARK
|
||||
? &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) {
|
||||
wayl_win_alpha_changed(term->window);
|
||||
|
|
@ -1568,24 +1592,49 @@ osc_dispatch(struct terminal *term)
|
|||
break;
|
||||
}
|
||||
|
||||
case 112:
|
||||
case 112: {
|
||||
LOG_DBG("resetting cursor color");
|
||||
term->colors.cursor_fg = term->conf->cursor.color.text;
|
||||
term->colors.cursor_bg = term->conf->cursor.color.cursor;
|
||||
|
||||
const struct color_theme *theme =
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
case 117:
|
||||
case 117: {
|
||||
LOG_DBG("resetting selection background color");
|
||||
term->colors.selection_bg = term->conf->colors.selection_bg;
|
||||
term->colors.use_custom_selection = term->conf->colors.use_custom.selection;
|
||||
break;
|
||||
|
||||
case 119:
|
||||
LOG_DBG("resetting selection foreground color");
|
||||
term->colors.selection_fg = term->conf->colors.selection_fg;
|
||||
term->colors.use_custom_selection = term->conf->colors.use_custom.selection;
|
||||
const struct color_theme *theme =
|
||||
term->colors.active_theme == COLOR_THEME_DARK
|
||||
? &term->conf->colors_dark
|
||||
: &term->conf->colors_light;
|
||||
|
||||
term->colors.selection_bg = theme->selection_bg;
|
||||
break;
|
||||
}
|
||||
|
||||
case 119: {
|
||||
LOG_DBG("resetting selection foreground color");
|
||||
|
||||
const struct color_theme *theme =
|
||||
term->colors.active_theme == COLOR_THEME_DARK
|
||||
? &term->conf->colors_dark
|
||||
: &term->conf->colors_light;
|
||||
|
||||
term->colors.selection_fg = theme->selection_fg;
|
||||
break;
|
||||
}
|
||||
|
||||
case 133:
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ void render_refresh_icon(struct terminal *term) {}
|
|||
|
||||
void render_overlay(struct terminal *term) {}
|
||||
|
||||
void render_buffer_release_callback(struct buffer *buf, void *data) {}
|
||||
|
||||
bool
|
||||
render_xcursor_is_valid(const struct seat *seat, const char *cursor)
|
||||
{
|
||||
|
|
@ -129,7 +131,7 @@ render_worker_thread(void *_ctx)
|
|||
}
|
||||
|
||||
bool
|
||||
render_do_linear_blending(const struct terminal *term)
|
||||
wayl_do_linear_blending(const struct wayland *wayl, const struct config *conf)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -201,11 +203,13 @@ void urls_reset(struct terminal *term) {}
|
|||
|
||||
void shm_unref(struct buffer *buf) {}
|
||||
void shm_chain_free(struct buffer_chain *chain) {}
|
||||
enum shm_bit_depth shm_chain_bit_depth(const struct buffer_chain *chain) { return SHM_BITS_8; }
|
||||
|
||||
struct buffer_chain *
|
||||
shm_chain_new(
|
||||
struct wayland *wayl, bool scrollable, size_t pix_instances,
|
||||
bool ten_bit_it_if_capable)
|
||||
enum shm_bit_depth desired_bit_depth,
|
||||
void (*release_cb)(struct buffer *buf, void *data), void *cb_data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
10
pyproject.toml
Normal file
10
pyproject.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[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'
|
||||
12
quirks.c
12
quirks.c
|
|
@ -67,6 +67,7 @@ quirk_weston_csd_off(struct terminal *term)
|
|||
quirk_weston_subsurface_desync_off(term->window->csd.surface[i].sub);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static bool
|
||||
is_sway(void)
|
||||
{
|
||||
|
|
@ -82,13 +83,4 @@ is_sway(void)
|
|||
|
||||
return is_sway;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
2
quirks.h
2
quirks.h
|
|
@ -21,5 +21,3 @@ void quirk_weston_subsurface_desync_off(struct wl_subsurface *sub);
|
|||
/* Shortcuts to call desync_{on,off} on all CSD subsurfaces */
|
||||
void quirk_weston_csd_on(struct terminal *term);
|
||||
void quirk_weston_csd_off(struct terminal *term);
|
||||
|
||||
void quirk_sway_subsurface_unmap(struct terminal *term);
|
||||
|
|
|
|||
463
render.c
463
render.c
|
|
@ -293,7 +293,7 @@ static inline uint32_t
|
|||
color_dim(const struct terminal *term, uint32_t color)
|
||||
{
|
||||
const struct config *conf = term->conf;
|
||||
const uint8_t custom_dim = conf->colors.use_custom.dim;
|
||||
const uint8_t custom_dim = conf->colors_dark.use_custom.dim;
|
||||
|
||||
if (unlikely(custom_dim != 0)) {
|
||||
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) {
|
||||
/* "Regular" color, return the corresponding "dim" */
|
||||
return conf->colors.dim[i];
|
||||
return conf->colors_dark.dim[i];
|
||||
}
|
||||
|
||||
else if (term->colors.table[8 + i] == color) {
|
||||
|
|
@ -312,7 +312,14 @@ color_dim(const struct terminal *term, uint32_t color)
|
|||
}
|
||||
}
|
||||
|
||||
return color_blend_towards(color, 0x00000000, conf->dim.amount);
|
||||
const struct color_theme *theme = term->colors.active_theme == COLOR_THEME_DARK
|
||||
? &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
|
||||
|
|
@ -626,7 +633,7 @@ draw_cursor(const struct terminal *term, const struct cell *cell,
|
|||
pixman_color_t cursor_color;
|
||||
pixman_color_t text_color;
|
||||
cursor_colors_for_cell(term, cell, fg, bg, &cursor_color, &text_color,
|
||||
render_do_linear_blending(term));
|
||||
wayl_do_linear_blending(term->wl, term->conf));
|
||||
|
||||
if (unlikely(!term->kbd_focus)) {
|
||||
switch (term->conf->cursor.unfocused_style) {
|
||||
|
|
@ -694,58 +701,82 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
const int x = term->margins.left + col * width;
|
||||
const int y = term->margins.top + row_no * height;
|
||||
|
||||
bool is_selected = cell->attrs.selected;
|
||||
|
||||
uint32_t _fg = 0;
|
||||
uint32_t _bg = 0;
|
||||
|
||||
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 {
|
||||
/* 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) {
|
||||
if (unlikely(cell->attrs.reverse)) {
|
||||
uint32_t swap = _fg;
|
||||
_fg = _bg;
|
||||
_bg = swap;
|
||||
}
|
||||
|
||||
else if (!term->window->is_fullscreen && term->colors.alpha != 0xffff) {
|
||||
switch (term->conf->colors.alpha_mode) {
|
||||
switch (term->conf->colors_dark.alpha_mode) {
|
||||
case ALPHA_MODE_DEFAULT: {
|
||||
if (cell->attrs.bg_src == COLOR_DEFAULT) {
|
||||
alpha = term->colors.alpha;
|
||||
|
|
@ -806,12 +837,6 @@ 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)
|
||||
_fg = color_dim(term, _fg);
|
||||
if (term->conf->bold_in_bright.enabled && cell->attrs.bold)
|
||||
|
|
@ -820,7 +845,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
if (cell->attrs.blink && term->blink.state == BLINK_OFF)
|
||||
_fg = color_blend_towards(_fg, 0x00000000, term->conf->dim.amount);
|
||||
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
pixman_color_t fg = color_hex_to_pixman(_fg, gamma_correct);
|
||||
pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, alpha, gamma_correct);
|
||||
|
||||
|
|
@ -1150,8 +1175,8 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
|
||||
if (unlikely(cell->attrs.url)) {
|
||||
pixman_color_t url_color = color_hex_to_pixman(
|
||||
term->conf->colors.use_custom.url
|
||||
? term->conf->colors.url
|
||||
term->conf->colors_dark.use_custom.url
|
||||
? term->conf->colors_dark.url
|
||||
: term->colors.table[3],
|
||||
gamma_correct);
|
||||
draw_underline(term, pix, font, &url_color, x, y, cell_cols);
|
||||
|
|
@ -1180,7 +1205,8 @@ static void
|
|||
render_urgency(struct terminal *term, struct buffer *buf)
|
||||
{
|
||||
uint32_t red = term->colors.table[1];
|
||||
pixman_color_t bg = color_hex_to_pixman(red, render_do_linear_blending(term));
|
||||
pixman_color_t bg = color_hex_to_pixman(
|
||||
red, wayl_do_linear_blending(term->wl, term->conf));
|
||||
|
||||
int width = min(min(term->margins.left, term->margins.right),
|
||||
min(term->margins.top, term->margins.bottom));
|
||||
|
|
@ -1211,7 +1237,7 @@ render_margin(struct terminal *term, struct buffer *buf,
|
|||
const int bmargin = term->height - term->margins.bottom;
|
||||
const int line_count = end_line - start_line;
|
||||
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
const uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg;
|
||||
uint16_t alpha = term->colors.alpha;
|
||||
|
||||
|
|
@ -1699,7 +1725,7 @@ render_ime_preedit_for_seat(struct terminal *term, struct seat *seat,
|
|||
if (unlikely(term->is_searching))
|
||||
return;
|
||||
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
|
||||
/* Adjust cursor position to viewport */
|
||||
struct coord cursor;
|
||||
|
|
@ -1951,10 +1977,6 @@ render_overlay(struct terminal *term)
|
|||
wl_surface_commit(overlay->surface.surf);
|
||||
term->render.last_overlay_style = OVERLAY_NONE;
|
||||
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;
|
||||
}
|
||||
|
|
@ -1969,8 +1991,9 @@ render_overlay(struct terminal *term)
|
|||
|
||||
case OVERLAY_FLASH:
|
||||
color = color_hex_to_pixman_with_alpha(
|
||||
term->conf->colors.flash,
|
||||
term->conf->colors.flash_alpha, render_do_linear_blending(term));
|
||||
term->conf->colors_dark.flash,
|
||||
term->conf->colors_dark.flash_alpha,
|
||||
wayl_do_linear_blending(term->wl, term->conf));
|
||||
break;
|
||||
|
||||
case OVERLAY_NONE:
|
||||
|
|
@ -1989,7 +2012,7 @@ render_overlay(struct terminal *term)
|
|||
}
|
||||
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
term->render.chains.overlay, term->width, term->height, true);
|
||||
term->render.chains.overlay, term->width, term->height);
|
||||
pixman_image_set_clip_region32(buf->pix[0], NULL);
|
||||
|
||||
/* Bounding rectangle of damaged areas - for wl_surface_damage_buffer() */
|
||||
|
|
@ -2208,6 +2231,56 @@ render_worker_thread(void *_ctx)
|
|||
|
||||
case -2:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -2215,6 +2288,22 @@ render_worker_thread(void *_ctx)
|
|||
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
|
||||
get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
|
||||
{
|
||||
|
|
@ -2234,16 +2323,21 @@ get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
|
|||
const int button_width = title_visible
|
||||
? roundf(term->conf->csd.button_width * scale) : 0;
|
||||
|
||||
const int button_close_width = term->width >= 1 * button_width
|
||||
? button_width : 0;
|
||||
int remaining_width = term->width;
|
||||
|
||||
const int button_maximize_width =
|
||||
term->width >= 2 * button_width && term->window->wm_capabilities.maximize
|
||||
? button_width : 0;
|
||||
const int button_close_width = remaining_width >= button_width ? button_width : 0;
|
||||
remaining_width -= button_close_width;
|
||||
const int button_close_start = remaining_width;
|
||||
|
||||
const int button_minimize_width =
|
||||
term->width >= 3 * button_width && term->window->wm_capabilities.minimize
|
||||
? button_width : 0;
|
||||
const int button_maximize_width = remaining_width >= button_width &&
|
||||
term->window->wm_capabilities.maximize ? button_width : 0;
|
||||
remaining_width -= button_maximize_width;
|
||||
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
|
||||
|
|
@ -2268,9 +2362,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};
|
||||
|
||||
/* Positioned relative to CSD_SURF_TITLE */
|
||||
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){term->width - 2 * button_width, 0, button_maximize_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_MINIMIZE: return (struct csd_data){button_minimize_start, 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_CLOSE: return (struct csd_data){ button_close_start, 0, button_close_width, title_height};
|
||||
|
||||
case CSD_SURF_COUNT:
|
||||
break;
|
||||
|
|
@ -2312,7 +2406,7 @@ render_osd(struct terminal *term, const struct wayl_sub_surface *sub_surf,
|
|||
pixman_image_set_clip_region32(buf->pix[0], &clip);
|
||||
pixman_region32_fini(&clip);
|
||||
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
uint16_t alpha = _bg >> 24 | (_bg >> 24 << 8);
|
||||
pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, alpha, gamma_correct);
|
||||
pixman_image_fill_rectangles(
|
||||
|
|
@ -2416,10 +2510,10 @@ render_csd_title(struct terminal *term, const struct csd_data *info,
|
|||
|
||||
uint32_t bg = term->conf->csd.color.title_set
|
||||
? term->conf->csd.color.title
|
||||
: 0xffu << 24 | term->conf->colors.fg;
|
||||
: 0xffu << 24 | term->conf->colors_dark.fg;
|
||||
uint32_t fg = term->conf->csd.color.buttons_set
|
||||
? term->conf->csd.color.buttons
|
||||
: term->conf->colors.bg;
|
||||
: term->conf->colors_dark.bg;
|
||||
|
||||
if (!term->visual_focus) {
|
||||
bg = color_dim(term, bg);
|
||||
|
|
@ -2453,7 +2547,7 @@ render_csd_border(struct terminal *term, enum csd_surface surf_idx,
|
|||
if (info->width == 0 || info->height == 0)
|
||||
return;
|
||||
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
|
||||
{
|
||||
/* Fully transparent - no need to do a color space transform */
|
||||
|
|
@ -2513,7 +2607,7 @@ render_csd_border(struct terminal *term, enum csd_surface surf_idx,
|
|||
uint32_t _color =
|
||||
conf->csd.color.border_set ? conf->csd.color.border :
|
||||
conf->csd.color.title_set ? conf->csd.color.title :
|
||||
0xffu << 24 | term->conf->colors.fg;
|
||||
0xffu << 24 | term->conf->colors_dark.fg;
|
||||
if (!term->visual_focus)
|
||||
_color = color_dim(term, _color);
|
||||
|
||||
|
|
@ -2533,7 +2627,7 @@ static pixman_color_t
|
|||
get_csd_button_fg_color(const struct terminal *term)
|
||||
{
|
||||
const struct config *conf = term->conf;
|
||||
uint32_t _color = conf->colors.bg;
|
||||
uint32_t _color = conf->colors_dark.bg;
|
||||
uint16_t alpha = 0xffff;
|
||||
|
||||
if (conf->csd.color.buttons_set) {
|
||||
|
|
@ -2542,7 +2636,7 @@ get_csd_button_fg_color(const struct terminal *term)
|
|||
}
|
||||
|
||||
return color_hex_to_pixman_with_alpha(
|
||||
_color, alpha, render_do_linear_blending(term));
|
||||
_color, alpha, wayl_do_linear_blending(term->wl, term->conf));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2778,7 +2872,7 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx,
|
|||
|
||||
switch (surf_idx) {
|
||||
case CSD_SURF_MINIMIZE:
|
||||
_color = term->conf->colors.table[4]; /* blue */
|
||||
_color = term->conf->colors_dark.table[4]; /* blue */
|
||||
is_set = term->conf->csd.color.minimize_set;
|
||||
conf_color = &term->conf->csd.color.minimize;
|
||||
is_active = term->active_surface == TERM_SURF_BUTTON_MINIMIZE &&
|
||||
|
|
@ -2786,7 +2880,7 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx,
|
|||
break;
|
||||
|
||||
case CSD_SURF_MAXIMIZE:
|
||||
_color = term->conf->colors.table[2]; /* green */
|
||||
_color = term->conf->colors_dark.table[2]; /* green */
|
||||
is_set = term->conf->csd.color.maximize_set;
|
||||
conf_color = &term->conf->csd.color.maximize;
|
||||
is_active = term->active_surface == TERM_SURF_BUTTON_MAXIMIZE &&
|
||||
|
|
@ -2794,7 +2888,7 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx,
|
|||
break;
|
||||
|
||||
case CSD_SURF_CLOSE:
|
||||
_color = term->conf->colors.table[1]; /* red */
|
||||
_color = term->conf->colors_dark.table[1]; /* red */
|
||||
is_set = term->conf->csd.color.close_set;
|
||||
conf_color = &term->conf->csd.color.quit;
|
||||
is_active = term->active_surface == TERM_SURF_BUTTON_CLOSE &&
|
||||
|
|
@ -2819,7 +2913,7 @@ render_csd_button(struct terminal *term, enum csd_surface surf_idx,
|
|||
if (!term->visual_focus)
|
||||
_color = color_dim(term, _color);
|
||||
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
pixman_color_t color = color_hex_to_pixman_with_alpha(_color, alpha, gamma_correct);
|
||||
render_csd_part(term, surf->surf, buf, info->width, info->height, &color);
|
||||
|
||||
|
|
@ -2876,7 +2970,7 @@ render_csd(struct terminal *term)
|
|||
}
|
||||
|
||||
struct buffer *bufs[CSD_SURF_COUNT];
|
||||
shm_get_many(term->render.chains.csd, CSD_SURF_COUNT, widths, heights, bufs, true);
|
||||
shm_get_many(term->render.chains.csd, CSD_SURF_COUNT, widths, heights, bufs);
|
||||
|
||||
for (size_t i = CSD_SURF_LEFT; i <= CSD_SURF_BOTTOM; i++)
|
||||
render_csd_border(term, i, &infos[i], bufs[i]);
|
||||
|
|
@ -2894,13 +2988,8 @@ render_scrollback_position(struct terminal *term)
|
|||
struct wl_window *win = term->window;
|
||||
|
||||
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);
|
||||
|
||||
/* Work around Sway bug - unmapping a sub-surface does not damage
|
||||
* the underlying surface */
|
||||
quirk_sway_subsurface_unmap(term);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3021,16 +3110,16 @@ render_scrollback_position(struct terminal *term)
|
|||
}
|
||||
|
||||
struct buffer_chain *chain = term->render.chains.scrollback_indicator;
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height, false);
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height);
|
||||
|
||||
wl_subsurface_set_position(
|
||||
win->scrollback_indicator.sub, roundf(x / scale), roundf(y / scale));
|
||||
|
||||
uint32_t fg = term->colors.table[0];
|
||||
uint32_t bg = term->colors.table[8 + 4];
|
||||
if (term->conf->colors.use_custom.scrollback_indicator) {
|
||||
fg = term->conf->colors.scrollback_indicator.fg;
|
||||
bg = term->conf->colors.scrollback_indicator.bg;
|
||||
if (term->conf->colors_dark.use_custom.scrollback_indicator) {
|
||||
fg = term->conf->colors_dark.scrollback_indicator.fg;
|
||||
bg = term->conf->colors_dark.scrollback_indicator.bg;
|
||||
}
|
||||
|
||||
render_osd(
|
||||
|
|
@ -3064,7 +3153,7 @@ render_render_timer(struct terminal *term, struct timespec render_time)
|
|||
height = roundf(scale * ceilf(height / scale));
|
||||
|
||||
struct buffer_chain *chain = term->render.chains.render_timer;
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height, false);
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height);
|
||||
|
||||
wl_subsurface_set_position(
|
||||
win->render_timer.sub,
|
||||
|
|
@ -3097,14 +3186,6 @@ force_full_repaint(struct terminal *term, struct buffer *buf)
|
|||
static void
|
||||
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) {
|
||||
memcpy(new->data, old->data, new->height * new->stride);
|
||||
return;
|
||||
|
|
@ -3235,7 +3316,18 @@ grid_render(struct terminal *term)
|
|||
if (term->shutdown.in_progress)
|
||||
return;
|
||||
|
||||
struct timespec start_time, start_double_buffering = {0}, stop_double_buffering = {0};
|
||||
struct timespec start_time;
|
||||
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)
|
||||
clock_gettime(CLOCK_MONOTONIC, &start_time);
|
||||
|
|
@ -3244,15 +3336,14 @@ grid_render(struct terminal *term)
|
|||
xassert(term->height > 0);
|
||||
|
||||
struct buffer_chain *chain = term->render.chains.grid;
|
||||
bool use_alpha = !term->window->is_fullscreen &&
|
||||
term->colors.alpha != 0xffff;
|
||||
struct buffer *buf = shm_get_buffer(
|
||||
chain, term->width, term->height, use_alpha);
|
||||
struct buffer *buf = shm_get_buffer(chain, term->width, term->height);
|
||||
|
||||
/* Dirty old and current cursor cell, to ensure they're repainted */
|
||||
dirty_old_cursor(term);
|
||||
dirty_cursor(term);
|
||||
|
||||
LOG_DBG("buffer age: %u (%p)", buf->age, (void *)buf);
|
||||
|
||||
if (term->render.last_buf == NULL ||
|
||||
term->render.last_buf->width != buf->width ||
|
||||
term->render.last_buf->height != buf->height ||
|
||||
|
|
@ -3269,9 +3360,27 @@ grid_render(struct terminal *term)
|
|||
xassert(term->render.last_buf->width == buf->width);
|
||||
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);
|
||||
reapply_old_damage(term, buf, term->render.last_buf);
|
||||
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) {
|
||||
|
|
@ -3499,27 +3608,40 @@ grid_render(struct terminal *term)
|
|||
struct timespec 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;
|
||||
timespec_sub(&end_time, &start_time, &render_time);
|
||||
|
||||
struct timespec 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;
|
||||
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) {
|
||||
case RENDER_TIMER_LOG:
|
||||
case RENDER_TIMER_BOTH:
|
||||
LOG_INFO(
|
||||
"frame rendered in %lds %9ldns "
|
||||
"(%lds %9ldns rendering, %lds %9ldns double buffering)",
|
||||
"(%lds %9ldns wait, %lds %9ldns rendering, %lds %9ldns double buffering) not included: %lds %ldns pre-apply damage",
|
||||
(long)total_render_time.tv_sec,
|
||||
total_render_time.tv_nsec,
|
||||
(long)wait_time.tv_sec,
|
||||
wait_time.tv_nsec,
|
||||
(long)render_time.tv_sec,
|
||||
render_time.tv_nsec,
|
||||
(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;
|
||||
|
||||
case RENDER_TIMER_OSD:
|
||||
|
|
@ -3662,7 +3784,7 @@ render_search_box(struct terminal *term)
|
|||
size_t glyph_offset = term->render.search_glyph_offset;
|
||||
|
||||
struct buffer_chain *chain = term->render.chains.search;
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height, true);
|
||||
struct buffer *buf = shm_get_buffer(chain, width, height);
|
||||
|
||||
pixman_region32_t clip;
|
||||
pixman_region32_init_rect(&clip, 0, 0, width, height);
|
||||
|
|
@ -3674,18 +3796,18 @@ render_search_box(struct terminal *term)
|
|||
|
||||
const bool is_match = term->search.match_len == text_len;
|
||||
const bool custom_colors = is_match
|
||||
? term->conf->colors.use_custom.search_box_match
|
||||
: term->conf->colors.use_custom.search_box_no_match;
|
||||
? term->conf->colors_dark.use_custom.search_box_match
|
||||
: term->conf->colors_dark.use_custom.search_box_no_match;
|
||||
|
||||
/* Background - yellow on empty/match, red on mismatch (default) */
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
const pixman_color_t color = color_hex_to_pixman(
|
||||
is_match
|
||||
? (custom_colors
|
||||
? term->conf->colors.search_box.match.bg
|
||||
? term->conf->colors_dark.search_box.match.bg
|
||||
: term->colors.table[3])
|
||||
: (custom_colors
|
||||
? term->conf->colors.search_box.no_match.bg
|
||||
? term->conf->colors_dark.search_box.no_match.bg
|
||||
: term->colors.table[1]),
|
||||
gamma_correct);
|
||||
|
||||
|
|
@ -3707,8 +3829,8 @@ render_search_box(struct terminal *term)
|
|||
pixman_color_t fg = color_hex_to_pixman(
|
||||
custom_colors
|
||||
? (is_match
|
||||
? term->conf->colors.search_box.match.fg
|
||||
: term->conf->colors.search_box.no_match.fg)
|
||||
? term->conf->colors_dark.search_box.match.fg
|
||||
: term->conf->colors_dark.search_box.no_match.fg)
|
||||
: term->colors.table[0],
|
||||
gamma_correct);
|
||||
|
||||
|
|
@ -4127,13 +4249,13 @@ render_urls(struct terminal *term)
|
|||
|
||||
struct buffer_chain *chain = term->render.chains.url;
|
||||
struct buffer *bufs[render_count];
|
||||
shm_get_many(chain, render_count, widths, heights, bufs, false);
|
||||
shm_get_many(chain, render_count, widths, heights, bufs);
|
||||
|
||||
uint32_t fg = term->conf->colors.use_custom.jump_label
|
||||
? term->conf->colors.jump_label.fg
|
||||
uint32_t fg = term->conf->colors_dark.use_custom.jump_label
|
||||
? term->conf->colors_dark.jump_label.fg
|
||||
: term->colors.table[0];
|
||||
uint32_t bg = term->conf->colors.use_custom.jump_label
|
||||
? term->conf->colors.jump_label.bg
|
||||
uint32_t bg = term->conf->colors_dark.use_custom.jump_label
|
||||
? term->conf->colors_dark.jump_label.bg
|
||||
: term->colors.table[3];
|
||||
|
||||
for (size_t i = 0; i < render_count; i++) {
|
||||
|
|
@ -4279,6 +4401,7 @@ delayed_reflow_of_normal_grid(struct terminal *term)
|
|||
term->interactive_resizing.old_hide_cursor = false;
|
||||
|
||||
/* Invalidate render pointers */
|
||||
render_wait_for_preapply_damage(term);
|
||||
shm_unref(term->render.last_buf);
|
||||
term->render.last_buf = NULL;
|
||||
term->render.last_cursor.row = NULL;
|
||||
|
|
@ -4571,9 +4694,12 @@ render_resize(struct terminal *term, int width, int height, uint8_t opts)
|
|||
const int total_x_pad = term->width - grid_width;
|
||||
const int total_y_pad = term->height - grid_height;
|
||||
|
||||
const bool centered_padding = term->conf->center
|
||||
|| term->window->is_fullscreen
|
||||
|| term->window->is_maximized;
|
||||
const enum center_when center = term->conf->center_when;
|
||||
const bool centered_padding =
|
||||
center == CENTER_ALWAYS ||
|
||||
(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) {
|
||||
term->margins.left = total_x_pad / 2;
|
||||
|
|
@ -4850,6 +4976,7 @@ damage_view:
|
|||
tll_free(term->normal.scroll_damage);
|
||||
tll_free(term->alt.scroll_damage);
|
||||
|
||||
render_wait_for_preapply_damage(term);
|
||||
shm_unref(term->render.last_buf);
|
||||
term->render.last_buf = NULL;
|
||||
term_damage_view(term);
|
||||
|
|
@ -4904,8 +5031,9 @@ render_xcursor_update(struct seat *seat)
|
|||
|
||||
const enum wp_cursor_shape_device_v1_shape custom_shape =
|
||||
(shape == CURSOR_SHAPE_CUSTOM && xcursor != NULL
|
||||
? cursor_string_to_server_shape(xcursor)
|
||||
: 0);
|
||||
? cursor_string_to_server_shape(
|
||||
xcursor, seat->wayl->shape_manager_version)
|
||||
: 0);
|
||||
|
||||
if (shape != CURSOR_SHAPE_CUSTOM || custom_shape != 0) {
|
||||
xassert(custom_shape == 0 || shape == CURSOR_SHAPE_CUSTOM);
|
||||
|
|
@ -5248,9 +5376,76 @@ render_xcursor_set(struct seat *seat, struct terminal *term,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
render_do_linear_blending(const struct terminal *term)
|
||||
void
|
||||
render_buffer_release_callback(struct buffer *buf, void *data)
|
||||
{
|
||||
return term->conf->gamma_correct != GAMMA_CORRECT_DISABLED &&
|
||||
term->wl->color_management.img_description != NULL;
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
|
|
|||
3
render.h
3
render.h
|
|
@ -48,4 +48,5 @@ struct csd_data {
|
|||
|
||||
struct csd_data get_csd_data(const struct terminal *term, enum csd_surface surf_idx);
|
||||
|
||||
bool render_do_linear_blending(const struct terminal *term);
|
||||
void render_buffer_release_callback(struct buffer *buf, void *data);
|
||||
void render_wait_for_preapply_damage(struct terminal *term);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import termios
|
|||
from datetime import datetime
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('files', type=argparse.FileType('rb'), nargs='+')
|
||||
parser.add_argument('--iterations', type=int, default=20)
|
||||
|
|
@ -24,12 +24,12 @@ def main():
|
|||
termios.TIOCGWINSZ,
|
||||
struct.pack('HHHH', 0, 0, 0, 0)))
|
||||
|
||||
times = {name: [] for name in [f.name for f in args.files]}
|
||||
times: dict[str, list[float]] = {name: [] for name in [f.name for f in args.files]}
|
||||
|
||||
for f in args.files:
|
||||
bench_bytes = f.read()
|
||||
|
||||
for i in range(args.iterations):
|
||||
for _ in range(args.iterations):
|
||||
start = datetime.now()
|
||||
sys.stdout.buffer.write(bench_bytes)
|
||||
stop = datetime.now()
|
||||
|
|
@ -48,4 +48,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import struct
|
|||
import sys
|
||||
import termios
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ColorVariant(enum.IntEnum):
|
||||
NONE = enum.auto()
|
||||
|
|
@ -17,7 +19,7 @@ class ColorVariant(enum.IntEnum):
|
|||
RGB = enum.auto()
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'out', type=argparse.FileType(mode='w'), nargs='?', help='name of output file')
|
||||
|
|
@ -38,10 +40,16 @@ def main():
|
|||
opts = parser.parse_args()
|
||||
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:
|
||||
try:
|
||||
def dummy(*args):
|
||||
def dummy(*args: Any) -> None:
|
||||
"""Need a handler installed for sigwait() to trigger."""
|
||||
_ = args
|
||||
pass
|
||||
signal.signal(signal.SIGWINCH, dummy)
|
||||
|
||||
|
|
@ -53,6 +61,9 @@ def main():
|
|||
termios.TIOCGWINSZ,
|
||||
struct.pack('HHHH', 0, 0, 0, 0)))
|
||||
|
||||
assert width is not None
|
||||
assert height is not None
|
||||
|
||||
if width > 0 and height > 0:
|
||||
break
|
||||
|
||||
|
|
@ -71,9 +82,11 @@ def main():
|
|||
|
||||
if opts.rows is not None:
|
||||
lines = opts.rows
|
||||
assert lines is not None
|
||||
height = 15 * lines # PGO helper binary hardcodes cell height to 15px
|
||||
if opts.cols is not None:
|
||||
cols = opts.cols
|
||||
assert cols is not None
|
||||
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:
|
||||
|
|
@ -190,8 +203,8 @@ def main():
|
|||
# The sixel 'alphabet'
|
||||
sixels = '?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
|
||||
|
||||
last_pos = None
|
||||
last_size = None
|
||||
last_pos: tuple[int, int] | None = None
|
||||
last_size: tuple[int, int] = 0, 0
|
||||
|
||||
for _ in range(20):
|
||||
if last_pos is not None and random.randrange(2):
|
||||
|
|
@ -254,4 +267,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from typing import Dict, Union
|
||||
|
||||
|
||||
class Capability:
|
||||
def __init__(self, name: str, value: Union[bool, int, str]):
|
||||
def __init__(self, name: str, value: bool | int | str):
|
||||
self._name = name
|
||||
self._value = value
|
||||
|
||||
|
|
@ -17,25 +15,37 @@ class Capability:
|
|||
return self._name
|
||||
|
||||
@property
|
||||
def value(self) -> Union[bool, int, str]:
|
||||
def value(self) -> bool | int | str:
|
||||
return self._value
|
||||
|
||||
def __lt__(self, other):
|
||||
def __lt__(self, other: object) -> bool:
|
||||
if not isinstance(other, Capability):
|
||||
return NotImplemented
|
||||
return self._name < other._name
|
||||
|
||||
def __le__(self, other):
|
||||
def __le__(self, other: object) -> bool:
|
||||
if not isinstance(other, Capability):
|
||||
return NotImplemented
|
||||
return self._name <= other._name
|
||||
|
||||
def __eq__(self, other):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, Capability):
|
||||
return NotImplemented
|
||||
return self._name == other._name
|
||||
|
||||
def __ne__(self, other):
|
||||
return self._name != other._name
|
||||
def __ne__(self, other: object) -> bool:
|
||||
if not isinstance(other, Capability):
|
||||
return NotImplemented
|
||||
return bool(self._name != other._name)
|
||||
|
||||
def __gt__(self, other):
|
||||
return self._name > other._name
|
||||
def __gt__(self, other: object) -> bool:
|
||||
if not isinstance(other, Capability):
|
||||
return NotImplemented
|
||||
return bool(self._name > other._name)
|
||||
|
||||
def __ge__(self, other):
|
||||
def __ge__(self, other: object) -> bool:
|
||||
if not isinstance(other, Capability):
|
||||
return NotImplemented
|
||||
return self._name >= other._name
|
||||
|
||||
|
||||
|
|
@ -53,7 +63,7 @@ class StringCapability(Capability):
|
|||
# see terminfo(5) for valid escape sequences
|
||||
|
||||
# Control characters
|
||||
def translate_ctrl_chr(m):
|
||||
def translate_ctrl_chr(m: re.Match[str]) -> str:
|
||||
ctrl = m.group(1)
|
||||
if ctrl == '?':
|
||||
return '\\x7f'
|
||||
|
|
@ -85,7 +95,7 @@ class Fragment:
|
|||
def __init__(self, name: str, description: str):
|
||||
self._name = name
|
||||
self._description = description
|
||||
self._caps = {}
|
||||
self._caps = dict[str, Capability]()
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
|
|
@ -96,18 +106,18 @@ class Fragment:
|
|||
return self._description
|
||||
|
||||
@property
|
||||
def caps(self) -> Dict[str, Capability]:
|
||||
def caps(self) -> dict[str, Capability]:
|
||||
return self._caps
|
||||
|
||||
def add_capability(self, cap: Capability):
|
||||
def add_capability(self, cap: Capability) -> None:
|
||||
assert cap.name not in self._caps
|
||||
self._caps[cap.name] = cap
|
||||
|
||||
def del_capability(self, name: str):
|
||||
def del_capability(self, name: str) -> None:
|
||||
del self._caps[name]
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('source_entry_name')
|
||||
parser.add_argument('source', type=argparse.FileType('r'))
|
||||
|
|
@ -120,15 +130,15 @@ def main():
|
|||
source = opts.source
|
||||
target = opts.target
|
||||
|
||||
lines = []
|
||||
for l in source.readlines():
|
||||
l = l.strip()
|
||||
if l.startswith('#'):
|
||||
lines = list[str]()
|
||||
for line in source.readlines():
|
||||
line = line.strip()
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
lines.append(l)
|
||||
lines.append(line)
|
||||
|
||||
fragments = {}
|
||||
cur_fragment = None
|
||||
fragments = dict[str, Fragment]()
|
||||
cur_fragment: Fragment | None = None
|
||||
|
||||
for m in re.finditer(
|
||||
r'(?P<name>(?P<entry_name>[-+\w@]+)\|(?P<entry_desc>.+?),)|'
|
||||
|
|
@ -147,17 +157,20 @@ def main():
|
|||
|
||||
elif m.group('bool_cap') is not None:
|
||||
name = m.group('bool_name')
|
||||
assert cur_fragment is not None
|
||||
cur_fragment.add_capability(BoolCapability(name))
|
||||
|
||||
elif m.group('int_cap') is not None:
|
||||
name = m.group('int_name')
|
||||
value = int(m.group('int_val'), 0)
|
||||
cur_fragment.add_capability(IntCapability(name, value))
|
||||
int_value = int(m.group('int_val'), 0)
|
||||
assert cur_fragment is not None
|
||||
cur_fragment.add_capability(IntCapability(name, int_value))
|
||||
|
||||
elif m.group('str_cap') is not None:
|
||||
name = m.group('str_name')
|
||||
value = m.group('str_val')
|
||||
cur_fragment.add_capability(StringCapability(name, value))
|
||||
str_value = m.group('str_val')
|
||||
assert cur_fragment is not None
|
||||
cur_fragment.add_capability(StringCapability(name, str_value))
|
||||
|
||||
else:
|
||||
assert False
|
||||
|
|
@ -166,6 +179,9 @@ def main():
|
|||
for frag in fragments.values():
|
||||
for cap in frag.caps.values():
|
||||
if cap.name == 'use':
|
||||
assert isinstance(cap, StringCapability)
|
||||
assert isinstance(cap.value, str)
|
||||
|
||||
use_frag = fragments[cap.value]
|
||||
for use_cap in use_frag.caps.values():
|
||||
frag.add_capability(use_cap)
|
||||
|
|
@ -185,8 +201,9 @@ def main():
|
|||
entry.add_capability(StringCapability('TN', target_entry_name))
|
||||
entry.add_capability(StringCapability('name', target_entry_name))
|
||||
entry.add_capability(IntCapability('RGB', 8)) # 8 bits per channel
|
||||
entry.add_capability(StringCapability('query-os-name', os.uname().sysname))
|
||||
|
||||
terminfo_parts = []
|
||||
terminfo_parts = list[str]()
|
||||
for cap in sorted(entry.caps.values()):
|
||||
name = cap.name
|
||||
value = str(cap.value)
|
||||
|
|
@ -210,4 +227,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
class Codepoint:
|
||||
def __init__(self, start: int, end: None|int = None):
|
||||
def __init__(self, start: int, end: None | int = None):
|
||||
self.start = start
|
||||
self.end = start if end is None else end
|
||||
self.vs15 = False
|
||||
|
|
@ -15,7 +14,7 @@ class Codepoint:
|
|||
return f'{self.start:x}-{self.end:x}, vs15={self.vs15}, vs16={self.vs16}'
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('input', type=argparse.FileType('r'))
|
||||
parser.add_argument('output', type=argparse.FileType('w'))
|
||||
|
|
@ -100,4 +99,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -2,51 +2,31 @@
|
|||
|
||||
import argparse
|
||||
import math
|
||||
import sys
|
||||
|
||||
|
||||
# Note: we use a pure gamma 2.2 function, rather than the piece-wise
|
||||
# sRGB transfer function, since that is what all compositors do.
|
||||
|
||||
def srgb_to_linear(f: float) -> float:
|
||||
assert(f >= 0 and f <= 1.0)
|
||||
|
||||
if f <= 0.04045:
|
||||
return f / 12.92
|
||||
|
||||
return math.pow((f + 0.055) / 1.055, 2.4)
|
||||
return math.pow(f, 2.2)
|
||||
|
||||
|
||||
def linear_to_srgb(f: float) -> float:
|
||||
if f < 0.0031308:
|
||||
return f * 12.92
|
||||
|
||||
return 1.055 * math.pow(f, 1 / 2.4) - 0.055
|
||||
return math.pow(f, 1 / 2.2)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('c_output', type=argparse.FileType('w'))
|
||||
parser.add_argument('h_output', type=argparse.FileType('w'))
|
||||
opts = parser.parse_args()
|
||||
|
||||
linear_table: list[int] = []
|
||||
srgb_table: list[int] = []
|
||||
|
||||
for i in range(256):
|
||||
linear_table.append(int(srgb_to_linear(float(i) / 255) * 65535 + 0.5))
|
||||
|
||||
for i in range(4096):
|
||||
srgb_table.append(int(linear_to_srgb(float(i) / 4095) * 255 + 0.5))
|
||||
|
||||
for i in range(256):
|
||||
while True:
|
||||
linear = linear_table[i]
|
||||
srgb = srgb_table[linear >> 4]
|
||||
|
||||
if i == srgb:
|
||||
break
|
||||
|
||||
linear_table[i] += 1
|
||||
|
||||
|
||||
opts.h_output.write("#pragma once\n")
|
||||
opts.h_output.write("#include <stdint.h>\n")
|
||||
|
|
@ -87,4 +67,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
main()
|
||||
|
|
|
|||
12
search.c
12
search.c
|
|
@ -283,8 +283,13 @@ matches_cell(const struct terminal *term, const struct cell *cell, size_t search
|
|||
if (composed == NULL && base == 0 && term->search.buf[search_ofs] == U' ')
|
||||
return 1;
|
||||
|
||||
if (c32ncasecmp(&base, &term->search.buf[search_ofs], 1) != 0)
|
||||
return -1;
|
||||
if (hasc32upper(term->search.buf)) {
|
||||
if (c32ncmp(&base, &term->search.buf[search_ofs], 1) != 0)
|
||||
return -1;
|
||||
} else {
|
||||
if (c32ncasecmp(&base, &term->search.buf[search_ofs], 1) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (composed != NULL) {
|
||||
if (search_ofs + composed->count > term->search.len)
|
||||
|
|
@ -1479,7 +1484,8 @@ search_input(struct seat *seat, struct terminal *term,
|
|||
count = xkb_compose_state_get_utf8(
|
||||
seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
|
||||
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;
|
||||
} else {
|
||||
count = xkb_state_key_get_utf8(
|
||||
|
|
|
|||
13
selection.c
13
selection.c
|
|
@ -19,6 +19,7 @@
|
|||
#include "char32.h"
|
||||
#include "commands.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "extract.h"
|
||||
#include "grid.h"
|
||||
#include "misc.h"
|
||||
|
|
@ -558,9 +559,15 @@ selection_find_quote_left(struct terminal *term, struct coord *pos,
|
|||
if (*quote_char == '\0' ? (wc == '"' || wc == '\'')
|
||||
: wc == *quote_char)
|
||||
{
|
||||
pos->row = next_row;
|
||||
pos->col = next_col + 1;
|
||||
xassert(pos->col < term->cols);
|
||||
xassert(next_col + 1 <= term->cols);
|
||||
if (next_col + 1 == term->cols) {
|
||||
xassert(next_row < pos->row);
|
||||
pos->row = next_row + 1;
|
||||
pos->col = 0;
|
||||
} else {
|
||||
pos->row = next_row;
|
||||
pos->col = next_col + 1;
|
||||
}
|
||||
|
||||
*quote_char = wc;
|
||||
return true;
|
||||
|
|
|
|||
83
server.c
83
server.c
|
|
@ -30,7 +30,7 @@ struct client;
|
|||
struct terminal_instance;
|
||||
|
||||
struct server {
|
||||
const struct config *conf;
|
||||
struct config *conf;
|
||||
struct fdm *fdm;
|
||||
struct reaper *reaper;
|
||||
struct wayland *wayl;
|
||||
|
|
@ -156,10 +156,61 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
xassert(events & EPOLLIN);
|
||||
|
||||
if (client->instance != NULL) {
|
||||
uint8_t dummy[128];
|
||||
ssize_t count = read(fd, dummy, sizeof(dummy));
|
||||
LOG_WARN("client unexpectedly sent %zd bytes", count);
|
||||
return true; /* TODO: shutdown instead? */
|
||||
struct client_ipc_hdr ipc_hdr;
|
||||
ssize_t count = read(fd, &ipc_hdr, sizeof(ipc_hdr));
|
||||
|
||||
if (count != sizeof(ipc_hdr)) {
|
||||
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) {
|
||||
|
|
@ -505,7 +556,7 @@ prepare_socket(int fd)
|
|||
}
|
||||
|
||||
struct server *
|
||||
server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||
server_init(struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||
struct wayland *wayl)
|
||||
{
|
||||
int fd;
|
||||
|
|
@ -617,3 +668,23 @@ server_destroy(struct server *server)
|
|||
unlink(server->sock_path);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
5
server.h
5
server.h
|
|
@ -6,6 +6,9 @@
|
|||
#include "wayland.h"
|
||||
|
||||
struct server;
|
||||
struct server *server_init(const struct config *conf, struct fdm *fdm,
|
||||
struct server *server_init(struct config *conf, struct fdm *fdm,
|
||||
struct reaper *reaper, struct wayland *wayl);
|
||||
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);
|
||||
|
|
|
|||
157
shm.c
157
shm.c
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include <pixman.h>
|
||||
|
||||
#include <fcft/stride.h>
|
||||
#include <tllist.h>
|
||||
|
||||
#define LOG_MODULE "shm"
|
||||
|
|
@ -21,6 +20,7 @@
|
|||
#include "log.h"
|
||||
#include "debug.h"
|
||||
#include "macros.h"
|
||||
#include "stride.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#if !defined(MAP_UNINITIALIZED)
|
||||
|
|
@ -61,6 +61,8 @@ static off_t max_pool_size = 512 * 1024 * 1024;
|
|||
static bool can_punch_hole = false;
|
||||
static bool can_punch_hole_initialized = false;
|
||||
|
||||
static size_t min_stride_alignment = 0;
|
||||
|
||||
struct buffer_pool {
|
||||
int fd; /* memfd */
|
||||
struct wl_shm_pool *wl_pool;
|
||||
|
|
@ -82,9 +84,11 @@ struct buffer_private {
|
|||
struct buffer_pool *pool;
|
||||
off_t offset; /* Offset into memfd where data begins */
|
||||
size_t size;
|
||||
bool with_alpha;
|
||||
|
||||
bool scrollable;
|
||||
|
||||
void (*release_cb)(struct buffer *buf, void *data);
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
struct buffer_chain {
|
||||
|
|
@ -93,11 +97,11 @@ struct buffer_chain {
|
|||
size_t pix_instances;
|
||||
bool scrollable;
|
||||
|
||||
pixman_format_code_t pixman_fmt_without_alpha;
|
||||
enum wl_shm_format shm_format_without_alpha;
|
||||
pixman_format_code_t pixman_fmt;
|
||||
enum wl_shm_format shm_format;
|
||||
|
||||
pixman_format_code_t pixman_fmt_with_alpha;
|
||||
enum wl_shm_format shm_format_with_alpha;
|
||||
void (*release_cb)(struct buffer *buf, void *data);
|
||||
void *cb_data;
|
||||
};
|
||||
|
||||
static tll(struct buffer_private *) deferred;
|
||||
|
|
@ -113,6 +117,12 @@ shm_set_max_pool_size(off_t _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
|
||||
buffer_destroy_dont_close(struct buffer *buf)
|
||||
{
|
||||
|
|
@ -224,6 +234,10 @@ buffer_release(void *data, struct wl_buffer *wl_buffer)
|
|||
xassert(found);
|
||||
if (!found)
|
||||
LOG_WARN("deferred delete: buffer not on the 'deferred' list");
|
||||
} else {
|
||||
if (buffer->release_cb != NULL) {
|
||||
buffer->release_cb(&buffer->public, buffer->cb_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -231,7 +245,6 @@ static const struct wl_buffer_listener buffer_listener = {
|
|||
.release = &buffer_release,
|
||||
};
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
static size_t
|
||||
page_size(void)
|
||||
{
|
||||
|
|
@ -248,7 +261,6 @@ page_size(void)
|
|||
xassert(size > 0);
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
instantiate_offset(struct buffer_private *buf, off_t new_offset)
|
||||
|
|
@ -269,9 +281,7 @@ instantiate_offset(struct buffer_private *buf, off_t new_offset)
|
|||
wl_buf = wl_shm_pool_create_buffer(
|
||||
pool->wl_pool, new_offset,
|
||||
buf->public.width, buf->public.height, buf->public.stride,
|
||||
buf->with_alpha
|
||||
? buf->chain->shm_format_with_alpha
|
||||
: buf->chain->shm_format_without_alpha);
|
||||
buf->chain->shm_format);
|
||||
|
||||
if (wl_buf == NULL) {
|
||||
LOG_ERR("failed to create SHM buffer");
|
||||
|
|
@ -281,9 +291,7 @@ instantiate_offset(struct buffer_private *buf, off_t new_offset)
|
|||
/* One pixman image for each worker thread (do we really need multiple?) */
|
||||
for (size_t i = 0; i < buf->public.pix_instances; i++) {
|
||||
pix[i] = pixman_image_create_bits_no_clear(
|
||||
buf->with_alpha
|
||||
? buf->chain->pixman_fmt_with_alpha
|
||||
: buf->chain->pixman_fmt_without_alpha,
|
||||
buf->chain->pixman_fmt,
|
||||
buf->public.width, buf->public.height,
|
||||
(uint32_t *)mmapped, buf->public.stride);
|
||||
|
||||
|
|
@ -318,8 +326,7 @@ err:
|
|||
static void NOINLINE
|
||||
get_new_buffers(struct buffer_chain *chain, size_t count,
|
||||
int widths[static count], int heights[static count],
|
||||
struct buffer *bufs[static count], bool with_alpha,
|
||||
bool immediate_purge)
|
||||
struct buffer *bufs[static count], bool immediate_purge)
|
||||
{
|
||||
xassert(count == 1 || !chain->scrollable);
|
||||
/*
|
||||
|
|
@ -338,7 +345,14 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
|
|||
size_t total_size = 0;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
stride[i] = stride_for_format_and_width(
|
||||
with_alpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8, widths[i]);
|
||||
chain->pixman_fmt, 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];
|
||||
total_size += sizes[i];
|
||||
}
|
||||
|
|
@ -380,9 +394,11 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
|
|||
goto err;
|
||||
}
|
||||
|
||||
const size_t page_sz = page_size();
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
off_t offset = chain->scrollable && max_pool_size > 0
|
||||
? (max_pool_size / 4) & ~(page_size() - 1)
|
||||
? (max_pool_size / 4) & ~(page_sz - 1)
|
||||
: 0;
|
||||
off_t memfd_size = chain->scrollable && max_pool_size > 0
|
||||
? max_pool_size
|
||||
|
|
@ -392,7 +408,8 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
|
|||
off_t memfd_size = total_size;
|
||||
#endif
|
||||
|
||||
xassert(chain->scrollable || (offset == 0 && memfd_size == total_size));
|
||||
/* Page align */
|
||||
memfd_size = (memfd_size + page_sz - 1) & ~(page_sz - 1);
|
||||
|
||||
LOG_DBG("memfd-size: %lu, initial offset: %lu", memfd_size, offset);
|
||||
|
||||
|
|
@ -424,6 +441,9 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
|
|||
memfd_size = total_size;
|
||||
chain->scrollable = false;
|
||||
|
||||
/* Page align */
|
||||
memfd_size = (memfd_size + page_sz - 1) & ~(page_sz - 1);
|
||||
|
||||
if (ftruncate(pool_fd, memfd_size) < 0) {
|
||||
LOG_ERRNO("failed to set size of SHM backing memory file");
|
||||
goto err;
|
||||
|
|
@ -489,11 +509,12 @@ get_new_buffers(struct buffer_chain *chain, size_t count,
|
|||
.chain = chain,
|
||||
.ref_count = immediate_purge ? 0 : 1,
|
||||
.busy = true,
|
||||
.with_alpha = with_alpha,
|
||||
.pool = pool,
|
||||
.offset = 0,
|
||||
.size = sizes[i],
|
||||
.scrollable = chain->scrollable,
|
||||
.release_cb = chain->release_cb,
|
||||
.cb_data = chain->cb_data,
|
||||
};
|
||||
|
||||
if (!instantiate_offset(buf, offset)) {
|
||||
|
|
@ -559,13 +580,13 @@ shm_did_not_use_buf(struct buffer *_buf)
|
|||
void
|
||||
shm_get_many(struct buffer_chain *chain, size_t count,
|
||||
int widths[static count], int heights[static count],
|
||||
struct buffer *bufs[static count], bool with_alpha)
|
||||
struct buffer *bufs[static count])
|
||||
{
|
||||
get_new_buffers(chain, count, widths, heights, bufs, with_alpha, true);
|
||||
get_new_buffers(chain, count, widths, heights, bufs, true);
|
||||
}
|
||||
|
||||
struct buffer *
|
||||
shm_get_buffer(struct buffer_chain *chain, int width, int height, bool with_alpha)
|
||||
shm_get_buffer(struct buffer_chain *chain, int width, int height)
|
||||
{
|
||||
LOG_DBG(
|
||||
"chain=%p: looking for a reusable %dx%d buffer "
|
||||
|
|
@ -576,9 +597,7 @@ shm_get_buffer(struct buffer_chain *chain, int width, int height, bool with_alph
|
|||
tll_foreach(chain->bufs, it) {
|
||||
struct buffer_private *buf = it->item;
|
||||
|
||||
if (buf->public.width != width || buf->public.height != height ||
|
||||
with_alpha != buf->with_alpha)
|
||||
{
|
||||
if (buf->public.width != width || buf->public.height != height) {
|
||||
LOG_DBG("purging mismatching buffer %p", (void *)buf);
|
||||
if (buffer_unref_no_remove_from_chain(buf))
|
||||
tll_remove(chain->bufs, it);
|
||||
|
|
@ -594,9 +613,9 @@ shm_get_buffer(struct buffer_chain *chain, int width, int height, bool with_alph
|
|||
else
|
||||
#endif
|
||||
{
|
||||
if (cached == NULL)
|
||||
if (cached == NULL) {
|
||||
cached = buf;
|
||||
else {
|
||||
} else {
|
||||
/* We have multiple buffers eligible for
|
||||
* reuse. Pick the "youngest" one, and mark the
|
||||
* other one for purging */
|
||||
|
|
@ -629,7 +648,7 @@ shm_get_buffer(struct buffer_chain *chain, int width, int height, bool with_alph
|
|||
}
|
||||
|
||||
struct buffer *ret;
|
||||
get_new_buffers(chain, 1, &width, &height, &ret, with_alpha, false);
|
||||
get_new_buffers(chain, 1, &width, &height, &ret, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -972,24 +991,43 @@ shm_unref(struct buffer *_buf)
|
|||
|
||||
struct buffer_chain *
|
||||
shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
|
||||
bool ten_bit_if_capable)
|
||||
enum shm_bit_depth desired_bit_depth,
|
||||
void (*release_cb)(struct buffer *buf, void *data), void *cb_data)
|
||||
{
|
||||
pixman_format_code_t pixman_fmt_without_alpha = PIXMAN_x8r8g8b8;
|
||||
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;
|
||||
pixman_format_code_t pixman_fmt = PIXMAN_a8r8g8b8;
|
||||
enum wl_shm_format shm_fmt = WL_SHM_FORMAT_ARGB8888;
|
||||
|
||||
static bool have_logged = false;
|
||||
static bool have_logged_10_fallback = false;
|
||||
|
||||
#if defined(HAVE_PIXMAN_RGBA_16)
|
||||
static bool have_logged_16_fallback = false;
|
||||
|
||||
if (ten_bit_if_capable) {
|
||||
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) {
|
||||
if (wayl->shm_have_abgr161616) {
|
||||
pixman_fmt = PIXMAN_a16b16g16r16;
|
||||
shm_fmt = WL_SHM_FORMAT_ABGR16161616;
|
||||
|
||||
pixman_fmt_with_alpha = PIXMAN_a2r10g10b10;
|
||||
shm_fmt_with_alpha = WL_SHM_FORMAT_ARGB2101010;
|
||||
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) {
|
||||
have_logged = true;
|
||||
|
|
@ -997,12 +1035,9 @@ shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
|
|||
}
|
||||
}
|
||||
|
||||
else if (wayl->shm_have_abgr2101010 && wayl->shm_have_xbgr2101010) {
|
||||
pixman_fmt_without_alpha = PIXMAN_x2b10g10r10;
|
||||
shm_fmt_without_alpha = WL_SHM_FORMAT_XBGR2101010;
|
||||
|
||||
pixman_fmt_with_alpha = PIXMAN_a2b10g10r10;
|
||||
shm_fmt_with_alpha = WL_SHM_FORMAT_ABGR2101010;
|
||||
else if (wayl->shm_have_abgr2101010) {
|
||||
pixman_fmt = PIXMAN_a2b10g10r10;
|
||||
shm_fmt = WL_SHM_FORMAT_ABGR2101010;
|
||||
|
||||
if (!have_logged) {
|
||||
have_logged = true;
|
||||
|
|
@ -1011,13 +1046,13 @@ shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
|
|||
}
|
||||
|
||||
else {
|
||||
if (!have_logged) {
|
||||
have_logged = true;
|
||||
if (!have_logged_10_fallback) {
|
||||
have_logged_10_fallback = true;
|
||||
|
||||
LOG_WARN(
|
||||
"10-bit surfaces requested, but compositor does not "
|
||||
"implement ARGB2101010+XRGB2101010, or "
|
||||
"ABGR2101010+XBGR2101010. Falling back to 8-bit surfaces");
|
||||
"ABGR2101010+XBGR2101010");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1034,11 +1069,11 @@ shm_chain_new(struct wayland *wayl, bool scrollable, size_t pix_instances,
|
|||
.pix_instances = pix_instances,
|
||||
.scrollable = scrollable,
|
||||
|
||||
.pixman_fmt_without_alpha = pixman_fmt_without_alpha,
|
||||
.shm_format_without_alpha = shm_fmt_without_alpha,
|
||||
.pixman_fmt = pixman_fmt,
|
||||
.shm_format = shm_fmt,
|
||||
|
||||
.pixman_fmt_with_alpha = pixman_fmt_with_alpha,
|
||||
.shm_format_with_alpha = shm_fmt_with_alpha,
|
||||
.release_cb = release_cb,
|
||||
.cb_data = cb_data,
|
||||
};
|
||||
return chain;
|
||||
}
|
||||
|
|
@ -1058,3 +1093,17 @@ shm_chain_free(struct buffer_chain *chain)
|
|||
|
||||
free(chain);
|
||||
}
|
||||
|
||||
enum shm_bit_depth
|
||||
shm_chain_bit_depth(const struct buffer_chain *chain)
|
||||
{
|
||||
const pixman_format_code_t fmt = chain->pixman_fmt;
|
||||
|
||||
return fmt == PIXMAN_a8r8g8b8
|
||||
? SHM_BITS_8
|
||||
#if defined(HAVE_PIXMAN_RGBA_16)
|
||||
: fmt == PIXMAN_a16b16g16r16
|
||||
? SHM_BITS_16
|
||||
#endif
|
||||
: SHM_BITS_10;
|
||||
}
|
||||
|
|
|
|||
14
shm.h
14
shm.h
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <tllist.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "wayland.h"
|
||||
|
||||
struct damage;
|
||||
|
|
@ -41,14 +42,20 @@ struct buffer {
|
|||
};
|
||||
|
||||
void shm_fini(void);
|
||||
|
||||
/* TODO: combine into shm_init() */
|
||||
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 *shm_chain_new(
|
||||
struct wayland *wayl, bool scrollable, size_t pix_instances,
|
||||
bool ten_bit_it_if_capable);
|
||||
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);
|
||||
|
||||
enum shm_bit_depth shm_chain_bit_depth(const struct buffer_chain *chain);
|
||||
|
||||
/*
|
||||
* Returns a single buffer.
|
||||
*
|
||||
|
|
@ -58,8 +65,7 @@ void shm_chain_free(struct buffer_chain *chain);
|
|||
*
|
||||
* A newly allocated buffer has an age of 1234.
|
||||
*/
|
||||
struct buffer *shm_get_buffer(
|
||||
struct buffer_chain *chain, int width, int height, bool with_alpha);
|
||||
struct buffer *shm_get_buffer(struct buffer_chain *chain, int width, int height);
|
||||
/*
|
||||
* Returns many buffers, described by 'info', all sharing the same SHM
|
||||
* buffer pool.
|
||||
|
|
@ -77,7 +83,7 @@ struct buffer *shm_get_buffer(
|
|||
void shm_get_many(
|
||||
struct buffer_chain *chain, size_t count,
|
||||
int widths[static count], int heights[static count],
|
||||
struct buffer *bufs[static count], bool with_alpha);
|
||||
struct buffer *bufs[static count]);
|
||||
|
||||
void shm_did_not_use_buf(struct buffer *buf);
|
||||
|
||||
|
|
|
|||
28
sixel.c
28
sixel.c
|
|
@ -110,23 +110,34 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
|
|||
term->sixel.image.height = 0;
|
||||
term->sixel.image.alloc_height = 0;
|
||||
term->sixel.image.bottom_pixel = 0;
|
||||
term->sixel.linear_blending = render_do_linear_blending(term);
|
||||
term->sixel.linear_blending = wayl_do_linear_blending(term->wl, term->conf);
|
||||
term->sixel.pixman_fmt = PIXMAN_a8r8g8b8;
|
||||
|
||||
if (term->conf->tweak.surface_bit_depth == SHM_10_BIT) {
|
||||
if (term->wl->shm_have_argb2101010 && term->wl->shm_have_xrgb2101010) {
|
||||
/*
|
||||
* Use higher-precision sixel surfaces if we're using
|
||||
* 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.pixman_fmt = PIXMAN_a2r10g10b10;
|
||||
}
|
||||
|
||||
else if (term->wl->shm_have_abgr2101010 && term->wl->shm_have_xbgr2101010) {
|
||||
else if (term->wl->shm_have_abgr2101010) {
|
||||
term->sixel.use_10bit = true;
|
||||
term->sixel.pixman_fmt = PIXMAN_a2b10g10r10;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t active_palette_entries = min(
|
||||
ALEN(term->conf->colors.sixel), term->sixel.palette_size);
|
||||
ALEN(term->conf->colors_dark.sixel), term->sixel.palette_size);
|
||||
|
||||
if (term->sixel.use_private_palette) {
|
||||
xassert(term->sixel.private_palette == NULL);
|
||||
|
|
@ -134,7 +145,7 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
|
|||
term->sixel.palette_size, sizeof(term->sixel.private_palette[0]));
|
||||
|
||||
memcpy(
|
||||
term->sixel.private_palette, term->conf->colors.sixel,
|
||||
term->sixel.private_palette, term->conf->colors_dark.sixel,
|
||||
active_palette_entries * sizeof(term->sixel.private_palette[0]));
|
||||
|
||||
if (term->sixel.linear_blending || term->sixel.use_10bit) {
|
||||
|
|
@ -153,7 +164,7 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
|
|||
term->sixel.palette_size, sizeof(term->sixel.shared_palette[0]));
|
||||
|
||||
memcpy(
|
||||
term->sixel.shared_palette, term->conf->colors.sixel,
|
||||
term->sixel.shared_palette, term->conf->colors_dark.sixel,
|
||||
active_palette_entries * sizeof(term->sixel.shared_palette[0]));
|
||||
|
||||
if (term->sixel.linear_blending || term->sixel.use_10bit) {
|
||||
|
|
@ -1548,6 +1559,9 @@ resize(struct terminal *term, int new_width_mutable, int new_height_mutable)
|
|||
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;
|
||||
const int old_width = term->sixel.image.width;
|
||||
|
|
|
|||
50
slave.c
50
slave.c
|
|
@ -436,8 +436,54 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
|||
add_to_env(&custom_env, "COLORTERM", "truecolor");
|
||||
add_to_env(&custom_env, "PWD", cwd);
|
||||
|
||||
del_from_env(&custom_env, "TERM_PROGRAM");
|
||||
del_from_env(&custom_env, "TERM_PROGRAM_VERSION");
|
||||
del_from_env(&custom_env, "TERM_PROGRAM"); /* Wezterm, Ghostty */
|
||||
del_from_env(&custom_env, "TERM_PROGRAM_VERSION"); /* Wezterm, Ghostty */
|
||||
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)
|
||||
add_to_env(&custom_env, "TERMINFO", FOOT_TERMINFO_PATH);
|
||||
|
|
|
|||
226
terminal.c
226
terminal.c
|
|
@ -199,7 +199,7 @@ add_utmp_record(const struct config *conf, struct reaper *reaper, int ptmx)
|
|||
return true;
|
||||
|
||||
char *const argv[] = {conf->utmp_helper_path, UTMP_ADD, getenv("WAYLAND_DISPLAY"), NULL};
|
||||
return spawn(reaper, NULL, argv, ptmx, ptmx, -1, NULL, NULL, NULL) >= 0;
|
||||
return spawn(reaper, NULL, argv, ptmx, -1, -1, NULL, NULL, NULL) >= 0;
|
||||
#else
|
||||
return true;
|
||||
#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};
|
||||
return spawn(reaper, NULL, argv, ptmx, ptmx, -1, NULL, NULL, NULL) >= 0;
|
||||
return spawn(reaper, NULL, argv, ptmx, -1, -1, NULL, NULL, NULL) >= 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
|
@ -719,6 +719,9 @@ initialize_render_workers(struct terminal *term)
|
|||
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.count, sizeof(term->render.workers.threads[0]));
|
||||
|
||||
|
|
@ -1073,19 +1076,20 @@ reload_fonts(struct terminal *term, bool resize_grid)
|
|||
|
||||
options->scaling_filter = conf->tweak.fcft_filter;
|
||||
options->color_glyphs.format = PIXMAN_a8r8g8b8;
|
||||
options->color_glyphs.srgb_decode = render_do_linear_blending(term);
|
||||
options->color_glyphs.srgb_decode =
|
||||
wayl_do_linear_blending(term->wl, term->conf);
|
||||
|
||||
if (conf->tweak.surface_bit_depth == SHM_10_BIT) {
|
||||
if ((term->wl->shm_have_argb2101010 && term->wl->shm_have_xrgb2101010) ||
|
||||
(term->wl->shm_have_abgr2101010 && term->wl->shm_have_xbgr2101010))
|
||||
{
|
||||
/*
|
||||
* Use a high-res buffer type for emojis. We don't want to
|
||||
* use an a2r10g0b10 type of surface, since we need more
|
||||
* than 2 bits for alpha.
|
||||
*/
|
||||
options->color_glyphs.format = PIXMAN_rgba_float;
|
||||
}
|
||||
if (shm_chain_bit_depth(term->render.chains.grid) >= SHM_BITS_10) {
|
||||
/*
|
||||
* Use a high-res buffer type for emojis. We don't want to use
|
||||
* an a2r10g0b10 type of surface, since we need more than 2
|
||||
* bits for alpha.
|
||||
*/
|
||||
#if defined(HAVE_PIXMAN_RGBA_16)
|
||||
options->color_glyphs.format = PIXMAN_a16b16g16r16;
|
||||
#else
|
||||
options->color_glyphs.format = PIXMAN_rgba_float;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct fcft_font *fonts[4];
|
||||
|
|
@ -1260,7 +1264,18 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
goto err;
|
||||
}
|
||||
|
||||
const bool ten_bit_surfaces = conf->tweak.surface_bit_depth == SHM_10_BIT;
|
||||
const enum shm_bit_depth desired_bit_depth =
|
||||
conf->tweak.surface_bit_depth == SHM_BITS_AUTO
|
||||
? wayl_do_linear_blending(wayl, conf) ? SHM_BITS_16 : SHM_BITS_8
|
||||
: 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 */
|
||||
*term = (struct terminal) {
|
||||
|
|
@ -1279,7 +1294,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
},
|
||||
.font_dpi = 0.,
|
||||
.font_dpi_before_unmap = -1.,
|
||||
.font_subpixel = (conf->colors.alpha == 0xffff /* Can't do subpixel rendering on transparent background */
|
||||
.font_subpixel = (theme->alpha == 0xffff /* Can't do subpixel rendering on transparent background */
|
||||
? FCFT_SUBPIXEL_DEFAULT
|
||||
: FCFT_SUBPIXEL_NONE),
|
||||
.cursor_keys_mode = CURSOR_KEYS_NORMAL,
|
||||
|
|
@ -1295,14 +1310,14 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
.state = 0, /* STATE_GROUND */
|
||||
},
|
||||
.colors = {
|
||||
.fg = conf->colors.fg,
|
||||
.bg = conf->colors.bg,
|
||||
.alpha = conf->colors.alpha,
|
||||
.cursor_fg = conf->cursor.color.text,
|
||||
.cursor_bg = conf->cursor.color.cursor,
|
||||
.selection_fg = conf->colors.selection_fg,
|
||||
.selection_bg = conf->colors.selection_bg,
|
||||
.use_custom_selection = conf->colors.use_custom.selection,
|
||||
.fg = theme->fg,
|
||||
.bg = theme->bg,
|
||||
.alpha = theme->alpha,
|
||||
.cursor_fg = (theme->use_custom.cursor ? 1u << 31 : 0) | theme->cursor.text,
|
||||
.cursor_bg = (theme->use_custom.cursor ? 1u << 31 : 0) | theme->cursor.cursor,
|
||||
.selection_fg = theme->selection_fg,
|
||||
.selection_bg = theme->selection_bg,
|
||||
.active_theme = conf->initial_color_theme,
|
||||
},
|
||||
.color_stack = {
|
||||
.stack = NULL,
|
||||
|
|
@ -1346,13 +1361,13 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
.render = {
|
||||
.chains = {
|
||||
.grid = shm_chain_new(wayl, true, 1 + conf->render_worker_count,
|
||||
ten_bit_surfaces),
|
||||
.search = shm_chain_new(wayl, false, 1 ,ten_bit_surfaces),
|
||||
.scrollback_indicator = shm_chain_new(wayl, false, 1, ten_bit_surfaces),
|
||||
.render_timer = shm_chain_new(wayl, false, 1, ten_bit_surfaces),
|
||||
.url = shm_chain_new(wayl, false, 1, ten_bit_surfaces),
|
||||
.csd = shm_chain_new(wayl, false, 1, ten_bit_surfaces),
|
||||
.overlay = shm_chain_new(wayl, false, 1, ten_bit_surfaces),
|
||||
desired_bit_depth, &render_buffer_release_callback, term),
|
||||
.search = shm_chain_new(wayl, false, 1 ,desired_bit_depth, NULL, NULL),
|
||||
.scrollback_indicator = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL),
|
||||
.render_timer = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL),
|
||||
.url = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL),
|
||||
.csd = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL),
|
||||
.overlay = shm_chain_new(wayl, false, 1, desired_bit_depth, NULL, NULL),
|
||||
},
|
||||
.scrollback_lines = conf->scrollback.lines,
|
||||
.app_sync_updates.timer_fd = app_sync_updates_fd,
|
||||
|
|
@ -1399,6 +1414,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
pixman_region32_init(&term->render.last_overlay_clip);
|
||||
|
||||
term_update_ascii_printer(term);
|
||||
memcpy(term->colors.table, theme->table, sizeof(term->colors.table));
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
const struct config_font_list *font_list = &conf->fonts[i];
|
||||
|
|
@ -1433,8 +1449,6 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
|||
xassert(tll_length(term->wl->monitors) > 0);
|
||||
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 */
|
||||
if ((term->window = wayl_win_init(term, token)) == NULL)
|
||||
goto err;
|
||||
|
|
@ -1495,7 +1509,7 @@ term_window_configured(struct terminal *term)
|
|||
xassert(term->window->is_configured);
|
||||
fdm_add(term->fdm, term->ptmx, EPOLLIN, &fdm_ptmx, term);
|
||||
|
||||
const bool gamma_correct = render_do_linear_blending(term);
|
||||
const bool gamma_correct = wayl_do_linear_blending(term->wl, term->conf);
|
||||
LOG_INFO("gamma-correct blending: %s", gamma_correct ? "enabled" : "disabled");
|
||||
}
|
||||
}
|
||||
|
|
@ -1884,6 +1898,8 @@ term_destroy(struct terminal *term)
|
|||
}
|
||||
}
|
||||
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);
|
||||
sem_destroy(&term->render.workers.start);
|
||||
sem_destroy(&term->render.workers.done);
|
||||
|
|
@ -2064,6 +2080,19 @@ erase_line(struct terminal *term, struct row *row)
|
|||
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
|
||||
term_reset(struct terminal *term, bool hard)
|
||||
{
|
||||
|
|
@ -2147,19 +2176,20 @@ term_reset(struct terminal *term, bool hard)
|
|||
if (!hard)
|
||||
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->blink.state = BLINK_ON;
|
||||
fdm_del(term->fdm, term->blink.fd); term->blink.fd = -1;
|
||||
term->colors.fg = term->conf->colors.fg;
|
||||
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));
|
||||
term_theme_apply(term, theme);
|
||||
term->colors.active_theme = term->conf->initial_color_theme;
|
||||
free(term->color_stack.stack);
|
||||
term->color_stack.stack = NULL;
|
||||
term->color_stack.size = 0;
|
||||
|
|
@ -2760,13 +2790,11 @@ UNITTEST
|
|||
},
|
||||
.kind = SELECTION_NONE,
|
||||
.auto_scroll = {
|
||||
.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK),
|
||||
.fd = -1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
xassert(term.selection.auto_scroll.fd >= 0);
|
||||
|
||||
#define populate_scrollback() do { \
|
||||
for (int i = 0; i < scrollback_rows; i++) { \
|
||||
if (term.normal.rows[i] == NULL) { \
|
||||
|
|
@ -2856,7 +2884,7 @@ UNITTEST
|
|||
|
||||
/* Cleanup */
|
||||
tll_free(term.normal.sixel_images);
|
||||
close(term.selection.auto_scroll.fd);
|
||||
xassert(term.selection.auto_scroll.fd == -1);
|
||||
for (int i = 0; i < scrollback_rows; i++)
|
||||
grid_row_free(term.normal.rows[i]);
|
||||
free(term.normal.rows);
|
||||
|
|
@ -3141,11 +3169,17 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
|
||||
sixel_scroll_down(term, rows);
|
||||
|
||||
bool view_follows = term->grid->view == term->grid->offset;
|
||||
const bool view_follows = term->grid->view == term->grid->offset;
|
||||
term->grid->offset -= rows;
|
||||
term->grid->offset += term->grid->num_rows;
|
||||
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 < term->grid->num_rows);
|
||||
|
||||
|
|
@ -3153,6 +3187,11 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
||||
selection_view_up(term, 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 */
|
||||
|
|
@ -3169,11 +3208,16 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
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);
|
||||
|
||||
#if defined(_DEBUG)
|
||||
for (int r = 0; r < term->rows; r++)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -3380,10 +3424,13 @@ report_mouse_click(struct terminal *term, int encoded_button, int row, int col,
|
|||
encoded_button, col + 1, row + 1, release ? 'm' : 'M');
|
||||
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",
|
||||
encoded_button, col_pixels + 1, row_pixels + 1, release ? 'm' : 'M');
|
||||
encoded_button, bounded_col + 1, bounded_row + 1, release ? 'm' : 'M');
|
||||
break;
|
||||
}
|
||||
|
||||
case MOUSE_URXVT:
|
||||
snprintf(response, sizeof(response), "\033[%d;%d;%dM",
|
||||
|
|
@ -3564,7 +3611,9 @@ term_xcursor_update_for_seat(struct terminal *term, struct seat *seat)
|
|||
if (seat->pointer.hidden)
|
||||
shape = CURSOR_SHAPE_HIDDEN;
|
||||
|
||||
else if (cursor_string_to_server_shape(term->mouse_user_cursor) != 0 ||
|
||||
else if (cursor_string_to_server_shape(
|
||||
term->mouse_user_cursor,
|
||||
term->wl->shape_manager_version) != 0 ||
|
||||
render_xcursor_is_valid(seat, term->mouse_user_cursor))
|
||||
{
|
||||
shape = CURSOR_SHAPE_CUSTOM;
|
||||
|
|
@ -3984,9 +4033,11 @@ term_print(struct terminal *term, char32_t wc, int width, bool insert_mode_disab
|
|||
cell->wc = term->vt.last_printed = wc;
|
||||
cell->attrs = term->vt.attrs;
|
||||
|
||||
if (term->vt.osc8.uri != NULL) {
|
||||
grid_row_uri_range_put(
|
||||
row, col, term->vt.osc8.uri, term->vt.osc8.id);
|
||||
if (unlikely(term->vt.osc8.uri != NULL)) {
|
||||
for (int i = 0; i < width && (col + i) < term->cols; i++) {
|
||||
grid_row_uri_range_put(
|
||||
row, col + i, term->vt.osc8.uri, term->vt.osc8.id);
|
||||
}
|
||||
|
||||
switch (term->conf->url.osc8_underline) {
|
||||
case OSC8_UNDERLINE_ALWAYS:
|
||||
|
|
@ -4693,3 +4744,68 @@ term_send_size_notification(struct terminal *term)
|
|||
term->rows, term->cols, height, width);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
18
terminal.h
18
terminal.h
|
|
@ -404,7 +404,7 @@ struct colors {
|
|||
uint32_t cursor_bg; /* cursor color */
|
||||
uint32_t selection_fg;
|
||||
uint32_t selection_bg;
|
||||
bool use_custom_selection;
|
||||
enum which_color_theme active_theme;
|
||||
};
|
||||
|
||||
struct terminal {
|
||||
|
|
@ -517,6 +517,7 @@ struct terminal {
|
|||
|
||||
bool num_lock_modifier;
|
||||
bool bell_action_enabled;
|
||||
bool report_theme_changes;
|
||||
|
||||
/* Saved DECSET modes - we save the SET state */
|
||||
struct {
|
||||
|
|
@ -547,6 +548,7 @@ struct terminal {
|
|||
bool ime:1;
|
||||
bool app_sync_updates:1;
|
||||
bool grapheme_shaping:1;
|
||||
bool report_theme_changes:1;
|
||||
|
||||
bool size_notifications:1;
|
||||
|
||||
|
|
@ -704,6 +706,14 @@ struct terminal {
|
|||
tll(int) queue;
|
||||
thrd_t *threads;
|
||||
struct buffer *buf;
|
||||
|
||||
struct {
|
||||
mtx_t lock;
|
||||
cnd_t cond;
|
||||
struct buffer *buf;
|
||||
struct timespec start;
|
||||
struct timespec stop;
|
||||
} preapplied_damage;
|
||||
} workers;
|
||||
|
||||
/* Last rendered cursor position */
|
||||
|
|
@ -714,6 +724,8 @@ struct terminal {
|
|||
} last_cursor;
|
||||
|
||||
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;
|
||||
struct buffer *last_overlay_buf;
|
||||
|
|
@ -982,6 +994,10 @@ void term_enable_size_notifications(struct terminal *term);
|
|||
void term_disable_size_notifications(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)
|
||||
{
|
||||
#if defined(FOOT_GRAPHEME_CLUSTERING)
|
||||
|
|
|
|||
|
|
@ -399,6 +399,16 @@ test_color(struct context *ctx, bool (*parse_fun)(struct context *ctx),
|
|||
BUG("[%s].%s=%s: failed to parse",
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -445,6 +455,18 @@ test_two_colors(struct context *ctx, bool (*parse_fun)(struct context *ctx),
|
|||
BUG("[%s].%s=%s: failed to parse",
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -460,6 +482,7 @@ test_section_main(void)
|
|||
test_string(&ctx, &parse_section_main, "shell", &conf.shell);
|
||||
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, "toplevel-tag", &conf.toplevel_tag);
|
||||
test_string(&ctx, &parse_section_main, "utmp-helper", &conf.utmp_helper_path);
|
||||
|
||||
test_c32string(&ctx, &parse_section_main, "word-delimiters", &conf.word_delimiters);
|
||||
|
|
@ -468,6 +491,8 @@ test_section_main(void)
|
|||
test_boolean(&ctx, &parse_section_main, "box-drawings-uses-font-glyphs", &conf.box_drawings_uses_font_glyphs);
|
||||
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, "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, "line-height", &conf.line_height);
|
||||
|
|
@ -496,6 +521,14 @@ test_section_main(void)
|
|||
(int []){STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN},
|
||||
(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: include (custom) */
|
||||
/* TODO: bold-text-in-bright (enum/boolean) */
|
||||
|
|
@ -670,69 +703,157 @@ test_section_touch(void)
|
|||
}
|
||||
|
||||
static void
|
||||
test_section_colors(void)
|
||||
test_section_colors_dark(void)
|
||||
{
|
||||
struct config conf = {0};
|
||||
struct context ctx = {
|
||||
.conf = &conf, .section = "colors", .path = "unittest"};
|
||||
.conf = &conf, .section = "colors-dark", .path = "unittest"};
|
||||
|
||||
test_invalid_key(&ctx, &parse_section_colors, "invalid-key");
|
||||
|
||||
test_color(&ctx, &parse_section_colors, "foreground", false, &conf.colors.fg);
|
||||
test_color(&ctx, &parse_section_colors, "background", false, &conf.colors.bg);
|
||||
test_color(&ctx, &parse_section_colors, "regular0", false, &conf.colors.table[0]);
|
||||
test_color(&ctx, &parse_section_colors, "regular1", false, &conf.colors.table[1]);
|
||||
test_color(&ctx, &parse_section_colors, "regular2", false, &conf.colors.table[2]);
|
||||
test_color(&ctx, &parse_section_colors, "regular3", false, &conf.colors.table[3]);
|
||||
test_color(&ctx, &parse_section_colors, "regular4", false, &conf.colors.table[4]);
|
||||
test_color(&ctx, &parse_section_colors, "regular5", false, &conf.colors.table[5]);
|
||||
test_color(&ctx, &parse_section_colors, "regular6", false, &conf.colors.table[6]);
|
||||
test_color(&ctx, &parse_section_colors, "regular7", false, &conf.colors.table[7]);
|
||||
test_color(&ctx, &parse_section_colors, "bright0", false, &conf.colors.table[8]);
|
||||
test_color(&ctx, &parse_section_colors, "bright1", false, &conf.colors.table[9]);
|
||||
test_color(&ctx, &parse_section_colors, "bright2", false, &conf.colors.table[10]);
|
||||
test_color(&ctx, &parse_section_colors, "bright3", false, &conf.colors.table[11]);
|
||||
test_color(&ctx, &parse_section_colors, "bright4", false, &conf.colors.table[12]);
|
||||
test_color(&ctx, &parse_section_colors, "bright5", false, &conf.colors.table[13]);
|
||||
test_color(&ctx, &parse_section_colors, "bright6", false, &conf.colors.table[14]);
|
||||
test_color(&ctx, &parse_section_colors, "bright7", false, &conf.colors.table[15]);
|
||||
test_color(&ctx, &parse_section_colors, "dim0", false, &conf.colors.dim[0]);
|
||||
test_color(&ctx, &parse_section_colors, "dim1", false, &conf.colors.dim[1]);
|
||||
test_color(&ctx, &parse_section_colors, "dim2", false, &conf.colors.dim[2]);
|
||||
test_color(&ctx, &parse_section_colors, "dim3", false, &conf.colors.dim[3]);
|
||||
test_color(&ctx, &parse_section_colors, "dim4", false, &conf.colors.dim[4]);
|
||||
test_color(&ctx, &parse_section_colors, "dim5", false, &conf.colors.dim[5]);
|
||||
test_color(&ctx, &parse_section_colors, "dim6", false, &conf.colors.dim[6]);
|
||||
test_color(&ctx, &parse_section_colors, "dim7", false, &conf.colors.dim[7]);
|
||||
test_color(&ctx, &parse_section_colors, "selection-foreground", false, &conf.colors.selection_fg);
|
||||
test_color(&ctx, &parse_section_colors, "selection-background", false, &conf.colors.selection_bg);
|
||||
test_color(&ctx, &parse_section_colors, "urls", false, &conf.colors.url);
|
||||
test_two_colors(&ctx, &parse_section_colors, "jump-labels", false,
|
||||
&conf.colors.jump_label.fg,
|
||||
&conf.colors.jump_label.bg);
|
||||
test_two_colors(&ctx, &parse_section_colors, "scrollback-indicator", false,
|
||||
&conf.colors.scrollback_indicator.fg,
|
||||
&conf.colors.scrollback_indicator.bg);
|
||||
test_two_colors(&ctx, &parse_section_colors, "search-box-no-match", false,
|
||||
&conf.colors.search_box.no_match.fg,
|
||||
&conf.colors.search_box.no_match.bg);
|
||||
test_two_colors(&ctx, &parse_section_colors, "search-box-match", false,
|
||||
&conf.colors.search_box.match.fg,
|
||||
&conf.colors.search_box.match.bg);
|
||||
test_color(&ctx, &parse_section_colors_dark, "foreground", false, &conf.colors_dark.fg);
|
||||
test_color(&ctx, &parse_section_colors_dark, "background", false, &conf.colors_dark.bg);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular0", false, &conf.colors_dark.table[0]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular1", false, &conf.colors_dark.table[1]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular2", false, &conf.colors_dark.table[2]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular3", false, &conf.colors_dark.table[3]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular4", false, &conf.colors_dark.table[4]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular5", false, &conf.colors_dark.table[5]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular6", false, &conf.colors_dark.table[6]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "regular7", false, &conf.colors_dark.table[7]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright0", false, &conf.colors_dark.table[8]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright1", false, &conf.colors_dark.table[9]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright2", false, &conf.colors_dark.table[10]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright3", false, &conf.colors_dark.table[11]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright4", false, &conf.colors_dark.table[12]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright5", false, &conf.colors_dark.table[13]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright6", false, &conf.colors_dark.table[14]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "bright7", false, &conf.colors_dark.table[15]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim0", false, &conf.colors_dark.dim[0]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim1", false, &conf.colors_dark.dim[1]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim2", false, &conf.colors_dark.dim[2]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim3", false, &conf.colors_dark.dim[3]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim4", false, &conf.colors_dark.dim[4]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim5", false, &conf.colors_dark.dim[5]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim6", false, &conf.colors_dark.dim[6]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "dim7", false, &conf.colors_dark.dim[7]);
|
||||
test_color(&ctx, &parse_section_colors_dark, "selection-foreground", false, &conf.colors_dark.selection_fg);
|
||||
test_color(&ctx, &parse_section_colors_dark, "selection-background", false, &conf.colors_dark.selection_bg);
|
||||
test_color(&ctx, &parse_section_colors_dark, "urls", false, &conf.colors_dark.url);
|
||||
test_two_colors(&ctx, &parse_section_colors_dark, "jump-labels", false,
|
||||
&conf.colors_dark.jump_label.fg,
|
||||
&conf.colors_dark.jump_label.bg);
|
||||
test_two_colors(&ctx, &parse_section_colors_dark, "scrollback-indicator", false,
|
||||
&conf.colors_dark.scrollback_indicator.fg,
|
||||
&conf.colors_dark.scrollback_indicator.bg);
|
||||
test_two_colors(&ctx, &parse_section_colors_dark, "search-box-no-match", false,
|
||||
&conf.colors_dark.search_box.no_match.fg,
|
||||
&conf.colors_dark.search_box.no_match.bg);
|
||||
test_two_colors(&ctx, &parse_section_colors_dark, "search-box-match", false,
|
||||
&conf.colors_dark.search_box.match.fg,
|
||||
&conf.colors_dark.search_box.match.bg);
|
||||
|
||||
test_enum(&ctx, &parse_section_colors, "alpha-mode", 3,
|
||||
test_two_colors(&ctx, &parse_section_colors_dark, "cursor", false,
|
||||
&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"},
|
||||
(int []){ALPHA_MODE_DEFAULT, ALPHA_MODE_MATCHING, ALPHA_MODE_ALL},
|
||||
(int *)&conf.colors.alpha_mode);
|
||||
(int *)&conf.colors_dark.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++) {
|
||||
char key_name[4];
|
||||
sprintf(key_name, "%zu", i);
|
||||
test_color(&ctx, &parse_section_colors, key_name, false,
|
||||
&conf.colors.table[i]);
|
||||
test_color(&ctx, &parse_section_colors_dark, key_name, false,
|
||||
&conf.colors_dark.table[i]);
|
||||
}
|
||||
|
||||
test_invalid_key(&ctx, &parse_section_colors, "256");
|
||||
test_invalid_key(&ctx, &parse_section_colors_dark, "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) */
|
||||
|
||||
|
|
@ -1385,6 +1506,9 @@ test_section_tweak(void)
|
|||
test_float(&ctx, &parse_section_tweak, "bold-text-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 */
|
||||
test_uint32(&ctx, &parse_section_tweak, "max-shm-pool-size-mb",
|
||||
&conf.tweak.max_shm_pool_size);
|
||||
|
|
@ -1407,7 +1531,8 @@ main(int argc, const char *const *argv)
|
|||
test_section_cursor();
|
||||
test_section_mouse();
|
||||
test_section_touch();
|
||||
test_section_colors();
|
||||
test_section_colors_dark();
|
||||
test_section_colors_light();
|
||||
test_section_csd();
|
||||
test_section_key_bindings();
|
||||
test_section_key_bindings_collisions();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- conf -*-
|
||||
# Aero root theme
|
||||
|
||||
[cursor]
|
||||
color=1a1a1a 9fd5f5
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=1a1a1a 9fd5f5
|
||||
foreground=dedeef
|
||||
background=1a1a1a
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- conf -*-
|
||||
# Alacritty
|
||||
|
||||
[cursor]
|
||||
color = 181818 56d8c9
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor = 181818 56d8c9
|
||||
background= 181818
|
||||
foreground= d8d8d8
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- conf -*-
|
||||
# https://github.com/romainl/Apprentice
|
||||
|
||||
[cursor]
|
||||
color=262626 6c6c6c
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=262626 6c6c6c
|
||||
foreground=bcbcbc
|
||||
background=262626
|
||||
regular0=1c1c1c
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
# theme: Ayu Mirage
|
||||
# description: a theme based on Ayu Mirage for Sublime Text (original: https://github.com/dempfi/ayu)
|
||||
|
||||
[cursor]
|
||||
color = ffcc66 665a44
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor = ffcc66 665a44
|
||||
foreground = cccac2
|
||||
background = 242936
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# _*_ conf _*_
|
||||
# Catppuccin Frappe
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
foreground=c6d0f5
|
||||
background=303446
|
||||
|
||||
|
|
@ -23,6 +23,11 @@ bright5=f4b8e4
|
|||
bright6=81c8be
|
||||
bright7=a5adce
|
||||
|
||||
cursor=232634 f2d5cf
|
||||
|
||||
16=ef9f76
|
||||
17=f2d5cf
|
||||
|
||||
selection-foreground=c6d0f5
|
||||
selection-background=4f5369
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
# _*_ conf _*_
|
||||
# Catppuccin Latte
|
||||
|
||||
[colors]
|
||||
[main]
|
||||
initial-color-theme=light
|
||||
|
||||
[colors-light]
|
||||
foreground=4c4f69
|
||||
background=eff1f5
|
||||
|
||||
|
|
@ -23,6 +26,11 @@ bright5=ea76cb
|
|||
bright6=179299
|
||||
bright7=bcc0cc
|
||||
|
||||
cursor=eff1f5 dc8a78
|
||||
|
||||
16=fe640b
|
||||
17=dc8a78
|
||||
|
||||
selection-foreground=4c4f69
|
||||
selection-background=ccced7
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# _*_ conf _*_
|
||||
# Catppuccin Macchiato
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
foreground=cad3f5
|
||||
background=24273a
|
||||
|
||||
|
|
@ -23,6 +23,11 @@ bright5=f5bde6
|
|||
bright6=8bd5ca
|
||||
bright7=a5adcb
|
||||
|
||||
cursor=181926 f4dbd6
|
||||
|
||||
16=f5a97f
|
||||
17=f4dbd6
|
||||
|
||||
selection-foreground=cad3f5
|
||||
selection-background=454a5f
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# _*_ conf _*_
|
||||
# Catppuccin Mocha
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
foreground=cdd6f4
|
||||
background=1e1e2e
|
||||
|
||||
|
|
@ -23,6 +23,11 @@ bright5=f5c2e7
|
|||
bright6=94e2d5
|
||||
bright7=a6adc8
|
||||
|
||||
cursor=11111b f5e0dc
|
||||
|
||||
16=fab387
|
||||
17=f5e0dc
|
||||
|
||||
selection-foreground=cdd6f4
|
||||
selection-background=414356
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
# author: ayushnix (https://sr.ht/~ayushnix)
|
||||
# description: A dark theme with bright cyberpunk colors (WCAG AAA compliant)
|
||||
|
||||
[cursor]
|
||||
color = 181818 cdcdcd
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor = 181818 cdcdcd
|
||||
foreground = cdcdcd
|
||||
background = 181818
|
||||
regular0 = 181818
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- conf -*-
|
||||
# Derp
|
||||
|
||||
[cursor]
|
||||
color=000000 ffffff
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=000000 ffffff
|
||||
foreground=ffffff
|
||||
background=000000
|
||||
regular0=111111
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
# Deus
|
||||
# Color palette based on: https://github.com/ajmwagar/vim-deus
|
||||
|
||||
[cursor]
|
||||
color=2c323b eaeaea
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=2c323b eaeaea
|
||||
background=2c323b
|
||||
foreground=eaeaea
|
||||
regular0=242a32
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- conf -*-
|
||||
# Dracula
|
||||
|
||||
[cursor]
|
||||
color=282a36 f8f8f2
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=282a36 f8f8f2
|
||||
foreground=f8f8f2
|
||||
background=282a36
|
||||
regular0=000000 # black
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- conf -*-
|
||||
# Dracula iTerm2 variant
|
||||
|
||||
[cursor]
|
||||
color=ffffff bbbbbb
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=ffffff bbbbbb
|
||||
foreground=f8f8f2
|
||||
background=1e1f29
|
||||
regular0=000000 # black
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
# text and the white background.
|
||||
# author: Eugen Rahaian <eugen@rah.ro>
|
||||
|
||||
[cursor]
|
||||
color=ffffff 515151
|
||||
[main]
|
||||
initial-color-theme=light
|
||||
|
||||
[colors]
|
||||
[colors-light]
|
||||
cursor=ffffff 515151
|
||||
background= ffffff
|
||||
foreground= 000000
|
||||
|
||||
|
|
|
|||
42
themes/gruvbox
Normal file
42
themes/gruvbox
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# -*- 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
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- conf -*-
|
||||
# Gruvbox
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
background=282828
|
||||
foreground=ebdbb2
|
||||
regular0=282828
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
# -*- conf -*-
|
||||
# Gruvbox - Light
|
||||
|
||||
[colors]
|
||||
[main]
|
||||
initial-color-theme=light
|
||||
|
||||
[colors-light]
|
||||
background=fbf1c7
|
||||
foreground=3c3836
|
||||
regular0=fbf1c7
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
# -*- conf -*-
|
||||
[cursor]
|
||||
color=141414 c9c9c9
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=141414 c9c9c9
|
||||
foreground=c9c9c9
|
||||
background=141414
|
||||
regular0=191918 # black
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# this foot theme is based on alacritty iterm theme:
|
||||
# https://github.com/alacritty/alacritty-theme/blob/master/themes/iterm.toml
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
foreground=fffbf6
|
||||
background=101421
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
# JetBrains Darcula
|
||||
# Palette based on the same theme from https://github.com/dexpota/kitty-themes
|
||||
|
||||
[cursor]
|
||||
color=202020 ffffff
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=202020 ffffff
|
||||
background=202020
|
||||
foreground=adadad
|
||||
regular0=000000 # black
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
# -*- conf -*-
|
||||
|
||||
[cursor]
|
||||
color=111111 cccccc
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=111111 cccccc
|
||||
foreground=dddddd
|
||||
background=000000
|
||||
regular0=000000 # black
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
# Material Amber
|
||||
# Based on material.io guidelines with Amber 50 background
|
||||
|
||||
[cursor]
|
||||
color=fff8e1 21201d
|
||||
[main]
|
||||
initial-color-theme=light
|
||||
|
||||
[colors]
|
||||
[colors-light]
|
||||
cursor=fff8e1 21201d
|
||||
foreground = 21201d
|
||||
background = fff8e1
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# Material
|
||||
# From https://github.com/MartinSeeler/iterm2-material-design
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
foreground=ECEFF1
|
||||
background=263238
|
||||
regular0=546E7A # black
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@
|
|||
# modus-operandi
|
||||
# See: https://protesilaos.com/emacs/modus-themes
|
||||
#
|
||||
[colors]
|
||||
|
||||
[main]
|
||||
initial-color-theme=light
|
||||
|
||||
[colors-light]
|
||||
background=ffffff
|
||||
foreground=000000
|
||||
regular0=000000
|
||||
|
|
@ -22,3 +26,5 @@ bright4=2544bb
|
|||
bright5=5317ac
|
||||
bright6=005a5f
|
||||
bright7=ffffff
|
||||
|
||||
jump-labels=dce0e8 0000ff
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# See: https://protesilaos.com/emacs/modus-themes
|
||||
#
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
background=000000
|
||||
foreground=ffffff
|
||||
regular0=000000
|
||||
|
|
|
|||
25
themes/modus-vivendi-tinted
Normal file
25
themes/modus-vivendi-tinted
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# -*- 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
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
# Molokai
|
||||
# Based on zhou13's at https://github.com/zhou13/molokai-terminal/blob/master/xterm/Xresources
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
background=1B1D1E
|
||||
foreground=CCCCCC
|
||||
regular0=1B1D1E
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- conf -*-
|
||||
# Monokai Pro
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
background=2D2A2E
|
||||
foreground=FCFCFA
|
||||
regular0=403E41
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
# moonfly
|
||||
# Based on https://github.com/bluz71/vim-moonfly-colors
|
||||
|
||||
[cursor]
|
||||
color = 080808 9e9e9e
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor = 080808 9e9e9e
|
||||
foreground = b2b2b2
|
||||
background = 080808
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
# https://xcolors.net/neon
|
||||
#
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
foreground=f8f8f8
|
||||
background=171717
|
||||
regular0=171717
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# _*_ conf _*_
|
||||
# Night Owl
|
||||
|
||||
[cursor]
|
||||
color=011627 80a4c2
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=011627 80a4c2
|
||||
foreground=d6deeb
|
||||
background=011627
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
# nightfly
|
||||
# Based on https://github.com/bluz71/vim-nightfly-guicolors
|
||||
|
||||
[cursor]
|
||||
color = 080808 9ca1aa
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor = 080808 9ca1aa
|
||||
foreground = acb4c2
|
||||
background = 011627
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@
|
|||
# https://github.com/n1ghtmare/noirblaze-kitty
|
||||
|
||||
|
||||
[cursor]
|
||||
color=121212 ff0088
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=121212 ff0088
|
||||
foreground=d5d5d5
|
||||
background=121212
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@
|
|||
# this specific foot theme is based on nord-alacritty:
|
||||
# https://github.com/arcticicestudio/nord-alacritty/blob/develop/src/nord.yml
|
||||
|
||||
[cursor]
|
||||
color = 2e3440 d8dee9
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor = 2e3440 d8dee9
|
||||
foreground = d8dee9
|
||||
background = 2e3440
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# -*- conf -*-
|
||||
# Nordiq
|
||||
|
||||
[cursor]
|
||||
color=eeeeee 9f515a
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=eeeeee 9f515a
|
||||
foreground=dbdee9
|
||||
background=0e1420
|
||||
regular0=5b6272
|
||||
|
|
|
|||
56
themes/nvim
Normal file
56
themes/nvim
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# -*- 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
|
||||
|
|
@ -3,10 +3,8 @@
|
|||
# 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
|
||||
|
||||
[cursor]
|
||||
color=14161b e0e2ea # NvimDarkGrey2 NvimLightGrey2
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=14161b e0e2ea # NvimDarkGrey2 NvimLightGrey2
|
||||
foreground=e0e2ea # NvimLightGrey2
|
||||
background=14161b # NvimDarkGrey2
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
# 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
|
||||
|
||||
[cursor]
|
||||
color=e0e2ea 14161b # NvimLightGrey2 NvimDarkGrey2
|
||||
[main]
|
||||
initial-color-theme=light
|
||||
|
||||
[colors]
|
||||
[colors-light]
|
||||
cursor=e0e2ea 14161b # NvimLightGrey2 NvimDarkGrey2
|
||||
foreground=14161b # NvimDarkGrey2
|
||||
background=e0e2ea # NvimLightGrey2
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
# OneDark
|
||||
# Palette based on the same theme from https://github.com/dexpota/kitty-themes
|
||||
|
||||
[cursor]
|
||||
color=111111 cccccc
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=111111 cccccc
|
||||
foreground=979eab
|
||||
background=282c34
|
||||
regular0=282c34 # black
|
||||
|
|
|
|||
|
|
@ -7,10 +7,8 @@
|
|||
# + cursor colors from:
|
||||
# https://github.com/sonph/onehalf/blob/master/iterm/OneHalfDark.itermcolors
|
||||
|
||||
[cursor]
|
||||
color=dcdfe4 a3b3cc
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
cursor=dcdfe4 a3b3cc
|
||||
foreground=dcdfe4
|
||||
background=282c34
|
||||
regular0=282c34 # black
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# -*- conf -*-
|
||||
# http://panda.siamak.me/
|
||||
|
||||
[colors]
|
||||
[colors-dark]
|
||||
# alpha=1.0
|
||||
background=1D1E20
|
||||
foreground=F0F0F0
|
||||
|
|
|
|||
49
themes/paper-color
Normal file
49
themes/paper-color
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# -*- 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
Loading…
Add table
Add a link
Reference in a new issue