Merge branch 'master' into releases/1.9

This commit is contained in:
Daniel Eklöf 2021-10-01 20:50:32 +02:00
commit a082fec786
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
38 changed files with 1032 additions and 469 deletions

View file

@ -45,4 +45,4 @@ tasks:
- codespell: |
pip install codespell
cd foot
~/.local/bin/codespell README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd
~/.local/bin/codespell -Ldoas README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd

View file

@ -86,4 +86,4 @@ codespell:
- apk add python3
- apk add py3-pip
- pip install codespell
- codespell README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd
- codespell -Ldoas README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd

View file

@ -1,5 +1,6 @@
# Changelog
* [Unreleased](#unreleased)
* [1.9.0](#1-9-0)
* [1.8.2](#1-8-2)
* [1.8.1](#1-8-1)
@ -29,6 +30,54 @@
* [1.2.0](#1-2-0)
## Unreleased
### Added
* Warn when it appears the primary font is not monospaced. Can be
disabled by setting `[tweak].font-monospace-warn=no`
(https://codeberg.org/dnkl/foot/issues/704).
* PGO build scripts, in the `pgo` directory. See INSTALL.md -
_Performance optimized, PGO_, for details
(https://codeberg.org/dnkl/foot/issues/701).
* Braille characters (U+2800 - U+28FF) are now rendered by foot
itself (https://codeberg.org/dnkl/foot/issues/702).
* `-e` command-line option. This option is simply ignored, to appease
program launchers that blindly pass `-e` to any terminal emulator
(https://codeberg.org/dnkl/foot/issues/184).
### Changed
* `-Ddefault-terminfo` is now also applied to the generated terminfo
definitions when `-Dterminfo=enabled`.
* `-Dcustom-terminfo-install-location` no longer accepts `no` as a
special value, to disable exporting `TERMINFO`. To achieve the same
result, simply dont set it at all. If it _is_ set, `TERMINFO` is
still exported, like before.
* The default install location for the terminfo definitions have been
changed back to `${datadir}/terminfo`.
* `dpi-aware=auto`: fonts are now scaled using the monitors DPI only
when **all** monitors have a scaling factor of one
(https://codeberg.org/dnkl/foot/issues/714).
### Deprecated
### Removed
### Fixed
* Added workaround for GNOME bug where multiple button press events
(for the same button) is sent to the CSDs without any release or
leave events in between (https://codeberg.org/dnkl/foot/issues/709).
* Line-wise selection not taking soft line-wrapping into account
(https://codeberg.org/dnkl/foot/issues/726).
### Security
### Contributors
* [craigbarnes](https://codeberg.org/craigbarnes)
## 1.9.0
### Added
@ -65,6 +114,8 @@
now translated to pixel values using the monitors scaling factor
when `dpi-aware=no`, or `dpi-aware=auto` and the scaling factor is
larger than 1 (https://codeberg.org/dnkl/foot/issues/680).
* Spawning a new terminal with a working directory that does not exist
is no longer a fatal error.
### Removed

View file

@ -128,23 +128,35 @@ reasons for this:
used by e.g. tmux.
* New capabilities added to the `xterm-256color` terminfo could
potentially break foot.
* There may be future additions or changes to foots terminfo.
As of ncurses 2021-07-31, ncurses ships a version of foots
terminfo. I still recommend building and installing the version
shipped with foot, since:
As of ncurses 2021-07-31, ncurses includes a version of foots
terminfo. **The recommendation is to use those**, and only install the
terminfo definitions from this git repo if the systems ncurses
predates 2021-07-31.
* It will be more up to date (and more importantly, guaranteed to
match the installed version of foot).
* The ncurses version is missing several of the non-standard capabilities.
But, note that the foot terminfo definitions in ncurses lack the
non-standard capabilities. This mostly affects tmux; without them,
`terminal-overrides` must be configured to enable truecolor
support. For this reason, it _is_ possible to install “our” terminfo
definitions as well, either in a non-default location, or under a
different name.
Foots terminfo will by default be built, and installed along with
foot itself. This can be disabled (for example, to simplify packaging
when the terminfo definitions are packaged in a separate
package). Instructions on how to do so is in [terminfo](#terminfo).
Both have their set of issues. When installing to a non-default
location, foot will set the environment variable `TERMINFO` in the
child process. However, there are many situations where this simply
does not work. See https://codeberg.org/dnkl/foot/issues/695 for
details.
I recommend packaging foots terminfo files in a separate package, to
allow them to be installed on remote systems without having to install
foot itself.
Installing them under a different name generally works well, but will
break applications that check if `$TERM == foot`.
Hence the recommendation to simply use ncurses terminfo definitions
if available.
If packaging “our” terminfo definitions, I recommend doing that as a
separate package, to allow them to be installed on remote systems
without having to install foot itself.
### Setup
@ -158,44 +170,43 @@ mkdir -p bld/release && cd bld/release
Available compile-time options:
| Option | Type | Default | Description | Extra dependencies |
|--------------------------------------|---------|----------------------------|----------------------------------|--------------------|
| `-Ddocs` | feature | `auto` | Builds and install documentation | scdoc |
| `-Dime` | bool | `true` | Enables IME support | None |
| `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc |
| `-Dterminfo` | feature | `enabled` | Build and install terminfo files | tic (ncurses) |
| `-Ddefault-terminfo` | string | `foot` | Default value of `TERM` | none |
| `-Dcustom-terminfo-install-location` | string | `${datadir}/foot/terminfo` | Value to set `TERMINFO` to | None |
| Option | Type | Default | Description | Extra dependencies |
|--------------------------------------|---------|-----------------------|----------------------------------|--------------------|
| `-Ddocs` | feature | `auto` | Builds and install documentation | scdoc |
| `-Dime` | bool | `true` | Enables IME support | None |
| `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc |
| `-Dterminfo` | feature | `enabled` | Build and install terminfo files | tic (ncurses) |
| `-Ddefault-terminfo` | string | `foot` | Default value of `TERM` | none |
| `-Dcustom-terminfo-install-location` | string | `${datadir}/terminfo` | Value to set `TERMINFO` to | None |
Documentation includes the man pages, the example `foot.ini`, readme,
changelog and license files.
`-Ddefault-terminfo`: I strongly recommend leaving the default
value. This option is meant to be used as a last resort on platforms
where individual terminfo files cannot easily be installed.
value. Use this option if you plan on installing the terminfo files
under a different name. Setting this changes the default value of
`$TERM`, and the names of the terminfo files (if
`-Dterminfo=enabled`).
`-Dcustom-terminfo-install-location` enables foots terminfo to
co-exist with ncurses version. The idea is that you install foots
terminfo to a non-standard location, for example
`/usr/share/foot/terminfo`. Use `-Dcustom-terminfo-install-location`
to tell foot where the terminfo is. Foot will set the environment
variable `TERMINFO` to this value (with `${prefix}` added). The value
is **relative to ${prefix}**.
co-exist with ncurses version, without changing the terminfo
names. The idea is that you install foots terminfo to a non-standard
location, for example `/usr/share/foot/terminfo`. Use
`-Dcustom-terminfo-install-location` to tell foot where the terminfo
is. Foot will set the environment variable `TERMINFO` to this value
(with `${prefix}` added). The value is **relative to ${prefix}**.
Conforming applications _should_ look in `TERMINFO` first, and
fallback to the builtin default (e.g. `/usr/share/terminfo`) if not
found. Thus, it will prefer foots version, if it exists (which it
typically will on localhost), and fallback to ncurses version if not
(e.g. on remote systems, where foots terminfo package has not been
installed).
Note that there are several issues with this approach:
https://codeberg.org/dnkl/foot/issues/695.
If set to `no`, foot will **not** set or modify `TERMINFO` at all. Use
this if you do not intend to use/support foots terminfo definitions
at all.
If left unset, foot will **not** set or modify `TERMINFO`.
`-Dterminfo` can be used to disable building the terminfo definitions
in the meson build. It does **not** change the default value of
`TERM`, and it does **not** disable `TERMINFO`.
`TERM`, and it does **not** disable `TERMINFO`, if
`-Dcustom-terminfo-install-location` has been set. Use this if
packaging the terminfo definitions in a separate package (and the
build script isnt shared with the foot package).
Example:
@ -212,11 +223,7 @@ be built as part of the regular build process, and installed to the
specified location.
Packagers may want to set `-Dterminfo=disabled`, and manually build
and install the terminfo files instead:
```sh
tic -o <output-directory> -x -e foot,foot-direct foot.info
```
and [install the terminfo](#terminfo) files instead.
### Release build
@ -267,6 +274,32 @@ slower!) binary.
#### Performance optimized, PGO
There are a lot more steps involved in a PGO build, and for this
reason there are a number of helper scripts available.
`pgo/pgo.sh` is a standalone script that pieces together the other
scripts in the `pgo` directory to do a complete PGO build. This script
is intended to be used when doing manual builds.
Example:
```sh
cd foot
./pgo/pgo.sh auto . /tmp/foot-pgo-build-output
```
(run `./pgo/pgo.sh` to get help on usage)
It supports a couple of different PGO builds; partial (covered in
detail below), full (also covered in detail below), and (full)
headless builds using Sway or cage.
Packagers may want to use it as inspiration, but may choose to support
only a specific build type; e.g. full/headless with Sway.
To do a manual PGO build, instead of using the script(s) mentioned
above, detailed instructions follows:
First, configure the build directory:
```sh
@ -413,7 +446,8 @@ terminfo files manually instead.
To build the terminfo files, run:
```sh
tic -o <output-directory> -x -e foot,foot-direct foot.info
sed 's/@default_terminfo@/foot/g' foot.info | \
tic -o <output-directory> -x -e foot,foot-direct -
```
Where _”output-directory”_ **must** match the value passed to

View file

@ -1,3 +1,5 @@
PGO=auto # auto|none|partial|full-current-session|full-headless-sway|full-headless-cage
pkgname=('foot-git' 'foot-terminfo-git')
pkgver=1.9.0
pkgrel=1
@ -14,76 +16,7 @@ pkgver() {
}
build() {
local compiler=other
local do_pgo=no
# makepkg uses -O2 by default, but we *really* want -O3
CFLAGS+=" -O3"
# Figure out which compiler we're using, and whether or not to do PGO
case $(${CC-cc} --version) in
*GCC*)
compiler=gcc
do_pgo=yes
;;
*clang*)
compiler=clang
# We need llvm to be able to manage the profiling data
if command -v llvm-profdata > /dev/null; then
do_pgo=yes
# Meson adds -fprofile-correction, which Clang doesn't
# understand
CFLAGS+=" -Wno-ignored-optimization-argument"
fi
;;
esac
meson --prefix=/usr --buildtype=release --wrap-mode=nofallback -Db_lto=true ..
if [[ ${do_pgo} == yes ]]; then
find -name "*.gcda" -delete
meson configure -Db_pgo=generate
ninja
# If fcft/tllist are subprojects, we need to ensure their tests
# have been executed, or well get “profile count data file not
# found” errors.
ninja test
local script_options="--scroll --scroll-region --colors-regular --colors-bright --colors-256 --colors-rgb --attr-bold --attr-italic --attr-underline --sixel"
tmp_file=$(mktemp)
if [[ -v WAYLAND_DISPLAY ]]; then
./footclient --version
./foot \
--config /dev/null \
--term=xterm \
sh -c "../scripts/generate-alt-random-writes.py ${script_options} ${tmp_file} && cat ${tmp_file}"
else
./footclient --version
./foot --version
../scripts/generate-alt-random-writes.py \
--rows=67 \
--cols=135 \
${script_options} \
${tmp_file}
./pgo ${tmp_file} ${tmp_file} ${tmp_file}
fi
rm "${tmp_file}"
if [[ ${compiler} == clang ]]; then
llvm-profdata merge default_*profraw --output=default.profdata
fi
meson configure -Db_pgo=use
fi
ninja
../pgo/pgo.sh ${PGO} .. . --prefix=/usr --wrap-mode=nofallback
}
check() {
@ -98,7 +31,7 @@ package_foot-git() {
provides=('foot')
DESTDIR="${pkgdir}/" ninja install
rm -rf "${pkgdir}/usr/share/foot/terminfo"
rm -rf "${pkgdir}/usr/share/terminfo"
}
package_foot-terminfo-git() {
@ -107,6 +40,6 @@ package_foot-terminfo-git() {
conflicts=('foot-terminfo')
provides=('foot-terminfo')
install -dm 755 "${pkgdir}/usr/share/foot/terminfo/f/"
cp f/* "${pkgdir}/usr/share/foot/terminfo/f/"
install -dm 755 "${pkgdir}/usr/share/terminfo/f/"
cp f/* "${pkgdir}/usr/share/terminfo/f/"
}

View file

@ -347,12 +347,12 @@ This is not how it is meant to be. Fonts are measured in _point sizes_
all mediums, be it printers or monitors, regardless of their DPI.
Foots default behavior is to use the monitors DPI to size fonts when
output scaling has been disabled. On monitors where output scaling has
been enabled, fonts will instead be sized using the scaling
factor.
output scaling has been disabled on **all** monitors. If at least one
monitor has output scaling enabled, fonts will instead by sized using
the scaling factor.
This can be changed to either **always** use the monitors DPI
(regardless of scaling factor), or to **never** use it. See the
(regardless of scaling factor), or to **never** use it, with the
`dpi-aware` option in `foot.ini`. See the man page, **foot.ini**(5)
for more information.

View file

@ -1953,6 +1953,95 @@ draw_quadrant(struct buf *buf, wchar_t wc)
quad_lower_right(buf);
}
static void NOINLINE
draw_braille(struct buf *buf, wchar_t wc)
{
int w = min(buf->width / 4, buf->height / 8);
int x_spacing = buf->width / 4;
int y_spacing = buf->height / 8;
int x_margin = x_spacing / 2;
int y_margin = y_spacing / 2;
int x_px_left = buf->width - 2 * x_margin - x_spacing - 2 * w;
int y_px_left = buf->height - 2 * y_margin - 3 * y_spacing - 4 * w;
LOG_DBG(
"braille: before adjusting: "
"cell: %dx%d, margin=%dx%d, spacing=%dx%d, width=%d, left=%dx%d",
buf->width, buf->height, x_margin, y_margin, x_spacing, y_spacing,
w, x_px_left, y_px_left);
/* First, try hard to ensure the DOT width is non-zero */
if (x_px_left >= 2 && y_px_left >= 4 && w == 0) {
w++;
x_px_left -= 2;
y_px_left -= 4;
}
/* Second, prefer a non-zero margin */
if (x_px_left >= 2 && x_margin == 0) { x_margin = 1; x_px_left -= 2; }
if (y_px_left >= 2 && y_margin == 0) { y_margin = 1; y_px_left -= 2; }
/* Third, increase spacing */
if (x_px_left >= 1) { x_spacing++; x_px_left--; }
if (y_px_left >= 3) { y_spacing++; y_px_left -= 3; }
/* Fourth, margins (“spacing”, but on the sides) */
if (x_px_left >= 2) { x_margin++; x_px_left -= 2; }
if (y_px_left >= 2) { y_margin++; y_px_left -= 2; }
/* Last - increase dot width */
if (x_px_left >= 2 && y_px_left >= 4) {
w++;
x_px_left -= 2;
y_px_left -= 4;
}
LOG_DBG(
"braille: after adjusting: "
"cell: %dx%d, margin=%dx%d, spacing=%dx%d, width=%d, left=%dx%d",
buf->width, buf->height, x_margin, y_margin, x_spacing, y_spacing,
w, x_px_left, y_px_left);
xassert(x_px_left <= 1 || y_px_left <= 1);
xassert(2 * x_margin + 2 * w + x_spacing <= buf->width);
xassert(2 * y_margin + 4 * w + 3 * y_spacing <= buf->height);
int x[2], y[4];
x[0] = x_margin;
x[1] = x_margin + w + x_spacing;
y[0] = y_margin;
y[1] = y[0] + w + y_spacing;
y[2] = y[1] + w + y_spacing;
y[3] = y[2] + w + y_spacing;
assert(wc >= 0x2800);
assert(wc <= 0x28ff);
uint8_t sym = wc - 0x2800;
/* Left side */
if (sym & 1)
rect(x[0], y[0], x[0] + w, y[0] + w);
if (sym & 2)
rect(x[0], y[1], x[0] + w, y[1] + w);
if (sym & 4)
rect(x[0], y[2], x[0] + w, y[2] + w);
/* Right side */
if (sym & 8)
rect(x[1], y[0], x[1] + w, y[0] + w);
if (sym & 16)
rect(x[1], y[1], x[1] + w, y[1] + w);
if (sym & 32)
rect(x[1], y[2], x[1] + w, y[2] + w);
/* 8-dot patterns */
if (sym & 64)
rect(x[0], y[3], x[0] + w, y[3] + w);
if (sym & 128)
rect(x[1], y[3], x[1] + w, y[3] + w);
}
static void
sextant_upper_left(struct buf *buf)
{
@ -2653,6 +2742,8 @@ draw_glyph(struct buf *buf, wchar_t wc)
case 0x2595: draw_right_one_eighth_block(buf); break;
case 0x2596 ... 0x259f: draw_quadrant(buf, wc); break;
case 0x2800 ... 0x28ff: draw_braille(buf, wc); break;
case 0x1fb00 ... 0x1fb3b: draw_sextant(buf, wc); break;
case 0x1fb3c ... 0x1fb40:
@ -2746,8 +2837,8 @@ box_drawing(const struct terminal *term, wchar_t wc)
abort();
}
double dpi = term_font_sized_by_dpi(term, term->scale) ? term->font_dpi : 96.;
double scale = term_font_sized_by_scale(term, term->scale) ? term->scale : 1.;
double dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.;
double scale = term->font_is_sized_by_dpi ? 1. : term->scale;
double cell_size = sqrt(pow(term->cell_width, 2) + pow(term->cell_height, 2));
int base_thickness =
@ -2798,8 +2889,7 @@ box_drawing(const struct terminal *term, wchar_t wc)
},
};
LOG_DBG("LIGHT=%d, HEAVY=%d",
_thickness(&buf, LIGHT), _thickness(&buf, HEAVY));
LOG_DBG("LIGHT=%d, HEAVY=%d", buf.thickness[LIGHT], buf.thickness[HEAVY]);
draw_glyph(&buf, wc);

View file

@ -54,27 +54,29 @@ version_and_features(void)
static void
print_usage(const char *prog_name)
{
static const char options[] =
"\nOptions:\n"
" -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"
" -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"
" -F,--fullscreen start in fullscreen mode\n"
" -L,--login-shell start shell as a login shell\n"
" -D,--working-directory=DIR directory to start in (CWD)\n"
" -s,--server-socket=PATH path to the server UNIX domain socket (default=$XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock)\n"
" -H,--hold remain open after child process exits\n"
" -N,--no-wait detach the client process from the running terminal, exiting immediately\n"
" -o,--override=[section.]key=value override configuration option\n"
" -d,--log-level={info|warning|error|none} log level (info)\n"
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
" -v,--version show the version number and quit\n"
" -e ignored (for compatibility with xterm -e)\n";
printf("Usage: %s [OPTIONS...]\n", prog_name);
printf("Usage: %s [OPTIONS...] command [ARGS...]\n", prog_name);
printf("\n");
printf("Options:\n");
printf(" -t,--term=TERM value to set the environment variable TERM to (%s)\n"
" -T,--title=TITLE initial window title (foot)\n"
" -a,--app-id=ID window application ID (foot)\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"
" -F,--fullscreen start in fullscreen mode\n"
" -L,--login-shell start shell as a login shell\n"
" -D,--working-directory=DIR directory to start in (CWD)\n"
" -s,--server-socket=PATH path to the server UNIX domain socket (default=$XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock)\n"
" -H,--hold remain open after child process exits\n"
" -N,--no-wait detach the client process from the running terminal, exiting immediately\n"
" -o,--override=[section.]key=value override configuration option\n"
" -d,--log-level={info|warning|error|none} log level (info)\n"
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
" -v,--version show the version number and quit\n",
FOOT_DEFAULT_TERM);
puts(options);
}
static bool NOINLINE
@ -144,7 +146,7 @@ main(int argc, char *const *argv)
struct client_string *cargv = NULL;
while (true) {
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNo:d:l::vh", longopts, NULL);
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNo:d:l::veh", longopts, NULL);
if (c == -1)
break;
@ -272,6 +274,9 @@ main(int argc, char *const *argv)
ret = EXIT_SUCCESS;
goto err;
case 'e':
break;
case '?':
goto err;
}

131
config.c
View file

@ -31,7 +31,19 @@
static const uint32_t default_foreground = 0xdcdccc;
static const uint32_t default_background = 0x111111;
static const uint32_t default_regular[] = {
#define cube6(r, g) \
r|g|0x00, r|g|0x5f, r|g|0x87, r|g|0xaf, r|g|0xd7, r|g|0xff
#define cube36(r) \
cube6(r, 0x0000), \
cube6(r, 0x5f00), \
cube6(r, 0x8700), \
cube6(r, 0xaf00), \
cube6(r, 0xd700), \
cube6(r, 0xff00)
static const uint32_t default_color_table[256] = {
// Regular
0x222222,
0xcc9393,
0x7f9f7f,
@ -40,9 +52,8 @@ static const uint32_t default_regular[] = {
0xdc8cc3,
0x93e0e3,
0xdcdccc,
};
static const uint32_t default_bright[] = {
// Bright
0x666666,
0xdca3a3,
0xbfebbf,
@ -51,6 +62,24 @@ static const uint32_t default_bright[] = {
0xfcace3,
0xb3ffff,
0xffffff,
// 6x6x6 RGB cube
// (color channels = i ? i*40+55 : 0, where i = 0..5)
cube36(0x000000),
cube36(0x5f0000),
cube36(0x870000),
cube36(0xaf0000),
cube36(0xd70000),
cube36(0xff0000),
// 24 shades of gray
// (color channels = i*10+8, where i = 0..23)
0x080808, 0x121212, 0x1c1c1c, 0x262626,
0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
0x585858, 0x626262, 0x6c6c6c, 0x767676,
0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6,
0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee
};
static const char *const binding_action_map[] = {
@ -2452,6 +2481,9 @@ parse_section_tweak(
conf->tweak.box_drawing_solid_shades ? "yes" : "no");
}
else if (strcmp(key, "font-monospace-warn") == 0)
conf->tweak.font_monospace_warn = str_to_bool(value);
else {
LOG_AND_NOTIFY_ERR("%s:%u: [tweak]: %s: invalid key", path, lineno, key);
return false;
@ -2884,25 +2916,6 @@ config_load(struct config *conf, const char *conf_path,
.colors = {
.fg = default_foreground,
.bg = default_background,
.table = {
default_regular[0],
default_regular[1],
default_regular[2],
default_regular[3],
default_regular[4],
default_regular[5],
default_regular[6],
default_regular[7],
default_bright[0],
default_bright[1],
default_bright[2],
default_bright[3],
default_bright[4],
default_bright[5],
default_bright[6],
default_bright[7],
},
.alpha = 0xffff,
.selection_fg = 0x80000000, /* Use default bg */
.selection_bg = 0x80000000, /* Use default fg */
@ -2957,35 +2970,13 @@ config_load(struct config *conf, const char *conf_path,
.damage_whole_window = false,
.box_drawing_base_thickness = 0.04,
.box_drawing_solid_shades = true,
.font_monospace_warn = true,
},
.notifications = tll_init(),
};
/* Initialize the color cube */
{
/* First 16 entries correspond to the "regular" and "bright"
* colors, and have already been initialized */
/* Then follows 216 RGB shades */
for (size_t r = 0; r < 6; r++) {
for (size_t g = 0; g < 6; g++) {
for (size_t b = 0; b < 6; b++) {
uint8_t red = r ? r * 40 + 55 : 0;
uint8_t green = g ? g * 40 + 55 : 0;
uint8_t blue = b ? b * 40 + 55 : 0;
conf->colors.table[16 + r * 6 * 6 + g * 6 + b]
= red << 16 | green << 8 | blue << 0;
}
}
}
/* And finally 24 shades of gray */
for (size_t i = 0; i < 24; i++) {
uint8_t level = i * 10 + 8;
conf->colors.table[232 + i] = level << 16 | level << 8 | level << 0;
}
}
memcpy(conf->colors.table, default_color_table, sizeof(default_color_table));
tokenize_cmdline("notify-send -a ${app-id} -i ${app-id} ${title} ${body}",
&conf->notify.argv.args);
@ -3356,3 +3347,51 @@ config_font_list_destroy(struct config_font_list *font_list)
font_list->count = 0;
font_list->arr = NULL;
}
bool
check_if_font_is_monospaced(const char *pattern,
user_notifications_t *notifications)
{
struct fcft_font *f = fcft_from_name(
1, (const char *[]){pattern}, ":size=8");
if (f == NULL)
return true;
static const wchar_t chars[] = {L'a', L'i', L'l', L'M', L'W'};
bool is_monospaced = true;
int last_width = -1;
for (size_t i = 0; i < sizeof(chars) / sizeof(chars[0]); i++) {
const struct fcft_glyph *g = fcft_glyph_rasterize(
f, chars[i], FCFT_SUBPIXEL_NONE);
if (g == NULL)
continue;
if (last_width >= 0 && g->advance.x != last_width) {
LOG_WARN("%s: font does not appear to be monospace; "
"check your config, or disable this warning by "
"setting [tweak].font-monospace-warn=no",
pattern);
user_notification_add(
notifications,
USER_NOTIFICATION_WARNING,
"%s: font does not appear to be monospace; "
"check your config, or disable this warning by "
"setting \033[1m[tweak].font-monospace-warn=no\033[22m",
pattern);
is_monospaced = false;
break;
}
last_width = g->advance.x;
}
fcft_destroy(f);
return is_monospaced;
}

View file

@ -70,7 +70,6 @@ struct config {
char *app_id;
wchar_t *word_delimiters;
bool login_shell;
bool no_wait;
bool locked_title;
struct {
@ -253,6 +252,7 @@ struct config {
off_t max_shm_pool_size;
float box_drawing_base_thickness;
bool box_drawing_solid_shades;
bool font_monospace_warn;
} tweak;
user_notifications_t notifications;
@ -269,3 +269,6 @@ struct config *config_clone(const struct config *old);
bool config_font_parse(const char *pattern, struct config_font *font);
void config_font_list_destroy(struct config_font_list *font_list);
bool check_if_font_is_monospaced(
const char *pattern, user_notifications_t *notifications);

45
csi.c
View file

@ -795,8 +795,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
*
* Note: tertiary DA responds with "FOOT".
*/
const char *reply = "\033[?62;4;22c";
term_to_slave(term, reply, strlen(reply));
static const char reply[] = "\033[?62;4;22c";
term_to_slave(term, reply, sizeof(reply) - 1);
break;
}
@ -1062,17 +1062,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
}
case 'S': {
int amount = min(
vt_param_get(term, 0, 1),
term->scroll_region.end - term->scroll_region.start);
const struct scroll_region *r = &term->scroll_region;
int amount = min(vt_param_get(term, 0, 1), r->end - r->start);
term_scroll(term, amount);
break;
}
case 'T': {
int amount = min(
vt_param_get(term, 0, 1),
term->scroll_region.end - term->scroll_region.start);
const struct scroll_region *r = &term->scroll_region;
int amount = min(vt_param_get(term, 0, 1), r->end - r->start);
term_scroll_reverse(term, amount);
break;
}
@ -1219,20 +1217,12 @@ csi_dispatch(struct terminal *term, uint8_t final)
break;
case 13: { /* report window position */
int x = -1;
int y = -1;
/* We don't know our position - always report (0,0) */
static const char reply[] = "\033[3;0;0t";
switch (vt_param_get(term, 1, 0)) {
case 0:
/* window position */
x = y = 0;
break;
case 2:
/* text area position */
x = y = 0;
case 0: /* window position */
case 2: /* text area position */
term_to_slave(term, reply, sizeof(reply) - 1);
break;
default:
@ -1240,12 +1230,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
break;
}
if (x >= 0 && y >= 0) {
char reply[64];
size_t n = xsnprintf(reply, sizeof(reply), "\033[3;%d;%dt",
x / term->scale, y / term->scale);
term_to_slave(term, reply, n);
}
break;
}
@ -1616,15 +1600,12 @@ csi_dispatch(struct terminal *term, uint8_t final)
}
case '!': {
switch (final) {
case 'p':
if (final == 'p') {
term_reset(term, false);
break;
default:
UNHANDLED();
break;
}
UNHANDLED();
break; /* private[0] == '!' */
}

View file

@ -141,6 +141,16 @@ the foot command line
*-v*,*--version*
Show the version number and quit.
*-e*
Ignored; for compatibility with *xterm -e*.
This option was added in response to several program launchers
passing *-e* to arbitrary terminals, under the assumption that
they all implement the same semantics for it as *xterm*(1).
Ignoring it allows foot to be invoked as e.g. *foot -e man foot*
with the same results as with xterm, instead of producing an
"invalid option" error.
# EXIT STATUS
Foot will exit with code 230 if there is a failure in foot itself.
@ -402,29 +412,6 @@ The following environment variables are set in the child process:
set according to either the *--term* command-line option or the
*term* config option in *foot.ini*(5).
*TERMINFO*
Path to foot's terminfo definitions. These are typically installed
in a non-standard location (though distributions may override
this), to allow them to co-exist with the foot terminfo
definitions in ncurses. Note that applications will search the
default location(s) if *TERM* does not exist in *TERMINFO*.
Note that applications like sudo and ssh will remove this
environment variable.
For sudo, you can create a file under _/etc/sudoers.d_ (name does
not matter) with the following content:
*Defaults env_keep += "TERMINFO"*
For ssh, you can edit _/etc/ssh/sshd_config_ (on the *server*),
and add:
*SetEnv TERMINFO=*_<path>_
Where path is the location of the terminfo definitions on the
*server*, typically /usr/share/foot/terminfo.
*COLORTERM*
This variable is set to *truecolor*, to indicate to client
applications that 24-bit RGB colors are supported.

View file

@ -6,8 +6,9 @@ foot.ini - configuration file for *foot*(1)
# DESCRIPTION
*foot* uses the standard _unix configuration format_, with section based
key/value pairs. The default section is unnamed (i.e. not prefixed
with a _[section]_).
key/value pairs. The default section is usually unnamed, i.e. not prefixed
with a _[section]_. However it can also be explicitly named _[main]_,
say if it needs to be reopened after any of the other sections.
foot will search for a configuration file in the following locations,
in this order:
@ -16,7 +17,7 @@ in this order:
- *~/.config/foot/foot.ini*
- *XDG_CONFIG_DIRS/foot/foot.ini*
# SECTION: default
# SECTION: main
*shell*
Executable to launch. Typically a shell. Default: _$SHELL_ if set,
@ -36,7 +37,8 @@ in this order:
Comma separated list of fonts to use, in fontconfig format. That
is, a font name followed by a list of colon-separated
options. Most noteworthy is *:size=n*, which is used to set the
font size.
font size. Note that the font size is also affected by the
*dpi-aware* option.
Examples:
- Dina:weight=bold:slant=italic
@ -144,11 +146,12 @@ in this order:
Default: _no_.
*dpi-aware*
*auto*, *yes*, or *no*. When set to *yes*, fonts are sized using
the monitor's DPI, making a font of a given size have the same
physical size, regardless of monitor. In other words, if you drag
a foot window between different monitors, the font size remains
the same.
*auto*, *yes*, or *no*.
When set to *yes*, fonts are sized using the monitor's DPI, making
a font of a given size have the same physical size, regardless of
monitor. In other words, if you drag a foot window between
different monitors, the font size remains the same.
In this mode, the monitor's scaling factor is ignored; doubling
the scaling factor will *not* double the font size.
@ -158,8 +161,22 @@ in this order:
scaling factor *does* double the font size.
Finally, if set to *auto*, fonts will be sized using the monitor's
DPI on monitors with a scaling factor of 1, but otherwise using
the scaling factor.
DPI if _all_ monitors have a scaling factor of 1. If at least one
monitor as a scaling factor larger than 1 (regardless of whether
the foot window is mapped on that monitor or not), fonts will be
scaled using the scaling factor.
Note that this option typically does not work with bitmap fonts,
which only contains a pre-defined set of sizes, and cannot be
dynamically scaled. Whichever size (of the available ones) that
best matches the DPI or scaling factor, will be used.
Also note that if the font size has been specified in pixels
(*:pixelsize=*_N_, instead of *:size=*_N_), DPI scaling
(*dpi-aware=yes*) will have no effect (the specified pixel size
will be used as is). But, if the monitor's scaling factor is used
to size the font (*dpi-aware=no*), the font's pixel size will be
multiplied with the scaling factor.
Default: _auto_
@ -179,7 +196,7 @@ in this order:
Default: _2x2_.
*resize-delay-ms*
Time, in milliseconds, of "idle time" "before foot sends the new
Time, in milliseconds, of "idle time" before foot sends the new
window dimensions to the client application while doing an
interactive resize of a foot window. Idle time in this context is
a period of time where the window size is not changing.
@ -1022,6 +1039,17 @@ any of these options.
Default: _double-width_
*font-monospace-warn*
Boolean. When enabled, foot will use heuristics to try to verify
the primary font is a monospace font, and warn if it is not.
Disable this if you still want to use the font, even if foot
thinks it is not monospaced.
You may also want to disable it to get slightly faster startup times.
Default: _yes_
*max-shm-pool-size-mb*
This option controls the amount of virtual address space used by
the pixmap memory to which the terminal screen content is

View file

@ -79,6 +79,10 @@ terminal has terminated.
*-v*,*--version*
Show the version number and quit
*-e*
Ignored; for compatibility with *xterm -e*. See *foot*(1) for more
details.
# EXIT STATUS
Footlient will exit with code 220 if there is a failure in footclient
@ -146,29 +150,6 @@ The following environment variables are set in the child process:
set according to either the *--term* command-line option or the
*term* config option in *foot.ini*(5).
*TERMINFO*
Path to foot's terminfo definitions. These are typically installed
in a non-standard location (though distributions may override
this), to allow them to co-exist with the foot terminfo
definitions in ncurses. Note that applications will search the
default location(s) if *TERM* does not exist in *TERMINFO*.
Note that applications like sudo and ssh will remove this
environment variable.
For sudo, you can create a file under _/etc/sudoers.d_ (name does
not matter) with the following content:
*Defaults env_keep += "TERMINFO"*
For ssh, you can edit _/etc/ssh/sshd_config_ (on the *server*),
and add:
*SetEnv TERMINFO=*_<path>_
Where path is the location of the terminfo definitions on the
*server*, typically /usr/share/foot/terminfo.
*COLORTERM*
This variable is set to *truecolor*, to indicate to client
applications that 24-bit RGB colors are supported.

View file

@ -1,17 +1,17 @@
foot|foot terminal emulator,
use=foot+base,
@default_terminfo@|foot terminal emulator,
use=@default_terminfo@+base,
colors#256,
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48\:5\:%p1%d%;m,
setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38\:5\:%p1%d%;m,
foot-direct|foot with direct color indexing,
use=foot+base,
@default_terminfo@-direct|foot with direct color indexing,
use=@default_terminfo@+base,
colors#16777216,
RGB,
setab=\E[%?%p1%{8}%<%t4%p1%d%e48\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
setaf=\E[%?%p1%{8}%<%t3%p1%d%e38\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
foot+base|foot base fragment,
@default_terminfo@+base|foot base fragment,
am,
bce,
bw,

102
input.c
View file

@ -1694,50 +1694,6 @@ fdm_csd_move(struct fdm *fdm, int fd, int events, void *data)
struct wl_window *win = seat->mouse_focus->window;
/*
* Workaround GNOME bug
*
* Dragging the window, then stopping the drag (releasing the
* mouse button), *without* moving the mouse, and then clicking
* twice, waiting for the CSD timer, and finally clicking once
* more, results in the following sequence (keyboard and other
* irrelevant events filtered out, unless theyre needed to prove
* a point):
*
* dbg: input.c:1551: cancelling drag timer, moving window
* dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=873, surface=0x6070000036d0
* dbg: input.c:1432: seat0: pointer-leave: pointer=0x607000003660, serial=874, surface = 0x6070000396e0, old-moused = 0x622000006100
*
* --> drag stopped here
*
* --> LMB clicked first time after the drag (generates the enter event on *release*, but no button events)
* dbg: input.c:1360: pointer-enter: pointer=0x607000003660, serial=876, surface = 0x6070000396e0, new-moused = 0x622000006100
*
* --> LMB clicked, and held until the timer times out, second time after the drag
* dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=877, button=110, state=1
* dbg: input.c:1806: starting move timer
* dbg: input.c:1692: move timer timed out
* dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=878, surface=0x6070000036d0
*
* --> NOTE: ^^ no pointer leave event this time, only the keyboard leave
*
* --> LMB clicked one last time
* dbg: input.c:697: seat0: keyboard_enter: keyboard=0x607000003580, serial=879, surface=0x6070000036d0
* dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=880, button=110, state=1
* err: input.c:1741: BUG in wl_pointer_button(): assertion failed: 'it->item.button != button'
*
* What are we seeing?
*
* - GNOME does *not* send a pointer *enter* event after the drag
* has stopped
* - The second drag does *not* generate a pointer *leave* event
* - The missing leave event means were still tracking LMB as
* being held down in our seat struct.
* - This leads to an assert (debug builds) when LMB is clicked
* again (seats button list already contains LMB).
*/
tll_free(seat->mouse.buttons);
win->csd.move_timeout_fd = -1;
xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
return true;
@ -1774,6 +1730,62 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
} else
seat->mouse.count = 1;
/*
* Workaround GNOME bug
*
* Dragging the window, then stopping the drag (releasing the
* mouse button), *without* moving the mouse, and then
* clicking twice, waiting for the CSD timer, and finally
* clicking once more, results in the following sequence
* (keyboard and other irrelevant events filtered out, unless
* theyre needed to prove a point):
*
* dbg: input.c:1551: cancelling drag timer, moving window
* dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=873, surface=0x6070000036d0
* dbg: input.c:1432: seat0: pointer-leave: pointer=0x607000003660, serial=874, surface = 0x6070000396e0, old-moused = 0x622000006100
*
* --> drag stopped here
*
* --> LMB clicked first time after the drag (generates the
* enter event on *release*, but no button events)
* dbg: input.c:1360: pointer-enter: pointer=0x607000003660, serial=876, surface = 0x6070000396e0, new-moused = 0x622000006100
*
* --> LMB clicked, and held until the timer times out, second
* time after the drag
* dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=877, button=110, state=1
* dbg: input.c:1806: starting move timer
* dbg: input.c:1692: move timer timed out
* dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=878, surface=0x6070000036d0
*
* --> NOTE: ^^ no pointer leave event this time, only the
* keyboard leave
*
* --> LMB clicked one last time
* dbg: input.c:697: seat0: keyboard_enter: keyboard=0x607000003580, serial=879, surface=0x6070000036d0
* dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=880, button=110, state=1
* err: input.c:1741: BUG in wl_pointer_button(): assertion failed: 'it->item.button != button'
*
* What are we seeing?
*
* - GNOME does *not* send a pointer *enter* event after the drag
* has stopped
* - The second drag does *not* generate a pointer *leave* event
* - The missing leave event means were still tracking LMB as
* being held down in our seat struct.
* - This leads to an assert (debug builds) when LMB is clicked
* again (seats button list already contains LMB).
*
* Note: Ive also observed variants of the above
*/
tll_foreach(seat->mouse.buttons, it) {
if (it->item.button == button) {
LOG_WARN("multiple button press events for button %d "
"(compositor bug?)", button);
tll_remove(seat->mouse.buttons, it);
break;
}
}
#if defined(_DEBUG)
tll_foreach(seat->mouse.buttons, it)
xassert(it->item.button != button);
@ -1817,7 +1829,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
* 4. Release mouse button
* 5. BAM!
*/
LOG_WARN("stray button release event");
LOG_WARN("stray button release event (compositor bug?)");
return;
}

2
log.c
View file

@ -40,7 +40,7 @@ log_init(enum log_colorize _colorize, bool _do_syslog,
[LOG_FACILITY_DAEMON] = LOG_DAEMON,
};
colorize = _colorize == LOG_COLORIZE_NEVER ? false : _colorize == LOG_COLORIZE_ALWAYS ? true : isatty(STDERR_FILENO);
colorize = _colorize == LOG_COLORIZE_ALWAYS || (_colorize == LOG_COLORIZE_AUTO && isatty(STDERR_FILENO));
do_syslog = _do_syslog;
log_level = _log_level;

27
main.c
View file

@ -56,16 +56,13 @@ version_and_features(void)
static void
print_usage(const char *prog_name)
{
printf(
"Usage: %s [OPTIONS...]\n"
"Usage: %s [OPTIONS...] command [ARGS...]\n"
"\n"
"Options:\n"
static const char options[] =
"\nOptions:\n"
" -c,--config=PATH load configuration from PATH ($XDG_CONFIG_HOME/foot/foot.ini)\n"
" -C,--check-config verify configuration, exit with 0 if ok, otherwise exit with 1\n"
" -o,--override=[section.]key=value override configuration option\n"
" -f,--font=FONT comma separated list of fonts in fontconfig format (monospace)\n"
" -t,--term=TERM value to set the environment variable TERM to (%s)\n"
" -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"
" -m,--maximized start in maximized mode\n"
@ -81,8 +78,12 @@ print_usage(const char *prog_name)
" -d,--log-level={info|warning|error|none} log level (info)\n"
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
" -s,--log-no-syslog disable syslog logging (only applicable in server mode)\n"
" -v,--version show the version number and quit\n",
prog_name, prog_name, FOOT_DEFAULT_TERM);
" -v,--version show the version number and quit\n"
" -e ignored (for compatibility with xterm -e)\n";
printf("Usage: %s [OPTIONS...]\n", prog_name);
printf("Usage: %s [OPTIONS...] command [ARGS...]\n", prog_name);
puts(options);
}
bool
@ -216,7 +217,7 @@ main(int argc, char *const *argv)
config_override_t overrides = tll_init();
while (true) {
int c = getopt_long(argc, argv, "+c:Co:t:T:a:LD:f:w:W:s::HmFPp:d:l::Svh", longopts, NULL);
int c = getopt_long(argc, argv, "+c:Co:t:T:a:LD:f:w:W:s::HmFPp:d:l::Sveh", longopts, NULL);
if (c == -1)
break;
@ -375,6 +376,9 @@ main(int argc, char *const *argv)
print_usage(prog_name);
return EXIT_SUCCESS;
case 'e':
break;
case '?':
return ret;
}
@ -480,6 +484,11 @@ main(int argc, char *const *argv)
conf.presentation_timings = presentation_timings;
conf.hold_at_exit = hold;
if (conf.tweak.font_monospace_warn && conf.fonts[0].count > 0) {
check_if_font_is_monospaced(
conf.fonts[0].arr[0].pattern, &conf.notifications);
}
struct fdm *fdm = NULL;
struct reaper *reaper = NULL;
struct wayland *wayl = NULL;

View file

@ -35,17 +35,15 @@ add_project_arguments(
language: 'c',
)
default_terminfo_install_location = join_paths(get_option('datadir'), 'foot', 'terminfo')
terminfo_install_location = get_option('custom-terminfo-install-location')
if terminfo_install_location == ''
terminfo_install_location = default_terminfo_install_location
endif
if terminfo_install_location != 'no'
if terminfo_install_location != ''
add_project_arguments(
['-DFOOT_TERMINFO_PATH="@0@"'.format(
join_paths(get_option('prefix'), terminfo_install_location))],
language: 'c')
else
terminfo_install_location = join_paths(get_option('datadir'), 'terminfo')
endif
# Compute the relative path used by compiler invocations.
@ -246,15 +244,24 @@ endif
tic = find_program('tic', native: true, required: get_option('terminfo'))
if tic.found()
conf_data = configuration_data(
{
'default_terminfo': get_option('default-terminfo'),
}
)
preprocessed = configure_file(
input: 'foot.info',
output: 'foot.info.preprocessed',
configuration: conf_data,
)
custom_target(
'terminfo',
output: 'f',
input: 'foot.info',
command: [tic, '-x', '-o', '@OUTDIR@', '-e', 'foot,foot-direct', '@INPUT@'],
output: get_option('default-terminfo')[0],
input: preprocessed,
command: [tic, '-x', '-o', '@OUTDIR@', '-e', '@0@,@0@-direct'.format(get_option('default-terminfo')), '@INPUT@'],
install: true,
install_dir: (terminfo_install_location != 'no'
? terminfo_install_location
: default_terminfo_install_location)
install_dir: terminfo_install_location
)
endif
@ -267,8 +274,9 @@ summary(
'IME': get_option('ime'),
'Grapheme clustering': utf8proc.found(),
'Build terminfo': tic.found(),
'Terminfo install location': terminfo_install_location,
'Default TERM': get_option('default-terminfo'),
'Terminfo custom install location': terminfo_install_location,
'Set TERMINFO': get_option('custom-terminfo-install-location') != '',
},
bool_yn: true
)

View file

@ -11,5 +11,5 @@ option('terminfo', type: 'feature', value: 'enabled', description: 'Build and in
option('default-terminfo', type: 'string', value: 'foot',
description: 'Default value of the "term" option in foot.ini.')
option('custom-terminfo-install-location', type: 'string',
description: 'Path to foot\'s terminfo, relative to ${prefix}. If set to anything but “no“, foot will set TERMINFO to this value in the client process.')
option('custom-terminfo-install-location', type: 'string', value: '',
description: 'Path to foot\'s terminfo, relative to ${prefix}. If set, foot will set $TERMINFO to this value in the client process.')

8
pgo/full-current-session.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
set -eux
srcdir=$(realpath "${1}")
blddir=$(realpath "${2}")
"${srcdir}"/pgo/full-inner.sh "${srcdir}" "${blddir}"

14
pgo/full-headless-cage.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
set -eux
srcdir=$(realpath "${1}")
blddir=$(realpath "${2}")
runtime_dir=$(mktemp -d)
trap "rm -rf '${runtime_dir}'" EXIT INT HUP TERM
XDG_RUNTIME_DIR="${runtime_dir}" WLR_BACKENDS=headless cage "${srcdir}"/pgo/full-inner.sh "${srcdir}" "${blddir}"
# Cages exit code doesnt reflect our scripts exit code
[ -f "${blddir}"/pgo-ok ] || exit 1

View file

@ -0,0 +1,9 @@
#!/bin/sh
set -ux
srcdir=$(realpath "${1}")
blddir=$(realpath "${2}")
"${srcdir}"/pgo/full-inner.sh "${srcdir}" "${blddir}"
swaymsg exit

24
pgo/full-headless-sway.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bin/sh
set -eux
srcdir=$(realpath "${1}")
blddir=$(realpath "${2}")
runtime_dir=$(mktemp -d)
sway_conf=$(mktemp)
cleanup() {
rm -f "${sway_conf}"
rm -rf "${runtime_dir}"
}
trap cleanup EXIT INT HUP TERM
# Generate a custom config that executes our generate-pgo-data script
> "${sway_conf}" echo "exec '${srcdir}'/pgo/full-headless-sway-inner.sh '${srcdir}' '${blddir}'"
# Run Sway. full-headless-sway-inner.sh ends with a swaymsg exit
XDG_RUNTIME_DIR="${runtime_dir}" WLR_BACKENDS=headless sway -c "${sway_conf}"
# Sways exit code doesnt reflect our scripts exit code
[ -f "${blddir}"/pgo-ok ] || exit 1

30
pgo/full-inner.sh Executable file
View file

@ -0,0 +1,30 @@
#!/bin/sh
set -eux
srcdir=$(realpath "${1}")
blddir=$(realpath "${2}")
. "${srcdir}"/pgo/options
pgo_data=$(mktemp)
trap "rm -f '${pgo_data}'" EXIT INT HUP TERM
rm -f "${blddir}"/pgo-ok
# To ensure profiling data is generated in the build directory
cd "${blddir}"
LC_CTYPE=en_US.UTF-8 "${blddir}"/footclient --version
LC_CTYPE=en_US.UTF-8 "${blddir}"/foot \
--config=/dev/null \
--term=xterm \
sh -c "
set -eux
'${srcdir}/scripts/generate-alt-random-writes.py' \
${script_options} \"${pgo_data}\"
cat \"${pgo_data}\"
"
touch "${blddir}"/pgo-ok

1
pgo/options Normal file
View file

@ -0,0 +1 @@
script_options="--scroll --scroll-region --colors-regular --colors-bright --colors-256 --colors-rgb --attr-bold --attr-italic --attr-underline --sixel"

28
pgo/partial.sh Executable file
View file

@ -0,0 +1,28 @@
#!/bin/sh
set -eux
srcdir=$(realpath "${1}")
blddir=$(realpath "${2}")
. "${srcdir}"/pgo/options
pgo_data=$(mktemp)
trap "rm -f ${pgo_data}" EXIT INT HUP TERM
rm -f "${blddir}"/pgo-ok
"${srcdir}"/scripts/generate-alt-random-writes.py \
--rows=67 \
--cols=135 \
${script_options} \
"${pgo_data}"
# To ensure profiling data is generated in the build directory
cd "${blddir}"
"${blddir}"/footclient --version
"${blddir}"/foot --version
"${blddir}"/pgo "${pgo_data}"
touch "${blddir}"/pgo-ok

112
pgo/pgo.sh Executable file
View file

@ -0,0 +1,112 @@
#!/bin/sh
set -eu
usage_and_die() {
echo "Usage: ${0} none|partial|full-current-session|full-headless-sway|full-headless-cage|[auto] <source-dir> <build-dir> [meson options]"
exit 1
}
[ ${#} -ge 3 ] || usage_and_die
mode=${1}
srcdir=$(realpath "${2}")
blddir=$(realpath "${3}")
shift 3
# if [ -e "${blddir}" ]; then
# echo "error: ${blddir}: build directory already exists"
# exit 1
# fi
compiler=other
do_pgo=no
CFLAGS="${CFLAGS-} -O3"
case $(${CC-cc} --version) in
*GCC*)
compiler=gcc
do_pgo=yes
;;
*clang*)
compiler=clang
if command -v llvm-profdata > /dev/null; then
do_pgo=yes
CFLAGS="${CFLAGS} -Wno-ignored-optimization-argument"
fi
;;
esac
case ${mode} in
partial|full-current-session|full-headless-sway|full-headless-cage)
;;
none)
do_pgo=no
;;
auto)
# TODO: once Sway 1.6.2 has been released, prefer
# full-headless-sway
if [ -n "${WAYLAND_DISPLAY+x}" ]; then
mode=full-current-session
# elif command -v sway > /dev/null; then # Requires 1.6.2
# mode=full-headless-sway
elif command -v cage > /dev/null; then
mode=full-headless-cage
else
mode=partial
fi
;;
*)
usage_and_die
;;
esac
set -x
# echo "source: ${srcdir}"
# echo "build: ${blddir}"
# echo "compiler: ${compiler}"
# echo "mode: ${mode}"
# echo "CFLAGS: ${CFLAGS}"
export CFLAGS
meson setup --buildtype=release -Db_lto=true "${@}" "${blddir}" "${srcdir}"
if [ ${do_pgo} = yes ]; then
find "${blddir}" \
'(' \
-name "*.gcda" -o \
-name "*.profraw" -o \
-name default.profdata \
')' \
-delete
meson configure "${blddir}" -Db_pgo=generate
ninja -C "${blddir}"
# If fcft/tllist are subprojects, we need to ensure their tests
# have been executed, or well get “profile count data file not
# found” errors.
ninja -C "${blddir}" test
# Run mode-dependent script to generate profiling data
"${srcdir}"/pgo/${mode}.sh "${srcdir}" "${blddir}"
if [ ${compiler} = clang ]; then
llvm-profdata \
merge \
"${blddir}"/default_*.profraw \
--output="${blddir}"/default.profdata
fi
meson configure "${blddir}" -Db_pgo=use
fi
ninja -C "${blddir}"

View file

@ -513,7 +513,12 @@ render_cell(struct terminal *term, pixman_image_t *pix,
if (base != 0) {
if (unlikely(
/* Classic box drawings */
(base >= 0x2500 && base <= 0x259f) ||
(base >= GLYPH_BOX_DRAWING_FIRST &&
base <= GLYPH_BOX_DRAWING_LAST) ||
/* Braille */
(base >= GLYPH_BRAILLE_FIRST &&
base <= GLYPH_BRAILLE_LAST) ||
/*
* Unicode 13 "Symbols for Legacy Computing"
@ -521,38 +526,50 @@ render_cell(struct terminal *term, pixman_image_t *pix,
*
* Note, the full range is U+1FB00 - U+1FBF9
*/
/* Unicode 13 sextants */
(base >= 0x1fb00 && base <= 0x1fb8b) ||
(base >= 0x1fb9a && base <= 0x1fb9b)) &&
(base >= GLYPH_LEGACY_FIRST &&
base <= GLYPH_LEGACY_LAST)) &&
likely(!term->conf->box_drawings_uses_font_glyphs))
{
/* Box drawing characters */
size_t idx = base >= 0x1fb00
? (base >= 0x1fb9a
? base - 0x1fb9a + 300
: base - 0x1fb00 + 160)
: base - 0x2500;
xassert(idx < ALEN(term->box_drawing));
struct fcft_glyph ***arr;
size_t count;
size_t idx;
if (likely(term->box_drawing[idx] != NULL))
single = term->box_drawing[idx];
if (base >= GLYPH_LEGACY_FIRST) {
arr = &term->custom_glyphs.legacy;
count = GLYPH_LEGACY_COUNT;
idx = base - GLYPH_LEGACY_FIRST;
} else if (base >= GLYPH_BRAILLE_FIRST) {
arr = &term->custom_glyphs.braille;
count = GLYPH_BRAILLE_COUNT;
idx = base - GLYPH_BRAILLE_FIRST;
} else {
arr = &term->custom_glyphs.box_drawing;
count = GLYPH_BOX_DRAWING_COUNT;
idx = base - GLYPH_BOX_DRAWING_FIRST;
}
if (unlikely(*arr == NULL))
*arr = xcalloc(count, sizeof((*arr)[0]));
if (likely((*arr)[idx] != NULL))
single = (*arr)[idx];
else {
mtx_lock(&term->render.workers.lock);
/* Parallel thread may have instantiated it while we took the lock */
if (term->box_drawing[idx] == NULL)
term->box_drawing[idx] = box_drawing(term, base);
/* Other thread may have instantiated it while we
* acquired the lock */
single = (*arr)[idx];
if (likely(single == NULL))
single = (*arr)[idx] = box_drawing(term, base);
mtx_unlock(&term->render.workers.lock);
single = term->box_drawing[idx];
xassert(single != NULL);
}
glyph_count = 1;
glyphs = &single;
cell_cols = single->cols;
if (single != NULL) {
glyph_count = 1;
glyphs = &single;
cell_cols = single->cols;
}
}
else if (base >= CELL_COMB_CHARS_LO && base <= CELL_COMB_CHARS_HI)
@ -624,6 +641,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
&clip, x, y,
render_width, term->cell_height);
pixman_image_set_clip_region32(pix, &clip);
pixman_region32_fini(&clip);
/* Background */
pixman_image_fill_rectangles(

View file

@ -378,6 +378,50 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
}
}
void
selection_find_line_boundary_left(struct terminal *term, struct coord *pos,
bool spaces_only)
{
int next_row = pos->row;
pos->col = 0;
while (true) {
if (--next_row < 0)
return;
const struct row *row = grid_row_in_view(term->grid, next_row);
assert(row != NULL);
if (row->linebreak)
return;
pos->col = 0;
pos->row = next_row;
}
}
void
selection_find_line_boundary_right(struct terminal *term, struct coord *pos,
bool spaces_only)
{
int next_row = pos->row;
pos->col = term->cols - 1;
while (true) {
const struct row *row = grid_row_in_view(term->grid, next_row);
assert(row != NULL);
if (row->linebreak)
return;
if (++next_row >= term->rows)
return;
pos->col = term->cols - 1;
pos->row = next_row;
}
}
void
selection_start(struct terminal *term, int col, int row,
enum selection_kind kind,
@ -421,13 +465,19 @@ selection_start(struct terminal *term, int col, int row,
break;
}
case SELECTION_LINE_WISE:
term->selection.start = (struct coord){0, term->grid->view + row};
term->selection.pivot.start = term->selection.start;
term->selection.pivot.end = (struct coord){term->cols - 1, term->grid->view + row};
case SELECTION_LINE_WISE: {
struct coord start = {0, row}, end = {term->cols - 1, row};
selection_find_line_boundary_left(term, &start, spaces_only);
selection_find_line_boundary_right(term, &end, spaces_only);
selection_update(term, term->cols - 1, row);
term->selection.start = (struct coord){
start.col, term->grid->view + start.row};
term->selection.pivot.start = term->selection.start;
term->selection.pivot.end = (struct coord){end.col, term->grid->view + end.row};
selection_update(term, end.col, end.row);
break;
}
case SELECTION_NONE:
BUG("Invalid selection kind");
@ -756,13 +806,21 @@ selection_update(struct terminal *term, int col, int row)
case SELECTION_LINE_WISE:
switch (term->selection.direction) {
case SELECTION_LEFT:
new_end.col = 0;
case SELECTION_LEFT: {
struct coord end = {0, row};
selection_find_line_boundary_left(
term, &end, term->selection.spaces_only);
new_end = (struct coord){end.col, term->grid->view + end.row};
break;
}
case SELECTION_RIGHT:
new_end.col = term->cols - 1;
case SELECTION_RIGHT: {
struct coord end = {col, row};
selection_find_line_boundary_right(
term, &end, term->selection.spaces_only);
new_end = (struct coord){end.col, term->grid->view + end.row};
break;
}
case SELECTION_UNDIR:
break;
@ -870,6 +928,8 @@ selection_extend_normal(struct terminal *term, int col, int row,
}
}
const bool spaces_only = term->selection.spaces_only;
switch (term->selection.kind) {
case SELECTION_CHAR_WISE:
xassert(new_kind == SELECTION_CHAR_WISE);
@ -883,10 +943,8 @@ selection_extend_normal(struct terminal *term, int col, int row,
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
struct coord pivot_end = pivot_start;
selection_find_word_boundary_left(
term, &pivot_start, term->selection.spaces_only);
selection_find_word_boundary_right(
term, &pivot_end, term->selection.spaces_only);
selection_find_word_boundary_left(term, &pivot_start, spaces_only);
selection_find_word_boundary_right(term, &pivot_end, spaces_only);
term->selection.pivot.start =
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
@ -895,13 +953,22 @@ selection_extend_normal(struct terminal *term, int col, int row,
break;
}
case SELECTION_LINE_WISE:
case SELECTION_LINE_WISE: {
xassert(new_kind == SELECTION_CHAR_WISE ||
new_kind == SELECTION_LINE_WISE);
new_kind == SELECTION_LINE_WISE);
term->selection.pivot.start = (struct coord){0, new_start.row};
term->selection.pivot.end = (struct coord){term->cols - 1, new_start.row};
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
struct coord pivot_end = pivot_start;
selection_find_line_boundary_left(term, &pivot_start, spaces_only);
selection_find_line_boundary_right(term, &pivot_end, spaces_only);
term->selection.pivot.start =
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
term->selection.pivot.end =
(struct coord){pivot_end.col, term->grid->view + pivot_end.row};
break;
}
case SELECTION_BLOCK:
case SELECTION_NONE:

View file

@ -277,20 +277,22 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
const bool need_to_clone_conf =
tll_length(overrides)> 0 ||
cdata.hold != server->conf->hold_at_exit ||
cdata.no_wait != server->conf->no_wait;
cdata.hold != server->conf->hold_at_exit;
struct config *conf = NULL;
if (need_to_clone_conf) {
conf = config_clone(server->conf);
if (cdata.no_wait != server->conf->no_wait)
conf->no_wait = cdata.no_wait;
if (cdata.hold != server->conf->hold_at_exit)
conf->hold_at_exit = cdata.hold;
config_override_apply(conf, &overrides, false);
if (conf->tweak.font_monospace_warn && conf->fonts[0].count > 0) {
check_if_font_is_monospaced(
conf->fonts[0].arr[0].pattern,
&conf->notifications);
}
}
*instance = (struct terminal_instance) {
@ -311,7 +313,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
goto shutdown;
}
if (conf != NULL && conf->no_wait) {
if (cdata.no_wait) {
// the server owns the instance
tll_push_back(server->terminals, instance);
client_send_exit_code(client, 0);

35
sixel.c
View file

@ -15,16 +15,6 @@
static size_t count;
static uint32_t
get_bg(const struct terminal *term)
{
return term->sixel.transparent_bg
? 0x00000000u
: 0xffu << 24 | (term->vt.attrs.have_bg
? term->vt.attrs.bg
: term->colors.bg);
}
void
sixel_fini(struct terminal *term)
{
@ -78,9 +68,14 @@ sixel_init(struct terminal *term, int p1, int p2, int p3)
term->sixel.palette = term->sixel.shared_palette;
}
uint32_t bg = get_bg(term);
term->sixel.default_bg = term->sixel.transparent_bg
? 0x00000000u
: 0xffu << 24 | (term->vt.attrs.have_bg
? term->vt.attrs.bg
: term->colors.bg);
for (size_t i = 0; i < 1 * 6; i++)
term->sixel.image.data[i] = bg;
term->sixel.image.data[i] = term->sixel.default_bg;
count = 0;
}
@ -1118,7 +1113,7 @@ resize_horizontally(struct terminal *term, int new_width)
/* Width (and thus stride) change - need to allocate a new buffer */
uint32_t *new_data = xmalloc(new_width * alloc_height * sizeof(uint32_t));
uint32_t bg = get_bg(term);
uint32_t bg = term->sixel.default_bg;
/* Copy old rows, and initialize new columns to background color */
for (int r = 0; r < height; r++) {
@ -1167,7 +1162,7 @@ resize_vertically(struct terminal *term, int new_height)
return false;
}
uint32_t bg = get_bg(term);
uint32_t bg = term->sixel.default_bg;
/* Initialize new rows to background color */
for (int r = old_height; r < new_height; r++) {
@ -1204,7 +1199,7 @@ resize(struct terminal *term, int new_width, int new_height)
xassert(alloc_new_height - new_height < 6);
uint32_t *new_data = NULL;
uint32_t bg = get_bg(term);
uint32_t bg = term->sixel.default_bg;
if (new_width == old_width) {
/* Width (and thus stride) is the same, so we can simply
@ -1277,8 +1272,6 @@ sixel_add(struct terminal *term, int col, int width, uint32_t color, uint8_t six
static void
sixel_add_many(struct terminal *term, uint8_t c, unsigned count)
{
uint32_t color = term->sixel.palette[term->sixel.color_idx];
int col = term->sixel.pos.col;
int width = term->sixel.image.width;
@ -1288,6 +1281,7 @@ sixel_add_many(struct terminal *term, uint8_t c, unsigned count)
return;
}
uint32_t color = term->sixel.color;
for (unsigned i = 0; i < count; i++, col++)
sixel_add(term, col, width, color, c);
@ -1407,7 +1401,7 @@ decgra(struct terminal *term, uint8_t c)
}
term->sixel.state = SIXEL_DECSIXEL;
sixel_put(term, c);
decsixel(term, c);
break;
}
}
@ -1514,10 +1508,11 @@ decgci(struct terminal *term, uint8_t c)
break;
}
}
}
} else
term->sixel.color = term->sixel.palette[term->sixel.color_idx];
term->sixel.state = SIXEL_DECSIXEL;
sixel_put(term, c);
decsixel(term, c);
break;
}
}

View file

@ -269,7 +269,7 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
if (chdir(cwd) < 0) {
const int errno_copy = errno;
LOG_ERRNO("failed to change working directory");
LOG_ERRNO("failed to change working directory to %s", cwd);
(void)!write(fork_pipe[1], &errno_copy, sizeof(errno_copy));
_exit(errno_copy);
}

View file

@ -48,6 +48,11 @@ spawn(struct reaper *reaper, const char *cwd, char *const argv[],
if (sigaction(SIGHUP, &(struct sigaction){.sa_handler = SIG_DFL}, NULL) < 0)
goto child_err;
if (cwd != NULL && chdir(cwd) < 0) {
LOG_WARN("failed to change working directory to %s: %s",
cwd, strerror(errno));
}
bool close_stderr = stderr_fd >= 0;
bool close_stdout = stdout_fd >= 0 && stdout_fd != stderr_fd;
bool close_stdin = stdin_fd >= 0 && stdin_fd != stdout_fd && stdin_fd != stderr_fd;
@ -58,7 +63,6 @@ spawn(struct reaper *reaper, const char *cwd, char *const argv[],
|| (close_stdout && close(stdout_fd) < 0))) ||
(stderr_fd >= 0 && (dup2(stderr_fd, STDERR_FILENO) < 0
|| (close_stderr && close(stderr_fd) < 0))) ||
(cwd != NULL && chdir(cwd) < 0) ||
execvp(argv[0], argv) < 0)
{
goto child_err;

View file

@ -230,13 +230,11 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
}
uint8_t buf[24 * 1024];
ssize_t count = sizeof(buf);
const size_t max_iterations = !hup ? 10 : (size_t)-1ll;
for (size_t i = 0; i < max_iterations && pollin; i++) {
xassert(pollin);
count = read(term->ptmx, buf, sizeof(buf));
ssize_t count = read(term->ptmx, buf, sizeof(buf));
if (count < 0) {
if (errno == EAGAIN || errno == EIO) {
@ -628,15 +626,28 @@ err_sem_destroy:
}
static void
free_box_drawing(struct fcft_glyph **box_drawing)
free_custom_glyph(struct fcft_glyph **glyph)
{
if (*box_drawing == NULL)
if (*glyph == NULL)
return;
free(pixman_image_get_data((*box_drawing)->pix));
pixman_image_unref((*box_drawing)->pix);
free(*box_drawing);
*box_drawing = NULL;
free(pixman_image_get_data((*glyph)->pix));
pixman_image_unref((*glyph)->pix);
free(*glyph);
*glyph = NULL;
}
static void
free_custom_glyphs(struct fcft_glyph ***glyphs, size_t count)
{
if (*glyphs == NULL)
return;
for (size_t i = 0; i < count; i++)
free_custom_glyph(&(*glyphs)[i]);
free(*glyphs);
*glyphs = NULL;
}
static bool
@ -649,18 +660,27 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4])
term->fonts[i] = fonts[i];
}
for (size_t i = 0; i < ALEN(term->box_drawing); i++)
free_box_drawing(&term->box_drawing[i]);
free_custom_glyphs(
&term->custom_glyphs.box_drawing, GLYPH_BOX_DRAWING_COUNT);
free_custom_glyphs(
&term->custom_glyphs.braille, GLYPH_BRAILLE_COUNT);
free_custom_glyphs(
&term->custom_glyphs.legacy, GLYPH_LEGACY_COUNT);
const int old_cell_width = term->cell_width;
const int old_cell_height = term->cell_height;
const struct config *conf = term->conf;
const struct fcft_glyph *M = fcft_glyph_rasterize(
term->fonts[0], L'M', term->font_subpixel);
term->cell_width =
(term->fonts[0]->space_advance.x > 0
? term->fonts[0]->space_advance.x
: term->fonts[0]->max_advance.x)
(M != NULL
? M->advance.x
: (term->fonts[0]->space_advance.x > 0
? term->fonts[0]->space_advance.x
: term->fonts[0]->max_advance.x))
+ term_pt_or_px_as_pixels(term, &conf->letter_spacing);
term->cell_height = term->font_line_height.px >= 0
@ -793,25 +813,48 @@ get_font_subpixel(const struct terminal *term)
return FCFT_SUBPIXEL_DEFAULT;
}
bool
term_font_sized_by_dpi(const struct terminal *term, int scale)
static bool
term_font_size_by_dpi(const struct terminal *term)
{
return term->conf->dpi_aware == DPI_AWARE_YES ||
(term->conf->dpi_aware == DPI_AWARE_AUTO && scale <= 1);
}
switch (term->conf->dpi_aware) {
case DPI_AWARE_YES: return true;
case DPI_AWARE_NO: return false;
bool
term_font_sized_by_scale(const struct terminal *term, int scale)
{
return !term_font_sized_by_dpi(term, scale);
case DPI_AWARE_AUTO:
/*
* Scale using DPI if all monitors have a scaling factor or 1.
*
* The idea is this: if a user, with multiple monitors, have
* enabled scaling on at least one monitor, then he/she has
* most likely done so to match the size of his/hers other
* monitors.
*
* I.e. if the user has one monitor with a scaling factor of
* one, and another with a scaling factor of two, he/she
* expects things to be twice as large on the second
* monitor.
*
* If we (foot) scale using DPI on the first monitor, and
* using the scaling factor on the second monitor, foot will
* *not* look twice as big on the second monitor.
*/
tll_foreach(term->wl->monitors, it) {
const struct monitor *mon = &it->item;
if (mon->scale > 1)
return false;
}
return true;
}
BUG("unhandled DPI awareness value");
}
int
term_pt_or_px_as_pixels(const struct terminal *term,
const struct pt_or_px *pt_or_px)
{
double scale = term_font_sized_by_scale(term, term->scale) ? term->scale : 1.;
double dpi = term_font_sized_by_dpi(term, term->scale) ? term->font_dpi : 96.;
double scale = !term->font_is_sized_by_dpi ? term->scale : 1.;
double dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.;
return pt_or_px->px == 0
? round(pt_or_px->pt * scale * dpi / 72)
@ -858,8 +901,7 @@ reload_fonts(struct terminal *term)
bool use_px_size = term->font_sizes[i][j].px_size > 0;
char size[64];
const int scale =
term_font_sized_by_scale(term, term->scale) ? term->scale : 1;
const int scale = term->font_is_sized_by_dpi ? 1 : term->scale;
if (use_px_size)
snprintf(size, sizeof(size), ":pixelsize=%d",
@ -894,7 +936,7 @@ reload_fonts(struct terminal *term)
const size_t count_bold_italic = custom_bold_italic ? counts[3] : counts[0];
const char **names_bold_italic = (const char **)(custom_bold_italic ? names[3] : names[0]);
const bool use_dpi = term_font_sized_by_dpi(term, term->scale);
const bool use_dpi = term->font_is_sized_by_dpi;
char *attrs[4] = {NULL};
int attr_len[4] = {-1, -1, -1, -1}; /* -1, so that +1 (below) results in 0 */
@ -1587,8 +1629,13 @@ term_destroy(struct terminal *term)
for (size_t i = 0; i < 4; i++)
free(term->font_sizes[i]);
for (size_t i = 0; i < ALEN(term->box_drawing); i++)
free_box_drawing(&term->box_drawing[i]);
free_custom_glyphs(
&term->custom_glyphs.box_drawing, GLYPH_BOX_DRAWING_COUNT);
free_custom_glyphs(
&term->custom_glyphs.braille, GLYPH_BRAILLE_COUNT);
free_custom_glyphs(
&term->custom_glyphs.legacy, GLYPH_LEGACY_COUNT);
free(term->search.buf);
@ -1983,8 +2030,8 @@ term_font_dpi_changed(struct terminal *term, int old_scale)
float dpi = get_font_dpi(term);
xassert(term->scale > 0);
bool was_scaled_using_dpi = term_font_sized_by_dpi(term, old_scale);
bool will_scale_using_dpi = term_font_sized_by_dpi(term, term->scale);
bool was_scaled_using_dpi = term->font_is_sized_by_dpi;
bool will_scale_using_dpi = term_font_size_by_dpi(term);
bool need_font_reload =
was_scaled_using_dpi != will_scale_using_dpi ||
@ -1994,15 +2041,16 @@ term_font_dpi_changed(struct terminal *term, int old_scale)
if (need_font_reload) {
LOG_DBG("DPI/scale change: DPI-awareness=%s, "
"DPI: %.2f -> %.2f, scale: %d, "
"DPI: %.2f -> %.2f, scale: %d -> %d, "
"sizing font based on monitor's %s",
term->conf->dpi_aware == DPI_AWARE_AUTO ? "auto" :
term->conf->dpi_aware == DPI_AWARE_YES ? "yes" : "no",
term->font_dpi, dpi, term->scale,
term->font_dpi, dpi, old_scale, term->scale,
will_scale_using_dpi ? "DPI" : "scaling factor");
}
term->font_dpi = dpi;
term->font_is_sized_by_dpi = will_scale_using_dpi;
if (!need_font_reload)
return true;

View file

@ -329,16 +329,31 @@ struct terminal {
struct config_font *font_sizes[4];
struct pt_or_px font_line_height;
float font_dpi;
bool font_is_sized_by_dpi;
int16_t font_x_ofs;
int16_t font_y_ofs;
enum fcft_subpixel font_subpixel;
/*
* 0-159: U+02500+0259F
* 160-299: U+1FB00-1FB8B
* 300-301: U+1FB9A-1FB9B
*/
struct fcft_glyph *box_drawing[302];
struct {
struct fcft_glyph **box_drawing;
struct fcft_glyph **braille;
struct fcft_glyph **legacy;
#define GLYPH_BOX_DRAWING_FIRST 0x2500
#define GLYPH_BOX_DRAWING_LAST 0x259F
#define GLYPH_BOX_DRAWING_COUNT \
(GLYPH_BOX_DRAWING_LAST - GLYPH_BOX_DRAWING_FIRST + 1)
#define GLYPH_BRAILLE_FIRST 0x2800
#define GLYPH_BRAILLE_LAST 0x28FF
#define GLYPH_BRAILLE_COUNT \
(GLYPH_BRAILLE_LAST - GLYPH_BRAILLE_FIRST + 1)
#define GLYPH_LEGACY_FIRST 0x1FB00
#define GLYPH_LEGACY_LAST 0x1FB9B
#define GLYPH_LEGACY_COUNT \
(GLYPH_LEGACY_LAST - GLYPH_LEGACY_FIRST + 1)
} custom_glyphs;
bool is_sending_paste_data;
ptmx_buffer_list_t ptmx_buffers;
@ -560,6 +575,7 @@ struct terminal {
uint32_t *private_palette; /* Private palette, used when private mode 1070 is enabled */
uint32_t *shared_palette; /* Shared palette, used when private mode 1070 is disabled */
uint32_t *palette; /* Points to either private_palette or shared_palette */
uint32_t color;
struct {
uint32_t *data; /* Raw image data, in ARGB */
@ -576,6 +592,7 @@ struct terminal {
unsigned param_idx; /* Parameters seen */
bool transparent_bg;
uint32_t default_bg;
/* Application configurable */
unsigned palette_size; /* Number of colors in palette */
@ -644,8 +661,6 @@ bool term_font_size_reset(struct terminal *term);
bool term_font_dpi_changed(struct terminal *term, int old_scale);
void term_font_subpixel_changed(struct terminal *term);
bool term_font_sized_by_dpi(const struct terminal *term, int scale);
bool term_font_sized_by_scale(const struct terminal *term, int scale);
int term_pt_or_px_as_pixels(
const struct terminal *term, const struct pt_or_px *pt_or_px);

22
themes/hacktober Normal file
View file

@ -0,0 +1,22 @@
[cursor]
color=141414 c9c9c9
[colors]
foreground=c9c9c9
background=141414
regular0=191918 # black
regular1=b34538 # red
regular2=587744 # green
regular3=d08949 # yellow
regular4=206ec5 # blue
regular5=864651 # magenta
regular6=ac9166 # cyan
regular7=f1eee7 # white
bright0=2c2b2a # bright black
bright1=b33323 # bright red
bright2=42824a # bright green
bright3=c75a22 # bright yellow
bright4=5389c5 # bright blue
bright5=e795a5 # bright magenta
bright6=ebc587 # bright cyan
bright7=ffffff # bright white

View file

@ -340,6 +340,11 @@ update_terms_on_monitor(struct monitor *mon)
tll_foreach(wayl->terms, it) {
struct terminal *term = it->item;
if (term->conf->dpi_aware == DPI_AWARE_AUTO) {
update_term_for_output_change(term);
continue;
}
tll_foreach(term->window->on_outputs, it2) {
if (it2->item == mon) {
update_term_for_output_change(term);