mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
Merge branch 'master' into releases/1.9
This commit is contained in:
commit
a082fec786
38 changed files with 1032 additions and 469 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
51
CHANGELOG.md
51
CHANGELOG.md
|
|
@ -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 don’t 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 monitor’s 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 monitor’s 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
|
||||
|
|
|
|||
124
INSTALL.md
124
INSTALL.md
|
|
@ -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 foot’s terminfo.
|
||||
|
||||
As of ncurses 2021-07-31, ncurses ships a version of foot’s
|
||||
terminfo. I still recommend building and installing the version
|
||||
shipped with foot, since:
|
||||
As of ncurses 2021-07-31, ncurses includes a version of foot’s
|
||||
terminfo. **The recommendation is to use those**, and only install the
|
||||
terminfo definitions from this git repo if the system’s 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.
|
||||
|
||||
Foot’s 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 foot’s 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 foot’s terminfo to
|
||||
co-exist with ncurses’ version. The idea is that you install foot’s
|
||||
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 foot’s 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 foot’s version, if it exists (which it
|
||||
typically will on localhost), and fallback to ncurses’ version if not
|
||||
(e.g. on remote systems, where foot’s 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 foot’s 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 isn’t 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
|
||||
|
|
|
|||
79
PKGBUILD
79
PKGBUILD
|
|
@ -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 we’ll 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/"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
Foot’s default behavior is to use the monitor’s 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 monitor’s 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
45
client.c
45
client.c
|
|
@ -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
131
config.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
5
config.h
5
config.h
|
|
@ -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
45
csi.c
|
|
@ -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] == '!' */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
10
foot.info
10
foot.info
|
|
@ -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
102
input.c
|
|
@ -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 they’re 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 we’re still tracking LMB as
|
||||
* being held down in our seat struct.
|
||||
* - This leads to an assert (debug builds) when LMB is clicked
|
||||
* again (seat’s 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
|
||||
* they’re 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 we’re still tracking LMB as
|
||||
* being held down in our seat struct.
|
||||
* - This leads to an assert (debug builds) when LMB is clicked
|
||||
* again (seat’s button list already contains LMB).
|
||||
*
|
||||
* Note: I’ve 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
2
log.c
|
|
@ -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
27
main.c
|
|
@ -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;
|
||||
|
|
|
|||
32
meson.build
32
meson.build
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
8
pgo/full-current-session.sh
Executable 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
14
pgo/full-headless-cage.sh
Executable 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}"
|
||||
|
||||
# Cage’s exit code doesn’t reflect our script’s exit code
|
||||
[ -f "${blddir}"/pgo-ok ] || exit 1
|
||||
9
pgo/full-headless-sway-inner.sh
Executable file
9
pgo/full-headless-sway-inner.sh
Executable 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
24
pgo/full-headless-sway.sh
Executable 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}"
|
||||
|
||||
# Sway’s exit code doesn’t reflect our script’s exit code
|
||||
[ -f "${blddir}"/pgo-ok ] || exit 1
|
||||
30
pgo/full-inner.sh
Executable file
30
pgo/full-inner.sh
Executable 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
1
pgo/options
Normal 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
28
pgo/partial.sh
Executable 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
112
pgo/pgo.sh
Executable 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 we’ll 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}"
|
||||
64
render.c
64
render.c
|
|
@ -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(
|
||||
|
|
|
|||
101
selection.c
101
selection.c
|
|
@ -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:
|
||||
|
|
|
|||
14
server.c
14
server.c
|
|
@ -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
35
sixel.c
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
slave.c
2
slave.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
6
spawn.c
6
spawn.c
|
|
@ -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;
|
||||
|
|
|
|||
116
terminal.c
116
terminal.c
|
|
@ -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;
|
||||
|
|
|
|||
31
terminal.h
31
terminal.h
|
|
@ -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
22
themes/hacktober
Normal 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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue