mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-28 07:58:00 -04: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: |
|
- codespell: |
|
||||||
pip install codespell
|
pip install codespell
|
||||||
cd foot
|
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 python3
|
||||||
- apk add py3-pip
|
- apk add py3-pip
|
||||||
- pip install codespell
|
- 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
|
# Changelog
|
||||||
|
|
||||||
|
* [Unreleased](#unreleased)
|
||||||
* [1.9.0](#1-9-0)
|
* [1.9.0](#1-9-0)
|
||||||
* [1.8.2](#1-8-2)
|
* [1.8.2](#1-8-2)
|
||||||
* [1.8.1](#1-8-1)
|
* [1.8.1](#1-8-1)
|
||||||
|
|
@ -29,6 +30,54 @@
|
||||||
* [1.2.0](#1-2-0)
|
* [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
|
## 1.9.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
@ -65,6 +114,8 @@
|
||||||
now translated to pixel values using the monitor’s scaling factor
|
now translated to pixel values using the monitor’s scaling factor
|
||||||
when `dpi-aware=no`, or `dpi-aware=auto` and the scaling factor is
|
when `dpi-aware=no`, or `dpi-aware=auto` and the scaling factor is
|
||||||
larger than 1 (https://codeberg.org/dnkl/foot/issues/680).
|
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
|
### Removed
|
||||||
|
|
|
||||||
124
INSTALL.md
124
INSTALL.md
|
|
@ -128,23 +128,35 @@ reasons for this:
|
||||||
used by e.g. tmux.
|
used by e.g. tmux.
|
||||||
* New capabilities added to the `xterm-256color` terminfo could
|
* New capabilities added to the `xterm-256color` terminfo could
|
||||||
potentially break foot.
|
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
|
As of ncurses 2021-07-31, ncurses includes a version of foot’s
|
||||||
terminfo. I still recommend building and installing the version
|
terminfo. **The recommendation is to use those**, and only install the
|
||||||
shipped with foot, since:
|
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
|
But, note that the foot terminfo definitions in ncurses’ lack the
|
||||||
match the installed version of foot).
|
non-standard capabilities. This mostly affects tmux; without them,
|
||||||
* The ncurses version is missing several of the non-standard capabilities.
|
`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
|
Both have their set of issues. When installing to a non-default
|
||||||
foot itself. This can be disabled (for example, to simplify packaging
|
location, foot will set the environment variable `TERMINFO` in the
|
||||||
when the terminfo definitions are packaged in a separate
|
child process. However, there are many situations where this simply
|
||||||
package). Instructions on how to do so is in [terminfo](#terminfo).
|
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
|
Installing them under a different name generally works well, but will
|
||||||
allow them to be installed on remote systems without having to install
|
break applications that check if `$TERM == foot`.
|
||||||
foot itself.
|
|
||||||
|
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
|
### Setup
|
||||||
|
|
@ -158,44 +170,43 @@ mkdir -p bld/release && cd bld/release
|
||||||
|
|
||||||
Available compile-time options:
|
Available compile-time options:
|
||||||
|
|
||||||
| Option | Type | Default | Description | Extra dependencies |
|
| Option | Type | Default | Description | Extra dependencies |
|
||||||
|--------------------------------------|---------|----------------------------|----------------------------------|--------------------|
|
|--------------------------------------|---------|-----------------------|----------------------------------|--------------------|
|
||||||
| `-Ddocs` | feature | `auto` | Builds and install documentation | scdoc |
|
| `-Ddocs` | feature | `auto` | Builds and install documentation | scdoc |
|
||||||
| `-Dime` | bool | `true` | Enables IME support | None |
|
| `-Dime` | bool | `true` | Enables IME support | None |
|
||||||
| `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc |
|
| `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc |
|
||||||
| `-Dterminfo` | feature | `enabled` | Build and install terminfo files | tic (ncurses) |
|
| `-Dterminfo` | feature | `enabled` | Build and install terminfo files | tic (ncurses) |
|
||||||
| `-Ddefault-terminfo` | string | `foot` | Default value of `TERM` | none |
|
| `-Ddefault-terminfo` | string | `foot` | Default value of `TERM` | none |
|
||||||
| `-Dcustom-terminfo-install-location` | string | `${datadir}/foot/terminfo` | Value to set `TERMINFO` to | None |
|
| `-Dcustom-terminfo-install-location` | string | `${datadir}/terminfo` | Value to set `TERMINFO` to | None |
|
||||||
|
|
||||||
Documentation includes the man pages, the example `foot.ini`, readme,
|
Documentation includes the man pages, the example `foot.ini`, readme,
|
||||||
changelog and license files.
|
changelog and license files.
|
||||||
|
|
||||||
`-Ddefault-terminfo`: I strongly recommend leaving the default
|
`-Ddefault-terminfo`: I strongly recommend leaving the default
|
||||||
value. This option is meant to be used as a last resort on platforms
|
value. Use this option if you plan on installing the terminfo files
|
||||||
where individual terminfo files cannot easily be installed.
|
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
|
`-Dcustom-terminfo-install-location` enables foot’s terminfo to
|
||||||
co-exist with ncurses’ version. The idea is that you install foot’s
|
co-exist with ncurses’ version, without changing the terminfo
|
||||||
terminfo to a non-standard location, for example
|
names. The idea is that you install foot’s terminfo to a non-standard
|
||||||
`/usr/share/foot/terminfo`. Use `-Dcustom-terminfo-install-location`
|
location, for example `/usr/share/foot/terminfo`. Use
|
||||||
to tell foot where the terminfo is. Foot will set the environment
|
`-Dcustom-terminfo-install-location` to tell foot where the terminfo
|
||||||
variable `TERMINFO` to this value (with `${prefix}` added). The value
|
is. Foot will set the environment variable `TERMINFO` to this value
|
||||||
is **relative to ${prefix}**.
|
(with `${prefix}` added). The value is **relative to ${prefix}**.
|
||||||
|
|
||||||
Conforming applications _should_ look in `TERMINFO` first, and
|
Note that there are several issues with this approach:
|
||||||
fallback to the builtin default (e.g. `/usr/share/terminfo`) if not
|
https://codeberg.org/dnkl/foot/issues/695.
|
||||||
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).
|
|
||||||
|
|
||||||
If set to `no`, foot will **not** set or modify `TERMINFO` at all. Use
|
If left unset, foot will **not** set or modify `TERMINFO`.
|
||||||
this if you do not intend to use/support foot’s terminfo definitions
|
|
||||||
at all.
|
|
||||||
|
|
||||||
`-Dterminfo` can be used to disable building the terminfo definitions
|
`-Dterminfo` can be used to disable building the terminfo definitions
|
||||||
in the meson build. It does **not** change the default value of
|
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:
|
Example:
|
||||||
|
|
||||||
|
|
@ -212,11 +223,7 @@ be built as part of the regular build process, and installed to the
|
||||||
specified location.
|
specified location.
|
||||||
|
|
||||||
Packagers may want to set `-Dterminfo=disabled`, and manually build
|
Packagers may want to set `-Dterminfo=disabled`, and manually build
|
||||||
and install the terminfo files instead:
|
and [install the terminfo](#terminfo) files instead.
|
||||||
|
|
||||||
```sh
|
|
||||||
tic -o <output-directory> -x -e foot,foot-direct foot.info
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Release build
|
### Release build
|
||||||
|
|
@ -267,6 +274,32 @@ slower!) binary.
|
||||||
|
|
||||||
#### Performance optimized, PGO
|
#### 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:
|
First, configure the build directory:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|
@ -413,7 +446,8 @@ terminfo files manually instead.
|
||||||
To build the terminfo files, run:
|
To build the terminfo files, run:
|
||||||
|
|
||||||
```sh
|
```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
|
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')
|
pkgname=('foot-git' 'foot-terminfo-git')
|
||||||
pkgver=1.9.0
|
pkgver=1.9.0
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
|
|
@ -14,76 +16,7 @@ pkgver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
local compiler=other
|
../pgo/pgo.sh ${PGO} .. . --prefix=/usr --wrap-mode=nofallback
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
|
|
@ -98,7 +31,7 @@ package_foot-git() {
|
||||||
provides=('foot')
|
provides=('foot')
|
||||||
|
|
||||||
DESTDIR="${pkgdir}/" ninja install
|
DESTDIR="${pkgdir}/" ninja install
|
||||||
rm -rf "${pkgdir}/usr/share/foot/terminfo"
|
rm -rf "${pkgdir}/usr/share/terminfo"
|
||||||
}
|
}
|
||||||
|
|
||||||
package_foot-terminfo-git() {
|
package_foot-terminfo-git() {
|
||||||
|
|
@ -107,6 +40,6 @@ package_foot-terminfo-git() {
|
||||||
conflicts=('foot-terminfo')
|
conflicts=('foot-terminfo')
|
||||||
provides=('foot-terminfo')
|
provides=('foot-terminfo')
|
||||||
|
|
||||||
install -dm 755 "${pkgdir}/usr/share/foot/terminfo/f/"
|
install -dm 755 "${pkgdir}/usr/share/terminfo/f/"
|
||||||
cp f/* "${pkgdir}/usr/share/foot/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.
|
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
|
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
|
output scaling has been disabled on **all** monitors. If at least one
|
||||||
been enabled, fonts will instead be sized using the scaling
|
monitor has output scaling enabled, fonts will instead by sized using
|
||||||
factor.
|
the scaling factor.
|
||||||
|
|
||||||
This can be changed to either **always** use the monitor’s DPI
|
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)
|
`dpi-aware` option in `foot.ini`. See the man page, **foot.ini**(5)
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1953,6 +1953,95 @@ draw_quadrant(struct buf *buf, wchar_t wc)
|
||||||
quad_lower_right(buf);
|
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
|
static void
|
||||||
sextant_upper_left(struct buf *buf)
|
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 0x2595: draw_right_one_eighth_block(buf); break;
|
||||||
case 0x2596 ... 0x259f: draw_quadrant(buf, wc); 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 0x1fb00 ... 0x1fb3b: draw_sextant(buf, wc); break;
|
||||||
|
|
||||||
case 0x1fb3c ... 0x1fb40:
|
case 0x1fb3c ... 0x1fb40:
|
||||||
|
|
@ -2746,8 +2837,8 @@ box_drawing(const struct terminal *term, wchar_t wc)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
double dpi = term_font_sized_by_dpi(term, term->scale) ? term->font_dpi : 96.;
|
double dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.;
|
||||||
double scale = term_font_sized_by_scale(term, term->scale) ? term->scale : 1.;
|
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));
|
double cell_size = sqrt(pow(term->cell_width, 2) + pow(term->cell_height, 2));
|
||||||
|
|
||||||
int base_thickness =
|
int base_thickness =
|
||||||
|
|
@ -2798,8 +2889,7 @@ box_drawing(const struct terminal *term, wchar_t wc)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_DBG("LIGHT=%d, HEAVY=%d",
|
LOG_DBG("LIGHT=%d, HEAVY=%d", buf.thickness[LIGHT], buf.thickness[HEAVY]);
|
||||||
_thickness(&buf, LIGHT), _thickness(&buf, HEAVY));
|
|
||||||
|
|
||||||
draw_glyph(&buf, wc);
|
draw_glyph(&buf, wc);
|
||||||
|
|
||||||
|
|
|
||||||
45
client.c
45
client.c
|
|
@ -54,27 +54,29 @@ version_and_features(void)
|
||||||
static void
|
static void
|
||||||
print_usage(const char *prog_name)
|
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...]\n", prog_name);
|
||||||
printf("Usage: %s [OPTIONS...] command [ARGS...]\n", prog_name);
|
printf("Usage: %s [OPTIONS...] command [ARGS...]\n", prog_name);
|
||||||
printf("\n");
|
puts(options);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool NOINLINE
|
static bool NOINLINE
|
||||||
|
|
@ -144,7 +146,7 @@ main(int argc, char *const *argv)
|
||||||
struct client_string *cargv = NULL;
|
struct client_string *cargv = NULL;
|
||||||
|
|
||||||
while (true) {
|
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)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -272,6 +274,9 @@ main(int argc, char *const *argv)
|
||||||
ret = EXIT_SUCCESS;
|
ret = EXIT_SUCCESS;
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
131
config.c
131
config.c
|
|
@ -31,7 +31,19 @@
|
||||||
static const uint32_t default_foreground = 0xdcdccc;
|
static const uint32_t default_foreground = 0xdcdccc;
|
||||||
static const uint32_t default_background = 0x111111;
|
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,
|
0x222222,
|
||||||
0xcc9393,
|
0xcc9393,
|
||||||
0x7f9f7f,
|
0x7f9f7f,
|
||||||
|
|
@ -40,9 +52,8 @@ static const uint32_t default_regular[] = {
|
||||||
0xdc8cc3,
|
0xdc8cc3,
|
||||||
0x93e0e3,
|
0x93e0e3,
|
||||||
0xdcdccc,
|
0xdcdccc,
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32_t default_bright[] = {
|
// Bright
|
||||||
0x666666,
|
0x666666,
|
||||||
0xdca3a3,
|
0xdca3a3,
|
||||||
0xbfebbf,
|
0xbfebbf,
|
||||||
|
|
@ -51,6 +62,24 @@ static const uint32_t default_bright[] = {
|
||||||
0xfcace3,
|
0xfcace3,
|
||||||
0xb3ffff,
|
0xb3ffff,
|
||||||
0xffffff,
|
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[] = {
|
static const char *const binding_action_map[] = {
|
||||||
|
|
@ -2452,6 +2481,9 @@ parse_section_tweak(
|
||||||
conf->tweak.box_drawing_solid_shades ? "yes" : "no");
|
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 {
|
else {
|
||||||
LOG_AND_NOTIFY_ERR("%s:%u: [tweak]: %s: invalid key", path, lineno, key);
|
LOG_AND_NOTIFY_ERR("%s:%u: [tweak]: %s: invalid key", path, lineno, key);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2884,25 +2916,6 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
.colors = {
|
.colors = {
|
||||||
.fg = default_foreground,
|
.fg = default_foreground,
|
||||||
.bg = default_background,
|
.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,
|
.alpha = 0xffff,
|
||||||
.selection_fg = 0x80000000, /* Use default bg */
|
.selection_fg = 0x80000000, /* Use default bg */
|
||||||
.selection_bg = 0x80000000, /* Use default fg */
|
.selection_bg = 0x80000000, /* Use default fg */
|
||||||
|
|
@ -2957,35 +2970,13 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
.damage_whole_window = false,
|
.damage_whole_window = false,
|
||||||
.box_drawing_base_thickness = 0.04,
|
.box_drawing_base_thickness = 0.04,
|
||||||
.box_drawing_solid_shades = true,
|
.box_drawing_solid_shades = true,
|
||||||
|
.font_monospace_warn = true,
|
||||||
},
|
},
|
||||||
|
|
||||||
.notifications = tll_init(),
|
.notifications = tll_init(),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Initialize the color cube */
|
memcpy(conf->colors.table, default_color_table, sizeof(default_color_table));
|
||||||
{
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenize_cmdline("notify-send -a ${app-id} -i ${app-id} ${title} ${body}",
|
tokenize_cmdline("notify-send -a ${app-id} -i ${app-id} ${title} ${body}",
|
||||||
&conf->notify.argv.args);
|
&conf->notify.argv.args);
|
||||||
|
|
@ -3356,3 +3347,51 @@ config_font_list_destroy(struct config_font_list *font_list)
|
||||||
font_list->count = 0;
|
font_list->count = 0;
|
||||||
font_list->arr = NULL;
|
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;
|
char *app_id;
|
||||||
wchar_t *word_delimiters;
|
wchar_t *word_delimiters;
|
||||||
bool login_shell;
|
bool login_shell;
|
||||||
bool no_wait;
|
|
||||||
bool locked_title;
|
bool locked_title;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -253,6 +252,7 @@ struct config {
|
||||||
off_t max_shm_pool_size;
|
off_t max_shm_pool_size;
|
||||||
float box_drawing_base_thickness;
|
float box_drawing_base_thickness;
|
||||||
bool box_drawing_solid_shades;
|
bool box_drawing_solid_shades;
|
||||||
|
bool font_monospace_warn;
|
||||||
} tweak;
|
} tweak;
|
||||||
|
|
||||||
user_notifications_t notifications;
|
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);
|
bool config_font_parse(const char *pattern, struct config_font *font);
|
||||||
void config_font_list_destroy(struct config_font_list *font_list);
|
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".
|
* Note: tertiary DA responds with "FOOT".
|
||||||
*/
|
*/
|
||||||
const char *reply = "\033[?62;4;22c";
|
static const char reply[] = "\033[?62;4;22c";
|
||||||
term_to_slave(term, reply, strlen(reply));
|
term_to_slave(term, reply, sizeof(reply) - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1062,17 +1062,15 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'S': {
|
case 'S': {
|
||||||
int amount = min(
|
const struct scroll_region *r = &term->scroll_region;
|
||||||
vt_param_get(term, 0, 1),
|
int amount = min(vt_param_get(term, 0, 1), r->end - r->start);
|
||||||
term->scroll_region.end - term->scroll_region.start);
|
|
||||||
term_scroll(term, amount);
|
term_scroll(term, amount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'T': {
|
case 'T': {
|
||||||
int amount = min(
|
const struct scroll_region *r = &term->scroll_region;
|
||||||
vt_param_get(term, 0, 1),
|
int amount = min(vt_param_get(term, 0, 1), r->end - r->start);
|
||||||
term->scroll_region.end - term->scroll_region.start);
|
|
||||||
term_scroll_reverse(term, amount);
|
term_scroll_reverse(term, amount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1219,20 +1217,12 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 13: { /* report window position */
|
case 13: { /* report window position */
|
||||||
|
|
||||||
int x = -1;
|
|
||||||
int y = -1;
|
|
||||||
|
|
||||||
/* We don't know our position - always report (0,0) */
|
/* 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)) {
|
switch (vt_param_get(term, 1, 0)) {
|
||||||
case 0:
|
case 0: /* window position */
|
||||||
/* window position */
|
case 2: /* text area position */
|
||||||
x = y = 0;
|
term_to_slave(term, reply, sizeof(reply) - 1);
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
/* text area position */
|
|
||||||
x = y = 0;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -1240,12 +1230,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1616,15 +1600,12 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
||||||
}
|
}
|
||||||
|
|
||||||
case '!': {
|
case '!': {
|
||||||
switch (final) {
|
if (final == 'p') {
|
||||||
case 'p':
|
|
||||||
term_reset(term, false);
|
term_reset(term, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
UNHANDLED();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNHANDLED();
|
||||||
break; /* private[0] == '!' */
|
break; /* private[0] == '!' */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,16 @@ the foot command line
|
||||||
*-v*,*--version*
|
*-v*,*--version*
|
||||||
Show the version number and quit.
|
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
|
# EXIT STATUS
|
||||||
|
|
||||||
Foot will exit with code 230 if there is a failure in foot itself.
|
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
|
set according to either the *--term* command-line option or the
|
||||||
*term* config option in *foot.ini*(5).
|
*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*
|
*COLORTERM*
|
||||||
This variable is set to *truecolor*, to indicate to client
|
This variable is set to *truecolor*, to indicate to client
|
||||||
applications that 24-bit RGB colors are supported.
|
applications that 24-bit RGB colors are supported.
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,9 @@ foot.ini - configuration file for *foot*(1)
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
*foot* uses the standard _unix configuration format_, with section based
|
*foot* uses the standard _unix configuration format_, with section based
|
||||||
key/value pairs. The default section is unnamed (i.e. not prefixed
|
key/value pairs. The default section is usually unnamed, i.e. not prefixed
|
||||||
with a _[section]_).
|
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,
|
foot will search for a configuration file in the following locations,
|
||||||
in this order:
|
in this order:
|
||||||
|
|
@ -16,7 +17,7 @@ in this order:
|
||||||
- *~/.config/foot/foot.ini*
|
- *~/.config/foot/foot.ini*
|
||||||
- *XDG_CONFIG_DIRS/foot/foot.ini*
|
- *XDG_CONFIG_DIRS/foot/foot.ini*
|
||||||
|
|
||||||
# SECTION: default
|
# SECTION: main
|
||||||
|
|
||||||
*shell*
|
*shell*
|
||||||
Executable to launch. Typically a shell. Default: _$SHELL_ if set,
|
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
|
Comma separated list of fonts to use, in fontconfig format. That
|
||||||
is, a font name followed by a list of colon-separated
|
is, a font name followed by a list of colon-separated
|
||||||
options. Most noteworthy is *:size=n*, which is used to set the
|
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:
|
Examples:
|
||||||
- Dina:weight=bold:slant=italic
|
- Dina:weight=bold:slant=italic
|
||||||
|
|
@ -144,11 +146,12 @@ in this order:
|
||||||
Default: _no_.
|
Default: _no_.
|
||||||
|
|
||||||
*dpi-aware*
|
*dpi-aware*
|
||||||
*auto*, *yes*, or *no*. When set to *yes*, fonts are sized using
|
*auto*, *yes*, or *no*.
|
||||||
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
|
When set to *yes*, fonts are sized using the monitor's DPI, making
|
||||||
a foot window between different monitors, the font size remains
|
a font of a given size have the same physical size, regardless of
|
||||||
the same.
|
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
|
In this mode, the monitor's scaling factor is ignored; doubling
|
||||||
the scaling factor will *not* double the font size.
|
the scaling factor will *not* double the font size.
|
||||||
|
|
@ -158,8 +161,22 @@ in this order:
|
||||||
scaling factor *does* double the font size.
|
scaling factor *does* double the font size.
|
||||||
|
|
||||||
Finally, if set to *auto*, fonts will be sized using the monitor's
|
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
|
DPI if _all_ monitors have a scaling factor of 1. If at least one
|
||||||
the scaling factor.
|
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_
|
Default: _auto_
|
||||||
|
|
||||||
|
|
@ -179,7 +196,7 @@ in this order:
|
||||||
Default: _2x2_.
|
Default: _2x2_.
|
||||||
|
|
||||||
*resize-delay-ms*
|
*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
|
window dimensions to the client application while doing an
|
||||||
interactive resize of a foot window. Idle time in this context is
|
interactive resize of a foot window. Idle time in this context is
|
||||||
a period of time where the window size is not changing.
|
a period of time where the window size is not changing.
|
||||||
|
|
@ -1022,6 +1039,17 @@ any of these options.
|
||||||
|
|
||||||
Default: _double-width_
|
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*
|
*max-shm-pool-size-mb*
|
||||||
This option controls the amount of virtual address space used by
|
This option controls the amount of virtual address space used by
|
||||||
the pixmap memory to which the terminal screen content is
|
the pixmap memory to which the terminal screen content is
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,10 @@ terminal has terminated.
|
||||||
*-v*,*--version*
|
*-v*,*--version*
|
||||||
Show the version number and quit
|
Show the version number and quit
|
||||||
|
|
||||||
|
*-e*
|
||||||
|
Ignored; for compatibility with *xterm -e*. See *foot*(1) for more
|
||||||
|
details.
|
||||||
|
|
||||||
# EXIT STATUS
|
# EXIT STATUS
|
||||||
|
|
||||||
Footlient will exit with code 220 if there is a failure in footclient
|
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
|
set according to either the *--term* command-line option or the
|
||||||
*term* config option in *foot.ini*(5).
|
*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*
|
*COLORTERM*
|
||||||
This variable is set to *truecolor*, to indicate to client
|
This variable is set to *truecolor*, to indicate to client
|
||||||
applications that 24-bit RGB colors are supported.
|
applications that 24-bit RGB colors are supported.
|
||||||
|
|
|
||||||
10
foot.info
10
foot.info
|
|
@ -1,17 +1,17 @@
|
||||||
foot|foot terminal emulator,
|
@default_terminfo@|foot terminal emulator,
|
||||||
use=foot+base,
|
use=@default_terminfo@+base,
|
||||||
colors#256,
|
colors#256,
|
||||||
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48\:5\:%p1%d%;m,
|
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,
|
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,
|
@default_terminfo@-direct|foot with direct color indexing,
|
||||||
use=foot+base,
|
use=@default_terminfo@+base,
|
||||||
colors#16777216,
|
colors#16777216,
|
||||||
RGB,
|
RGB,
|
||||||
setab=\E[%?%p1%{8}%<%t4%p1%d%e48\:2\:\:%p1%{65536}%/%d\:%p1%{256}%/%{255}%&%d\:%p1%{255}%&%d%;m,
|
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,
|
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,
|
am,
|
||||||
bce,
|
bce,
|
||||||
bw,
|
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;
|
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;
|
win->csd.move_timeout_fd = -1;
|
||||||
xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
|
xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1774,6 +1730,62 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
} else
|
} else
|
||||||
seat->mouse.count = 1;
|
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)
|
#if defined(_DEBUG)
|
||||||
tll_foreach(seat->mouse.buttons, it)
|
tll_foreach(seat->mouse.buttons, it)
|
||||||
xassert(it->item.button != button);
|
xassert(it->item.button != button);
|
||||||
|
|
@ -1817,7 +1829,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
||||||
* 4. Release mouse button
|
* 4. Release mouse button
|
||||||
* 5. BAM!
|
* 5. BAM!
|
||||||
*/
|
*/
|
||||||
LOG_WARN("stray button release event");
|
LOG_WARN("stray button release event (compositor bug?)");
|
||||||
return;
|
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,
|
[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;
|
do_syslog = _do_syslog;
|
||||||
log_level = _log_level;
|
log_level = _log_level;
|
||||||
|
|
||||||
|
|
|
||||||
27
main.c
27
main.c
|
|
@ -56,16 +56,13 @@ version_and_features(void)
|
||||||
static void
|
static void
|
||||||
print_usage(const char *prog_name)
|
print_usage(const char *prog_name)
|
||||||
{
|
{
|
||||||
printf(
|
static const char options[] =
|
||||||
"Usage: %s [OPTIONS...]\n"
|
"\nOptions:\n"
|
||||||
"Usage: %s [OPTIONS...] command [ARGS...]\n"
|
|
||||||
"\n"
|
|
||||||
"Options:\n"
|
|
||||||
" -c,--config=PATH load configuration from PATH ($XDG_CONFIG_HOME/foot/foot.ini)\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"
|
" -C,--check-config verify configuration, exit with 0 if ok, otherwise exit with 1\n"
|
||||||
" -o,--override=[section.]key=value override configuration option\n"
|
" -o,--override=[section.]key=value override configuration option\n"
|
||||||
" -f,--font=FONT comma separated list of fonts in fontconfig format (monospace)\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"
|
" -T,--title=TITLE initial window title (foot)\n"
|
||||||
" -a,--app-id=ID window application ID (foot)\n"
|
" -a,--app-id=ID window application ID (foot)\n"
|
||||||
" -m,--maximized start in maximized mode\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"
|
" -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"
|
" -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"
|
" -s,--log-no-syslog disable syslog logging (only applicable in server mode)\n"
|
||||||
" -v,--version show the version number and quit\n",
|
" -v,--version show the version number and quit\n"
|
||||||
prog_name, prog_name, FOOT_DEFAULT_TERM);
|
" -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
|
bool
|
||||||
|
|
@ -216,7 +217,7 @@ main(int argc, char *const *argv)
|
||||||
config_override_t overrides = tll_init();
|
config_override_t overrides = tll_init();
|
||||||
|
|
||||||
while (true) {
|
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)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
@ -375,6 +376,9 @@ main(int argc, char *const *argv)
|
||||||
print_usage(prog_name);
|
print_usage(prog_name);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -480,6 +484,11 @@ main(int argc, char *const *argv)
|
||||||
conf.presentation_timings = presentation_timings;
|
conf.presentation_timings = presentation_timings;
|
||||||
conf.hold_at_exit = hold;
|
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 fdm *fdm = NULL;
|
||||||
struct reaper *reaper = NULL;
|
struct reaper *reaper = NULL;
|
||||||
struct wayland *wayl = NULL;
|
struct wayland *wayl = NULL;
|
||||||
|
|
|
||||||
32
meson.build
32
meson.build
|
|
@ -35,17 +35,15 @@ add_project_arguments(
|
||||||
language: 'c',
|
language: 'c',
|
||||||
)
|
)
|
||||||
|
|
||||||
default_terminfo_install_location = join_paths(get_option('datadir'), 'foot', 'terminfo')
|
|
||||||
terminfo_install_location = get_option('custom-terminfo-install-location')
|
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(
|
add_project_arguments(
|
||||||
['-DFOOT_TERMINFO_PATH="@0@"'.format(
|
['-DFOOT_TERMINFO_PATH="@0@"'.format(
|
||||||
join_paths(get_option('prefix'), terminfo_install_location))],
|
join_paths(get_option('prefix'), terminfo_install_location))],
|
||||||
language: 'c')
|
language: 'c')
|
||||||
|
else
|
||||||
|
terminfo_install_location = join_paths(get_option('datadir'), 'terminfo')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Compute the relative path used by compiler invocations.
|
# Compute the relative path used by compiler invocations.
|
||||||
|
|
@ -246,15 +244,24 @@ endif
|
||||||
|
|
||||||
tic = find_program('tic', native: true, required: get_option('terminfo'))
|
tic = find_program('tic', native: true, required: get_option('terminfo'))
|
||||||
if tic.found()
|
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(
|
custom_target(
|
||||||
'terminfo',
|
'terminfo',
|
||||||
output: 'f',
|
output: get_option('default-terminfo')[0],
|
||||||
input: 'foot.info',
|
input: preprocessed,
|
||||||
command: [tic, '-x', '-o', '@OUTDIR@', '-e', 'foot,foot-direct', '@INPUT@'],
|
command: [tic, '-x', '-o', '@OUTDIR@', '-e', '@0@,@0@-direct'.format(get_option('default-terminfo')), '@INPUT@'],
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: (terminfo_install_location != 'no'
|
install_dir: terminfo_install_location
|
||||||
? terminfo_install_location
|
|
||||||
: default_terminfo_install_location)
|
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
@ -267,8 +274,9 @@ summary(
|
||||||
'IME': get_option('ime'),
|
'IME': get_option('ime'),
|
||||||
'Grapheme clustering': utf8proc.found(),
|
'Grapheme clustering': utf8proc.found(),
|
||||||
'Build terminfo': tic.found(),
|
'Build terminfo': tic.found(),
|
||||||
|
'Terminfo install location': terminfo_install_location,
|
||||||
'Default TERM': get_option('default-terminfo'),
|
'Default TERM': get_option('default-terminfo'),
|
||||||
'Terminfo custom install location': terminfo_install_location,
|
'Set TERMINFO': get_option('custom-terminfo-install-location') != '',
|
||||||
},
|
},
|
||||||
bool_yn: true
|
bool_yn: true
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,5 @@ option('terminfo', type: 'feature', value: 'enabled', description: 'Build and in
|
||||||
option('default-terminfo', type: 'string', value: 'foot',
|
option('default-terminfo', type: 'string', value: 'foot',
|
||||||
description: 'Default value of the "term" option in foot.ini.')
|
description: 'Default value of the "term" option in foot.ini.')
|
||||||
|
|
||||||
option('custom-terminfo-install-location', type: 'string',
|
option('custom-terminfo-install-location', type: 'string', value: '',
|
||||||
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.')
|
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 (base != 0) {
|
||||||
if (unlikely(
|
if (unlikely(
|
||||||
/* Classic box drawings */
|
/* 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"
|
* 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
|
* Note, the full range is U+1FB00 - U+1FBF9
|
||||||
*/
|
*/
|
||||||
|
(base >= GLYPH_LEGACY_FIRST &&
|
||||||
/* Unicode 13 sextants */
|
base <= GLYPH_LEGACY_LAST)) &&
|
||||||
(base >= 0x1fb00 && base <= 0x1fb8b) ||
|
|
||||||
(base >= 0x1fb9a && base <= 0x1fb9b)) &&
|
|
||||||
|
|
||||||
likely(!term->conf->box_drawings_uses_font_glyphs))
|
likely(!term->conf->box_drawings_uses_font_glyphs))
|
||||||
{
|
{
|
||||||
/* Box drawing characters */
|
struct fcft_glyph ***arr;
|
||||||
size_t idx = base >= 0x1fb00
|
size_t count;
|
||||||
? (base >= 0x1fb9a
|
size_t idx;
|
||||||
? base - 0x1fb9a + 300
|
|
||||||
: base - 0x1fb00 + 160)
|
|
||||||
: base - 0x2500;
|
|
||||||
xassert(idx < ALEN(term->box_drawing));
|
|
||||||
|
|
||||||
if (likely(term->box_drawing[idx] != NULL))
|
if (base >= GLYPH_LEGACY_FIRST) {
|
||||||
single = term->box_drawing[idx];
|
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 {
|
else {
|
||||||
mtx_lock(&term->render.workers.lock);
|
mtx_lock(&term->render.workers.lock);
|
||||||
|
|
||||||
/* Parallel thread may have instantiated it while we took the lock */
|
/* Other thread may have instantiated it while we
|
||||||
if (term->box_drawing[idx] == NULL)
|
* acquired the lock */
|
||||||
term->box_drawing[idx] = box_drawing(term, base);
|
single = (*arr)[idx];
|
||||||
|
if (likely(single == NULL))
|
||||||
|
single = (*arr)[idx] = box_drawing(term, base);
|
||||||
mtx_unlock(&term->render.workers.lock);
|
mtx_unlock(&term->render.workers.lock);
|
||||||
|
|
||||||
single = term->box_drawing[idx];
|
|
||||||
xassert(single != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glyph_count = 1;
|
if (single != NULL) {
|
||||||
glyphs = &single;
|
glyph_count = 1;
|
||||||
cell_cols = single->cols;
|
glyphs = &single;
|
||||||
|
cell_cols = single->cols;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (base >= CELL_COMB_CHARS_LO && base <= CELL_COMB_CHARS_HI)
|
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,
|
&clip, x, y,
|
||||||
render_width, term->cell_height);
|
render_width, term->cell_height);
|
||||||
pixman_image_set_clip_region32(pix, &clip);
|
pixman_image_set_clip_region32(pix, &clip);
|
||||||
|
pixman_region32_fini(&clip);
|
||||||
|
|
||||||
/* Background */
|
/* Background */
|
||||||
pixman_image_fill_rectangles(
|
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
|
void
|
||||||
selection_start(struct terminal *term, int col, int row,
|
selection_start(struct terminal *term, int col, int row,
|
||||||
enum selection_kind kind,
|
enum selection_kind kind,
|
||||||
|
|
@ -421,13 +465,19 @@ selection_start(struct terminal *term, int col, int row,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SELECTION_LINE_WISE:
|
case SELECTION_LINE_WISE: {
|
||||||
term->selection.start = (struct coord){0, term->grid->view + row};
|
struct coord start = {0, row}, end = {term->cols - 1, row};
|
||||||
term->selection.pivot.start = term->selection.start;
|
selection_find_line_boundary_left(term, &start, spaces_only);
|
||||||
term->selection.pivot.end = (struct coord){term->cols - 1, term->grid->view + row};
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SELECTION_NONE:
|
case SELECTION_NONE:
|
||||||
BUG("Invalid selection kind");
|
BUG("Invalid selection kind");
|
||||||
|
|
@ -756,13 +806,21 @@ selection_update(struct terminal *term, int col, int row)
|
||||||
|
|
||||||
case SELECTION_LINE_WISE:
|
case SELECTION_LINE_WISE:
|
||||||
switch (term->selection.direction) {
|
switch (term->selection.direction) {
|
||||||
case SELECTION_LEFT:
|
case SELECTION_LEFT: {
|
||||||
new_end.col = 0;
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SELECTION_RIGHT:
|
case SELECTION_RIGHT: {
|
||||||
new_end.col = term->cols - 1;
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SELECTION_UNDIR:
|
case SELECTION_UNDIR:
|
||||||
break;
|
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) {
|
switch (term->selection.kind) {
|
||||||
case SELECTION_CHAR_WISE:
|
case SELECTION_CHAR_WISE:
|
||||||
xassert(new_kind == 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_start = {new_start.col, new_start.row - term->grid->view};
|
||||||
struct coord pivot_end = pivot_start;
|
struct coord pivot_end = pivot_start;
|
||||||
|
|
||||||
selection_find_word_boundary_left(
|
selection_find_word_boundary_left(term, &pivot_start, spaces_only);
|
||||||
term, &pivot_start, term->selection.spaces_only);
|
selection_find_word_boundary_right(term, &pivot_end, spaces_only);
|
||||||
selection_find_word_boundary_right(
|
|
||||||
term, &pivot_end, term->selection.spaces_only);
|
|
||||||
|
|
||||||
term->selection.pivot.start =
|
term->selection.pivot.start =
|
||||||
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
|
(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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SELECTION_LINE_WISE:
|
case SELECTION_LINE_WISE: {
|
||||||
xassert(new_kind == SELECTION_CHAR_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};
|
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
|
||||||
term->selection.pivot.end = (struct coord){term->cols - 1, new_start.row};
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SELECTION_BLOCK:
|
case SELECTION_BLOCK:
|
||||||
case SELECTION_NONE:
|
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 =
|
const bool need_to_clone_conf =
|
||||||
tll_length(overrides)> 0 ||
|
tll_length(overrides)> 0 ||
|
||||||
cdata.hold != server->conf->hold_at_exit ||
|
cdata.hold != server->conf->hold_at_exit;
|
||||||
cdata.no_wait != server->conf->no_wait;
|
|
||||||
|
|
||||||
struct config *conf = NULL;
|
struct config *conf = NULL;
|
||||||
if (need_to_clone_conf) {
|
if (need_to_clone_conf) {
|
||||||
conf = config_clone(server->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)
|
if (cdata.hold != server->conf->hold_at_exit)
|
||||||
conf->hold_at_exit = cdata.hold;
|
conf->hold_at_exit = cdata.hold;
|
||||||
|
|
||||||
config_override_apply(conf, &overrides, false);
|
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) {
|
*instance = (struct terminal_instance) {
|
||||||
|
|
@ -311,7 +313,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf != NULL && conf->no_wait) {
|
if (cdata.no_wait) {
|
||||||
// the server owns the instance
|
// the server owns the instance
|
||||||
tll_push_back(server->terminals, instance);
|
tll_push_back(server->terminals, instance);
|
||||||
client_send_exit_code(client, 0);
|
client_send_exit_code(client, 0);
|
||||||
|
|
|
||||||
35
sixel.c
35
sixel.c
|
|
@ -15,16 +15,6 @@
|
||||||
|
|
||||||
static size_t count;
|
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
|
void
|
||||||
sixel_fini(struct terminal *term)
|
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;
|
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++)
|
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;
|
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 */
|
/* 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 *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 */
|
/* Copy old rows, and initialize new columns to background color */
|
||||||
for (int r = 0; r < height; r++) {
|
for (int r = 0; r < height; r++) {
|
||||||
|
|
@ -1167,7 +1162,7 @@ resize_vertically(struct terminal *term, int new_height)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t bg = get_bg(term);
|
uint32_t bg = term->sixel.default_bg;
|
||||||
|
|
||||||
/* Initialize new rows to background color */
|
/* Initialize new rows to background color */
|
||||||
for (int r = old_height; r < new_height; r++) {
|
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);
|
xassert(alloc_new_height - new_height < 6);
|
||||||
|
|
||||||
uint32_t *new_data = NULL;
|
uint32_t *new_data = NULL;
|
||||||
uint32_t bg = get_bg(term);
|
uint32_t bg = term->sixel.default_bg;
|
||||||
|
|
||||||
if (new_width == old_width) {
|
if (new_width == old_width) {
|
||||||
/* Width (and thus stride) is the same, so we can simply
|
/* 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
|
static void
|
||||||
sixel_add_many(struct terminal *term, uint8_t c, unsigned count)
|
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 col = term->sixel.pos.col;
|
||||||
int width = term->sixel.image.width;
|
int width = term->sixel.image.width;
|
||||||
|
|
||||||
|
|
@ -1288,6 +1281,7 @@ sixel_add_many(struct terminal *term, uint8_t c, unsigned count)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t color = term->sixel.color;
|
||||||
for (unsigned i = 0; i < count; i++, col++)
|
for (unsigned i = 0; i < count; i++, col++)
|
||||||
sixel_add(term, col, width, color, c);
|
sixel_add(term, col, width, color, c);
|
||||||
|
|
||||||
|
|
@ -1407,7 +1401,7 @@ decgra(struct terminal *term, uint8_t c)
|
||||||
}
|
}
|
||||||
|
|
||||||
term->sixel.state = SIXEL_DECSIXEL;
|
term->sixel.state = SIXEL_DECSIXEL;
|
||||||
sixel_put(term, c);
|
decsixel(term, c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1514,10 +1508,11 @@ decgci(struct terminal *term, uint8_t c)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
term->sixel.color = term->sixel.palette[term->sixel.color_idx];
|
||||||
|
|
||||||
term->sixel.state = SIXEL_DECSIXEL;
|
term->sixel.state = SIXEL_DECSIXEL;
|
||||||
sixel_put(term, c);
|
decsixel(term, c);
|
||||||
break;
|
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) {
|
if (chdir(cwd) < 0) {
|
||||||
const int errno_copy = errno;
|
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));
|
(void)!write(fork_pipe[1], &errno_copy, sizeof(errno_copy));
|
||||||
_exit(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)
|
if (sigaction(SIGHUP, &(struct sigaction){.sa_handler = SIG_DFL}, NULL) < 0)
|
||||||
goto child_err;
|
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_stderr = stderr_fd >= 0;
|
||||||
bool close_stdout = stdout_fd >= 0 && stdout_fd != stderr_fd;
|
bool close_stdout = stdout_fd >= 0 && stdout_fd != stderr_fd;
|
||||||
bool close_stdin = stdin_fd >= 0 && stdin_fd != stdout_fd && stdin_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))) ||
|
|| (close_stdout && close(stdout_fd) < 0))) ||
|
||||||
(stderr_fd >= 0 && (dup2(stderr_fd, STDERR_FILENO) < 0
|
(stderr_fd >= 0 && (dup2(stderr_fd, STDERR_FILENO) < 0
|
||||||
|| (close_stderr && close(stderr_fd) < 0))) ||
|
|| (close_stderr && close(stderr_fd) < 0))) ||
|
||||||
(cwd != NULL && chdir(cwd) < 0) ||
|
|
||||||
execvp(argv[0], argv) < 0)
|
execvp(argv[0], argv) < 0)
|
||||||
{
|
{
|
||||||
goto child_err;
|
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];
|
uint8_t buf[24 * 1024];
|
||||||
ssize_t count = sizeof(buf);
|
|
||||||
|
|
||||||
const size_t max_iterations = !hup ? 10 : (size_t)-1ll;
|
const size_t max_iterations = !hup ? 10 : (size_t)-1ll;
|
||||||
|
|
||||||
for (size_t i = 0; i < max_iterations && pollin; i++) {
|
for (size_t i = 0; i < max_iterations && pollin; i++) {
|
||||||
xassert(pollin);
|
xassert(pollin);
|
||||||
count = read(term->ptmx, buf, sizeof(buf));
|
ssize_t count = read(term->ptmx, buf, sizeof(buf));
|
||||||
|
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
if (errno == EAGAIN || errno == EIO) {
|
if (errno == EAGAIN || errno == EIO) {
|
||||||
|
|
@ -628,15 +626,28 @@ err_sem_destroy:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
return;
|
||||||
|
|
||||||
free(pixman_image_get_data((*box_drawing)->pix));
|
free(pixman_image_get_data((*glyph)->pix));
|
||||||
pixman_image_unref((*box_drawing)->pix);
|
pixman_image_unref((*glyph)->pix);
|
||||||
free(*box_drawing);
|
free(*glyph);
|
||||||
*box_drawing = NULL;
|
*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
|
static bool
|
||||||
|
|
@ -649,18 +660,27 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4])
|
||||||
term->fonts[i] = fonts[i];
|
term->fonts[i] = fonts[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < ALEN(term->box_drawing); i++)
|
free_custom_glyphs(
|
||||||
free_box_drawing(&term->box_drawing[i]);
|
&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_width = term->cell_width;
|
||||||
const int old_cell_height = term->cell_height;
|
const int old_cell_height = term->cell_height;
|
||||||
|
|
||||||
const struct config *conf = term->conf;
|
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->cell_width =
|
||||||
(term->fonts[0]->space_advance.x > 0
|
(M != NULL
|
||||||
? term->fonts[0]->space_advance.x
|
? M->advance.x
|
||||||
: term->fonts[0]->max_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_pt_or_px_as_pixels(term, &conf->letter_spacing);
|
||||||
|
|
||||||
term->cell_height = term->font_line_height.px >= 0
|
term->cell_height = term->font_line_height.px >= 0
|
||||||
|
|
@ -793,25 +813,48 @@ get_font_subpixel(const struct terminal *term)
|
||||||
return FCFT_SUBPIXEL_DEFAULT;
|
return FCFT_SUBPIXEL_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
term_font_sized_by_dpi(const struct terminal *term, int scale)
|
term_font_size_by_dpi(const struct terminal *term)
|
||||||
{
|
{
|
||||||
return term->conf->dpi_aware == DPI_AWARE_YES ||
|
switch (term->conf->dpi_aware) {
|
||||||
(term->conf->dpi_aware == DPI_AWARE_AUTO && scale <= 1);
|
case DPI_AWARE_YES: return true;
|
||||||
}
|
case DPI_AWARE_NO: return false;
|
||||||
|
|
||||||
bool
|
case DPI_AWARE_AUTO:
|
||||||
term_font_sized_by_scale(const struct terminal *term, int scale)
|
/*
|
||||||
{
|
* Scale using DPI if all monitors have a scaling factor or 1.
|
||||||
return !term_font_sized_by_dpi(term, scale);
|
*
|
||||||
|
* 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
|
int
|
||||||
term_pt_or_px_as_pixels(const struct terminal *term,
|
term_pt_or_px_as_pixels(const struct terminal *term,
|
||||||
const struct pt_or_px *pt_or_px)
|
const struct pt_or_px *pt_or_px)
|
||||||
{
|
{
|
||||||
double scale = term_font_sized_by_scale(term, term->scale) ? term->scale : 1.;
|
double scale = !term->font_is_sized_by_dpi ? term->scale : 1.;
|
||||||
double dpi = term_font_sized_by_dpi(term, term->scale) ? term->font_dpi : 96.;
|
double dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.;
|
||||||
|
|
||||||
return pt_or_px->px == 0
|
return pt_or_px->px == 0
|
||||||
? round(pt_or_px->pt * scale * dpi / 72)
|
? 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;
|
bool use_px_size = term->font_sizes[i][j].px_size > 0;
|
||||||
char size[64];
|
char size[64];
|
||||||
|
|
||||||
const int scale =
|
const int scale = term->font_is_sized_by_dpi ? 1 : term->scale;
|
||||||
term_font_sized_by_scale(term, term->scale) ? term->scale : 1;
|
|
||||||
|
|
||||||
if (use_px_size)
|
if (use_px_size)
|
||||||
snprintf(size, sizeof(size), ":pixelsize=%d",
|
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 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 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};
|
char *attrs[4] = {NULL};
|
||||||
int attr_len[4] = {-1, -1, -1, -1}; /* -1, so that +1 (below) results in 0 */
|
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++)
|
for (size_t i = 0; i < 4; i++)
|
||||||
free(term->font_sizes[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);
|
free(term->search.buf);
|
||||||
|
|
||||||
|
|
@ -1983,8 +2030,8 @@ term_font_dpi_changed(struct terminal *term, int old_scale)
|
||||||
float dpi = get_font_dpi(term);
|
float dpi = get_font_dpi(term);
|
||||||
xassert(term->scale > 0);
|
xassert(term->scale > 0);
|
||||||
|
|
||||||
bool was_scaled_using_dpi = term_font_sized_by_dpi(term, old_scale);
|
bool was_scaled_using_dpi = term->font_is_sized_by_dpi;
|
||||||
bool will_scale_using_dpi = term_font_sized_by_dpi(term, term->scale);
|
bool will_scale_using_dpi = term_font_size_by_dpi(term);
|
||||||
|
|
||||||
bool need_font_reload =
|
bool need_font_reload =
|
||||||
was_scaled_using_dpi != will_scale_using_dpi ||
|
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) {
|
if (need_font_reload) {
|
||||||
LOG_DBG("DPI/scale change: DPI-awareness=%s, "
|
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",
|
"sizing font based on monitor's %s",
|
||||||
term->conf->dpi_aware == DPI_AWARE_AUTO ? "auto" :
|
term->conf->dpi_aware == DPI_AWARE_AUTO ? "auto" :
|
||||||
term->conf->dpi_aware == DPI_AWARE_YES ? "yes" : "no",
|
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");
|
will_scale_using_dpi ? "DPI" : "scaling factor");
|
||||||
}
|
}
|
||||||
|
|
||||||
term->font_dpi = dpi;
|
term->font_dpi = dpi;
|
||||||
|
term->font_is_sized_by_dpi = will_scale_using_dpi;
|
||||||
|
|
||||||
if (!need_font_reload)
|
if (!need_font_reload)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
31
terminal.h
31
terminal.h
|
|
@ -329,16 +329,31 @@ struct terminal {
|
||||||
struct config_font *font_sizes[4];
|
struct config_font *font_sizes[4];
|
||||||
struct pt_or_px font_line_height;
|
struct pt_or_px font_line_height;
|
||||||
float font_dpi;
|
float font_dpi;
|
||||||
|
bool font_is_sized_by_dpi;
|
||||||
int16_t font_x_ofs;
|
int16_t font_x_ofs;
|
||||||
int16_t font_y_ofs;
|
int16_t font_y_ofs;
|
||||||
enum fcft_subpixel font_subpixel;
|
enum fcft_subpixel font_subpixel;
|
||||||
|
|
||||||
/*
|
struct {
|
||||||
* 0-159: U+02500+0259F
|
struct fcft_glyph **box_drawing;
|
||||||
* 160-299: U+1FB00-1FB8B
|
struct fcft_glyph **braille;
|
||||||
* 300-301: U+1FB9A-1FB9B
|
struct fcft_glyph **legacy;
|
||||||
*/
|
|
||||||
struct fcft_glyph *box_drawing[302];
|
#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;
|
bool is_sending_paste_data;
|
||||||
ptmx_buffer_list_t ptmx_buffers;
|
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 *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 *shared_palette; /* Shared palette, used when private mode 1070 is disabled */
|
||||||
uint32_t *palette; /* Points to either private_palette or shared_palette */
|
uint32_t *palette; /* Points to either private_palette or shared_palette */
|
||||||
|
uint32_t color;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32_t *data; /* Raw image data, in ARGB */
|
uint32_t *data; /* Raw image data, in ARGB */
|
||||||
|
|
@ -576,6 +592,7 @@ struct terminal {
|
||||||
unsigned param_idx; /* Parameters seen */
|
unsigned param_idx; /* Parameters seen */
|
||||||
|
|
||||||
bool transparent_bg;
|
bool transparent_bg;
|
||||||
|
uint32_t default_bg;
|
||||||
|
|
||||||
/* Application configurable */
|
/* Application configurable */
|
||||||
unsigned palette_size; /* Number of colors in palette */
|
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);
|
bool term_font_dpi_changed(struct terminal *term, int old_scale);
|
||||||
void term_font_subpixel_changed(struct terminal *term);
|
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(
|
int term_pt_or_px_as_pixels(
|
||||||
const struct terminal *term, const struct pt_or_px *pt_or_px);
|
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) {
|
tll_foreach(wayl->terms, it) {
|
||||||
struct terminal *term = it->item;
|
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) {
|
tll_foreach(term->window->on_outputs, it2) {
|
||||||
if (it2->item == mon) {
|
if (it2->item == mon) {
|
||||||
update_term_for_output_change(term);
|
update_term_for_output_change(term);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue