mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-03 05:03:39 +02:00
Compare commits
1 Commits
copilot/ad
...
curve
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e6b26dd7e |
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -1,7 +1,3 @@
|
||||
kitty/terminfo.h linguist-generated=true
|
||||
terminfo/kitty.termcap linguist-generated=true
|
||||
terminfo/kitty.terminfo linguist-generated=true
|
||||
terminfo/x/xterm-kitty linguist-generated=true
|
||||
kitty/char-props-data.h linguist-generated=true
|
||||
kitty_tests/GraphemeBreakTest.json linguist-generated=true
|
||||
kitty/charsets.c linguist-generated=true
|
||||
@@ -11,7 +7,6 @@ kitty/rgb.py linguist-generated=true
|
||||
kitty/srgb_gamma.* linguist-generated=true
|
||||
kitty/gl-wrapper.* linguist-generated=true
|
||||
kitty/glfw-wrapper.* linguist-generated=true
|
||||
kitty/color-names.h linguist-generated=true
|
||||
kitty/parse-graphics-command.h linguist-generated=true
|
||||
kitty/parse-multicell-command.h linguist-generated=true
|
||||
kitty/options/types.py linguist-generated=true
|
||||
|
||||
35
.github/copilot-instructions.md
vendored
35
.github/copilot-instructions.md
vendored
@@ -1,35 +0,0 @@
|
||||
Before implementing any code changes or responding to a request, run the
|
||||
following command:
|
||||
|
||||
python3 .github/workflows/ci.py build
|
||||
|
||||
This will download needed dependencies, then create all generated files
|
||||
and build the project, making it ready for inspection.
|
||||
|
||||
# Repository Build & Test Instructions
|
||||
|
||||
## Build Procedures
|
||||
- **Build command:** Run `./dev.sh build` to build the project
|
||||
- Run `gen/config.py` to update generated config parsing code for both kitty
|
||||
and kitten. The `gen/go_code.py` generator is run automatically by the build
|
||||
command to keep generated Go code files up to date.
|
||||
- To build individual kittens use the build command above **do not** try to run go build
|
||||
yourself.
|
||||
|
||||
Once a build is done, the kitty and kitten binaries will be in the `kitty/launcher` directory.
|
||||
Note that the kitty binary can run python files using `kitty +launch file.py`.
|
||||
When it does so the kitty fast_data_types module is available to the python
|
||||
code.
|
||||
|
||||
## Test Procedures
|
||||
- To run the complete test suite, run `./test.py`
|
||||
- To run a specific test, run `./test.py test_name` where `test_name` is the name of the test without the
|
||||
leading `test_` for Python tests and without the leading `Test` for Go tests.
|
||||
- Do not use go test or ./setup.py test to run tests
|
||||
|
||||
## PR guidance
|
||||
When creating a pull request, if the changes in the pull request are user
|
||||
visible compared to the previous kitty release, add an entry in the file docs/changelog.rst
|
||||
describing the change. If the changes include changes to Go code, run gofmt on
|
||||
the changed Go files to ensure they are formatted correctly, before submitting
|
||||
your changes.
|
||||
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
@@ -13,15 +13,3 @@ updates:
|
||||
all-go-deps:
|
||||
patterns:
|
||||
- "*" # group all non-security update PRs
|
||||
cooldown:
|
||||
default-days: 7
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
191
.github/workflows/ci.py
vendored
191
.github/workflows/ci.py
vendored
@@ -4,33 +4,24 @@
|
||||
|
||||
import glob
|
||||
import io
|
||||
import json
|
||||
import lzma
|
||||
import os
|
||||
import platform
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import time
|
||||
from urllib.request import Request, urlopen
|
||||
from urllib.request import urlopen
|
||||
|
||||
BUNDLE_URL = 'https://download.calibre-ebook.com/ci/kitty/{}-64.tar.xz'
|
||||
FONTS_URL = 'https://download.calibre-ebook.com/ci/fonts.tar.xz'
|
||||
NERD_URL = 'https://github.com/ryanoasis/nerd-fonts/releases/latest/download/NerdFontsSymbolsOnly.tar.xz'
|
||||
is_bundle = os.environ.get('KITTY_BUNDLE') == '1'
|
||||
is_codeql = os.environ.get('KITTY_CODEQL') == '1'
|
||||
is_macos = 'darwin' in sys.platform.lower()
|
||||
running_under_sanitizer = os.environ.get('KITTY_SANITIZE') == '1'
|
||||
SW = ''
|
||||
SLANG_INSTALL_DIR = '/tmp/slang'
|
||||
|
||||
|
||||
def do_print_crash_reports() -> None:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
time.sleep(2)
|
||||
print('Printing available crash reports...')
|
||||
if is_macos:
|
||||
end_time = time.monotonic() + 90
|
||||
@@ -70,25 +61,9 @@ def run(*a: str, print_crash_reports: bool = False) -> None:
|
||||
raise SystemExit(f'The following process failed with exit code: {ret}:\n{cmd}')
|
||||
|
||||
|
||||
def download_with_retry(url: str | Request, count: int = 5) -> bytes:
|
||||
for i in range(count):
|
||||
try:
|
||||
print('Downloading', getattr(url, 'full_url', url), flush=True)
|
||||
with urlopen(url) as f:
|
||||
ans: bytes = f.read()
|
||||
return ans
|
||||
except Exception as err:
|
||||
if getattr(err, 'code', -1) == 403:
|
||||
raise
|
||||
if i >= count - 1:
|
||||
raise
|
||||
print(f'Download failed with error {err} retrying...', file=sys.stderr)
|
||||
time.sleep(1)
|
||||
return b''
|
||||
|
||||
|
||||
def install_fonts() -> None:
|
||||
data = download_with_retry(FONTS_URL)
|
||||
with urlopen(FONTS_URL) as f:
|
||||
data = f.read()
|
||||
fonts_dir = os.path.expanduser('~/Library/Fonts' if is_macos else '~/.local/share/fonts')
|
||||
os.makedirs(fonts_dir, exist_ok=True)
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||
@@ -96,7 +71,8 @@ def install_fonts() -> None:
|
||||
tf.extractall(fonts_dir, filter='fully_trusted')
|
||||
except TypeError:
|
||||
tf.extractall(fonts_dir)
|
||||
data = download_with_retry(NERD_URL)
|
||||
with urlopen(NERD_URL) as f:
|
||||
data = f.read()
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||
try:
|
||||
tf.extractall(fonts_dir, filter='fully_trusted')
|
||||
@@ -104,52 +80,23 @@ def install_fonts() -> None:
|
||||
tf.extractall(fonts_dir)
|
||||
|
||||
|
||||
def install_slang_compiler() -> None:
|
||||
os_name = 'macos' if is_macos else 'linux'
|
||||
machine = platform.machine().lower()
|
||||
arch = 'aarch64' if machine in ('aarch64', 'arm64') else 'x86_64'
|
||||
|
||||
with open('bypy/sources.json') as f:
|
||||
data = json.loads(f.read())
|
||||
for dep in data:
|
||||
if dep['name'].startswith('slang '):
|
||||
version = dep['name'].split()[-1]
|
||||
break
|
||||
url = f'https://github.com/shader-slang/slang/releases/download/v{version}/slang-{version}-{os_name}-{arch}.tar.gz'
|
||||
install_dir = SLANG_INSTALL_DIR
|
||||
os.makedirs(install_dir, exist_ok=True)
|
||||
data = download_with_retry(url)
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:gz') as tf:
|
||||
try:
|
||||
tf.extractall(install_dir, filter='fully_trusted')
|
||||
except TypeError:
|
||||
# filter parameter not supported on older Python versions
|
||||
tf.extractall(install_dir)
|
||||
|
||||
pc_dir = os.path.join(install_dir, 'lib', 'pkgconfig')
|
||||
pp = os.environ.get('PKG_CONFIG_PATH', '')
|
||||
os.environ['PKG_CONFIG_PATH'] = f'{pc_dir}:{pp}' if pp else pc_dir
|
||||
|
||||
|
||||
def install_deps() -> None:
|
||||
print('Installing kitty dependencies...')
|
||||
sys.stdout.flush()
|
||||
if is_macos:
|
||||
if not is_codeql: # for some reason brew fails on CodeQL we dont need it anyway
|
||||
items = [x.split()[1].strip('"') for x in open('Brewfile').readlines() if x.strip().startswith('brew ')]
|
||||
openssl = 'openssl'
|
||||
items.remove('go') # already installed by ci.yml
|
||||
import ssl
|
||||
if ssl.OPENSSL_VERSION_INFO[0] == 1:
|
||||
openssl += '@1.1'
|
||||
run('brew', 'install', 'fish', openssl, *items)
|
||||
items = [x.split()[1].strip('"') for x in open('Brewfile').readlines() if x.strip().startswith('brew ')]
|
||||
openssl = 'openssl'
|
||||
items.remove('go') # already installed by ci.yml
|
||||
import ssl
|
||||
if ssl.OPENSSL_VERSION_INFO[0] == 1:
|
||||
openssl += '@1.1'
|
||||
run('brew', 'install', 'fish', openssl, *items)
|
||||
else:
|
||||
run('sudo apt-get update')
|
||||
run('sudo apt-get install -y --fix-missing libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev ca-certificates'
|
||||
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev ca-certificates'
|
||||
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libx11-xcb-dev zsh'
|
||||
' libpng-dev liblcms2-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev libxxhash-dev uuid-dev'
|
||||
' libsimde-dev libsystemd-dev libcairo2-dev zsh bash dash systemd-coredump gdb'
|
||||
' libwayland-dev wayland-protocols glslang-tools')
|
||||
' libsimde-dev libsystemd-dev libcairo2-dev zsh bash dash systemd-coredump gdb')
|
||||
# for some reason these directories are world writable which causes zsh
|
||||
# compinit to break
|
||||
run('sudo chmod -R og-w /usr/share/zsh')
|
||||
@@ -160,21 +107,16 @@ def install_deps() -> None:
|
||||
if sys.version_info[:2] < (3, 7):
|
||||
cmd += ' importlib-resources dataclasses'
|
||||
run(cmd)
|
||||
install_slang_compiler()
|
||||
install_fonts()
|
||||
|
||||
|
||||
def set_slangc() -> None:
|
||||
slangc = os.path.join(SW if is_bundle else SLANG_INSTALL_DIR, 'bin', 'slangc')
|
||||
os.environ['SLANGC'] = slangc
|
||||
|
||||
|
||||
def build_kitty() -> None:
|
||||
python = shutil.which('python3') if is_bundle else sys.executable
|
||||
cmd = f'{python} setup.py build --verbose'
|
||||
if running_under_sanitizer:
|
||||
if is_macos:
|
||||
cmd += ' --debug' # for better crash report to debug SIGILL issue
|
||||
if os.environ.get('KITTY_SANITIZE') == '1':
|
||||
cmd += ' --debug --sanitize'
|
||||
set_slangc()
|
||||
run(cmd)
|
||||
|
||||
|
||||
@@ -182,17 +124,12 @@ def test_kitty() -> None:
|
||||
if is_macos:
|
||||
run('ulimit -c unlimited')
|
||||
run('sudo chmod -R 777 /cores')
|
||||
if running_under_sanitizer:
|
||||
os.environ['MallocNanoZone'] = '0'
|
||||
set_slangc()
|
||||
run('./test.py', print_crash_reports=True)
|
||||
|
||||
|
||||
def package_kitty() -> None:
|
||||
set_slangc()
|
||||
python = 'python3' if is_macos else 'python'
|
||||
run(f'{python} setup.py linux-package --update-check-interval=0 --verbose')
|
||||
run('make FAIL_WARN=1 docs')
|
||||
if is_macos:
|
||||
run('python3 setup.py kitty.app --update-check-interval=0 --verbose')
|
||||
run('kitty.app/Contents/MacOS/kitty +runpy "from kitty.constants import *; print(kitty_exe())"')
|
||||
@@ -207,8 +144,7 @@ def replace_in_file(path: str, src: str, dest: str) -> None:
|
||||
|
||||
def setup_bundle_env() -> None:
|
||||
global SW
|
||||
os.environ['SW'] = SW = '/Users/Shared/kitty-build/sw/sw' if is_macos else os.path.join(
|
||||
os.environ['GITHUB_WORKSPACE'], 'sw')
|
||||
os.environ['SW'] = SW = '/Users/Shared/kitty-build/sw/sw' if is_macos else os.path.join(os.environ['GITHUB_WORKSPACE'], 'sw')
|
||||
os.environ['PKG_CONFIG_PATH'] = os.path.join(SW, 'lib', 'pkgconfig')
|
||||
if is_macos:
|
||||
os.environ['PATH'] = '{}:{}'.format('/usr/local/opt/sphinx-doc/bin', os.environ['PATH'])
|
||||
@@ -218,13 +154,12 @@ def setup_bundle_env() -> None:
|
||||
os.environ['PATH'] = '{}:{}'.format(os.path.join(SW, 'bin'), os.environ['PATH'])
|
||||
|
||||
|
||||
def install_bundle(dest: str = '', which: str = '') -> None:
|
||||
dest = dest or SW
|
||||
def install_bundle() -> None:
|
||||
cwd = os.getcwd()
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
os.chdir(dest)
|
||||
which = which or ('macos' if is_macos else 'linux')
|
||||
data = download_with_retry(BUNDLE_URL.format(which))
|
||||
os.makedirs(SW)
|
||||
os.chdir(SW)
|
||||
with urlopen(BUNDLE_URL.format('macos' if is_macos else 'linux')) as f:
|
||||
data = f.read()
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||
try:
|
||||
tf.extractall(filter='fully_trusted')
|
||||
@@ -235,83 +170,13 @@ def install_bundle(dest: str = '', which: str = '') -> None:
|
||||
for dirpath, dirnames, filenames in os.walk('.'):
|
||||
for f in filenames:
|
||||
if f.endswith('.pc') or (f.endswith('.py') and f.startswith('_sysconfig')):
|
||||
replace_in_file(os.path.join(dirpath, f), '/sw/sw', dest)
|
||||
replace_in_file(os.path.join(dirpath, f), '/sw/sw', SW)
|
||||
replaced += 1
|
||||
if replaced < 2:
|
||||
raise SystemExit('Failed to replace path to SW in bundle')
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
def install_grype(exe: str = '/tmp/grype') -> str:
|
||||
raw = download_with_retry('https://download.calibre-ebook.com/ci/grype.xz')
|
||||
raw = lzma.decompress(raw)
|
||||
with open(exe, 'wb') as f:
|
||||
f.write(raw)
|
||||
os.fchmod(f.fileno(), 0o755)
|
||||
subprocess.check_call([exe, 'db', 'update'])
|
||||
return exe
|
||||
|
||||
|
||||
IGNORED_DEPENDENCY_CVES = [
|
||||
# Python stdlib
|
||||
'CVE-2025-8194', # DoS in tarfile
|
||||
'CVE-2025-6069', # DoS in HTMLParser
|
||||
'CVE-2025-13836', # DoS in http client reading from malicious server
|
||||
'CVE-2025-12084', # DoS in xml.dom.minidom unused in kitty
|
||||
'CVE-2025-13837', # DoS in plistlib reading plist. We only use plistlib for writing
|
||||
'CVE-2025-6075', # Quadratic complexity in os.path.expandvars()
|
||||
# python stdlib all these are erroneously marked as fixed in python 3.15
|
||||
# when it hasnt even been released. Sigh.
|
||||
'CVE-2026-1299',
|
||||
'CVE-2026-0865',
|
||||
'CVE-2025-15282',
|
||||
'CVE-2026-0672',
|
||||
'CVE-2025-15366',
|
||||
'CVE-2025-15367',
|
||||
'CVE-2025-12781',
|
||||
'CVE-2025-11468',
|
||||
'CVE-2026-2297',
|
||||
'CVE-2026-3644',
|
||||
'CVE-2026-4224',
|
||||
'CVE-2026-4519',
|
||||
'CVE-2026-1502',
|
||||
'CVE-2026-7210', # DoS in unused XML parser
|
||||
'CVE-2026-3276', # DoS in unicodedata.normalize()
|
||||
'CVE-2026-7774', # tarfile.data_filter path traversal bypass
|
||||
# github.com/nwaples/rardecode/v2
|
||||
'CVE-2025-11579', # rardecode is version 2.2.1, not vulnerable
|
||||
'CVE-2026-2673', # openssl fix not released
|
||||
]
|
||||
|
||||
|
||||
def check_dependencies() -> None:
|
||||
grype = install_grype()
|
||||
with open((gc := os.path.expanduser('~/.grype.yml')), 'w') as f:
|
||||
print('ignore:', file=f)
|
||||
for x in IGNORED_DEPENDENCY_CVES:
|
||||
print(' - vulnerability:', x, file=f)
|
||||
dest = os.path.join(SW, 'linux')
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
install_bundle(dest, os.path.basename(dest))
|
||||
dest = os.path.join(SW, 'macos')
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
install_bundle(dest, os.path.basename(dest))
|
||||
cmdline = [grype, '--by-cve', '--config', gc, '--fail-on', 'medium', '--only-fixed', '--add-cpes-if-none']
|
||||
if (subprocess.run(cmdline + ['dir:' + SW])).returncode != 0:
|
||||
raise SystemExit('grype found problems during filesystem scan')
|
||||
# Now test against the SBOM
|
||||
import runpy
|
||||
orig = sys.argv, sys.stdout
|
||||
sys.argv = ['bypy', 'sbom', 'kovidgoyal/kitty', '1.0.0']
|
||||
buf = io.StringIO()
|
||||
sys.stdout = buf
|
||||
runpy.run_path('bypy-src')
|
||||
sys.argv, sys.stdout = orig
|
||||
print(buf.getvalue())
|
||||
if (subprocess.run(cmdline, input=buf.getvalue().encode())).returncode != 0:
|
||||
raise SystemExit('grype found problems during SBOM scan')
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if is_bundle:
|
||||
setup_bundle_env()
|
||||
@@ -324,23 +189,15 @@ def main() -> None:
|
||||
if action == 'build':
|
||||
build_kitty()
|
||||
elif action == 'package':
|
||||
build_kitty()
|
||||
test_kitty()
|
||||
package_kitty()
|
||||
elif action == 'test':
|
||||
test_kitty()
|
||||
elif action == 'govulncheck':
|
||||
subprocess.check_call(['go', 'install', 'golang.org/x/vuln/cmd/govulncheck@latest'])
|
||||
subprocess.check_call(['govulncheck', '-mode=binary', 'kitty/launcher/kitten'])
|
||||
subprocess.check_call(['govulncheck', './...'])
|
||||
elif action == 'gofmt':
|
||||
q = subprocess.check_output('gofmt -s -l tools kittens'.split()).decode()
|
||||
if q.strip():
|
||||
q = '\n'.join(filter(lambda x: not x.rstrip().endswith('_generated.go'), q.strip().splitlines())).strip()
|
||||
if q:
|
||||
raise SystemExit(q)
|
||||
elif action == 'check-dependencies':
|
||||
check_dependencies()
|
||||
else:
|
||||
raise SystemExit(f'Unknown action: {action}')
|
||||
|
||||
|
||||
59
.github/workflows/ci.yml
vendored
59
.github/workflows/ci.yml
vendored
@@ -23,15 +23,15 @@ jobs:
|
||||
cc: [gcc, clang]
|
||||
include:
|
||||
- python: a
|
||||
pyver: "3.11"
|
||||
pyver: "3.10"
|
||||
sanitize: 0
|
||||
|
||||
- python: b
|
||||
pyver: "3.12"
|
||||
pyver: "3.11"
|
||||
sanitize: 1
|
||||
|
||||
- python: c
|
||||
pyver: "3.13"
|
||||
pyver: "3.12"
|
||||
sanitize: 1
|
||||
|
||||
|
||||
@@ -45,18 +45,18 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6.0.3
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python ${{ matrix.pyver }}
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.pyver }}
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
CFLAGS: -funsigned-char
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6.0.3
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # needed for :commit: docs role
|
||||
persist-credentials: false
|
||||
@@ -85,18 +85,18 @@ jobs:
|
||||
run: if grep -Inr ':code:`\s' kitty kitty_tests kittens docs *.py *.asciidoc *.rst *.go .gitattributes .gitignore; then echo Space at code block start found, aborting.; exit 1; fi
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.14"
|
||||
python-version: "3.13"
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: false
|
||||
|
||||
- name: Cache Go build artifacts separately
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
${{ runner.os }}-golang-static-
|
||||
|
||||
- name: Install build-only deps
|
||||
run: python -m pip install -r docs/requirements.txt ruff mypy types-requests types-docutils types-Pygments
|
||||
run: python -m pip install -r docs/requirements.txt ruff mypy types-requests types-docutils
|
||||
|
||||
- name: Run ruff
|
||||
run: ruff check .
|
||||
@@ -117,12 +117,21 @@ jobs:
|
||||
- name: Build kitty package
|
||||
run: python .github/workflows/ci.py package
|
||||
|
||||
- name: Build kitty
|
||||
run: python setup.py build --debug
|
||||
|
||||
- name: Run mypy
|
||||
run: which python && python -m mypy --version && ./test.py mypy
|
||||
|
||||
- name: Run go vet
|
||||
run: go version && go vet -tags testing ./...
|
||||
|
||||
- name: Build man page
|
||||
run: make FAIL_WARN=1 man
|
||||
|
||||
- name: Build HTML docs
|
||||
run: make FAIL_WARN=1 html
|
||||
|
||||
- name: Build static kittens
|
||||
run: python setup.py build-static-binaries
|
||||
|
||||
@@ -134,16 +143,15 @@ jobs:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
env:
|
||||
KITTY_BUNDLE: 1
|
||||
KITTY_SANITIZE: 1
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6.0.3
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
@@ -158,24 +166,33 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6.0.3
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # needed for :commit: docs role
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.14"
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Build kitty
|
||||
run: python3 .github/workflows/ci.py build
|
||||
|
||||
- name: Test kitty
|
||||
run: python3 .github/workflows/ci.py test
|
||||
|
||||
- name: Install deps for docs
|
||||
run: python3 -m pip install -r docs/requirements.txt
|
||||
|
||||
- name: Builds docs
|
||||
run: make FAIL_WARN=1 docs
|
||||
|
||||
- name: Build kitty package
|
||||
run: python3 .github/workflows/ci.py package
|
||||
|
||||
@@ -187,7 +204,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6.0.3
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
@@ -196,7 +213,7 @@ jobs:
|
||||
run: sudo apt-get update && sudo apt-get install -y curl xz-utils build-essential git pkg-config libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libgl1-mesa-dev libxkbcommon-x11-dev libfontconfig-dev libx11-xcb-dev libdbus-1-dev
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
|
||||
45
.github/workflows/codeql-analysis.yml
vendored
45
.github/workflows/codeql-analysis.yml
vendored
@@ -1,14 +1,17 @@
|
||||
name: "CodeQL"
|
||||
name: "Code scanning - action"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
branches: [master, ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 22 * * 5'
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
@@ -16,56 +19,30 @@ jobs:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
security-events: write # to upload SARIF results (github/codeql-action/analyze)
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: python
|
||||
os: ubuntu-latest
|
||||
- language: c
|
||||
os: ubuntu-latest
|
||||
- language: c
|
||||
os: macos-latest
|
||||
- language: go
|
||||
os: ubuntu-latest
|
||||
- language: actions
|
||||
os: ubuntu-latest
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
KITTY_BUNDLE: 1
|
||||
KITTY_CODEQL: 1
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6.0.3
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Go
|
||||
if: matrix.language == 'c' || matrix.language == 'go'
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4.36.2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
trap-caching: false
|
||||
languages: python, c, go
|
||||
|
||||
- name: Build kitty
|
||||
if: matrix.language == 'c' || matrix.language == 'go'
|
||||
run: python3 .github/workflows/ci.py build
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4.36.2
|
||||
|
||||
- name: Run govulncheck
|
||||
if: matrix.language == 'go'
|
||||
run: python3 .github/workflows/ci.py govulncheck
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
39
.github/workflows/depscan.yml
vendored
39
.github/workflows/depscan.yml
vendored
@@ -1,39 +0,0 @@
|
||||
name: Depscan
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 12 * * 5'
|
||||
|
||||
env:
|
||||
CI: 'true'
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
LC_ALL: en_US.UTF-8
|
||||
LANG: en_US.UTF-8
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
dependecy-scanner:
|
||||
name: Scan dependencies for vulnerabilities
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
KITTY_BUNDLE: 1
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6.0.3
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
|
||||
- name: Checkout bypy
|
||||
uses: actions/checkout@v6.0.3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
repository: kovidgoyal/bypy
|
||||
path: bypy-src
|
||||
|
||||
- name: Check dependencies
|
||||
run: python3 .github/workflows/ci.py check-dependencies
|
||||
97
.github/workflows/macos_crash_report.py
vendored
97
.github/workflows/macos_crash_report.py
vendored
@@ -2,99 +2,17 @@
|
||||
# License: GPLv3 Copyright: 2024, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import json
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import defaultdict, namedtuple
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from functools import cached_property
|
||||
from typing import IO, Mapping, Optional
|
||||
from typing import IO, List, Mapping, Optional
|
||||
|
||||
Frame = namedtuple('Frame', 'image_name image_base image_offset symbol symbol_offset')
|
||||
Register = namedtuple('Register', 'name value')
|
||||
|
||||
# Cache mapping filename (basename) -> absolute path, built once on first use.
|
||||
_build_file_cache: Optional[dict[str, str]] = None
|
||||
|
||||
|
||||
def _build_filename_cache() -> dict[str, str]:
|
||||
"""Walk the repo build tree and map each filename to its absolute path.
|
||||
|
||||
The script lives at <repo>/.github/workflows/, so the repo root is two
|
||||
levels up. We scan the whole repo tree so we find both in-tree build
|
||||
artefacts (e.g. kitty/fast_data_types.so) and those under build/.
|
||||
"""
|
||||
cache: dict[str, str] = {}
|
||||
repo_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
for dirpath, _dirnames, filenames in os.walk(repo_root):
|
||||
for fname in filenames:
|
||||
# Keep the first occurrence (shallowest path wins).
|
||||
if fname not in cache:
|
||||
cache[fname] = os.path.join(dirpath, fname)
|
||||
return cache
|
||||
|
||||
|
||||
def _resolve_image_path(image_path: str) -> str:
|
||||
"""Return the real filesystem path for *image_path*.
|
||||
|
||||
Crash reports on macOS redact parts of paths for privacy, replacing
|
||||
directory components with ``*`` (e.g. ``/Users/USER/*/fast_data_types.so``).
|
||||
These are *not* glob patterns — the ``*`` is a literal privacy placeholder.
|
||||
When such a path is detected, look up the basename in the build-file cache.
|
||||
"""
|
||||
if '*' not in image_path and '?' not in image_path:
|
||||
return image_path
|
||||
|
||||
global _build_file_cache
|
||||
if _build_file_cache is None:
|
||||
_build_file_cache = _build_filename_cache()
|
||||
|
||||
basename = os.path.basename(image_path)
|
||||
return _build_file_cache.get(basename, image_path)
|
||||
|
||||
|
||||
def _get_source_locations(frames: list[Frame]) -> dict[int, str]:
|
||||
"""Use atos to look up source file and line number for each frame.
|
||||
|
||||
Returns a mapping of frame index -> 'source_file:line_number' string.
|
||||
Only frames with a known image path and base address are processed.
|
||||
"""
|
||||
# Group frames by (image_path, load_address) so we can batch atos calls.
|
||||
by_image: dict[tuple[str, int], list[tuple[int, int]]] = defaultdict(list) # (path, base) -> [(address, frame_idx)]
|
||||
for i, frame in enumerate(frames):
|
||||
if frame.image_name and frame.image_base is not None and frame.image_offset is not None:
|
||||
addr = frame.image_base + frame.image_offset
|
||||
by_image[(frame.image_name, frame.image_base)].append((addr, i))
|
||||
|
||||
result: dict[int, str] = {}
|
||||
for (image_path, load_addr), addr_frame_pairs in by_image.items():
|
||||
addresses = [addr for addr, _ in addr_frame_pairs]
|
||||
frame_indices = [idx for _, idx in addr_frame_pairs]
|
||||
# Paths in crash reports may have privacy-redacted components (e.g.
|
||||
# /Users/USER/*/fast_data_types.so). Resolve to a real path using the
|
||||
# cached build-file index before passing to atos.
|
||||
resolved_path = _resolve_image_path(image_path)
|
||||
try:
|
||||
cmd = ['atos', '-o', resolved_path, '-l', hex(load_addr)] + [hex(a) for a in addresses]
|
||||
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
if proc.returncode == 0:
|
||||
lines = proc.stdout.splitlines()
|
||||
for frame_idx, line in zip(frame_indices, lines):
|
||||
# atos output: "func_name (in binary) (source_file:line)"
|
||||
# Extract the trailing "(file:line)" part. Use [^:]+ for the
|
||||
# file portion since colons in filenames are rare/invalid on
|
||||
# macOS, and this avoids false-matches with parentheses in paths.
|
||||
m = re.search(r'\(([^:()]+:\d+)\)\s*$', line)
|
||||
if m:
|
||||
result[frame_idx] = m.group(1)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def surround(x: str, start: int, end: int) -> str:
|
||||
if sys.stdout.isatty():
|
||||
@@ -351,7 +269,7 @@ class UserModeCrashReport(CrashReportBase):
|
||||
return int(self._parse_field('Triggered by Thread'))
|
||||
|
||||
@cached_property
|
||||
def frames(self) -> list[Frame]:
|
||||
def frames(self) -> List[Frame]:
|
||||
result = []
|
||||
if self._is_json:
|
||||
thread_index = self.faulting_thread
|
||||
@@ -386,7 +304,7 @@ class UserModeCrashReport(CrashReportBase):
|
||||
return result
|
||||
|
||||
@cached_property
|
||||
def registers(self) -> list[Register]:
|
||||
def registers(self) -> List[Register]:
|
||||
result = []
|
||||
if self._is_json:
|
||||
thread_index = self._data['faultingThread']
|
||||
@@ -490,9 +408,8 @@ class UserModeCrashReport(CrashReportBase):
|
||||
|
||||
result += '\n\n'
|
||||
|
||||
source_locations = _get_source_locations(self.frames)
|
||||
result += bold('Frames:\n')
|
||||
for i, frame in enumerate(self.frames):
|
||||
for frame in self.frames:
|
||||
image_base = '_HEADER'
|
||||
if frame.image_base is not None:
|
||||
image_base = f'0x{frame.image_base:x}'
|
||||
@@ -501,14 +418,12 @@ class UserModeCrashReport(CrashReportBase):
|
||||
result += f' + 0x{frame.image_offset:x}'
|
||||
if frame.symbol is not None:
|
||||
result += f' ({frame.symbol} + 0x{frame.symbol_offset:x})'
|
||||
if i in source_locations:
|
||||
result += f' [{source_locations[i]}]'
|
||||
result += '\n'
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_crash_report_from_file(crash_report_file: IO[str]) -> CrashReportBase:
|
||||
def get_crash_report_from_file(crash_report_file: IO) -> CrashReportBase:
|
||||
metadata = json.loads(crash_report_file.readline())
|
||||
|
||||
try:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -13,7 +13,6 @@
|
||||
/tags
|
||||
/build/
|
||||
/fonts/
|
||||
/shaders/
|
||||
/linux-package/
|
||||
/kitty.app/
|
||||
/glad/out/
|
||||
@@ -30,5 +29,3 @@ __pycache__/
|
||||
.cache
|
||||
bypy/b
|
||||
bypy/virtual-machines.conf
|
||||
_codeql_detected_source_root
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
= kitty - the fast, feature-rich, cross-platform, GPU based terminal
|
||||
|
||||
If you live in the terminal, *kitty* is made for **you**!
|
||||
|
||||
See https://sw.kovidgoyal.net/kitty/[the kitty website].
|
||||
|
||||
image:https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg["Build status", link="https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI"]
|
||||
|
||||
12
SECURITY.md
12
SECURITY.md
@@ -7,12 +7,6 @@ and released just like all other bugs.
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
Preferably send an email to kovid at kovidgoyal.net or open a private security
|
||||
advisory using the GitHub security advisory facility.
|
||||
|
||||
Note that I will generally respond to security communication within 72 hours. Once
|
||||
the bug is confirmed, it will be fixed or at least mitigated within another 72
|
||||
hours, at which time the fix will typically be committed to master and hence be
|
||||
public. That timeline might be extended based on the severity of the issue and the
|
||||
current state of master in terms of making a new release, if so, it will be
|
||||
done in consultation with the issue reporter.
|
||||
Preferably send an email to kovid at kovidgoyal.net or open an issue in the
|
||||
GitHub repository, though the latter means you are disclosing the vulnerability
|
||||
publicly before it can be fixed.
|
||||
|
||||
@@ -50,7 +50,7 @@ def run_parsing_benchmark(cell_width: int = 10, cell_height: int = 20, scrollbac
|
||||
|
||||
screen = Screen(None, rows, columns, scrollback, cell_width, cell_height, 0, ToChild())
|
||||
|
||||
def parse_bytes(data: bytes|memoryview) -> None:
|
||||
def parse_bytes(data: bytes) -> None:
|
||||
data = memoryview(data)
|
||||
while data:
|
||||
dest = screen.test_create_write_buffer()
|
||||
|
||||
@@ -96,8 +96,8 @@ func get_dependencies(path string) (ans []dependency) {
|
||||
for _, line := range lines("otool", "-L", path) {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.Contains(line, "compatibility") && !strings.HasSuffix(line, ":") {
|
||||
before, _, _ := strings.Cut(line, "(")
|
||||
dep := strings.TrimSpace(before)
|
||||
idx := strings.IndexByte(line, '(')
|
||||
dep := strings.TrimSpace(line[:idx])
|
||||
ans = append(ans, dependency{path: dep, is_id: dep == install_name})
|
||||
}
|
||||
}
|
||||
@@ -279,12 +279,8 @@ func dependencies(args []string) {
|
||||
which = "macos"
|
||||
case "linux":
|
||||
which = "linux"
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
case "arm64", "arm64be":
|
||||
url = strings.Replace(url, "-64.", "-arm64.", 1)
|
||||
default:
|
||||
exit(fmt.Sprintf("Pre-built binaries are not available for the %s architecture", runtime.GOARCH))
|
||||
if runtime.GOARCH != "amd64" {
|
||||
exit("Pre-built dependencies are only available for the amd64 CPU architecture")
|
||||
}
|
||||
}
|
||||
if which == "" {
|
||||
@@ -393,7 +389,6 @@ func build(args []string) {
|
||||
}
|
||||
root := root_dir()
|
||||
os.Setenv("DEVELOP_ROOT", root)
|
||||
os.Setenv("SLANGC", filepath.Join(root, "bin", "slangc"))
|
||||
prepend("PKG_CONFIG_PATH", filepath.Join(root, "lib", "pkgconfig"))
|
||||
if runtime.GOOS == "darwin" {
|
||||
os.Setenv("PKGCONFIG_EXE", filepath.Join(root, "bin", "pkg-config"))
|
||||
|
||||
@@ -11,7 +11,7 @@ import sys
|
||||
import tempfile
|
||||
from contextlib import suppress
|
||||
|
||||
from bypy.constants import BIN, LIBDIR, PREFIX, PYTHON, ismacos, worker_env
|
||||
from bypy.constants import LIBDIR, PREFIX, PYTHON, ismacos, worker_env
|
||||
from bypy.constants import SRC as KITTY_DIR
|
||||
from bypy.utils import run_shell, walk
|
||||
|
||||
@@ -39,7 +39,6 @@ def run(*args, **extra_env):
|
||||
env.update(extra_env)
|
||||
env['SW'] = PREFIX
|
||||
env['LD_LIBRARY_PATH'] = LIBDIR
|
||||
env['SLANGC'] = os.path.join(BIN, 'slangc')
|
||||
if ismacos:
|
||||
env['PKGCONFIG_EXE'] = os.path.join(PREFIX, 'bin', 'pkg-config')
|
||||
cwd = env.pop('cwd', KITTY_DIR)
|
||||
@@ -90,7 +89,7 @@ def build_frozen_tools(kitty_exe):
|
||||
|
||||
def sanitize_source_folder(path: str) -> None:
|
||||
for q in walk(path):
|
||||
if os.path.splitext(q)[1] not in ('.py', '.glsl', '.slang', '.ttf', '.otf', '.json'):
|
||||
if os.path.splitext(q)[1] not in ('.py', '.glsl', '.ttf', '.otf', '.json'):
|
||||
os.unlink(q)
|
||||
|
||||
|
||||
@@ -100,7 +99,6 @@ def build_c_extensions(ext_dir, args):
|
||||
shutil.copytree(
|
||||
KITTY_DIR, writeable_src_dir, symlinks=True,
|
||||
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o', '*.so', '*.dylib', '*.pyd'))
|
||||
shutil.rmtree(os.path.join(writeable_src_dir, 'shaders'))
|
||||
|
||||
with suppress(FileNotFoundError):
|
||||
os.unlink(os.path.join(writeable_src_dir, 'kitty', 'launcher', 'kitty'))
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
image 'https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-{}.img'
|
||||
image 'https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-{}.img'
|
||||
|
||||
deps 'bison flex libxcursor-dev libxrandr-dev libxi-dev libxinerama-dev libgl1-mesa-dev libx11-xcb-dev libxcb-xkb-dev libfontconfig1-dev libdbus-1-dev libsystemd-dev'
|
||||
|
||||
@@ -10,7 +10,7 @@ import subprocess
|
||||
import tarfile
|
||||
import time
|
||||
|
||||
from bypy.constants import BIN, LIBDIR, OUTPUT_DIR, PREFIX, python_major_minor_version
|
||||
from bypy.constants import OUTPUT_DIR, PREFIX, python_major_minor_version
|
||||
from bypy.freeze import extract_extension_modules, freeze_python, path_to_freeze_dir
|
||||
from bypy.utils import get_dll_path, mkdtemp, py_compile, walk
|
||||
|
||||
@@ -90,14 +90,6 @@ def copy_libs(env):
|
||||
shutil.copy2(x, dest)
|
||||
dest = os.path.join(dest, os.path.basename(x))
|
||||
subprocess.check_call(['chrpath', '-d', dest])
|
||||
# Copy slang
|
||||
x = 'libslang-compiler.so'
|
||||
shutil.copy2(os.path.join(LIBDIR, f'{x}.0.0.0.0'), env.lib_dir)
|
||||
os.symlink(f'{x}.0.0.0.0', os.path.join(env.lib_dir, x))
|
||||
for x in ('glsl-module', 'glslang'):
|
||||
x = f'libslang-{x}-0.0.0.so'
|
||||
shutil.copy2(os.path.join(LIBDIR, x), env.lib_dir)
|
||||
shutil.copy2(os.path.join(BIN, 'slangc'), env.bin_dir)
|
||||
|
||||
|
||||
def add_ca_certs(env):
|
||||
@@ -146,6 +138,10 @@ def copy_python(env):
|
||||
shutil.rmtree(env.py_dir)
|
||||
|
||||
|
||||
def build_launcher(env):
|
||||
iv['build_frozen_launcher']([path_to_freeze_dir(), env.obj_dir])
|
||||
|
||||
|
||||
def is_elf(path):
|
||||
with open(path, 'rb') as f:
|
||||
return f.read(4) == b'\x7fELF'
|
||||
@@ -232,7 +228,7 @@ def main():
|
||||
env = Env(os.path.join(ext_dir, kitty_constants['appname']))
|
||||
copy_libs(env)
|
||||
copy_python(env)
|
||||
iv['build_frozen_launcher']([path_to_freeze_dir(), env.obj_dir])
|
||||
build_launcher(env)
|
||||
files = find_binaries(env)
|
||||
fix_permissions(files)
|
||||
add_ca_certs(env)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Requires installation of XCode >= 10.3 and go 1.26 and Python 3 and
|
||||
# python3 -m pip install certifi meson ninja
|
||||
# Requires installation of XCode >= 10.3 and go 1.23 and Python 3 and
|
||||
# python3 -m pip install certifi
|
||||
|
||||
vm_name 'macos-kitty'
|
||||
root '/Users/Shared/kitty-build'
|
||||
python '/usr/local/bin/python3'
|
||||
universal 'true'
|
||||
deploy_target '12.0'
|
||||
deploy_target '11.0'
|
||||
|
||||
@@ -12,7 +12,7 @@ import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
|
||||
from bypy.constants import BIN, LIBDIR, PREFIX, PYTHON, SW, python_major_minor_version
|
||||
from bypy.constants import PREFIX, PYTHON, SW, python_major_minor_version
|
||||
from bypy.freeze import extract_extension_modules, freeze_python, path_to_freeze_dir
|
||||
from bypy.macos_sign import codesign, create_entitlements_file, make_certificate_useable, notarize_app, verify_signature
|
||||
from bypy.utils import current_dir, mkdtemp, py_compile, run_shell, timeit, walk
|
||||
@@ -301,7 +301,7 @@ class Freeze(object):
|
||||
self.fix_dependencies_in_lib(join(self.frameworks_dir, basename(path)))
|
||||
|
||||
@flush
|
||||
def add_misc_libraries(self) -> None:
|
||||
def add_misc_libraries(self):
|
||||
for x in (
|
||||
'sqlite3.0',
|
||||
'z.1',
|
||||
@@ -319,22 +319,6 @@ class Freeze(object):
|
||||
dest = join(self.frameworks_dir, x)
|
||||
self.set_id(dest, f'{self.FID}/{x}')
|
||||
self.fix_dependencies_in_lib(dest)
|
||||
# Copy slang
|
||||
x = 'libslang-compiler.0.0.0.0.dylib'
|
||||
shutil.copy2(os.path.join(LIBDIR, x), self.frameworks_dir)
|
||||
os.symlink(x, os.path.join(self.frameworks_dir, 'libslang-compiler.dylib'))
|
||||
dest = join(self.frameworks_dir, x)
|
||||
self.set_id(dest, f'{self.FID}/{x}')
|
||||
self.fix_dependencies_in_lib(dest)
|
||||
for x in ('glsl-module', 'glslang'):
|
||||
x = f'libslang-{x}-0.0.0.dylib'
|
||||
shutil.copy2(os.path.join(LIBDIR, x), self.frameworks_dir)
|
||||
dest = join(self.frameworks_dir, x)
|
||||
self.set_id(dest, f'{self.FID}/{x}')
|
||||
dest = os.path.join(self.contents_dir, 'MacOS')
|
||||
shutil.copy2(os.path.join(BIN, 'slangc'), dest)
|
||||
dest = os.path.join(dest, 'slangc')
|
||||
self.fix_dependencies_in_lib(dest)
|
||||
|
||||
@flush
|
||||
def add_package_dir(self, x, dest=None):
|
||||
|
||||
@@ -1,310 +1,321 @@
|
||||
[
|
||||
{
|
||||
"name": "zlib 1.3.2",
|
||||
"name": "zlib",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:d7a0654783a4da529d1bb793b7ad9c3318020af77667bcae35f95d0e42a792f3",
|
||||
"filename": "zlib-1.3.1.tar.xz",
|
||||
"hash": "sha256:38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32",
|
||||
"urls": ["https://zlib.net/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "bzip2 1.0.8",
|
||||
"name": "bzip2",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "bzip2-1.0.8.tar.gz",
|
||||
"hash": "sha256:ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269",
|
||||
"urls": ["https://www.sourceware.org/pub/{name}/{filename}"]
|
||||
"urls": ["https://www.sourceware.org/pub/bzip2/bzip2-latest.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "pkg-config 0.29.2",
|
||||
"type": "build",
|
||||
"name": "pkg-config",
|
||||
"os": "macos",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "pkg-config-0.29.2.tar.gz",
|
||||
"hash": "sha256:6fc69c01688c9458a57eb9a1664c9aba372ccda420a02bf4429fe610e7e7d591",
|
||||
"urls": ["https://pkg-config.freedesktop.org/releases/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "openssl 3.5.7",
|
||||
"name": "openssl",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:a8c0d28a529ca480f9f36cf5792e2cd21984552a3c8e4aa11a24aa31aeac98e8",
|
||||
"filename": "openssl-3.3.0.tar.gz",
|
||||
"hash": "sha256:53e66b043322a606abf0087e7699a0e033a37fa13feb9742df35c3a33b18fb02",
|
||||
"urls": ["https://www.openssl.org/source/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "cmake 3.29.3",
|
||||
"type": "build",
|
||||
"name": "cmake",
|
||||
"os": "macos",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "cmake-3.29.3.tar.gz",
|
||||
"hash": "sha256:252aee1448d49caa04954fd5e27d189dd51570557313e7b281636716a238bccb",
|
||||
"urls": ["https://cmake.org/files/v{version_except_last}/{filename}"]
|
||||
"urls": ["https://cmake.org/files/v3.19/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "expat 2.6.2",
|
||||
"name": "expat",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "expat-2.6.2.tar.xz",
|
||||
"hash": "sha256:ee14b4c5d8908b1bec37ad937607eab183d4d9806a08adee472c3c3121d27364",
|
||||
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_{version_with_underscores}/{filename}"]
|
||||
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_2_6_2/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libxml2 2.15.3",
|
||||
"name": "libxml2",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:78262a6e7ac170d6528ebfe2efccdf220191a5af6a6cd61ea4a9a9a5042c7a07",
|
||||
"urls": ["https://download.gnome.org/sources/libxml2/{version_except_last}/{filename}"]
|
||||
"filename": "libxml2-2.12.7.tar.xz",
|
||||
"hash": "sha256:24ae78ff1363a973e6d8beba941a7945da2ac056e19b53956aeb6927fd6cfb56",
|
||||
"urls": ["https://download.gnome.org/sources/libxml2/2.12/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xkbcommon 1.7.0",
|
||||
"name": "xkbcommon",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "libxkbcommon-1.7.0.tar.xz",
|
||||
"hash": "sha256:65782f0a10a4b455af9c6baab7040e2f537520caa2ec2092805cdfd36863b247",
|
||||
"urls": ["https://xkbcommon.org/download/lib{filename}"]
|
||||
"urls": ["https://xkbcommon.org/download/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sqlite 3.53.2",
|
||||
"name": "sqlite",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:588ad51949419a56ebe81fe56193d510c559eb94c9a57748387860b5d3069316",
|
||||
"urls": ["https://www.sqlite.org/2026/{name}-autoconf-3530200.{file_extension}"]
|
||||
"filename": "sqlite-autoconf-3450300.tar.gz",
|
||||
"hash": "sha256:b2809ca53124c19c60f42bf627736eae011afdcc205bb48270a5ee9a38191531",
|
||||
"urls": ["https://www.sqlite.org/2024/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libffi 3.4.6",
|
||||
"name": "libffi",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "libffi-3.4.6.tar.gz",
|
||||
"hash": "sha256:b0dea9df23c863a7a50e825440f3ebffabd65df1497108e5d437747843895a4e",
|
||||
"urls": ["https://github.com/libffi/libffi/releases/download/v{version}/{filename}"]
|
||||
"urls": ["https://github.com/libffi/libffi/releases/download/v3.4.6/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ncurses 6.5",
|
||||
"name": "ncurses",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "ncurses-6.5.tar.gz",
|
||||
"hash": "sha256:136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6",
|
||||
"urls": ["https://ftp.gnu.org/gnu/ncurses/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "readline 8.2",
|
||||
"name": "readline",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "readline-8.2.tar.gz",
|
||||
"hash": "sha256:3feb7171f16a84ee82ca18a36d7b9be109a52c04f492a053331d7d1095007c35",
|
||||
"urls": ["https://ftp.gnu.org/gnu/readline/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xz 5.8.3",
|
||||
"name": "xz",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:3d3a1b973af218114f4f889bbaa2f4c037deaae0c8e815eec381c3d546b974a0",
|
||||
"filename": "xz-5.2.5.tar.gz",
|
||||
"hash": "sha256:f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
|
||||
"urls": ["https://tukaani.org/xz/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libxxhash 0.8.2",
|
||||
"name": "libxxhash",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "xxHash-0.8.2.tar.gz",
|
||||
"hash": "sha256:baee0c6afd4f03165de7a4e67988d16f0f2b257b51d0e3cb91909302a26a79c4",
|
||||
"urls": ["https://github.com/Cyan4973/xxHash/archive/refs/tags/v{version}.{file_extension}"]
|
||||
"urls": ["https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.2.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xcrypt 4.4.36",
|
||||
"name": "xcrypt",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "xcrypt-4.4.36.tar.gz",
|
||||
"hash": "sha256:b979838d5f1f238869d467484793b72b8bca64c4eae696fdbba0a9e0b6c28453",
|
||||
"urls": ["https://github.com/besser82/libxcrypt/archive/v{version}.{file_extension}"]
|
||||
"urls": ["https://github.com/besser82/libxcrypt/archive/v4.4.36.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "python 3.14.6",
|
||||
"name": "python",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:143b1dddefaec3bd2e21e3b839b34a2b7fb9842272883c576420d605e9f30c63",
|
||||
"urls": ["https://www.python.org/ftp/python/{version}/Python-{version}.{file_extension}"]
|
||||
"filename": "Python-3.12.3.tar.xz",
|
||||
"hash": "sha256:56bfef1fdfc1221ce6720e43a661e3eb41785dd914ce99698d8c7896af4bdaa1",
|
||||
"urls": ["https://www.python.org/ftp/python/3.12.3/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libpng 1.6.57",
|
||||
"name": "libpng",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:d10c20d7171569804cae8dfc13ba6dcd0662c41ed39d43d4d429314aafb10a80",
|
||||
"filename": "libpng-1.6.43.tar.xz",
|
||||
"hash": "sha256:6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c",
|
||||
"urls": ["https://downloads.sourceforge.net/sourceforge/libpng/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "lcms2 2.17",
|
||||
"name": "lcms2",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:d11af569e42a1baa1650d20ad61d12e41af4fead4aa7964a01f93b08b53ab074",
|
||||
"urls": ["https://github.com/mm2/Little-CMS/releases/download/lcms{version}/lcms2-{version}.{file_extension}"]
|
||||
"filename": "lcms2-2.16.tar.gz",
|
||||
"hash": "sha256:d873d34ad8b9b4cea010631f1a6228d2087475e4dc5e763eb81acc23d9d45a51",
|
||||
"urls": ["https://github.com/mm2/Little-CMS/archive/2.16/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "graphite 1.3.14",
|
||||
"name": "graphite",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tgz",
|
||||
"filename": "graphite2-1.3.14.tgz",
|
||||
"hash": "sha256:f99d1c13aa5fa296898a181dff9b82fb25f6cc0933dbaa7a475d8109bd54209d",
|
||||
"urls": ["https://downloads.sourceforge.net/silgraphite/graphite2-{version}.{file_extension}"]
|
||||
"urls": ["https://downloads.sourceforge.net/silgraphite/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "pcre 10.43",
|
||||
"name": "pcre",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.bz2",
|
||||
"filename": "pcre2-10.43.tar.bz2",
|
||||
"hash": "sha256:e2a53984ff0b07dfdb5ae4486bbb9b21cca8e7df2434096cc9bf1b728c350bcb",
|
||||
"urls": ["https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/pcre2-{version}.{file_extension}"]
|
||||
"urls": ["https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "iconv 1.17",
|
||||
"name": "iconv",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "libiconv-1.17.tar.gz",
|
||||
"hash": "sha256:8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313",
|
||||
"urls": ["https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{version}.{file_extension}"]
|
||||
"urls": ["https://ftp.gnu.org/pub/gnu/libiconv/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "glib 2.86.3",
|
||||
"os": "linux",
|
||||
"name": "installer",
|
||||
"comment": "Needed infrastructure for installing pure python packages (wheels)",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:b3211d8d34b9df5dca05787ef0ad5d7ca75dec998b970e1aab0001d229977c65",
|
||||
"urls": ["https://download.gnome.org/sources/glib/{version_except_last}/{filename}"]
|
||||
"filename": "installer-0.7.0-py3-none-any.whl",
|
||||
"hash": "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
|
||||
"urls": ["pypi"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libbrotli 1.1.0",
|
||||
"name": "packaging",
|
||||
"comment": "Needed for glib for some absurd reason",
|
||||
"unix": {
|
||||
"filename": "packaging-23.1-py3-none-any.whl",
|
||||
"hash": "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
|
||||
"urls": ["pypi"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "glib",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "glib-2.80.2.tar.xz",
|
||||
"hash": "sha256:b9cfb6f7a5bd5b31238fd5d56df226b2dda5ea37611475bf89f6a0f9400fe8bd",
|
||||
"urls": ["https://download.gnome.org/sources/glib/2.80/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "brotli",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "brotli-1.1.0.tar.gz",
|
||||
"hash": "sha256:e720a6ca29428b803f4ad165371771f5398faba397edf6778837a18599ea13ff",
|
||||
"urls": ["https://github.com/google/brotli/archive/v{version}/{filename}"]
|
||||
"urls": ["https://github.com/google/brotli/archive/v1.1.0/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "pixman 0.44.2",
|
||||
"name": "pixman",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "pixman-0.44.2.tar.xz",
|
||||
"hash": "sha256:50baf820dde0c5ff9714d03d2df4970f606a3d3b1024f5404c0398a9821cc4b0",
|
||||
"urls": ["https://www.cairographics.org/releases/{filename}"]
|
||||
"urls": ["https://www.cairographics.org/releases/pixman-0.44.2.tar.xz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "freetype 2.13.2",
|
||||
"name": "freetype",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "freetype-2.13.2.tar.xz",
|
||||
"hash": "sha256:12991c4e55c506dd7f9b765933e62fd2be2e06d421505d7950a132e4f1bb484d",
|
||||
"urls": ["https://download.savannah.gnu.org/releases/freetype/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "fontconfig 2.17.1",
|
||||
"name": "fontconfig",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:9f5cae93f4fffc1fbc05ae99cdfc708cd60dfd6612ffc0512827025c026fa541",
|
||||
"urls": ["https://gitlab.freedesktop.org/api/v4/projects/890/packages/generic/fontconfig/{version}/{filename}"]
|
||||
"filename": "fontconfig-2.13.1.tar.bz2",
|
||||
"hash": "sha256:f655dd2a986d7aa97e052261b36aa67b0a64989496361eca8d604e6414006741",
|
||||
"urls": ["https://www.fontconfig.org/release/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "cairo 1.18.2",
|
||||
"name": "cairo",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "cairo-1.18.2.tar.xz",
|
||||
"hash": "sha256:a62b9bb42425e844cc3d6ddde043ff39dbabedd1542eba57a2eb79f85889d45a",
|
||||
"urls": ["https://www.cairographics.org/releases/{filename}"]
|
||||
"urls": ["https://www.cairographics.org/releases/cairo-1.18.2.tar.xz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "harfbuzz 12.3.0",
|
||||
"name": "harfbuzz",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:8660ebd3c27d9407fc8433b5d172bafba5f0317cb0bb4339f28e5370c93d42b7",
|
||||
"urls": ["https://github.com/harfbuzz/harfbuzz/releases/download/{version}/{filename}"]
|
||||
"filename": "harfbuzz-8.5.0.tar.xz",
|
||||
"hash": "sha256:77e4f7f98f3d86bf8788b53e6832fb96279956e1c3961988ea3d4b7ca41ddc27",
|
||||
"urls": ["https://github.com/harfbuzz/harfbuzz/releases/download/8.5.0/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "simde 0.8.2",
|
||||
"name": "simde",
|
||||
"comment": "Cannot update till gcc in the build VM is updated as simde 0.8 requires newer gcc",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:59068edc3420e75c5ff85ecfd80a77196fb3a151227a666cc20abb313a5360bf",
|
||||
"urls": ["https://github.com/simd-everywhere/simde/releases/download/v{version}/simde-amalgamated-{version}.{file_extension}"]
|
||||
"filename": "simde-amalgamated-0.7.6.tar.xz",
|
||||
"hash": "sha256:703eac1f2af7de1f7e4aea2286130b98e1addcc0559426e78304c92e2b4eb5e1",
|
||||
"urls": ["https://github.com/simd-everywhere/simde/releases/download/v0.7.6/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "slang 2026.12.2",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:1ed5ebf7886849ea621d6dabee20248e8551c80134aa8c4433746879cb20dea3",
|
||||
"urls": ["git-submodules://github.com/shader-slang/slang.git"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "wayland 1.24.0",
|
||||
"name": "wayland",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:82892487a01ad67b334eca83b54317a7c86a03a89cfadacfef5211f11a5d0536",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland/-/releases/{version}/downloads/{filename}"]
|
||||
"filename": "wayland-1.23.0.tar.xz",
|
||||
"hash": "sha256:05b3e1574d3e67626b5974f862f36b5b427c7ceeb965cb36a4e6c2d342e45ab2",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.23.0/downloads/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "wayland-protocols 1.45",
|
||||
"name": "wayland-protocols",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:4d2b2a9e3e099d017dc8107bf1c334d27bb87d9e4aff19a0c8d856d17cd41ef0",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/{version}/downloads/{filename}"]
|
||||
"filename": "wayland-protocols-1.41.tar.xz",
|
||||
"hash": "sha256:2786b6b1b79965e313f2c289c12075b9ed700d41844810c51afda10ee329576b",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/1.41/downloads/{filename}"]
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
@@ -13,6 +13,6 @@ for attr in ('linguist-generated', 'linguist-vendored'):
|
||||
fname = line.split(':', 1)[0]
|
||||
all_files.discard(fname)
|
||||
|
||||
all_files -= {'gen/rowcolumn-diacritics.txt'}
|
||||
all_files -= {'gen/nerd-fonts-glyphs.txt', 'gen/rowcolumn-diacritics.txt'}
|
||||
cp = subprocess.run(['cloc', '--list-file', '-'], input='\n'.join(all_files).encode())
|
||||
raise SystemExit(cp.returncode)
|
||||
|
||||
@@ -8,7 +8,4 @@ using the ``map`` and ``mouse_map`` directives in :file:`kitty.conf`. For
|
||||
configuration examples, see the default shortcut links for each action.
|
||||
To read about keyboard mapping in more detail, see :doc:`mapping`.
|
||||
|
||||
You can also browse and trigger these actions by pressing :sc:`command_palette`
|
||||
to run the :doc:`/kittens/command-palette`.
|
||||
|
||||
.. include:: /generated/actions.rst
|
||||
|
||||
@@ -25,7 +25,6 @@ Previous shell prompt :sc:`scroll_to_previous_prompt` (see :ref:`shell_int
|
||||
Next shell prompt :sc:`scroll_to_next_prompt` (see :ref:`shell_integration`)
|
||||
Browse scrollback in less :sc:`show_scrollback`
|
||||
Browse last cmd output :sc:`show_last_command_output` (see :ref:`shell_integration`)
|
||||
Search scrollback in less :sc:`search_scrollback` (also :kbd:`⌘+F` on macOS)
|
||||
========================= =======================
|
||||
|
||||
The scroll actions only take effect when the terminal is in the main screen.
|
||||
@@ -41,7 +40,7 @@ Action Shortcut
|
||||
======================== =======================
|
||||
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
|
||||
Close tab :sc:`close_tab` (also :kbd:`⌘+w` on macOS)
|
||||
Next tab :sc:`next_tab` (also :kbd:`⌃+⇥` and :kbd:`⇧+⌘+]` on macOS)
|
||||
Next tab :sc:`next_tab` (also :kbd:`⇧+⌃+⇥` and :kbd:`⇧+⌘+]` on macOS)
|
||||
Previous tab :sc:`previous_tab` (also :kbd:`⇧+⌃+⇥` and :kbd:`⇧+⌘+[` on macOS)
|
||||
Next layout :sc:`next_layout`
|
||||
Move tab forward :sc:`move_tab_forward`
|
||||
@@ -117,9 +116,6 @@ Similarly, you can detach the current tab, with::
|
||||
# asks which OS Window to move the tab into
|
||||
map ctrl+f4 detach_tab ask
|
||||
|
||||
Note that tabs can be re-arranged, detached and moved to another OS Window in
|
||||
the same kitty instance using drag and drop.
|
||||
|
||||
Finally, you can define a shortcut to close all windows in a tab other than the
|
||||
currently active window::
|
||||
|
||||
|
||||
@@ -82,14 +82,13 @@ These dependencies are needed when building against system libraries only.
|
||||
|
||||
Run-time dependencies:
|
||||
|
||||
* ``python``
|
||||
* ``python`` >= 3.8
|
||||
* ``harfbuzz`` >= 2.2.0
|
||||
* ``zlib``
|
||||
* ``libpng``
|
||||
* ``liblcms2``
|
||||
* ``libxxhash``
|
||||
* ``openssl``
|
||||
* ``shader-slang`` (for the slangc compiler)
|
||||
* ``pixman`` (not needed on macOS)
|
||||
* ``cairo`` (not needed on macOS)
|
||||
* ``freetype`` (not needed on macOS)
|
||||
|
||||
@@ -9,79 +9,6 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
Recent major new features
|
||||
---------------------------
|
||||
|
||||
Vertical tabs [0.48]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
kitty now has support for :pull:`vertical tabs <9855>` along the left or right edge of the OS
|
||||
Window. Useful for people that have wide aspect ratio windows.
|
||||
|
||||
Drag and drop for terminal programs [0.47]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
kitty now has a new :doc:`/kittens/dnd` kitten that allows you to seamlessly
|
||||
drag and drop files between kitty and any GUI program like the OS file manager
|
||||
or a webapp. It even works over SSH! It is powered by a new :doc:`protocol
|
||||
</dnd-protocol>` allowing the use of drag and drop from any TUI program.
|
||||
|
||||
Mousing [0.46]
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
kitty already had excellent mouse support, but now it is taking it to the next
|
||||
level. The kitty scrollback buffer grew support for :opt:`smooth scrolling
|
||||
<pixel_scroll>` and :opt:`momentum based scrolling <momentum_scroll>`
|
||||
for a natural, smooth and kinetic scrolling experience.
|
||||
|
||||
Additionally, you can now :opt:`drag kitty tabs around <drag_threshold>` with the mouse
|
||||
to re-order them, move them to another kitty OS Window or even detach them into
|
||||
their own OS Window.
|
||||
|
||||
Finally, a long requested feature, the ability to resize kitty windows (aka
|
||||
splits) with the mouse was implemented.
|
||||
|
||||
Choose files, fast [0.45]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A new :doc:`kitten to select files at the speed of thought
|
||||
</kittens/choose-files>` with a keyboard first interface and support for
|
||||
content previews of text files with syntax highlighting, images, videos, e-books
|
||||
and more. Allows you to select files for use at the shell prompt or other
|
||||
terminal workflows with just a few keystrokes, similar to how fuzzy finders
|
||||
like `fzf <https://github.com/junegunn/fzf/>`__ operate, but designed for
|
||||
files in particular, leveraging the various innovations of kitty such as image
|
||||
display and variable sized text.
|
||||
|
||||
On Linux, it can even be used as a :doc:`drop in replacement </kittens/desktop-ui>`
|
||||
for the File Open/Save dialog boxes in GUI programs.
|
||||
|
||||
|
||||
Sessions [0.43]
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
kitty has long had support for :doc:`sessions`, aka simple text files where you
|
||||
can define what tabs, windows and programs you wish to run in kitty. Now in
|
||||
addition to that kitty has the ability to :ref:`create and switch between
|
||||
sessions <goto_session>` with a single keypress and also to manually setup some
|
||||
tabs/windows in kitty and :ref:`save it as a session file <complex_sessions>`,
|
||||
for seamless and intuitive session file creation.
|
||||
|
||||
A scrollbar for the kitty scrollback [0.43]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A long requested feature, kitty has finally :pull:`gotten a scrollbar <8945>`
|
||||
that can be used with the mouse for browsing its scrollback. The bar appear
|
||||
automatically when you start scrolling backwards and is :opt:`extensively
|
||||
configurable <scrollbar>` in kitty.conf. Note that the old ``scrollback_indicator_opacity``
|
||||
option is deprecated.
|
||||
|
||||
Multiple cursors [0.43]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
kitty has pioneered a new :doc:`escape code protocol
|
||||
<multiple-cursors-protocol>` that allows terminal applications to use multiple
|
||||
cursors, rendered natively. These are typically used in editors to make the
|
||||
same edit at multiple locations. Now terminal based editors can use properly
|
||||
rendered native cursors, just like their GUI cousins, at last.
|
||||
|
||||
Access kitty with a single keypress [0.42]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -179,687 +106,12 @@ consumption to do the same tasks.
|
||||
Detailed list of changes
|
||||
-------------------------------------
|
||||
|
||||
0.48.0 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Implement vertical tabs by setting :opt:`tab_bar_edge` to ``left`` or ``right`` (:pull:`9855`)
|
||||
|
||||
- Graphics protocol: Add a new :ref:`transient usage hint <image_usage_hints>` that clients can send to terminals to indicate an image is meant for only short duration use (:pull:`10092`)
|
||||
|
||||
- kitten @ get-text: Add support for :code:`alternate` and :code:`alternate_scrollback` extents to fetch text from the alternate screen buffer (:iss:`10165`)
|
||||
|
||||
- Wayland: Fix first OS window being a few cells too small when ``initial_window_width/initial_window_height`` are set in cells and a fractional display scale is in use (:iss:`10146`)
|
||||
|
||||
- kitty binary builds are now built on Ubuntu 22 upgraded from Ubuntu 18 for improved performance from better compilers
|
||||
|
||||
- macOS: Fix incorrect horizontal alignment when using text sizing protocol (:iss:`10179`)
|
||||
|
||||
- ``edit-in-kitty``: Return exit code from underlying editor process on exit (:iss:`10198`)
|
||||
|
||||
|
||||
0.47.4 [2026-06-15]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Linux: Fix a regression in the previous release that broke rendering of bitmap color fonts (:pull:`10145`)
|
||||
|
||||
- Linux: Allow fake italics defined via a matrix in fontconfig settings to work for fonts like Fira Code that do not ship with an italic face (:pull:`10120`)
|
||||
|
||||
0.47.3 [2026-06-12]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- macOS: Show a key symbol on the active tab if the macOS Secure Input feature is enabled
|
||||
|
||||
- Fix regression that broke unserialization of splits layout in previous release (:iss:`10124`)
|
||||
|
||||
- Fix :opt:`focus_follows_mouse` switching the active window when returning to a desktop/space, even though the mouse did not move. Now the window under a stationary cursor is left alone, while moving the mouse across windows still switches focus as before.
|
||||
|
||||
- Sanitise responses to color control escape codes to avoid command injection for shells that do not use the kitty keyboard protocol (:cve:`2026-54057`)
|
||||
|
||||
- choose fonts kitten: Fix a rare timing based race causing kitten to crash at startup (:pull:`10128`)
|
||||
|
||||
- Wayland: Fix mouse input getting broken when starting a tab drag and releasing the mouse button before the drag is actually registered (:pull:`10136`)
|
||||
|
||||
|
||||
0.47.2 [2026-06-07]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Allow dragging to move scrollbar after clicking on track when :opt:`scrollbar_jump_on_click` is enabled (:pull:`10085`)
|
||||
|
||||
- macOS: Fix regression in 0.47.0 that broke passing :kbd:`Cmd+C` on to terminal applications when no text is selected (:iss:`10087`)
|
||||
|
||||
- ``kitten @ set-background-image``: Fix ``--layout=configured`` changing layout to centered instead (:iss:`10089`)
|
||||
|
||||
- Splits layout: add an ``equalize`` action and an ``equalize_on_close`` option to redistribute split space proportionally (:iss:`3489`)
|
||||
|
||||
- Fix matching var/env on tabs not working as expected (:iss:`10095`)
|
||||
|
||||
- When watching for changed config files do not recursively watch all sub directories of the directory containing the config file (:iss:`10102`)
|
||||
|
||||
- File transfer protocol: use O_NOFOLLOW when opening regular files (:cve:`2026-54055`)
|
||||
|
||||
- dnd kitten: Protect against drops from malicious sources (:cve:`2026-54056`)
|
||||
|
||||
|
||||
0.47.1 [2026-05-28]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Fix a regression in the previous release that caused :ac:`copy_or_noop` to stop working correctly (:pull:`10041`)
|
||||
|
||||
- macOS: Fix a regression in the previous release that caused URLs to be quoted when dropping into shells (:iss:`10054`)
|
||||
|
||||
- Fix a regression in the previous release that broke automatic color scheme changes when using a background image (:iss:`10058`)
|
||||
|
||||
- Fix :opt:`auto_reload_config` not working when :file:`kitty.conf` is a symlink (:iss:`10066`)
|
||||
|
||||
- Fix a regression in the previous release that broke dragging of URLs to the shell prompt from programs that dont support MOVE drag operations
|
||||
|
||||
- Preserve user-set tab stops across window resizes instead of resetting to 8 column default
|
||||
|
||||
- Add support for the DECST8C escape sequence (``CSI ? 5 W``) to reset tab stops to every 8 columns
|
||||
|
||||
- X11: Fix panel/quick-access-terminal windows not staying on top under KDE after they are hidden once (:iss:`10082`)
|
||||
|
||||
0.47.0 [2026-05-19]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- A new :doc:`Drag and drop kitten </kittens/dnd>` to allow drag and drop of files from your shell to any GUI program even across SSH (:iss:`9984`)
|
||||
|
||||
- A new option :opt:`palette_generate` to automatically generate the 256 color palette from the first 16 colors (:pull:`9426`)
|
||||
|
||||
- For builtin key mappings automatically :ref:`fallback <mapping-fallback>` to matching the US-PC layout key when the pressed key has no matches and is a non-English character (:pull:`9671`)
|
||||
|
||||
- Allow drag and drop of windows to re-arrange them, move them to another tab/OS Window or detach them into a new OS Window. See :ac:`toggle_window_title_bars` to temporarily show window title bars to drag them around (:pull:`9626`)
|
||||
|
||||
- Have :ac:`scroll_line_up` and :ac:`scroll_line_down` smooth scroll by default. Can be restored to old behavior by re-mapping without the ``smooth`` argument (:iss:`9689`)
|
||||
|
||||
- Draw a progress bar at the top of the window when a program reports progress using the OSC 9;4 escape sequence, controlled by :opt:`progress_bar` (:iss:`9777`)
|
||||
|
||||
- Automatically reload configuration on changes, controlled by :opt:`auto_reload_config`
|
||||
|
||||
- Allow specifying multiple background images for :opt:`background_image` that are stored on GPU to allow fast image switching (:pull:`9836`)
|
||||
|
||||
- :doc:`Remote control <remote-control>`: Expose :code:`session_name` and :code:`last_focused_at` in the output of ``kitten @ ls`` for each window (:iss:`9732`, :iss:`9799`)
|
||||
|
||||
- Allow optionally dragging URLs with the mouse, see :sc:`start_simple_selection` (:pull:`9804`)
|
||||
|
||||
- Change :opt:`focus_follows_mouse` to switch the active window only when the mouse crosses into a different window, instead of on every mouse motion event. Prevents accidental mouse bumps from undoing a keyboard-driven window switch.
|
||||
|
||||
- Wayland: Use hold gestures to cancel momentum scrolling when fingers are placed on the trackpad, for a more natural kinetic scrolling experience (:iss:`9863`)
|
||||
|
||||
- macOS: Switch to new Tahoe style application icon with different background in light and dark modes
|
||||
|
||||
- Fix thickness of diagonal lines in box drawing characters not the same as horizontal/vertical lines (:iss:`9719`)
|
||||
|
||||
- Graphics protocol: Fix crash when handling invalid PNG image with direct transmission (:cve:`2026-33633`)
|
||||
|
||||
- Graphics protocol: Fix crash when handling invalid offset values in graphics compose commands (:cve:`2026-33642`)
|
||||
|
||||
- X11: Fix a regression in the previous release that caused an occasional crash on input device removal (:iss:`9723`)
|
||||
|
||||
- XWayland: Fix a regression where some wheel mice were not scrolling properly (:pull:`9770`)
|
||||
|
||||
- Command palette: Improve searching to use word level matching (:pull:`9727`)
|
||||
|
||||
- hints kitten: A new option to set the background color of matched text (:pull:`9745`)
|
||||
|
||||
- The :opt:`show_hyperlink_targets` option now allows specifying a keyboard modifier so that target URLs are only shown on hover when the modifier is pressed (:pull:`9741`)
|
||||
|
||||
- Fix a spurious mouse button release event being sent when dragging out of an OS window causes focus loss
|
||||
|
||||
- Fix scrollbar hover/interaction not working when the scrollbar is drawn in the window margin area (:iss:`9756`)
|
||||
|
||||
- Fix completion for ``edit-in-kitty`` not including some common text file types
|
||||
|
||||
- Allow holding the :kbd:`Alt` key and triple-clicking to select from the first cell even if it is empty (:pull:`9758`)
|
||||
|
||||
- Fix double click to rename tab being triggered too easily (:iss:`9774`)
|
||||
|
||||
- Fix a crash when user tries to select while the client program is using synchronised rendering and generating large amounts of output (:iss:`9778`)
|
||||
|
||||
- macOS: Add Copy and Paste menu items to the Edit menu in the global menu bar (:iss:`9780`)
|
||||
|
||||
- Fix dragging of splits layout borders sometimes moving in the wrong direction or having no effect (:pull:`9447`)
|
||||
|
||||
- Fix triple-click line selection and double-click word selection not extending wrapped lines beyond the edges of the viewport
|
||||
|
||||
- Password input in kittens: hide the cursor and display a blinking 🔒 at the end of typed characters to make it visually clear the user is entering a password
|
||||
|
||||
- edit-in-kitty: Ignore environment variables as some editors execute code present in env vars. Similarly ignore conf file specifications for colors (:cve:`2026-42851`)
|
||||
|
||||
- Command palette :sc:`command_palette`: nicer grouping of aliases and combined actions (:pull:`9819`)
|
||||
|
||||
- hints kitten: Fix trailing punctuation not being removed from URLs (:pull:`9828`)
|
||||
|
||||
- Fix copy/paste dropping spaces at soft-wrap boundaries when :opt:`strip_trailing_spaces` is set (:iss:`9834`)
|
||||
|
||||
- Allow setting negative values for :opt:`inactive_text_alpha` to control
|
||||
whether to only fade inactive windows or unfocused windows (:pull:`9837`)
|
||||
|
||||
- A new option :opt:`macos_fullscreen_ignore_safe_area_insets` to control
|
||||
whether to ignore the notch space when using :opt:`macos_traditional_fullscreen` (:pull:`9841`)
|
||||
|
||||
- Fix some responses from terminal sometimes leaking into shell after kitten exit (:iss:`9839`)
|
||||
|
||||
- Render block elements from the Unicode Symbols for Legacy Computing Supplement block (U+1CC00–U+1CEBF): separated block quadrants, separated block sextants, one sixteenth blocks, and one quarter block partial fills (:disc:`9849`)
|
||||
|
||||
- Improve performance of using active process data when rendering the tab bar by only scanning processes once per second (:iss:`9862`)
|
||||
|
||||
- macOS: Fix occasional phantom cursors being drawn on screen (:iss:`9725`)
|
||||
|
||||
- diff kitten: Keep the current (topmost) filename visible when scrolling, controlled by a new option :opt:`kitten-diff.sticky_header` (:pull:`9891`)
|
||||
|
||||
- Add an option to :opt:`focus_follows_mouse` to only switch focus on drops rather than movement (:pull:`9896`)
|
||||
|
||||
- Fix setting :opt:`momentum_scroll` to zero not *fully* disabling momentum scrolling (:iss:`9904`)
|
||||
|
||||
- macOS: Fix args passed via ``open --args`` being ignored when :file:`macos-launch-services-cmdline` is present (:iss:`9910`)
|
||||
|
||||
- :ac:`save_as_session`: when the filename input by the user has no extension, automatically add the ``.kitty-session`` extension (:pull:`9919`)
|
||||
|
||||
- Linux: Workaround bug in Nvidia drivers that caused color corruption when resuming after suspend (:iss:`9844`)
|
||||
|
||||
- choose-files kitten: Output a trailing newline when writing to a tty in text format (:iss:`9982`)
|
||||
|
||||
- ssh kitten: Sanitize user controlled data in error messages that might leak to shell (:cve:`2026-42850`)
|
||||
|
||||
- Linux: Respect the fontconfig matrix setting commonly used for fake slant with fonts that do not have italic variants (:pull:`9990`)
|
||||
|
||||
|
||||
0.46.2 [2026-03-21]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Watchers: Add an `on_quit` event to global watchers (:iss:`9675`)
|
||||
|
||||
- Wayland: Fix a crash on some compositors when dragging a tab between OS
|
||||
Windows (:iss:`9677`)
|
||||
|
||||
- Fix incorrect behavior when using the actions to move tab forward/backward
|
||||
with a tab_bar_filter active (:iss:`9672`)
|
||||
|
||||
- Prevent stacking of multiple rename tab windows (:iss:`9691`)
|
||||
|
||||
- choose files kitten: Fix a regression that caused incorrect highlight of matched letters
|
||||
|
||||
- macOS: When using :opt:`macos_traditional_fullscreen` do not render content under the notch (:pull:`9678`)
|
||||
|
||||
- X11: Fix massive scroll when switching focus between kitty and another application (:iss:`9703`)
|
||||
|
||||
- Markers: Fix marking not working for multicell characters (:iss:`9705`)
|
||||
|
||||
- Fix a regression in 0.46 that broke drag select in unfocused windows
|
||||
(:iss:`9713`)
|
||||
|
||||
0.46.1 [2026-03-16]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- diff kitten: Highlight moved lines using a different background color (:opt:`kitten-diff.mark_moved_lines`) (:iss:`3241`)
|
||||
|
||||
- Fix a regression that broke ``kitten update-self`` (:iss:`9642`)
|
||||
|
||||
- macOS: Clear bell alert badge on dock icon on mouse/keyboard activity (:iss:`9640`)
|
||||
|
||||
- Fix a regression that broke accept anyway shortcut in the paste confirmation dialog (:pull:`9640`)
|
||||
|
||||
- Fix kitty hanging on startup on Intel macs (:iss:`9643`)
|
||||
|
||||
- X11: Fix a regression that caused some high res scroll devices to be treated as line based scroll devices (:iss:`9649`)
|
||||
|
||||
- Wayland: Fix momentum scrolling not working on compositors that send a stop frame with no axis information (:iss:`9653`)
|
||||
|
||||
- Linux: Fix regression that broke drag and drop from GTK applications (:iss:`9656`)
|
||||
|
||||
- macOS: Fix using Fn key for start dictation not working (:iss:`9661`)
|
||||
|
||||
- Don't use neighboring tab colors for tab bar margins in translucent windows (:iss:`9663`)
|
||||
|
||||
- macOS: Fix OS window focus not restored when switching spaces (:iss:`9665`)
|
||||
|
||||
0.46.0 [2026-03-11]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Pixel scrolling for the kitty scrollback buffer controlled via :opt:`pixel_scroll` (:pull:`9330`)
|
||||
|
||||
- Linux: momentum scrolling in the kitty scrollback buffer for touchpads and touchscreens, see :opt:`momentum_scroll`
|
||||
|
||||
- X11: support high resolution scroll events from touchpads, etc
|
||||
|
||||
- macOS: Implement support for Apple dictation to input text in kitty (:iss:`3732`)
|
||||
|
||||
- Allow dragging tabs (opt:`drag_threshold`) in the tab bar to re-order, move to another OS Window or
|
||||
detach (:pull:`9296`)
|
||||
|
||||
- Allow dragging window borders to resize kitty windows in all the different
|
||||
layouts, controlled by :opt:`window_drag_tolerance` (:pull:`9447`)
|
||||
|
||||
- Allow showing :opt:`configurable window titles <window_title_bar>` for individual kitty
|
||||
windows via a window title bar (:pull:`9450`)
|
||||
|
||||
- A command palette (:sc:`command_palette`) to browse and trigger all mapped and unmapped actions
|
||||
(:pull:`9545`)
|
||||
|
||||
- choose-files kitten: Fix JXL image preview not working (:iss:`9323`)
|
||||
|
||||
- Fix tab bar rendering glitches when using :opt:`tab_bar_filter` in some
|
||||
circumstances (:iss:`9328`)
|
||||
|
||||
- Add support for specifying colors in :file:`kitty.conf` in OKLCH and LAB
|
||||
color spaces (:pull:`9325`)
|
||||
|
||||
- Fix a regression that broke using line numbers with the edit-in-kitty command
|
||||
(:pull:`9346`)
|
||||
|
||||
- Key maps: Allow specifying a timeout for multi key mappings and keyboard modes (:pull:`9551`)
|
||||
|
||||
- macOS: Fix changes to :opt:`macos_titlebar_color` while in full screen not being applied after exiting fullscreen (:iss:`9350`)
|
||||
|
||||
- ncurses: Fix ncurses not using dim because it is missing from the sgr property
|
||||
in terminfo even though it is present in the dim property.
|
||||
|
||||
- Fix a regression in the previous release that caused moving between neighbors
|
||||
in the vertical and horizontal layouts to go in the opposite direction (:iss:`9355`)
|
||||
|
||||
- Fix :ac:`goto_session` not respecting the focus_tab session directive when
|
||||
creating a session in an existing OS window (:iss:`9366`)
|
||||
|
||||
- Wayland: Fix a regression in the previous release that caused doubled key
|
||||
repeats on compositors that implement compositor side key repeat events
|
||||
(:iss:`9374`)
|
||||
|
||||
- icat: Fix a regression in the previous release when rendering GIF animations
|
||||
with frames that dispose onto background with non-zero delay using the native
|
||||
engine (:iss:`9376`)
|
||||
|
||||
- Wayland: Remove usage of the Wayland color management protocol to inform
|
||||
compositors of the color space used by kitty (:iss:`9341`)
|
||||
|
||||
- Linux: Fix a regression in 0.40 that caused horizontal alignment for emoji to
|
||||
be incorrect in some cases (:iss:`9395`)
|
||||
|
||||
- icat kitten: When catting multiple images display the images in input order (:iss:`9413`)
|
||||
|
||||
- kitten @: Fix relative paths for --password-file being resolved relative to
|
||||
CWD instead of the kitty config directory
|
||||
|
||||
- kitten choose-files: Add a new binding of :kbd:`Alt+Enter` to modify the name
|
||||
of an existing file when choosing a save file name (:iss:`9387`)
|
||||
|
||||
- kitten choose-files: Fix TAB completion in the choose save file name prompt
|
||||
not working with respect to the current working directory (:iss:`9387`)
|
||||
|
||||
- Fix line-at-once selection not extending wrapped lines into scrollback (:iss:`9437`)
|
||||
|
||||
- ssh kitten: Restore keyboard mode even if the ssh connection drops
|
||||
|
||||
- edit-in-kitty: Handle connection drop more gracefully (:pull:`9480`)
|
||||
|
||||
- macOS: Fix changing window title with global menubar menu open causes menu to
|
||||
get stuck (:pull:`9490`)
|
||||
|
||||
- Fix :opt:`focus_follows_mouse` not working during a drag and drop (:iss:`9497`)
|
||||
|
||||
- :ac:`goto_session`: Add a ``--active-only`` option to select from only active
|
||||
sessions (:pull:`9503`)
|
||||
|
||||
- Shell integration: Allow sending click events to shells using y co-ordinates
|
||||
relative to prompts (:iss:`9500`)
|
||||
|
||||
- A new action :ac:`copy_selection_or_last_command_output` (:pull:`9512`)
|
||||
|
||||
- Wayland: Add support for the background blur extension (:iss:`9534`)
|
||||
|
||||
- macOS: A new option :opt:`macos_dock_badge_on_bell` to show a badge on the
|
||||
kitty dock icon when a bell occurs (:pull:`9529`)
|
||||
|
||||
- macOS: Workaround for yet another Tahoe bug causing rendering to fail
|
||||
(:pull:`9520`)
|
||||
|
||||
- URL detection: Allow trailing asterisks in URLs (:iss:`9543`)
|
||||
|
||||
- Wayland: Add support for :code:`titlebar-only` in :opt:`hide_window_decorations`
|
||||
to hide the titlebar while keeping shadows for window resizing. (:pull:`9486`)
|
||||
|
||||
- Text sizing protocol: Fix alignment/cropping issues when rendering text with
|
||||
a fractional scale (:iss:`9471`)
|
||||
|
||||
- macOS: Fix a crash when using :opt:`macos_traditional_fullscreen` with split
|
||||
view (:pull:`9573`)
|
||||
|
||||
- macOS: Fix flickering during OS Window resize (:disc:`9582`)
|
||||
|
||||
- Cursor trail: Show a cursor trail when switching tabs (:pull:`9588`)
|
||||
|
||||
- Make shift+left click extend the current selection instead of starting a new
|
||||
selection when the mouse is not grabbed by the TUI application (:disc:`9608`)
|
||||
|
||||
- Allow double clicking on a tab to rename it (:pull:`9609`)
|
||||
|
||||
- :ac:`remote_control_script` resolve relative paths with respect to kitty
|
||||
config directory (:iss:`9625`)
|
||||
|
||||
- Splits layout: Add new mappable actions to maximize a window in the splits
|
||||
layout (:iss:`9629`)
|
||||
|
||||
|
||||
0.45.0 [2025-12-24]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- A new :doc:`kitten to select files at the speed of thought </kittens/choose-files>` with a keyboard first interface and support for content previews of text files with syntax highlighting, images, videos, e-books and more (:iss:`9263`)
|
||||
|
||||
- Add support for the `paste events protocol <https://rockorager.dev/misc/bracketed-paste-mime/>`__ (:iss:`9183`)
|
||||
|
||||
- icat kitten: Add support for animated PNG and animated WebP, netPBM images, ICC color profiles and CCIP color space metadata to the builtin engine
|
||||
|
||||
- icat kitten: Add a new flag :option:`kitty +kitten icat --fit` to control how images are scaled to fit the screen (:iss:`9201`)
|
||||
|
||||
- icat kitten: The :option:`kitty +kitten icat --scale-up` flag now takes effect when not using :option:`kitty +kitten icat --place` as well
|
||||
|
||||
- Add a mappable action :ac:`copy_last_command_output` to copy the output of the last
|
||||
command to the clipboard (:pull:`9185`)
|
||||
|
||||
- ssh kitten: Fix a bug where automatic login was not working (:iss:`9187`)
|
||||
|
||||
- Graphics: Fix overwrite composition mode for animation frames not being honored
|
||||
|
||||
- Automatic color scheme switching: Fix title bar and scroll bar colors not being updated (:iss:`9167`)
|
||||
|
||||
- macOS: Fix cycle through OS windows only swapping between the two most recent
|
||||
OS Windows. Also add a cycle through OS Windows backwards action.
|
||||
(:iss:`9215`)
|
||||
|
||||
- :ac:`goto_session`: allow specifying a directory to select a session file
|
||||
from the directory (:pull:`9219`)
|
||||
|
||||
- Have reloading config also reload the custom tab bar python modules (:disc:`9221`)
|
||||
|
||||
- kitten @ ls: Also output the neighbors for every window (:disc:`9225`)
|
||||
|
||||
- Have the :option:`kitty --start-as` flag be respected when used with
|
||||
:option:`kitty --single-instance` (:iss:`9228`)
|
||||
|
||||
- When expanding environment variables in :opt:`listen_on` allow the :opt:`env`
|
||||
directive to take effect
|
||||
|
||||
- macOS: Fix closing an OS Window when another OS Window is minimized causing
|
||||
the minimized window to be un-minimized (:iss:`8913`)
|
||||
|
||||
- Do not rewrap the text in the alternate screen buffer. Avoids flicker during
|
||||
live resize with no :opt:`resize_debounce_time` (:disc:`9142`)
|
||||
|
||||
- Add a default mapping :ac:`search_scrollback` to open the scrollback in a
|
||||
pager in search mode. If any text is currently selected it is automatically
|
||||
searched for.
|
||||
|
||||
- Wayland: Fix spurious key repeat events when some user defined callback takes
|
||||
a long time to execute (:iss:`9224`)
|
||||
|
||||
- When moving windows to a new tab/OS Window fix overlay windows not being
|
||||
grouped with their parent windows (:iss:`9266`)
|
||||
|
||||
- Linux: Fix a bug causing colors to occasionally all go black when using mesa
|
||||
>= 25.3.0 with nouveau GPU driver (:iss:`9235`)
|
||||
|
||||
- Fix :opt:`tab_bar_min_tabs` not respecting :opt:`tab_bar_filter` (:iss:`9278`)
|
||||
|
||||
- macOS: Workaround for regression in Tahoe 26.2 that breaks :option:`kitty --detach`
|
||||
(:iss:`9288`)
|
||||
|
||||
- macOS: Workaround for yet another Tahoe regression causing macOS to start an
|
||||
AutoFill helper process and not shut it down on application exit (:iss:`9299`)
|
||||
|
||||
0.44.0 [2025-11-03]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Allow kitty to read a specified set of environment variables from your
|
||||
login shell at startup using the :opt:`env` directive in kitty.conf
|
||||
(:iss:`9042`)
|
||||
|
||||
- A new option :opt:`draw_window_borders_for_single_window` to force kitty to
|
||||
always draw a window border even when only a single window is present
|
||||
(:pull:`9112`)
|
||||
|
||||
- Fix a regression in 0.43.0 that caused a black flicker when closing a tab in
|
||||
the presence of a background image (:iss:`9060`)
|
||||
|
||||
- Further improvements to rounded corner rendering, especially at low DPI
|
||||
(:pull:`9091`)
|
||||
|
||||
- Splits layout: Fix a bug that could cause a corrupted layout in some
|
||||
circumstances (:iss:`9059`)
|
||||
|
||||
- Fix a regression in the previous release that broke ``goto_session -1``
|
||||
|
||||
- Fix rendering broken on ancient GPU drivers that do not support rendering to 16 bit textures (:iss:`9068`)
|
||||
|
||||
- Fix tab bar sometimes showing incorrect tabs when it is filtered to show only
|
||||
tabs from the current session (:iss:`9079`)
|
||||
|
||||
- macOS: Workaround for bug in macOS Tahoe that caused OS Windows that are
|
||||
fullscreen to crash kitty when returning from sleep on some machines (:iss:`8983`)
|
||||
|
||||
- Graphics: Fix animated images sometimes not auto playing or auto playing at the wrong start frame if the same image id is used for a subsequent image
|
||||
|
||||
- Fix a regression in 0.43.0 that caused high CPU usage when :opt:`disable_ligatures` was set to ``cursor`` and the tab bar was visible (:iss:`9071`)
|
||||
|
||||
- macOS: Handle dropping of file promises into kitty in addition to file paths (:pull:`9084`)
|
||||
|
||||
- macOS: Fix indeterminate progress bar displayed on dock icon increasing speed when indeterminate progress is set without being cleared first (:iss:`9114`)
|
||||
|
||||
- macOS: Performance and power usage improvements of about 5-10% (:pull:`9131`)
|
||||
|
||||
- macOS: Add an item to the global menu to Cycle through OS windows
|
||||
|
||||
- macOS: Quick access terminal: Fix a crash when changing font size (:iss:`9178`)
|
||||
|
||||
- Wayland: Fix ``center-sized`` panels not working on smithay based compositors (:pull:`9117`)
|
||||
|
||||
- Wayland: Fix scrolling using some mouse wheels that produce "VALUE120" based
|
||||
scroll events too fast on some compositors (:pull:`9128`)
|
||||
|
||||
- Add support for Unicode 17
|
||||
|
||||
- Fix a regression in 0.43.0 that caused :opt:`tab_bar_margin_width` to be
|
||||
doubled on the right edge of the tab bar (:iss:`9154`)
|
||||
|
||||
- Session files: Add a new ``focus_tab`` command to specify which tab should be
|
||||
active when a session is loaded. Accepts either a plain number (0-based index)
|
||||
or a match expression for flexible tab selection, allowing sessions to preserve
|
||||
the active tab state (:doc:`sessions`)
|
||||
|
||||
- :ac:`save_as_session`: Add ``--base-dir`` option to specify a base directory
|
||||
for saving session files with relative paths, useful when the current working
|
||||
directory is not the desired location (:doc:`sessions`)
|
||||
|
||||
- Add ``state:focused_os_window`` match query to select all windows in the
|
||||
currently focused OS window (:ref:`search_syntax`)
|
||||
|
||||
- Session saving now preserves visual tab order and active tab rather than tab
|
||||
activation history as this is generally more important. In the future may
|
||||
have it save tab history as well (:pull:`9163`)
|
||||
|
||||
- The :sc:`reset_terminal` shortcut to reset the terminal now also resets termios state
|
||||
|
||||
0.43.1 [2025-10-01]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- ssh kitten: Allow specifying a password and/or TOTP authentication secret to
|
||||
automate interactive logins in scenarios where public key authentication is
|
||||
not supported (:pull:`9020`)
|
||||
|
||||
- macOS: Fix a bug where the color of a transparent titlebar was off when
|
||||
running in the release build versus the build from source. Also fix using a
|
||||
transparent titlebar causing the background opacity to be doubled.
|
||||
|
||||
- Fix a regression in the previous release that caused the incorrect tab to be
|
||||
active when loading a session (:iss:`9025`)
|
||||
|
||||
- macOS: Workaround for bug in macOS Tahoe that caused closed OS Windows to
|
||||
remain as invisible rectangles that intercept mouse events (:iss:`8952`)
|
||||
|
||||
- macOS: Fix a regression in the previous release that broke automatic
|
||||
switching of dark/light mode when setting :opt:`macos_titlebar_color` to an
|
||||
arbitrary color (:iss:`9034`)
|
||||
|
||||
- :ac:`goto_session`: Add ``--sort-by=alphabetical`` to have the interactive session
|
||||
picker list the sessions in a fixed order rather than by most recent
|
||||
(:disc:`9033`)
|
||||
|
||||
- Fix a regression in the previous release that caused the cursor trail to not
|
||||
be hidden properly (:iss:`9039`)
|
||||
|
||||
- Session files: Fix a regression in the previous release that broke matching on
|
||||
windows in the current tab (:iss:`9037`)
|
||||
|
||||
- Fix a regression in the previous release that broke clearing screen lines
|
||||
when in margin mode (:iss:`9049`)
|
||||
|
||||
|
||||
0.43.0 [2025-09-28]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- New support for creating and switching to :doc:`sessions` easily, allowing
|
||||
users to define and use sessions/projects efficiently (:iss:`8911`)
|
||||
|
||||
- Add a configurable :opt:`scrollbar` for the kitty scrollback (:pull:`8945`)
|
||||
|
||||
- A new protocol for :doc:`multiple cursors <multiple-cursors-protocol>` in the terminal (:iss:`8927`)
|
||||
|
||||
- macOS: Allow the window title bar to be semi-transparent when
|
||||
:opt:`background_opacity` is less than one and :opt:`macos_titlebar_color` is
|
||||
set to ``background`` (:pull:`8906`)
|
||||
|
||||
- A new :opt:`cursor_trail_color` setting to independently control the color of
|
||||
cursor trails (:pull:`8830`)
|
||||
|
||||
- macOS: Add the default :kbd:`Cmd+L` mapping from Terminal.app to erase the
|
||||
last command and its output (:disc:`6040`)
|
||||
|
||||
- Fix :opt:`background_opacity` being non-linear especially with light color themes.
|
||||
Note that this might require you to adjust the value of this setting to get
|
||||
back your current look. (:iss:`8869`)
|
||||
|
||||
- **backward incompatibility**: :opt:`background_opacity` no longer applies to
|
||||
:opt:`background_image` instead add an alpha channel to the image itself
|
||||
|
||||
- Add support for blinking text. Text marked as blinking now blinks in exact
|
||||
rhythm with the cursor. The blinking animation and max duration are
|
||||
controlled by :opt:`cursor_blink_interval` and
|
||||
:opt:`cursor_stop_blinking_after`. (:pull:`8551`)
|
||||
|
||||
- Allow using a custom python function to draw tab titles in the tab bar, see
|
||||
:opt:`tab_title_template`
|
||||
|
||||
- Wayland: Fix incorrect window size calculation when transitioning from
|
||||
full screen to non-full screen with client side decorations (:iss:`8826`)
|
||||
|
||||
- macOS: Fix hiding quick access terminal window not restoring focus to
|
||||
previously active application (:disc:`8840`)
|
||||
|
||||
- macOS: Fix showing the quick access terminal on a space other than the space
|
||||
it was last active on, after full screening some application causes the quick
|
||||
access terminal to appear on the old space (:iss:`8740`)
|
||||
|
||||
- macOS: When toggling open the quick access terminal move it to the currently
|
||||
active monitor (the monitor with the mouse pointer on it) (:iss:`9003`)
|
||||
|
||||
- macOS: Fix closing an OS Window when another OS Window is minimized causing
|
||||
the minimized window to be un-minimized (:iss:`8913`)
|
||||
|
||||
- Allow using backspace to move the cursor onto the previous line in cooked
|
||||
mode. This is indicated by the `bw` property in kitty's terminfo
|
||||
(:iss:`8841`)
|
||||
|
||||
- Watchers: A new event for global watchers corresponding to the tab bar being changed (:disc:`8842`)
|
||||
|
||||
- Fix a regression in 0.40.0 that broke handling of the VS16 variation selector
|
||||
when it caused a character to flow to the next line (:iss:`8848`)
|
||||
|
||||
- Fix rendering of underlines when using larger text sizes with the space and
|
||||
en-space characters (:iss:`8950`)
|
||||
|
||||
- Fix updating panel configuration on visibility toggle and via remote control
|
||||
not working (:iss:`8984`)
|
||||
|
||||
- Improve rendering of rounded rectangles (:pull:`9000`)
|
||||
|
||||
- Wayland: Update bundled copy of libwayland to 1.24 from 1.23.1 because the
|
||||
just released mesa 25.2.0 breaks with libwayland < 1.24 (:iss:`8884`)
|
||||
|
||||
- macOS: Pass the :kbd:`Cmd+C` shortcut to the application running in the
|
||||
terminal when no text is selected (:pull:`8946`)
|
||||
|
||||
- macOS: Workaround for bug in macOS Tahoe that caused OS Windows that are
|
||||
fullscreen on a monitor that is disconnected while macOS is asleep to crash kitty (:iss:`8983`)
|
||||
|
||||
|
||||
0.42.2 [2025-07-16]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- A new :ref:`protocol extension <mouse_leave_window>` to notify terminal programs that have turned on SGR Pixel mouse reporting when the mouse leaves the window (:disc:`8808`)
|
||||
|
||||
- clipboard kitten: Can now optionally take a password to avoid repeated
|
||||
permission prompts when accessing the clipboard. Based on a
|
||||
:ref:`protocol extension <clipboard_repeated_permission>`. (:iss:`8789`)
|
||||
|
||||
- A new :option:`launch --hold-after-ssh` to not close a launched window
|
||||
that connects directly to a remote host because of
|
||||
:option:`launch --cwd`:code:`=current` when the connection ends (:pull:`8807`)
|
||||
|
||||
- Fix :opt:`remember_window_position` not working because of a stupid typo (:iss:`8646`)
|
||||
|
||||
- A new :option:`kitty --grab-keyboard` that can be used to grab the keyboard so that global shortcuts are sent to kitty instead
|
||||
|
||||
- Remote control: Fix holding a remote control socket open causing the kitty I/O thread to go into a loop and not respond on other remote control sockets (:disc:`8670`)
|
||||
|
||||
- hints kitten: Preserve line breaks when the hint is over a line break (:iss:`8674`)
|
||||
|
||||
- Fix a segfault when using the :ac:`copy_ansi_to_clipboard` action (:iss:`8682`)
|
||||
|
||||
- Fix a crash when using linear easing curves for animations (:iss:`8692`)
|
||||
|
||||
- Graphics protocol: Add a note clarifying image update behavior on re-transmission (:iss:`8701`)
|
||||
|
||||
- Wayland GNOME: Fix incorrect OS Window tracking because GNOME has started
|
||||
activating windows on non-current workspaces (:iss:`8716`)
|
||||
|
||||
- Fix a regression in 0.40.0 that broke rendering of VS15 variation selectors in some circumstances (:iss:`8731`, :iss:`8794`)
|
||||
|
||||
- Fix a regression in 0.40.0 that broke serialization of tab characters as ANSI text (:iss:`8741`)
|
||||
|
||||
- Fix a regression in 0.40.0 that broke erasing of characters in a line in the presence of wide characters (:iss:`8758`)
|
||||
|
||||
- Fix a regression in 0.40.0 that broke hyperlinking of wide characters (:iss:`8796`)
|
||||
|
||||
- Fix a regression that broke using :kbd:`esc` to exit visual select window mode (:iss:`8767`)
|
||||
|
||||
- kitten run-shell: Fix SIGINT blocked when execing the shell (:iss:`8754`)
|
||||
|
||||
0.42.1 [2025-05-17]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Fix ambiguous width and private use characters not being rendered when used with variable width text-sizing protocol escape codes
|
||||
|
||||
- Quick access terminal: Restore focus to previously active window when hiding the quick access terminal window on macOS (:iss:`8627`)
|
||||
|
||||
- Wayland: Fix an abort if the terminal program sets a window title longer than 2KB that contains CSI escape sequences and multibyte UTF-8 (:iss:`8619`)
|
||||
|
||||
- Quick access terminal: Allow toggling the window to full screen using the standard kitty :sc:`toggle_fullscreen` shortcut (:iss:`8626`)
|
||||
|
||||
- Quick access terminal: Allow configuring the monitor to display the panel on in Wayland/X11 (:iss:`8630`)
|
||||
|
||||
- A new setting :opt:`remember_window_position` to optionally use the position of the last closed kitty OS Window as the position of the first kitty OS Window when running a new kitty instance (:pull:`8601`)
|
||||
|
||||
- Panel kitten: A new ``center-sized`` value for :option:`--edge <kitty +kitten panel --edge>` to allow easily creating sized and centered panels
|
||||
|
||||
- Wayland: The `kitty --name` flag now sets the XDG *window tag* on compositors
|
||||
that support the `xdg-toplevel-tag <https://wayland.app/protocols/xdg-toplevel-tag-v1>`__ protocol.
|
||||
|
||||
|
||||
0.42.0 [2025-05-11]
|
||||
0.42.0 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- A new kitten: :doc:`quick-access-terminal </kittens/quick-access-terminal>` to :ref:`quake`
|
||||
|
||||
- The :doc:`panel kitten </kittens/panel>` works on macOS and X11 as well as Wayland (:iss:`2590`)
|
||||
- The :doc:`panel kitten </kittens/panel>` now works on macOS as well as Wayland (:iss:`2590`)
|
||||
|
||||
- **Behavior change**: Now kitty does full grapheme segmentation following the
|
||||
Unicode 16 spec when splitting text into cells (:iss:`8533`)
|
||||
@@ -871,7 +123,7 @@ Detailed list of changes
|
||||
- launch: Allow creating desktop panels such as those created by the :doc:`panel kitten </kittens/panel>` (:iss:`8549`)
|
||||
|
||||
- Remote control: Allow modifying desktop panels and showing/hiding OS Windows
|
||||
using the ``kitten @ resize-os-window`` command (:iss:`8550`)
|
||||
using the `kitten @ resize-os-window` command (:iss:`8550`)
|
||||
|
||||
- Remote control launch: Allow waiting for a program launched in a new window
|
||||
to exit and get the exit code via the `kitty +launch
|
||||
@@ -908,7 +160,7 @@ Detailed list of changes
|
||||
|
||||
- :ac:`change_font_size` allow multiplying/dividing the current font size in addition to incrementing it (:iss:`8616`)
|
||||
|
||||
- Box drawing: Improve appearance of rounder corners, giving them a uniform line width (:iss:`8299`)
|
||||
- Box drawing: Improve appearance of rounder corners giving them a uniform line width (:iss:`8299`)
|
||||
|
||||
0.41.1 [2025-04-03]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -1285,7 +537,7 @@ Detailed list of changes
|
||||
|
||||
- Wayland labwc: Fix kitty timing out waiting for compositor to quit fucking around with scales on labwc (:iss:`7540`)
|
||||
|
||||
- Fix ``scrollback_indicator_opacity`` not actually controlling the opacity (:iss:`7557`)
|
||||
- Fix :opt:`scrollback_indicator_opacity` not actually controlling the opacity (:iss:`7557`)
|
||||
|
||||
- URL detection: Fix IPv6 hostnames breaking URL detection (:iss:`7565`)
|
||||
|
||||
@@ -1369,7 +621,7 @@ Detailed list of changes
|
||||
using the panel kitten for all compositors that support the `requisite Wayland
|
||||
protocol <https://wayland.app/protocols/wlr-layer-shell-unstable-v1>`__ which is practically speaking all of them but GNOME (:pull:`2590`)
|
||||
|
||||
- Show a small scrollback indicator along the right window edge when viewing
|
||||
- Show a small :opt:`scrollback indicator <scrollback_indicator_opacity>` along the right window edge when viewing
|
||||
the scrollback to keep track of scroll position (:iss:`2502`)
|
||||
|
||||
- Wayland: Support fractional scales so that there is no wasted drawing at larger scale followed by resizing in the compositor
|
||||
@@ -2132,7 +1384,7 @@ Detailed list of changes
|
||||
window resize (:iss:`5162`)
|
||||
|
||||
- Remote control: Fix commands with large or asynchronous payloads like
|
||||
:command:`kitty @ set-background-image`, :command:`kitty @ set-window-logo`
|
||||
:command:`kitty @ set-backround-image`, :command:`kitty @ set-window-logo`
|
||||
and :command:`kitty @ select-window` not working correctly
|
||||
when using a socket (:iss:`5165`)
|
||||
|
||||
@@ -3234,7 +2486,7 @@ Detailed list of changes
|
||||
do not display a box around active windows
|
||||
|
||||
- Add a new extensible escape code to allow terminal programs to trigger
|
||||
desktop notifications. See :ref:`notifications_on_the_desktop` (:iss:`1474`)
|
||||
desktop notifications. See :ref:`desktop_notifications` (:iss:`1474`)
|
||||
|
||||
- Implement special rendering for various characters from the set of "Symbols
|
||||
for Legacy Computing" from the Unicode 13 standard
|
||||
|
||||
@@ -15,7 +15,7 @@ of the escape code is::
|
||||
<OSC>5522;metadata;payload<ST>
|
||||
|
||||
Here, *metadata* is a colon separated list of key-value pairs and payload is
|
||||
base64 encoded data. :code:`OSC` is :code:`<ESC>]`.
|
||||
base64 encoded data. :code:`OSC` is :code:`<ESC>[`.
|
||||
:code:`ST` is the string terminator, :code:`<ESC>\\`.
|
||||
|
||||
Reading data from the system clipboard
|
||||
@@ -29,11 +29,11 @@ For example, to read plain text and PNG data, the payload would be::
|
||||
|
||||
text/plain image/png
|
||||
|
||||
encoded as :rfc:`base64 <4648>`. To read from the primary selection instead of the
|
||||
encoded as base64. To read from the primary selection instead of the
|
||||
clipboard, add the key ``loc=primary`` to the metadata section.
|
||||
|
||||
To get the list of MIME types available on the clipboard the payload must be
|
||||
just a period (``.``), encoded as :rfc:`base64 <4648>`.
|
||||
just a period (``.``), encoded as base64.
|
||||
|
||||
The terminal emulator will reply with a sequence of escape codes of the form::
|
||||
|
||||
@@ -51,8 +51,7 @@ for an individual type, into chunks of size **no more** than 4096 bytes (4096
|
||||
is the size of a chunk *before* base64 encoding). All
|
||||
the chunks for a given type must be transmitted sequentially and only once they
|
||||
are done the chunks for the next type, if any, should be sent. The end of data
|
||||
is indicated by a ``status=DONE`` packet. base64 padding bytes are required at
|
||||
the end of every base64 encoded chunk when padding is needed.
|
||||
is indicated by a ``status=DONE`` packet.
|
||||
|
||||
If an error occurs, instead of the opening ``status=OK`` packet the terminal
|
||||
must send a ``status=ERRORCODE`` packet. The error code must be one of:
|
||||
@@ -139,72 +138,6 @@ the data, but create multiple references to it in the system clipboard. Alias
|
||||
packets can be sent anytime after the initial write packet and before the end
|
||||
of data packet.
|
||||
|
||||
.. _clipboard_repeated_permission:
|
||||
|
||||
Avoiding repeated permission prompts
|
||||
--------------------------------------
|
||||
|
||||
.. versionadded:: 0.42.2
|
||||
using a password to avoid repeated confirmations
|
||||
|
||||
If a program like an editor wants to make use of the system clipboard, by
|
||||
default, the user is prompted on every read request. This can become quite
|
||||
fatiguing. To avoid this situation, this protocol allows sending a password
|
||||
and human friendly name with ``type=write`` and ``type=read`` requests. The
|
||||
terminal can then ask the user to allow all future requests using that
|
||||
password. If the user agrees, future requests on the same tty will be
|
||||
automatically allowed by the terminal. The editor or other program using
|
||||
this facility should ideally use a password randomly generated at startup,
|
||||
such as a UUID4. However, terminals may implement permanent/stored passwords.
|
||||
Users can then configure terminal programs they trust to use these password.
|
||||
|
||||
The password and the human name are encoded using the ``pw`` and ``name`` keys
|
||||
in the metadata. The values are UTF-8 strings that are base64 encoded.
|
||||
Specifying a password without a human friendly name is equivalent to not
|
||||
specifying a password and the terminal must treat the request as though
|
||||
it had no password.
|
||||
|
||||
Allowing terminal applications to respond to paste events
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. versionadded:: 0.44.1
|
||||
paste events via the 5522 mode
|
||||
|
||||
If a TUI application wants to handle paste events (like the user pressing the
|
||||
paste key shortcut used by the terminal or selecting paste from a terminal UI menu)
|
||||
it can enable the *paste events* private mode (5522), as described in this `ancillary
|
||||
specification <https://rockorager.dev/misc/bracketed-paste-mime/>`__. When that
|
||||
mode is set, the terminal will send the application a list of MIME types on the
|
||||
clipboard every time the user triggers a paste action. The application is then
|
||||
free to request whatever MIME data it wants from the list of types.
|
||||
|
||||
The mode can be enabled using the standard DECSET or DECRST control sequences.
|
||||
``CSI ? 5522 h`` to enable the mode. ``CSI ? 5522 l`` to disable the mode.
|
||||
|
||||
The terminal *should* send a one time password with the list of mime
|
||||
types, as the ``pw`` key (base64 encoded). The application can then use this
|
||||
password to request data from the clipboard without needing a permission
|
||||
prompt. The human name *should* be set to ``Paste event`` (base64 encoded) when
|
||||
the application uses this one time password.
|
||||
|
||||
Detecting support for this protocol
|
||||
-----------------------------------------
|
||||
|
||||
Applications can detect if a terminal supports this protocol with a standard
|
||||
DECRQM query:
|
||||
|
||||
.. code::
|
||||
|
||||
CSI ? 5522 $ p
|
||||
|
||||
To which the terminal will respond with a DECRPM response:
|
||||
|
||||
.. code::
|
||||
|
||||
CSI ? 5522 ; Ps $ y
|
||||
|
||||
A Ps value of 0 or 4 means the mode is not supported.
|
||||
|
||||
|
||||
Support for terminal multiplexers
|
||||
------------------------------------
|
||||
@@ -219,15 +152,11 @@ other characters must be stripped out from the id by the terminal emulator
|
||||
before retransmitting it.
|
||||
|
||||
Note that when using a terminal multiplexer it is possible for two different
|
||||
programs to overwrite each other's clipboard requests. This is fundamentally
|
||||
programs to overwrite each others clipboard requests. This is fundamentally
|
||||
unavoidable since the system clipboard is a single global shared resource.
|
||||
However, there is an additional complication where responses from this protocol
|
||||
However, there is an additional complication where responses form this protocol
|
||||
could get lost if, for instance, multiple write requests are received
|
||||
simultaneously. It is up to well designed multiplexers to ensure that only a
|
||||
single request is in flight at a time. The multiplexer can abort requests by
|
||||
sending back the ``EBUSY`` error code indicating some other window is trying
|
||||
to access the clipboard.
|
||||
|
||||
When the terminal sends an unsolicited paste event because the user triggered
|
||||
a paste and the 5522 mode is enabled, there will be no associated id. In this
|
||||
case, the multiplexer must forward the event to the currently active window.
|
||||
|
||||
@@ -52,8 +52,8 @@ than numbers. The syntax of the escape code is::
|
||||
<OSC> 21 ; key=value ; key=value ; ... <ST>
|
||||
|
||||
The spaces in the above definition are for reading clarity and should be ignored.
|
||||
Here, ``<OSC>`` is the two bytes ``0x1b (ESC)`` and ``0x5d (])``. ``<ST>`` is
|
||||
either ``0x07 (BEL)`` or the two bytes ``0x1b (ESC)`` and ``0x5c (\\)``.
|
||||
Here, ``<OSC>`` is the two bytes ``0x1b (ESC)`` and ``0x5d (])``. ``ST`` is
|
||||
either ``0x7 (BEL)`` or the two bytes ``0x1b (ESC)`` and ``0x5c (\\)``.
|
||||
|
||||
``key`` is a number from 0-255 to query or set the color values from the
|
||||
terminals ANSI color table, or one of the strings in the table below for
|
||||
@@ -69,7 +69,7 @@ selection_foreground The foreground color of selections
|
||||
cursor The color of the text cursor Foreground color
|
||||
cursor_text The color of text under the cursor Background color
|
||||
visual_bell The color of a visual bell Automatic color selection based on current screen colors
|
||||
transparent_background_color1..7 A background color that is rendered Unset
|
||||
transparent_background_color1..8 A background color that is rendered Unset
|
||||
with the specified opacity in cells that have
|
||||
the specified background color. An opacity
|
||||
value less than zero means, use the
|
||||
@@ -103,7 +103,7 @@ This indicates that the foreground color is red and the cursor color is
|
||||
undefined (typically the cursor takes the color of the text under it and the
|
||||
text takes the color of the background).
|
||||
|
||||
If the terminal does not know a field that a client sends to it for a query it
|
||||
If the terminal does not know a field that a client send to it for a query it
|
||||
must respond back with the ``field=?``, that is, it must send back a question
|
||||
mark as the value.
|
||||
|
||||
|
||||
120
docs/conf.py
120
docs/conf.py
@@ -18,9 +18,8 @@ from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.roles import set_classes
|
||||
from pygments.lexer import RegexLexer
|
||||
from pygments.lexer import bygroups as untyped_bygroups
|
||||
from pygments.token import Comment, Error, Keyword, Literal, Name, Number, String, Whitespace
|
||||
from pygments.lexer import RegexLexer, bygroups # type: ignore
|
||||
from pygments.token import Comment, Error, Keyword, Literal, Name, Number, String, Whitespace # type: ignore
|
||||
from sphinx import addnodes, version_info
|
||||
from sphinx.util.logging import getLogger
|
||||
|
||||
@@ -30,7 +29,7 @@ if kitty_src not in sys.path:
|
||||
|
||||
from kitty.conf.types import Definition, expand_opt_references # noqa
|
||||
from kitty.constants import str_version, website_url # noqa
|
||||
from kitty.fast_data_types import DND_CODE, Shlex, TEXT_SIZE_CODE # noqa
|
||||
from kitty.fast_data_types import Shlex, TEXT_SIZE_CODE # noqa
|
||||
|
||||
# config {{{
|
||||
# -- Project information -----------------------------------------------------
|
||||
@@ -121,7 +120,6 @@ string_replacements = {
|
||||
'_kitty_install_cmd': 'curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin',
|
||||
'_build_go_version': go_version('../go.mod'),
|
||||
'_text_size_code': str(TEXT_SIZE_CODE),
|
||||
'_dnd_code': str(DND_CODE),
|
||||
}
|
||||
|
||||
|
||||
@@ -239,13 +237,6 @@ def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
||||
usage='file-or-dir-to-copy ...', message=copy_message
|
||||
))
|
||||
del sys.modules['kittens.ssh.main']
|
||||
from kitty.session import save_as_session_message, save_as_session_options
|
||||
with open('generated/save-as-session.rst', 'w') as f:
|
||||
f.write(option_spec_as_rst(
|
||||
appname='save_as_session', ospec=save_as_session_options, heading_char='^',
|
||||
usage='[path-to-save-session-file-at]',
|
||||
message=save_as_session_message,
|
||||
))
|
||||
|
||||
from kitty.launch import options_spec as launch_options_spec
|
||||
with open('generated/launch.rst', 'w') as f:
|
||||
@@ -302,7 +293,7 @@ if you specify a program-to-run you can use the special placeholder
|
||||
|
||||
|
||||
def write_color_names_table() -> None: # {{{
|
||||
from kitty.fast_data_types import all_color_names
|
||||
from kitty.rgb import color_names
|
||||
def s(c: Any) -> str:
|
||||
return f'{c.red:02x}/{c.green:02x}/{c.blue:02x}'
|
||||
with open('generated/color-names.rst', 'w') as f:
|
||||
@@ -310,7 +301,7 @@ def write_color_names_table() -> None: # {{{
|
||||
p('=' * 50, '=' * 20)
|
||||
p('Name'.ljust(50), 'RGB value')
|
||||
p('=' * 50, '=' * 20)
|
||||
for name, col in all_color_names():
|
||||
for name, col in color_names.items():
|
||||
p(name.ljust(50), s(col))
|
||||
p('=' * 50, '=' * 20)
|
||||
# }}}
|
||||
@@ -369,45 +360,41 @@ def replace_string(app: Any, docname: str, source: List[str]) -> None: # {{{
|
||||
# config file docs {{{
|
||||
|
||||
|
||||
def bygroups(*args: Any) -> Any:
|
||||
return untyped_bygroups(*args) # type: ignore[no-untyped-call]
|
||||
|
||||
|
||||
class ConfLexer(RegexLexer):
|
||||
class ConfLexer(RegexLexer): # type: ignore
|
||||
name = 'Conf'
|
||||
aliases = ['conf']
|
||||
filenames = ['*.conf']
|
||||
|
||||
def map_flags(self: RegexLexer, val: str, start_pos: int) -> Iterator[Tuple[int, Any, str]]:
|
||||
expecting_arg = ''
|
||||
s = Shlex(val)
|
||||
from kitty.options.utils import allowed_key_map_options
|
||||
last_pos = 0
|
||||
while (tok := s.next_word())[0] > -1:
|
||||
x = tok[1]
|
||||
if tok[0] > last_pos:
|
||||
yield start_pos + last_pos, Whitespace, ' ' * (tok[0] - last_pos)
|
||||
last_pos = tok[0] + len(x)
|
||||
tok_start = start_pos + tok[0]
|
||||
if expecting_arg:
|
||||
yield tok_start, String, x
|
||||
expecting_arg = ''
|
||||
elif x.startswith('--'):
|
||||
expecting_arg = x[2:]
|
||||
k, sep, v = expecting_arg.partition('=')
|
||||
k = k.replace('-', '_')
|
||||
expecting_arg = k
|
||||
if expecting_arg not in allowed_key_map_options:
|
||||
yield tok_start, Error, x
|
||||
elif sep == '=':
|
||||
expecting_arg = ''
|
||||
s = Shlex(val)
|
||||
from kitty.options.utils import allowed_key_map_options
|
||||
last_pos = 0
|
||||
while (tok := s.next_word())[0] > -1:
|
||||
x = tok[1]
|
||||
if tok[0] > last_pos:
|
||||
yield start_pos + last_pos, Whitespace, ' ' * (tok[0] - last_pos)
|
||||
last_pos = tok[0] + len(x)
|
||||
tok_start = start_pos + tok[0]
|
||||
if expecting_arg:
|
||||
yield tok_start, String, x
|
||||
expecting_arg = ''
|
||||
yield tok_start, Name, x
|
||||
elif x.startswith('--'):
|
||||
expecting_arg = x[2:]
|
||||
k, sep, v = expecting_arg.partition('=')
|
||||
k = k.replace('-', '_')
|
||||
expecting_arg = k
|
||||
if expecting_arg not in allowed_key_map_options:
|
||||
yield tok_start, Error, x
|
||||
elif sep == '=':
|
||||
expecting_arg = ''
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
break
|
||||
break
|
||||
|
||||
def mapargs(self: 'ConfLexer', match: 're.Match[str]') -> Iterator[Tuple[int, Any, str]]:
|
||||
def mapargs(self: RegexLexer, match: 're.Match[str]') -> Iterator[Tuple[int, Any, str]]:
|
||||
start_pos = match.start()
|
||||
val = match.group()
|
||||
parts = val.split(maxsplit=1)
|
||||
@@ -471,7 +458,7 @@ class ConfLexer(RegexLexer):
|
||||
}
|
||||
|
||||
|
||||
class SessionLexer(RegexLexer):
|
||||
class SessionLexer(RegexLexer): # type: ignore
|
||||
name = 'Session'
|
||||
aliases = ['session']
|
||||
filenames = ['*.session']
|
||||
@@ -656,10 +643,33 @@ def monkeypatch_man_writer() -> None:
|
||||
'''
|
||||
Monkeypatch the docutils man translator to be nicer
|
||||
'''
|
||||
from docutils.nodes import figure
|
||||
from docutils.writers.manpage import Translator
|
||||
from docutils.nodes import Element
|
||||
from docutils.writers.manpage import Table, Translator
|
||||
from sphinx.writers.manpage import ManualPageTranslator
|
||||
|
||||
# Generate nicer tables https://sourceforge.net/p/docutils/bugs/475/
|
||||
class PatchedTable(Table): # type: ignore
|
||||
_options: list[str]
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.needs_border_removal = self._options == ['center']
|
||||
if self.needs_border_removal:
|
||||
self._options = ['box', 'center']
|
||||
|
||||
def as_list(self) -> list[str]:
|
||||
ans: list[str] = super().as_list()
|
||||
if self.needs_border_removal:
|
||||
# remove side and top borders as we use box in self._options
|
||||
ans[2] = ans[2][1:]
|
||||
a, b = ans[2].rpartition('|')[::2]
|
||||
ans[2] = a + b
|
||||
if ans[3] == '_\n':
|
||||
del ans[3] # top border
|
||||
del ans[-2] # bottom border
|
||||
return ans
|
||||
def visit_table(self: ManualPageTranslator, node: object) -> None:
|
||||
setattr(self, '_active_table', PatchedTable())
|
||||
setattr(ManualPageTranslator, 'visit_table', visit_table)
|
||||
|
||||
# Improve header generation
|
||||
def header(self: ManualPageTranslator) -> str:
|
||||
@@ -676,13 +686,13 @@ def monkeypatch_man_writer() -> None:
|
||||
|
||||
setattr(ManualPageTranslator, 'header', header)
|
||||
|
||||
def visit_image(self: ManualPageTranslator, node: figure) -> None:
|
||||
def visit_image(self: ManualPageTranslator, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_image(self: ManualPageTranslator, node: figure) -> None:
|
||||
def depart_image(self: ManualPageTranslator, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_figure(self: ManualPageTranslator, node: figure) -> None:
|
||||
def depart_figure(self: ManualPageTranslator, node: Element) -> None:
|
||||
self.body.append(' (images not supported)\n')
|
||||
Translator.depart_figure(self, node)
|
||||
|
||||
@@ -690,8 +700,8 @@ def monkeypatch_man_writer() -> None:
|
||||
setattr(ManualPageTranslator, 'depart_image', depart_image)
|
||||
setattr(ManualPageTranslator, 'depart_figure', depart_figure)
|
||||
|
||||
orig_astext = getattr(ManualPageTranslator, 'astext')
|
||||
def astext(self: ManualPageTranslator) -> Any:
|
||||
orig_astext = Translator.astext
|
||||
def astext(self: Translator) -> Any:
|
||||
b = []
|
||||
for line in self.body:
|
||||
if line.startswith('.SH'):
|
||||
@@ -700,9 +710,9 @@ def monkeypatch_man_writer() -> None:
|
||||
parts[0] = parts[0].capitalize()
|
||||
line = x + ' ' + '\n'.join(parts)
|
||||
b.append(line)
|
||||
setattr(self, 'body', b)
|
||||
self.body = b
|
||||
return orig_astext(self)
|
||||
setattr(ManualPageTranslator, 'astext', astext)
|
||||
setattr(Translator, 'astext', astext)
|
||||
|
||||
|
||||
def setup_man_pages() -> None:
|
||||
|
||||
@@ -16,8 +16,7 @@ frames-per-second. See below for an overview of all customization possibilities.
|
||||
You can open the config file within |kitty| by pressing :sc:`edit_config_file`
|
||||
(:kbd:`⌘+,` on macOS). A :file:`kitty.conf` with commented default
|
||||
configurations and descriptions will be created if the file does not exist.
|
||||
The configuration is automatically reloaded when modified, controlled by
|
||||
:opt:`auto_reload_config`. You can manually reload the config by pressing
|
||||
You can reload the config file within |kitty| by pressing
|
||||
:sc:`reload_config_file` (:kbd:`⌃+⌘+,` on macOS) or sending |kitty| the
|
||||
``SIGUSR1`` signal with ``kill -SIGUSR1 $KITTY_PID``. You can also display the
|
||||
current configuration by pressing :sc:`debug_config` (:kbd:`⌥+⌘+,` on macOS).
|
||||
@@ -63,6 +62,10 @@ by running a program using :code:`geninclude`. For example::
|
||||
geninclude dynamic.py
|
||||
|
||||
|
||||
.. note:: Syntax highlighting for :file:`kitty.conf` in vim is available via
|
||||
`vim-kitty <https://github.com/fladson/vim-kitty>`__.
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitty.rst
|
||||
|
||||
|
||||
@@ -98,4 +101,3 @@ See the :doc:`list of all the things you can make |kitty| can do </actions>`.
|
||||
:hidden:
|
||||
|
||||
actions
|
||||
wide-gamut-colors
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. _notifications_on_the_desktop:
|
||||
.. _desktop_notifications:
|
||||
|
||||
|
||||
Desktop notifications
|
||||
@@ -25,7 +25,7 @@ the set :code:`a-zA-Z0-9-_/\+.,(){}[]*&^%$#@!`~`. The payload must be
|
||||
interpreted based on the metadata section. The two semi-colons *must* always be
|
||||
present even when no metadata is present.
|
||||
|
||||
Before going into details, let's see how one can display a simple, single line
|
||||
Before going into details, lets see how one can display a simple, single line
|
||||
notification from a shell script::
|
||||
|
||||
printf '\x1b]99;;Hello world\x1b\\'
|
||||
@@ -395,7 +395,7 @@ Key Value
|
||||
``c`` ``c=1`` if the terminal supports close events, otherwise the ``c``
|
||||
must be omitted.
|
||||
|
||||
``o`` Comma separated list of occasions from the ``o`` key that the
|
||||
``o`` Comma separated list of occassions from the ``o`` key that the
|
||||
terminal implements. If no occasions are supported, the value
|
||||
``o=always`` must be sent in the query response.
|
||||
|
||||
@@ -405,7 +405,7 @@ Key Value
|
||||
|
||||
``s`` Comma separated list of sound names from the table of standard sound names above.
|
||||
Terminals will report the list of standard sound names they support.
|
||||
Terminals *should* support at least ``system`` and ``silent``.
|
||||
Terminals *should* support atleast ``system`` and ``silent``.
|
||||
|
||||
``u`` Comma separated list of urgency values that the terminal implements.
|
||||
If urgency is not supported, the ``u`` key must be absent from the
|
||||
@@ -450,10 +450,10 @@ Key Value Default Description
|
||||
encoded UTF-8
|
||||
application name
|
||||
|
||||
``g`` :ref:`identifier` ``unset`` Identifier for icon data. Make these globally unique,
|
||||
``g`` :ref:`identifier` ``unset`` Identifier for icon data. Make these globally unqiue,
|
||||
like an UUID.
|
||||
|
||||
``i`` :ref:`identifier` ``unset`` Identifier for the notification. Make these globally unique,
|
||||
``i`` :ref:`identifier` ``unset`` Identifier for the notification. Make these globally unqiue,
|
||||
like an UUID, so that terminal multiplexers can
|
||||
direct responses to the correct window. Note that for backwards
|
||||
compatibility reasons i=0 is special and should not be used.
|
||||
|
||||
@@ -1,561 +0,0 @@
|
||||
The Drag and Drop protocol
|
||||
==============================================
|
||||
|
||||
.. versionadded:: 0.47.0
|
||||
|
||||
This protocol enables drag and drop functionality for terminal programs
|
||||
that is as good as the drag and drop functionality available for GUI
|
||||
programs.
|
||||
|
||||
There is one central escape code used for this protocol, which is of the form::
|
||||
|
||||
OSC _dnd_code ; metadata ; payload ST
|
||||
|
||||
Here, ``OSC`` is the bytes ``ESC ] (0x1b 0x5b)`` and ST is ``ESC \\ (0x1b 0x5c)``.
|
||||
The ``metadata`` is a colon separated list of ``key=value`` pairs.
|
||||
The final part of the escape code is the payload data, whose meaning depends on the metadata.
|
||||
|
||||
The payload must be no more than 4096 bytes. When the payload is larger than 4096
|
||||
bytes, it is chunked up using the ``m`` key. An escape code that has a too long
|
||||
payload is transmitted in chunks. All but the last chunk must have ``m=1`` in
|
||||
their metadata. Each chunk must have a payload of no more than 4096 bytes.
|
||||
Only the first chunk is guaranteed to have metadata other than the ``m`` key.
|
||||
Subsequent chunks may optionally omit all
|
||||
metadata except the ``m`` and ``i`` keys. While a chunked transfer is in
|
||||
progress it is a protocol error to for the sending side to
|
||||
send any protocol related escape codes other than chunked ones or query (``t=q|Q``) ones.
|
||||
In particular, this means that the receiving side should use the metadata from
|
||||
the first chunk in a chain of chunks only.
|
||||
|
||||
All integer values used in this escape code must be 32-bit signed or unsigned
|
||||
integers encoded in decimal representation.
|
||||
|
||||
When transferring binary data the payload is :rfc:`base64 <4648>` encoded. The
|
||||
4096 bytes limit applies to *encoded bytes*, that is, it is applied after
|
||||
encoding. base64 padding bytes are optional and may or may not be present at
|
||||
the end of the last chunk.
|
||||
|
||||
Accepting drops
|
||||
-----------------
|
||||
|
||||
In order to inform the terminal emulator that the client accepts drops, it
|
||||
must send the following escape code::
|
||||
|
||||
OSC _dnd_code ; t=a ; payload ST
|
||||
|
||||
The payload here is a space separated list of MIME types the program accepts.
|
||||
The list of MIME types is optional, it is needed if the program wants to accept
|
||||
exotic or private use MIME types on platforms such as macOS, where the system
|
||||
does not deliver drop events unless the MIME type is registered.
|
||||
|
||||
When the client is done accepting drops, or at exit, it should send the escape
|
||||
code::
|
||||
|
||||
OSC _dnd_code ; t=A ST
|
||||
|
||||
to inform the terminal that it no longer wants drops.
|
||||
|
||||
Whenever the user drags something over the window, the terminal will send an
|
||||
escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=m:x=x:y=y:X=X:Y=Y:o=O ; optional MIME list ST
|
||||
|
||||
Here, ``x, y`` identify the cell over which the drag is currently present.
|
||||
The ``(0, 0)`` cell is at top left of the screen. ``X and Y`` are the pixel
|
||||
offsets from the top-left. The ``O`` value is the set of allowed operations,
|
||||
which can be ``1`` for copy, ``2`` for move and ``3`` for either, at the
|
||||
client's discretion. The optional list of MIMES is a space separated
|
||||
list of MIME types that are available for dropping. To avoid overhead, the
|
||||
terminal should only send this list for the first move event and subsequently
|
||||
only if the list changes.
|
||||
|
||||
When the drag leaves the window, the terminal will send the same event but
|
||||
with ``x, y = -1, -1`` to indicate that the drag has left the window. For such
|
||||
events the list of MIME types must be empty. Note that the terminal must never
|
||||
send negative cell co-ordinates for any other reason. No more movement escape
|
||||
codes ``t=m`` will be sent until this drop or another re-enters the window.
|
||||
|
||||
The client program must inform the terminal whether it will accept
|
||||
the potential drop and which MIME types of the set of offered MIME types it
|
||||
accepts. Until the client does so the terminal will indicate to the OS that
|
||||
the drop is not accepted. To do so, the client sends an escape code of the
|
||||
form::
|
||||
|
||||
OSC _dnd_code ; t=m:o=O ; MIME list ST
|
||||
|
||||
Here the ``o`` key is the operation the client intends to perform if a drop
|
||||
occurs which can be either ``1`` for copy or ``2`` for move or ``0`` for not
|
||||
accepted. The MIME list is the ordered list of MIME types from the offered list
|
||||
that the client wants. If no MIME type list is present, it is equivalent to no
|
||||
change in the offered list of MIME types. The list should be ordered in order
|
||||
of decreasing preference. Some platforms may show the user some
|
||||
indication of the first MIME type in the list.
|
||||
|
||||
When the user triggers a drop on the window, the terminal will send an escape
|
||||
code of the form::
|
||||
|
||||
OSC _dnd_code ; t=M: ... ; MIME list ST
|
||||
|
||||
This is the same as the movement escape codes above, except that ``t=M``
|
||||
(upper case M instead of lower case m), indicating this is a drop.
|
||||
Once this escape code is received, no more movement escape codes ``t=m``
|
||||
will be sent until a new drop enters the window. The MIME list here is
|
||||
mandatory, terminals must send the full list of MIME types available in
|
||||
the drop. The client program can now request data for the MIME types
|
||||
it is interested in.
|
||||
|
||||
Requesting data is done by sending an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx ST
|
||||
|
||||
Here ``idx`` is a 1-based index into the list of MIME types sent in the ``t=M``
|
||||
drop event. This will request data for the specified MIME type.
|
||||
The terminal must respond with a series of escape codes of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx; base64 encoded data possibly chunked ST
|
||||
|
||||
End of data is indicated by an empty payload and ``m=0``. If some error occurs while
|
||||
getting the data, the terminal must send an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=R:x=idx ; POSIX error name:optional description ST
|
||||
|
||||
Here ``POSIX error name`` is a POSIX symbolic error name such as ``ENOENT`` or
|
||||
``EIO`` or the value ``EUNKNOWN`` for an unknown error. Unless otherwise noted,
|
||||
any error response means the drop is terminated. The description is optional
|
||||
and must consist only of :ref:`safe_utf8`.
|
||||
|
||||
Once the client program finishes reading all the dropped data it needs, it must
|
||||
send an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:o=operation ST
|
||||
|
||||
That is, it must send a request for data with no MIME type specified. The
|
||||
terminal emulator must then inform the OS that the drop is completed. Any
|
||||
queued data requests must be discarded by the terminal. The ``operation``
|
||||
is required and must specify the final action the client took with the data.
|
||||
If unset (aka ``0``) the terminal must assume the drop was canceled.
|
||||
|
||||
Dropping from remote machines
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In order to support dropping of files from remote machines, the client
|
||||
must inform the terminal of its :ref:`machine id <machine_id>` using the escape code::
|
||||
|
||||
OSC _dnd_code ; t=a:x=1 ; machine id ST
|
||||
|
||||
Then, the client must first request the :rfc:`text/uri-list <2483>` MIME
|
||||
type to get a list of dropped URIs. When responding to this request,
|
||||
the terminal will send the usual ``t=r`` responses, but, in addition,
|
||||
if the client has sent its machine id and the terminal determines that
|
||||
the client is on a different machine based on the id, it will add the ``X=1``
|
||||
key to its response. The client should use this key to determine if it wants to
|
||||
request data for entries in the URI list. For every URI in the list, the client can
|
||||
send the terminal emulator a data request of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx:y=subidx ST
|
||||
|
||||
Here ``idx`` is the one based index of the ``text/uri-list`` MIME type. And
|
||||
``subidx`` is the one based index into the array of MIME types in
|
||||
the ``text/uri-list`` entry. The terminal will then read the file and
|
||||
transmit the data as for a normal MIME data request, except it will have
|
||||
``y=subidx`` as well in its response, for example::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx:y=subidx ; base64 encoded data possibly chunked ST
|
||||
|
||||
Similarly, error responses are as above, except for the addition of
|
||||
``y=subidx``, for example::
|
||||
|
||||
OSC _dnd_code ; t=R:x=idx:y=subidx ; POSIX error name:optional desc ST
|
||||
|
||||
Terminals must reply with ``ENOENT`` if the index is out of bounds.
|
||||
If the client does not first request the ``text/uri-list`` MIME type or that
|
||||
MIME type is not present in the drop, the terminal must reply with
|
||||
``EINVAL``. Terminals must support at least ``file://`` URIs.
|
||||
If the client requests an entry that is not a supported URI type the
|
||||
terminal must reply with ``EUNKNOWN``.
|
||||
|
||||
Terminals must ONLY send data for regular files, symbolic links and directories.
|
||||
See below for more details about sending symlinks.
|
||||
|
||||
If the terminal does not have permission to read the file it must reply with
|
||||
``EPERM``. Terminals must respond with ``EINVAL`` if the file is not a regular
|
||||
file or symlink or directory and ``ENOENT`` if the file does not exist. If an
|
||||
I/O error occurs the terminal must send ``EIO``.
|
||||
|
||||
For security reasons, terminals must reply with ``EPERM`` if the drag
|
||||
originated in the same window as the drop, this prevents malicious programs
|
||||
from reading files on the computer by starting their own drag. This is a
|
||||
defense in depth feature since drags can only be started by the terminal, but
|
||||
it helps in case of accidental drag starts and drops into the same window.
|
||||
|
||||
Clients may send multiple requests without waiting for any request to complete.
|
||||
Terminals may queue requests and respond in any order they choose, including
|
||||
interleaving responses to different requests. However, for simplicity, this
|
||||
specification recommends terminals queue requests and respond in first-in,
|
||||
first-out order. Every response can be matched to a corresponding request
|
||||
using the ``x``, ``y`` and ``Y`` keys. To prevent Denial of service attacks,
|
||||
if too many requests are received, terminals must deny the request
|
||||
with ``EMFILE`` and end the drop.
|
||||
|
||||
|
||||
Reading remote directories
|
||||
+++++++++++++++++++++++++++
|
||||
|
||||
If the file pointed to by a ``file://`` URL is actually a directory the terminal must instead respond with::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx:y=subidx:X=handle ; base64 encoded list of dir entries ST
|
||||
|
||||
The presence of ``X=handle`` indicates this is a directory response not a regular
|
||||
file or symlink. For regular files, ``X=0``. For symlinks, ``X=1``.
|
||||
For directories ``X`` is an arbitrary integer (``handle``) other than ``0`` or ``1``.
|
||||
Here, the payload is a null byte separated list of entries in the directory that are
|
||||
either regular files, directories or symlinks. The payload must be base64
|
||||
encoded and might be chunked if the directory has a lot of entries.
|
||||
|
||||
The client can now read the files in this directory using requests of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num ST
|
||||
|
||||
Here ``num`` is the 1-based index into the list of directory entries previously transmitted
|
||||
to the client. The terminal will respond with an escape code of the forms ::
|
||||
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num ; base64 encoded data of regular file ST
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num:X=1 ; base64 encoded symlink target ST
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num:X=child-handle ; base64 encoded list of entries in sub-dir ST
|
||||
|
||||
In case of any errors, the terminal will respond with::
|
||||
|
||||
OSC _dnd_code ; t=R:Y=handle:x=num ; POSIX error name:optional desc ST
|
||||
|
||||
In the above, the ``Y=handle`` and ``x=num`` keys allow the client to know
|
||||
which directory entry the response concerns. The ``handle`` points to the
|
||||
parent directory and ``num`` to the entry within the parent dir.
|
||||
|
||||
Once the client is done reading a directory it should transmit ``t=r:Y=handle`` to the terminal. The
|
||||
terminal can then free any resources associated with that directory. The
|
||||
directory handle is now invalid and terminals must return ``EINVAL`` if the
|
||||
client sends a request using an invalid directory handle. It is recommended
|
||||
that clients traverse directories breadth first to minimise resource usage in
|
||||
the terminal. Terminals may deny directory traversal requests if too many
|
||||
resources are used, in order to prevent Denial of service attacks. In such
|
||||
cases the terminal must respond with ``ENOMEM``.
|
||||
|
||||
|
||||
Starting drags
|
||||
-----------------
|
||||
|
||||
Terminal programs can inform the terminal emulator that they
|
||||
are willing to act as a source of drag data by sending the
|
||||
sending the escape code::
|
||||
|
||||
OSC _dnd_code ; t=o:x=1 ; optional machine id ST
|
||||
|
||||
On exit, or if the program no longer is willing to start drag gestures, it must
|
||||
send ``t=o:x=2`` to the terminal to indicate it no longer wants to offer drag data.
|
||||
The ``machine id`` is optional and is used to enable dragging from remote
|
||||
machines. See :ref:`below <machine_id>` for its semantics.
|
||||
|
||||
When the user performs the platform specific gesture to start a drag operation,
|
||||
the terminal will send the escape code ``t=o`` back to the terminal program
|
||||
informing it that it can potentially start a drag. The gesture is typically holding the
|
||||
left mouse button down and dragging a short distance, but this protocol does
|
||||
not mandate any particular gesture to start drag operations. The terminal, when
|
||||
sending the event will also set the ``x, y, X, Y`` keys to indicate the cell
|
||||
and pixel locations in the window of the start drag event.
|
||||
|
||||
If the terminal program determines that it wants to start a drag at that
|
||||
location, it must send the terminal the ``t=o:o=flags`` escape code again, but
|
||||
with a payload consisting of the space separated MIME types it offers. The
|
||||
``flags`` indicate what types of operations the client supports, ``1`` for
|
||||
copy, ``2`` for move and ``3`` for either. The transmission should be chunked
|
||||
if the list of MIME types is too long. Note that at this time the drag
|
||||
operation has not actually started, this gives the terminal program the
|
||||
opportunity to pre-send some data or set one or more images to act as
|
||||
thumbnails for the drag operation. If the list of MIME types is too long the
|
||||
terminal may cancel the operation by responding with ``t=E ; EFBIG`` or ``t=E ;
|
||||
ENOMEM``.
|
||||
|
||||
If at the time the terminal receives this request the drag gesture has already
|
||||
been terminated or the terminal otherwise determines that it is not appropriate
|
||||
to start the drag, it must reply with ``t=E ; EPERM`` to indicate the drag
|
||||
offer was not accepted.
|
||||
|
||||
For some well known types like ``text/plain`` or ``text/uri-list`` the
|
||||
terminal program should pre-send the data for them unless it is very large.
|
||||
This is because some platforms, such as macOS, need pre sent data to be able
|
||||
to interoperate with native programs. The terminal emulator should reply with
|
||||
``t=E ; EFBIG`` if too much data is sent and cancel the drag. Terminals must
|
||||
accept at least 64MB of pre sent data.
|
||||
|
||||
Pre sent data is sent with escape codes of the form::
|
||||
|
||||
OSC _dnd_code ; t=p:x=idx ; base64 encoded data ST
|
||||
|
||||
Here ``idx`` is the zero based index into the list of previously sent MIME
|
||||
types indicating this data is for that MIME type. Transmission should be chunked
|
||||
using the ``m`` key. End of data is indicated by sending the escape code with no
|
||||
payload and ``m=0``. Terminal programs should pre-read this data and only send
|
||||
the ``t=o`` key indicating the offer if the data is available.
|
||||
|
||||
To associate one or more images with the drag operation, the terminal program
|
||||
must transmit the data for the image with the ``idx`` value above being a
|
||||
negative number starting with ``-1`` for the first image and so on. Clients
|
||||
**must** transmit all images consecutively in order, starting with the first,
|
||||
then the second and so on. When transmitting images, the image data format is
|
||||
specified using the ``y`` key. A value of ``y=24`` mean 24bit RGB data and
|
||||
``y=32`` means 32bit RGBA data. Colors in the RGB/A data must be in the sRGB
|
||||
color space. Using ``y=100`` means the data is a PNG image. Using ``y=0`` means
|
||||
the payload is UTF-8 base64 encoded text. The terminal will render the text to
|
||||
display the image. Additionally, the ``X`` and ``Y`` keys must be used to
|
||||
specify the width and height of the image data in pixels. If the size of the
|
||||
transmitted data does not match the image dimensions the terminal must replay
|
||||
with ``t=E ; EINVAL``. When using ``y=0`` the ``X`` and ``Y`` keys specify the
|
||||
text size as ``base_font_size * X/Y``. Where ``base_font_size`` is the normal
|
||||
font size the terminal uses for text. Note that terminals **may** ignore
|
||||
newlines and render all text on a single line so client programs should not
|
||||
send too much text. The ``o`` key is used to specify if the background the
|
||||
text is drawn on is transparent or not. ``o=0`` means transparent and ``o=1024``
|
||||
means fully opaque. In other words background opacity is ``o/1024``.
|
||||
This is particularly useful when drawing a Unicode symbol as the icon for the drag.
|
||||
|
||||
Terminals are free to impose a limit on the amount of image data, to avoid
|
||||
Denial-of-service attacks. If the image data is too much or the image is too
|
||||
large they must reply with ``t=E ; EFBIG`` and abort the drag. By default, the
|
||||
drag will be started using the first image, if any. During the drag, the
|
||||
terminal program can change the image by sending::
|
||||
|
||||
OSC _dnd_code ; t=P:x=idx ST
|
||||
|
||||
Where ``idx`` is now a zero based index with zero being the first image and so on.
|
||||
Sending an ``idx`` out of bounds means the drag image should be removed.
|
||||
|
||||
Once the terminal program has sent all data and images for the drag
|
||||
operation, it indicates the drag should be started by sending ``t=P:x=-1``. At
|
||||
this time if the user has already cancelled the drag or the terminal determines
|
||||
the drag operation is not allowed, it must respond with ``t=E ; EPERM``. If any
|
||||
other error occurs starting the drag operation, it must respond with the appropriate
|
||||
POSIX error name and optional error description. If it determines that the image data after conversion to
|
||||
display format is too large, it must respond with ``t=E ; EFBIG``. If the drag
|
||||
operation is successfully started, it must respond with ``t=E ; OK``.
|
||||
|
||||
As the drag progresses, status changes are reported using the ``t=e`` escape
|
||||
code. The variants are listed in the table below:
|
||||
|
||||
.. list-table:: Drag offer events
|
||||
|
||||
* - Code
|
||||
- Description
|
||||
* - ``t=e : x=1 : y=idx``
|
||||
- The drag has been accepted by a client. ``idx`` is a zero based index into the list of MIME types
|
||||
pointing to the MIME type the client is likely to want
|
||||
* - ``t=e : x=2 : o=O``
|
||||
- The action the client is likely to perform has changed to the value indicated by the ``o`` key
|
||||
* - ``t=e : x=3``
|
||||
- The drag offer has been dropped onto a client, there are likely to be requests for data in the near future
|
||||
* - ``t=e : x=4 : y=0 or 1``
|
||||
- The drag is finished. If ``y=1`` then the drag was canceled by the user.
|
||||
* - ``t=e : x=5 : y=idx``
|
||||
- Request data for the MIME type at the zero based index ``idx`` in the list of MIME types
|
||||
|
||||
The client program should respond to data requests with escape codes of the
|
||||
form::
|
||||
|
||||
OSC _dnd_code ; t=e:y=idx:m=0 or 1 ; base64 encoded data ST
|
||||
|
||||
This, is the data for the MIME type identified by ``idx`` which is a zero based
|
||||
index into the list of MIME types. The data should be chunked using the
|
||||
``m`` key. End of data is denoted by ``m=0`` and an empty payload. If an error
|
||||
occurs the client should send::
|
||||
|
||||
OSC _dnd_code ; t=E:y=idx ; POSIX error name:optional description ST
|
||||
|
||||
Where ``POSIX error name`` is a POSIX symbolic error name such as ``ENOENT``
|
||||
if the MIME type is not found or ``EIO`` if an IO error occurred and so on. The
|
||||
description is optional and must contain only :ref:`safe_utf8`.
|
||||
|
||||
If the client wants to cancel the full drag at any time, it should send::
|
||||
|
||||
OSC _dnd_code ; t=E:y=-1 ST
|
||||
|
||||
If ``t=e`` or ``t=E`` escape codes are sent to the terminal before the drag is
|
||||
started and the terminal has responded with ``t=E ; OK``, the terminal must respond
|
||||
with ``t=E ; EINVAL`` and abort the drag.
|
||||
|
||||
Dragging to remote machines
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To support dragging to remote machines, first of all clients **must** pre-send
|
||||
the data for the ``text/uri-list`` MIME type. All ``file://`` URLs that point
|
||||
to directories **must** end with a ``/``. Then, terminals can
|
||||
examine the :ref:`machine_id` sent with the enable drag offers
|
||||
``t=o`` escape code to decide whether to request data for ``file://`` entries
|
||||
from the URI list. To request data for a particular entry, terminals send an
|
||||
escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=k:x=idx ST
|
||||
|
||||
Here ``idx`` is the one based index into the list of entries in the
|
||||
``text/uri-list`` MIME type. Then the client can respond with the data
|
||||
for that entry with an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=k:x=idx:m=0 or 1 ; base64 encoded file data ST
|
||||
OSC _dnd_code ; t=k:x=idx:X=1:m=0 or 1 ; base64 encoded symlink target ST
|
||||
OSC _dnd_code ; t=k:x=idx:X=handle:m=0 or 1 ; base64 encoded null separated list of directory entries ST
|
||||
|
||||
These represent possibly chunked data for files, symlinks and directories, as
|
||||
denoted by the ``X`` key. As above, end of data for an individual entry is
|
||||
indicated by an escape code with ``m=0`` and no payload. ``idx`` is the one
|
||||
based index into the list of entries in the ``text/uri-list`` MIME type.
|
||||
Only regular files, symlinks and directories should be sent. Terminals may send
|
||||
multiple requests before the data for the first request is received. Client
|
||||
programs should queue the requests and handle them in FIFO order.
|
||||
|
||||
Every directory must be transmitted with ``X=handle``. The payload
|
||||
is a null separated list of regular files, directories and symlinks in the
|
||||
directory. ``handle`` is an integer other than ``0`` or ``1``
|
||||
that serves as an identifier for the directory. Directories should be traversed
|
||||
in breadth first order. The children of a directory are sent by
|
||||
adding ``Y=parent-handle:y=num`` to the escape codes above. Here
|
||||
``parent-handle`` is the handle of the directory being traversed and ``num``
|
||||
is the one based index into the list of entries in the directory. Thus, the
|
||||
set of keys ``x, y, Y`` uniquely determine an entry. Clients **must** send all
|
||||
children of directories, recursively, terminals **must not** make requests
|
||||
for children of directories, only for the entries from the ``text/uri-list``.
|
||||
|
||||
If any error occurs in the client while reading the data, it can inform
|
||||
the terminal using::
|
||||
|
||||
OSC _dnd_code ; t=E ; POSIX error name:optional description ST
|
||||
|
||||
The terminal must then abort the drag.
|
||||
|
||||
Terminals are free to impose resource limits on how much data they accept,
|
||||
if a limit is breached or some errors occurs, they can abort the drag and
|
||||
inform the client of it with::
|
||||
|
||||
OSC _dnd_code ; t=E ; POSIX error name:optional description ST
|
||||
|
||||
The error code for too many resources is ``EMFILE``,
|
||||
for IO errors is ``EIO`` and so on.
|
||||
|
||||
Detecting support for this protocol
|
||||
-------------------------------------
|
||||
|
||||
Clients can query the terminal emulator for support of this protocol
|
||||
using::
|
||||
|
||||
OSC _dnd_code ; t=q:i=optional ST
|
||||
|
||||
The ``i`` key is optional, if present it will be echoed back in the responses
|
||||
from the terminal. A terminal supporting this protocol **must** respond with::
|
||||
|
||||
OSC _dnd_code ; t=q:i=echoed ; payload ST
|
||||
|
||||
Here, ``payload`` is a colon separated list of ``key=value`` pairs. These
|
||||
specify support for optional/future parts of this protocol. Currently the
|
||||
payload is empty, but that might change as the protocol evolves.
|
||||
|
||||
The client should send these escape codes followed by a request for the `primary device
|
||||
attributes <https://vt100.net/docs/vt510-rm/DA1.html>`_. If a response for the
|
||||
device attributes is received before a response for the queries, then the
|
||||
terminal does not support this protocol.
|
||||
|
||||
Multiplexers
|
||||
-----------------
|
||||
|
||||
To support multiplexers, the ``i`` key exists. When the terminal receives a
|
||||
``t=a`` or ``t=o`` escape code that has the ``i`` key set, all escape codes it
|
||||
sends to the terminal program must include the ``i`` key with the same value.
|
||||
This allows terminal multiplexers to direct the response codes to the correct
|
||||
client.
|
||||
|
||||
Metadata reference
|
||||
---------------------------
|
||||
|
||||
The table below shows all the metadata keys as well as what values they can
|
||||
take, and the default value they take when missing. All integers are 32-bit.
|
||||
|
||||
======= ==================== ========= =================
|
||||
Key Value Default Description
|
||||
======= ==================== ========= =================
|
||||
``t`` Single character. ``a`` The type of drag and drop event.
|
||||
``(a, A, ``a`` - start accepting drops
|
||||
)`` ``A`` - stop accepting drops
|
||||
``m`` - a drop move event
|
||||
``M`` - a drop dropped event
|
||||
``r`` - request dropped data
|
||||
``R`` - report an error
|
||||
``o`` - start offering drags or start a drag
|
||||
``p`` - present data for drag offers
|
||||
``P`` - Change drag image or start drag
|
||||
``e`` - a drag offer event occurred
|
||||
``E`` - a drag offer data error occurred
|
||||
``k`` - data for uri-list items in drag offer
|
||||
``q`` - query support for this protocol
|
||||
|
||||
``m`` Chunking indicator ``0`` ``0`` or ``1``
|
||||
|
||||
``i`` Postive integer ``0`` This id is for use by multiplexers.
|
||||
When it is set, all responses from
|
||||
the terminal in that session will
|
||||
have it set to the same value.
|
||||
|
||||
``o`` Positive integer ``0`` What drop operation to perform. ``0``
|
||||
means rejected, ``1`` means copy and
|
||||
``2`` means move.
|
||||
|
||||
**Keys for location**
|
||||
-----------------------------------------------------------
|
||||
``x`` Integer ``0`` Cell x-coordinate origin is 0, 0 at top left of screen
|
||||
``y`` Integer ``0`` Cell y-coordinate origin is 0, 0 at top left of screen
|
||||
``X`` Integer ``0`` Pixel x-coordinate origin is 0, 0 at top left of screen
|
||||
``Y`` Integer ``0`` Pixel y-coordinate origin is 0, 0 at top left of screen
|
||||
======= ==================== ========= =================
|
||||
|
||||
|
||||
.. _machine_id:
|
||||
|
||||
Machine id
|
||||
-----------------
|
||||
|
||||
The machine id is used to detect when the source and destination machines for a
|
||||
drag and drop are different. It is of the form: ``version:ASCII printable
|
||||
chars``. The leading ``version`` field allows for changing the format or
|
||||
semantics of this field in the future. The actual id is the machine id which
|
||||
is:
|
||||
|
||||
.. tab:: macOS
|
||||
|
||||
The value returned by the ``IOPlatformUUID`` system function.
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
The contents of the :file:`HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid`
|
||||
registry key.
|
||||
|
||||
.. tab:: Other
|
||||
|
||||
The contents of the :file:`/etc/machine-id` file with trailing whitespace removed
|
||||
|
||||
This machine id is then hashed using a :rfc:`HMAC <2104>` with :rfc:`SHA-256
|
||||
<6234>` as the digest algorithm and the key being the ASCII bytes:
|
||||
``tty-dnd-protocol-machine-id``. The hashing is done so as to not easily leak
|
||||
the actual machine id and to ensure that the value is of fixed size and
|
||||
consisting only of ASCII printable characters. This gives a final value of::
|
||||
|
||||
1:hashed machine id hexadecimal encoded
|
||||
|
||||
In the future, the ``version`` field may increase if the hashing algorithm is
|
||||
changed. If the terminal sees a version it does not understand, it must assume
|
||||
that the machine id does not match, aka the source and destination machines are
|
||||
different. This assumption means that remote drag and drop will still work, just with
|
||||
reduced performance in case of version mismatch.
|
||||
|
||||
|
||||
Support in other software
|
||||
------------------------------
|
||||
|
||||
Currently this protocol is supported in:
|
||||
|
||||
* The kitty terminal emulator and the :doc:`dnd kitten </kittens/dnd>`
|
||||
* The `yazi <https://github.com/sxyazi/yazi/pull/4005>`__ terminal file manager
|
||||
217
docs/faq.rst
217
docs/faq.rst
@@ -36,6 +36,78 @@ within a fixed width across all faces of the font, otherwise they aren't really
|
||||
monospaced.
|
||||
|
||||
|
||||
Using a color theme with a background color does not work well in vim?
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
First, be sure to `use a color scheme in vim <https://github.com/kovidgoyal/kitty/discussions/8196#discussioncomment-11739991>`__
|
||||
instead of relying on the terminal theme. Otherwise, background and text selection colours
|
||||
may be difficult to read.
|
||||
|
||||
Sadly, vim has very poor out-of-the-box detection for modern terminal features.
|
||||
Furthermore, it `recently broke detection even more <https://github.com/vim/vim/issues/11729>`__.
|
||||
It kind of, but not really, supports terminfo, except it overrides it with its own hard-coded
|
||||
values when it feels like it. Worst of all, it has no ability to detect modern
|
||||
features not present in terminfo, at all, even security sensitive ones like
|
||||
bracketed paste.
|
||||
|
||||
Thankfully, probably as a consequence of this lack of detection, vim allows users to
|
||||
configure these low level details. So, to make vim work well with any modern
|
||||
terminal, including kitty, add the following to your :file:`~/.vimrc`.
|
||||
|
||||
.. code-block:: vim
|
||||
|
||||
" Mouse support
|
||||
set mouse=a
|
||||
set ttymouse=sgr
|
||||
set balloonevalterm
|
||||
" Styled and colored underline support
|
||||
let &t_AU = "\e[58:5:%dm"
|
||||
let &t_8u = "\e[58:2:%lu:%lu:%lum"
|
||||
let &t_Us = "\e[4:2m"
|
||||
let &t_Cs = "\e[4:3m"
|
||||
let &t_ds = "\e[4:4m"
|
||||
let &t_Ds = "\e[4:5m"
|
||||
let &t_Ce = "\e[4:0m"
|
||||
" Strikethrough
|
||||
let &t_Ts = "\e[9m"
|
||||
let &t_Te = "\e[29m"
|
||||
" Truecolor support
|
||||
let &t_8f = "\e[38:2:%lu:%lu:%lum"
|
||||
let &t_8b = "\e[48:2:%lu:%lu:%lum"
|
||||
let &t_RF = "\e]10;?\e\\"
|
||||
let &t_RB = "\e]11;?\e\\"
|
||||
" Bracketed paste
|
||||
let &t_BE = "\e[?2004h"
|
||||
let &t_BD = "\e[?2004l"
|
||||
let &t_PS = "\e[200~"
|
||||
let &t_PE = "\e[201~"
|
||||
" Cursor control
|
||||
let &t_RC = "\e[?12$p"
|
||||
let &t_SH = "\e[%d q"
|
||||
let &t_RS = "\eP$q q\e\\"
|
||||
let &t_SI = "\e[5 q"
|
||||
let &t_SR = "\e[3 q"
|
||||
let &t_EI = "\e[1 q"
|
||||
let &t_VS = "\e[?12l"
|
||||
" Focus tracking
|
||||
let &t_fe = "\e[?1004h"
|
||||
let &t_fd = "\e[?1004l"
|
||||
execute "set <FocusGained>=\<Esc>[I"
|
||||
execute "set <FocusLost>=\<Esc>[O"
|
||||
" Window title
|
||||
let &t_ST = "\e[22;2t"
|
||||
let &t_RT = "\e[23;2t"
|
||||
|
||||
" vim hardcodes background color erase even if the terminfo file does
|
||||
" not contain bce. This causes incorrect background rendering when
|
||||
" using a color theme with a background color in terminals such as
|
||||
" kitty that do not support background color erase.
|
||||
let &t_ut=''
|
||||
|
||||
These settings must be placed **before** setting the ``colorscheme``. It is
|
||||
also important that the value of the vim ``term`` variable is not changed
|
||||
after these settings.
|
||||
|
||||
I get errors about the terminal being unknown or opening the terminal failing or functional keys like arrow keys don't work?
|
||||
-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -134,39 +206,30 @@ remote control command, for details, see :ref:`at-set-colors`.
|
||||
To change colors when SSHing into a remote host, use the :opt:`color_scheme
|
||||
<kitten-ssh.color_scheme>` setting for the :doc:`ssh kitten <kittens/ssh>`.
|
||||
|
||||
Additionally, you can use the escape code described in :doc:`color-stack`
|
||||
to set colors in a single window.
|
||||
Examples of using OSC escape codes to set colors::
|
||||
Additionally, You can use the
|
||||
`OSC terminal escape codes <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands>`__
|
||||
to set colors. Examples of using OSC escape codes to set colors::
|
||||
|
||||
Change the default foreground color:
|
||||
printf '\x1b]21;foreground=#ff0000\x1b\\'
|
||||
printf '\x1b]10;#ff0000\x1b\\'
|
||||
Change the default background color:
|
||||
printf '\x1b]21;background=blue\x1b\\'
|
||||
printf '\x1b]11;blue\x1b\\'
|
||||
Change the cursor color:
|
||||
printf '\x1b]21;cursor=blue\x1b\\'
|
||||
printf '\x1b]12;blue\x1b\\'
|
||||
Change the selection background color:
|
||||
printf '\x1b]21;selection_background=blue\x1b\\'
|
||||
printf '\x1b]17;blue\x1b\\'
|
||||
Change the selection foreground color:
|
||||
printf '\x1b]21;selection_foreground=blue\x1b\\'
|
||||
printf '\x1b]19;blue\x1b\\'
|
||||
Change the nth color (0 - 255):
|
||||
printf '\x1b]21;n=green\x1b\\'
|
||||
printf '\x1b]4;n;green\x1b\\'
|
||||
|
||||
See :doc:`color-stack` for details on the syntax for specifying colors and
|
||||
how to query current colors.
|
||||
You can use various syntaxes/names for color specifications in the above
|
||||
examples. See `XParseColor <https://linux.die.net/man/3/xparsecolor>`__
|
||||
for full details.
|
||||
|
||||
If a ``?`` is given rather than a color specification, kitty will respond
|
||||
with the current value for the specified color.
|
||||
|
||||
Why is there padding between the text area and the window border?
|
||||
------------------------------------------------------------------
|
||||
|
||||
Terminal screens are a grid of fixed size cells. When the window size is
|
||||
not an exact multiple of the cell size, there is some leftover space that
|
||||
appears as padding. Additionally you can add your own padding with
|
||||
:opt:`window_padding_width`. This padding can be particularly noticeable when
|
||||
using TUI programs that have a background color different from the terminal
|
||||
background color. In such cases either change their background color to match
|
||||
the terminal or more correctly, open a bug report against such programs and ask
|
||||
them to :doc:`change the terminal default background color <color-stack>`
|
||||
using OSC escape codes when starting and restore it when quitting to have it work automatically.
|
||||
|
||||
How do I specify command line options for kitty on macOS?
|
||||
---------------------------------------------------------------
|
||||
@@ -220,9 +283,9 @@ fonts to be freely resizable, so it does not support bitmapped fonts.
|
||||
symbols, so to force kitty to use the pure NERD font for NERD symbols,
|
||||
add the following line to :file:`kitty.conf`::
|
||||
|
||||
# Nerd Fonts v3.4.0
|
||||
# Nerd Fonts v3.3.0
|
||||
|
||||
symbol_map U+e000-U+e00a,U+e0a0-U+e0a2,U+e0a3,U+e0b0-U+e0b3,U+e0b4-U+e0c8,U+e0ca,U+e0cc-U+e0d7,U+e200-U+e2a9,U+e300-U+e3e3,U+e5fa-U+e6b7,U+e700-U+e8ef,U+ea60-U+ec1e,U+ed00-U+efce,U+f000-U+f2ff,U+f300-U+f381,U+f400-U+f533,U+f0001-U+f1af0 Symbols Nerd Font Mono
|
||||
symbol_map U+e000-U+e00a,U+ea60-U+ebeb,U+e0a0-U+e0c8,U+e0ca,U+e0cc-U+e0d7,U+e200-U+e2a9,U+e300-U+e3e3,U+e5fa-U+e6b7,U+e700-U+e8ef,U+ed00-U+efc1,U+f000-U+f2ff,U+f000-U+f2e0,U+f300-U+f381,U+f400-U+f533,U+f0001-U+f1af0 Symbols Nerd Font Mono
|
||||
|
||||
Those Unicode symbols not in the `Unicode private use areas
|
||||
<https://en.wikipedia.org/wiki/Private_Use_Areas>`__ are
|
||||
@@ -326,10 +389,6 @@ many alternate icons available, click on an icon to visit its homepage:
|
||||
:target: https://github.com/igrmk/twiskers
|
||||
:width: 256
|
||||
|
||||
.. image:: https://github.com/mtklr/kitty-nyan-icon/raw/main/kitty-nyan.svg
|
||||
:target: https://github.com/mtklr/kitty-nyan-icon
|
||||
:width: 256
|
||||
|
||||
You can put :file:`kitty.app.icns` (macOS only) or :file:`kitty.app.png` in the
|
||||
:ref:`kitty configuration directory <confloc>`, and this icon will be applied
|
||||
automatically at startup. On X11 and Wayland, this will set the icon for kitty windows.
|
||||
@@ -357,20 +416,13 @@ also set it with the following command:
|
||||
|
||||
You can also change the icon manually by following the steps:
|
||||
|
||||
.. tab:: macOS
|
||||
#. Find :file:`kitty.app` in the Applications folder, select it and press :kbd:`⌘+I`
|
||||
#. Drag :file:`kitty.icns` onto the application icon in the kitty info pane
|
||||
#. Delete the icon cache and restart Dock:
|
||||
|
||||
#. Find :file:`kitty.app` in the Applications folder, select it and press :kbd:`⌘+I`
|
||||
#. Drag :file:`kitty.icns` onto the application icon in the kitty info pane
|
||||
#. Delete the icon cache and restart Dock::
|
||||
.. code-block:: sh
|
||||
|
||||
rm /var/folders/*/*/*/com.apple.dock.iconcache; killall Dock
|
||||
|
||||
.. tab:: Linux
|
||||
|
||||
#. Copy :file:`kitty.desktop` from the installation location (usually
|
||||
:file:`/usr/share/applications` to :file:`~/.local/share/applications`
|
||||
#. Edit the copied desktop file changing the ``Icon`` line to have
|
||||
the absolute path to your desired icon.
|
||||
rm /var/folders/*/*/*/com.apple.dock.iconcache; killall Dock
|
||||
|
||||
|
||||
How do I map key presses in kitty to different keys in the terminal program?
|
||||
@@ -421,16 +473,6 @@ related to localization, such as :envvar:`LANG`, ``LC_*`` and loading of
|
||||
configuration files such as ``XDG_*``, :envvar:`KITTY_CONFIG_DIRECTORY` and,
|
||||
most importantly, ``PATH`` to locate binaries.
|
||||
|
||||
The simplest way to fix this is to have kitty load the environment variables
|
||||
from your shell configuration at startup using the :opt:`env` directive,
|
||||
adding the following to :file:`kitty.conf`::
|
||||
|
||||
env read_from_shell=PATH LANG LC_* XDG_* EDITOR VISUAL
|
||||
|
||||
This works for POSIX compliant shells and the fish shell. Note that it
|
||||
does add significantly to kitty startup time, so use only if really necessary.
|
||||
This feature was added in version ``0.43.2``.
|
||||
|
||||
To see the environment variables that kitty sees, you can add the following
|
||||
mapping to :file:`kitty.conf`::
|
||||
|
||||
@@ -511,79 +553,6 @@ maintains. These too allocate memory in large blocks and don't release it back
|
||||
to the OS immediately.
|
||||
|
||||
|
||||
Using a color theme with a background color does not work well in vim?
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
First, be sure to `use a color scheme in vim <https://github.com/kovidgoyal/kitty/discussions/8196#discussioncomment-11739991>`__
|
||||
instead of relying on the terminal theme. Otherwise, background and text selection colours
|
||||
may be difficult to read.
|
||||
|
||||
Sadly, vim has very poor out-of-the-box detection for modern terminal features.
|
||||
Furthermore, it `recently broke detection even more <https://github.com/vim/vim/issues/11729>`__.
|
||||
It kind of, but not really, supports terminfo, except it overrides it with its own hard-coded
|
||||
values when it feels like it. Worst of all, it has no ability to detect modern
|
||||
features not present in terminfo, at all, even security sensitive ones like
|
||||
bracketed paste.
|
||||
|
||||
Thankfully, probably as a consequence of this lack of detection, vim allows users to
|
||||
configure these low level details. So, to make vim work well with any modern
|
||||
terminal, including kitty, add the following to your :file:`~/.vimrc`.
|
||||
|
||||
.. code-block:: vim
|
||||
|
||||
" Mouse support
|
||||
set mouse=a
|
||||
set ttymouse=sgr
|
||||
set balloonevalterm
|
||||
" Styled and colored underline support
|
||||
let &t_AU = "\e[58:5:%dm"
|
||||
let &t_8u = "\e[58:2:%lu:%lu:%lum"
|
||||
let &t_Us = "\e[4:2m"
|
||||
let &t_Cs = "\e[4:3m"
|
||||
let &t_ds = "\e[4:4m"
|
||||
let &t_Ds = "\e[4:5m"
|
||||
let &t_Ce = "\e[4:0m"
|
||||
" Strikethrough
|
||||
let &t_Ts = "\e[9m"
|
||||
let &t_Te = "\e[29m"
|
||||
" Truecolor support
|
||||
let &t_8f = "\e[38:2:%lu:%lu:%lum"
|
||||
let &t_8b = "\e[48:2:%lu:%lu:%lum"
|
||||
let &t_RF = "\e]10;?\e\\"
|
||||
let &t_RB = "\e]11;?\e\\"
|
||||
" Bracketed paste
|
||||
let &t_BE = "\e[?2004h"
|
||||
let &t_BD = "\e[?2004l"
|
||||
let &t_PS = "\e[200~"
|
||||
let &t_PE = "\e[201~"
|
||||
" Cursor control
|
||||
let &t_RC = "\e[?12$p"
|
||||
let &t_SH = "\e[%d q"
|
||||
let &t_RS = "\eP$q q\e\\"
|
||||
let &t_SI = "\e[5 q"
|
||||
let &t_SR = "\e[3 q"
|
||||
let &t_EI = "\e[1 q"
|
||||
let &t_VS = "\e[?12l"
|
||||
" Focus tracking
|
||||
let &t_fe = "\e[?1004h"
|
||||
let &t_fd = "\e[?1004l"
|
||||
execute "set <FocusGained>=\<Esc>[I"
|
||||
execute "set <FocusLost>=\<Esc>[O"
|
||||
" Window title
|
||||
let &t_ST = "\e[22;2t"
|
||||
let &t_RT = "\e[23;2t"
|
||||
|
||||
" vim hardcodes background color erase even if the terminfo file does
|
||||
" not contain bce. This causes incorrect background rendering when
|
||||
" using a color theme with a background color in terminals such as
|
||||
" kitty that do not support background color erase.
|
||||
let &t_ut=''
|
||||
|
||||
These settings must be placed **before** setting the ``colorscheme``. It is
|
||||
also important that the value of the vim ``term`` variable is not changed
|
||||
after these settings.
|
||||
|
||||
|
||||
Why does kitty sometimes start slowly on my Linux system?
|
||||
-------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ receiving::
|
||||
|
||||
The client must then wait for responses from the terminal emulator. It
|
||||
is an error to send anymore commands to the terminal until an ``OK``
|
||||
response is received from the terminal. The terminal waits for the user to accept
|
||||
response is received from the terminal. The terminal wait for the user to accept
|
||||
the request. If accepted, it sends::
|
||||
|
||||
← action=status id=someid status=OK
|
||||
|
||||
@@ -224,14 +224,6 @@ Variables that kitty sets when running child programs
|
||||
Set when enabling :ref:`shell_integration`. It is automatically removed by
|
||||
the shell integration scripts.
|
||||
|
||||
.. envvar:: KITTY_SI_RUN_COMMAND_AT_STARTUP
|
||||
|
||||
Set this to an expression that the kitty shell integration scripts will
|
||||
``eval`` after the shell is started. Note that this environment variable
|
||||
is ignored when present in the environment in which kitty itself is launched
|
||||
in. It is most useful with the ``--env`` flag for the :doc:`launch <launch>`
|
||||
action.
|
||||
|
||||
.. envvar:: ZDOTDIR
|
||||
|
||||
Set when enabling :ref:`shell_integration` with :program:`zsh`, allowing
|
||||
|
||||
@@ -28,15 +28,12 @@ alpha-blending and text over graphics.
|
||||
Some applications that use the kitty graphics protocol:
|
||||
|
||||
* `awrit <https://github.com/chase/awrit>`_ - Chromium-based web browser rendered in Kitty with mouse and keyboard support
|
||||
* `blackcat <https://github.com/j-c-m/blackcat>`_ - a modern compatible cat with image support
|
||||
* `bicat <https://github.com/stevenxxiu/bicat>`_ - a terminal image viewer that also works in the Vifm file manager, with nested Tmux support
|
||||
* `broot <https://dystroy.org/broot/>`_ - a terminal file explorer and manager, with preview of images, SVG, PDF, etc.
|
||||
* `chafa <https://github.com/hpjansson/chafa>`_ - a terminal image viewer
|
||||
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
|
||||
* `fzf <https://github.com/junegunn/fzf/commit/d8188fce7b7bea982e7f9050c35e488e49fb8fd0>`_ - A command line fuzzy finder
|
||||
* `mpv <https://github.com/mpv-player/mpv/commit/874e28f4a41a916bb567a882063dd2589e9234e1>`_ - A video player that can play videos in the terminal
|
||||
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system information tool
|
||||
* `nvim <https://github.com/neovim/neovim/issues/30889>`__ - A TUI editor that can display images in the terminal
|
||||
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol
|
||||
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with image previews
|
||||
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
|
||||
@@ -56,7 +53,6 @@ Libraries:
|
||||
* `image.nvim <https://github.com/3rd/image.nvim>`_ - Bringing images to neovim
|
||||
* `image_preview.nvim <https://github.com/adelarsq/image_preview.nvim/>`_ - Image preview for neovim
|
||||
* `kui.nvim <https://github.com/romgrk/kui.nvim>`_ - Build sophisticated UIs inside neovim using the kitty graphics protocol
|
||||
* `kitty-graphics.el <https://github.com/cashmeredev/kitty-graphics.el>`_ - Images in emacs
|
||||
* `term-image <https://github.com/AnonymouX47/term-image>`_ - A Python library, CLI and TUI to display and browse images in the terminal
|
||||
* `glkitty <https://github.com/michaeljclark/glkitty>`_ - C library to draw OpenGL shaders in the terminal with a glgears demo
|
||||
|
||||
@@ -68,8 +64,6 @@ Other terminals that have implemented the graphics protocol:
|
||||
* `Warp <https://docs.warp.dev/getting-started/changelog#id-2025.03.26-v0.2025.03.26.08.10>`_
|
||||
* `wayst <https://github.com/91861/wayst>`_
|
||||
* `WezTerm <https://github.com/wez/wezterm/issues/986>`_
|
||||
* `iTerm2 <https://github.com/gnachman/iTerm2/commit/4fe5b2173193b6c3e45234b6b2ab7a144a5cfa01>`_
|
||||
* `xterm.js <https://github.com/xtermjs/xterm.js/discussions/5683>`_
|
||||
|
||||
|
||||
Getting the window size
|
||||
@@ -106,7 +100,7 @@ code to demonstrate its use
|
||||
buf = array.array('H', [0, 0, 0, 0])
|
||||
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
|
||||
print((
|
||||
'number of rows: {} number of columns: {} '
|
||||
'number of rows: {} number of columns: {}'
|
||||
'screen width: {} screen height: {}').format(*buf))
|
||||
|
||||
.. tab:: Go
|
||||
@@ -137,30 +131,19 @@ code to demonstrate its use
|
||||
}
|
||||
|
||||
|
||||
.. tab:: POSIX sh
|
||||
.. tab:: Bash
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
read rows cols <<EOF
|
||||
$(command stty size)
|
||||
EOF
|
||||
# This uses the kitten standalone binary from kitty to get the pixel sizes
|
||||
# since we can't do IOCTLs directly. Fortunately, kitten is a static exe
|
||||
# pre-built for every Unix like OS under the sun.
|
||||
|
||||
oldstty=$(command stty -g)
|
||||
command stty raw -echo
|
||||
printf "\033[14t"
|
||||
response=""
|
||||
while : ; do
|
||||
char=$(command dd bs=1 count=1 2>/dev/null)
|
||||
[ "$char" = "t" ] && break
|
||||
response="${response}${char}"
|
||||
done
|
||||
command stty "$oldstty"
|
||||
h=$(echo "$response" | cut -d';' -f2)
|
||||
w=$(echo "$response" | cut -d';' -f3)
|
||||
printf "number of rows: %d number of columns: %d" "$rows" "$cols"
|
||||
printf " screen width: %d screen height: %d\n" "$w" "$h"
|
||||
builtin read -r rows cols < <(command stty size)
|
||||
IFS=x builtin read -r width height < <(command kitten icat --print-window-size); builtin unset IFS
|
||||
builtin echo "number of rows: $rows number of columns: $cols screen width: $width screen height: $height"
|
||||
|
||||
|
||||
Note that some terminals return ``0`` for the width and height values. Such
|
||||
@@ -171,9 +154,7 @@ You can also use the *CSI t* escape code to get the screen size. Send
|
||||
``<ESC>[14t`` to ``STDOUT`` and kitty will reply on ``STDIN`` with
|
||||
``<ESC>[4;<height>;<width>t`` where ``height`` and ``width`` are the window
|
||||
size in pixels. This escape code is supported in many terminals, not just
|
||||
kitty. A more precise version of this escape code, which is however supported
|
||||
in less terminals is ``<ESC>[16t`` which causes the terminal to reply with the
|
||||
pixel dimensions of a single cell.
|
||||
kitty.
|
||||
|
||||
A minimal example
|
||||
------------------
|
||||
@@ -181,55 +162,61 @@ A minimal example
|
||||
Some minimal code to display PNG images in kitty, using the most basic
|
||||
features of the graphics protocol:
|
||||
|
||||
.. tab:: POSIX sh
|
||||
.. tab:: Bash
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
send_chunked() {
|
||||
first="y"
|
||||
while IFS= read -r chunk; do
|
||||
metadata=""; [ "$first" = "y" ] && { metadata="a=T,f=100,"; first="n"; }
|
||||
printf "\033_G%sm=1;%s\033\\" "${metadata}" "${chunk}"
|
||||
done
|
||||
[ "$first" = "n" ] && { printf "\033_Gm=0;\033\\"; return 0; }
|
||||
return 1
|
||||
}
|
||||
|
||||
#!/bin/bash
|
||||
transmit_png() {
|
||||
# Different systems have different or missing base64 executables.
|
||||
# The sed command below adds a trailing newline which openssl
|
||||
# base64 does not produce and is needed for reading via read -r
|
||||
{ command base64 -w 4096 "$1" 2>/dev/null | send_chunked; } || \
|
||||
{ command base64 -b 4096 "$1" 2>/dev/null | send_chunked; } || \
|
||||
{ command openssl base64 -e -A -in "$1" | command sed '$a\' | command fold -b -w 4096 | send_chunked; }
|
||||
data=$(base64 "$1")
|
||||
data="${data//[[:space:]]}"
|
||||
builtin local pos=0
|
||||
builtin local chunk_size=4096
|
||||
while [ $pos -lt ${#data} ]; do
|
||||
builtin printf "\e_G"
|
||||
[ $pos = "0" ] && printf "a=T,f=100,"
|
||||
builtin local chunk="${data:$pos:$chunk_size}"
|
||||
pos=$(($pos+$chunk_size))
|
||||
[ $pos -lt ${#data} ] && builtin printf "m=1"
|
||||
[ ${#chunk} -gt 0 ] && builtin printf ";%s" "${chunk}"
|
||||
builtin printf "\e\\"
|
||||
done
|
||||
}
|
||||
|
||||
transmit_png "$1"
|
||||
|
||||
|
||||
.. tab:: Python
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
from base64 import standard_b64encode
|
||||
|
||||
first, eof, buf = True, False, memoryview(bytearray(3 * 4096 // 4))
|
||||
w = sys.stdout.buffer.write
|
||||
def serialize_gr_command(**cmd):
|
||||
payload = cmd.pop('payload', None)
|
||||
cmd = ','.join(f'{k}={v}' for k, v in cmd.items())
|
||||
ans = []
|
||||
w = ans.append
|
||||
w(b'\033_G'), w(cmd.encode('ascii'))
|
||||
if payload:
|
||||
w(b';')
|
||||
w(payload)
|
||||
w(b'\033\\')
|
||||
return b''.join(ans)
|
||||
|
||||
def write_chunked(**cmd):
|
||||
data = standard_b64encode(cmd.pop('data'))
|
||||
while data:
|
||||
chunk, data = data[:4096], data[4096:]
|
||||
m = 1 if data else 0
|
||||
sys.stdout.buffer.write(serialize_gr_command(payload=chunk, m=m,
|
||||
**cmd))
|
||||
sys.stdout.flush()
|
||||
cmd.clear()
|
||||
|
||||
with open(sys.argv[-1], 'rb') as f:
|
||||
while not eof:
|
||||
p = buf[:]
|
||||
while p and not eof:
|
||||
n = f.readinto1(p)
|
||||
p, eof = p[n:], n == 0
|
||||
encoded = standard_b64encode(buf[:len(buf)-len(p)])
|
||||
metadata, first = "a=T,f=100," if first else "", False
|
||||
w(f'\x1b_G{metadata}m={0 if eof else 1};'.encode('ascii'))
|
||||
w(encoded)
|
||||
w(b'\x1b\\')
|
||||
write_chunked(a='T', f=100, data=f.read())
|
||||
|
||||
|
||||
Save this script as :file:`send-png`, then you can use it to display any PNG
|
||||
@@ -350,7 +337,7 @@ similar to reporting any other kind of I/O error. Since the file paths come
|
||||
from potentially untrusted sources, terminal emulators **must** refuse to read
|
||||
any device/socket/etc. special files. Only regular files are allowed.
|
||||
Additionally, terminal emulators may refuse to read files in *sensitive*
|
||||
parts of the filesystem, such as :file:`/proc`, :file:`/sys`, :file:`/dev`, etc.
|
||||
parts of the filesystem, such as :file:`/proc`, :file:`/sys`, :file:`/dev/`, etc.
|
||||
|
||||
Local client
|
||||
^^^^^^^^^^^^^^
|
||||
@@ -368,7 +355,7 @@ Here we tell the terminal emulator to read compressed image data from
|
||||
the specified shared memory object.
|
||||
|
||||
The client can also specify a size and offset to tell the terminal emulator
|
||||
to only read a part of the specified file. This is done using the ``S`` and ``O``
|
||||
to only read a part of the specified file. The is done using the ``S`` and ``O``
|
||||
keys respectively. For example::
|
||||
|
||||
<ESC>_Gs=10,v=2,t=s,S=80,O=10;<encoded /some-shared-memory-name><ESC>\
|
||||
@@ -480,11 +467,10 @@ id. To do so add the ``p`` key with a number between ``1`` and ``4294967295``.
|
||||
When you specify a placement id, it will be added to the acknowledgement code
|
||||
above. Every placement is uniquely identified by the pair of the ``image id``
|
||||
and the ``placement id``. If you specify a placement id for an image that does
|
||||
not have an id (i.e. has id=0), it will be ignored, i.e. the placement will not
|
||||
get an id. In particular this means there can exist multiple images with
|
||||
``image id=0, placement id=0``. Not specifying a placement id or using ``p=0``
|
||||
for multiple put commands (``a=p``) with the same non-zero image id results in
|
||||
multiple placements the image.
|
||||
not have an id (i.e. has id=0), it will be ignored. In particular this means
|
||||
there can exist multiple images with ``image id=0, placement id=0``. Not
|
||||
specifying a placement id or using ``p=0`` for multiple put commands (``a=p``)
|
||||
with the same non-zero image id results in multiple placements the image.
|
||||
|
||||
An example response::
|
||||
|
||||
@@ -495,14 +481,6 @@ second one will replace the first. This can be used to resize or move
|
||||
placements around the screen, without flicker.
|
||||
|
||||
|
||||
.. note::
|
||||
When re-transmitting image data for a specific id, the existing image and
|
||||
all its placements must be deleted. The new data replaces the old image data
|
||||
but is not actually displayed until a placement for it is created. This is
|
||||
to avoid divergent behavior in the case when unrelated programs happen to re-use
|
||||
image ids in the same session.
|
||||
|
||||
|
||||
.. versionadded:: 0.19.3
|
||||
Support for specifying placement ids (see :doc:`kittens/query_terminal` to query kitty version)
|
||||
|
||||
@@ -834,27 +812,6 @@ use the ``i`` key with the image id for all future communication.
|
||||
The ability to use image numbers (see :doc:`kittens/query_terminal` to query kitty version)
|
||||
|
||||
|
||||
.. _image_usage_hints:
|
||||
|
||||
Usage hints
|
||||
-----------------------------
|
||||
|
||||
Clients can specify *usage hints* when creating images using the ``N`` key.
|
||||
These hints allow the terminal to optimise resource consumption such as caching
|
||||
strategies. The value of ``N`` is a bitmask.
|
||||
|
||||
Currently the only usage hint defined is ``transient (N == 1)``.
|
||||
The terminal is free to assume that an image with this hint
|
||||
will be used for only a short time, and so may, for example, evict its
|
||||
data before other images when the image is soft deleted, has no visible
|
||||
placements and the terminal is under storage pressure, or skip writing
|
||||
its data to disk. The terminal is also free to ignore the hint. If an
|
||||
animation frame with the *transient* hint is composited onto another
|
||||
frame, and any of the involved frames have the hint, the resulting
|
||||
composited frame also has the hint. This hint must be specified when the
|
||||
image or frame data is transmitted. It has no effect on placement commands.
|
||||
|
||||
|
||||
.. _animation_protocol:
|
||||
|
||||
Animation
|
||||
@@ -929,12 +886,12 @@ on.
|
||||
Finally, while transferring frame data, the frame *gap* can also be specified
|
||||
using the ``z`` key. The gap is the number of milliseconds to wait before
|
||||
displaying the next frame when the animation is running. A value of ``z=0`` is
|
||||
ignored (acts as though ``z`` was unspecified), ``z=positive number`` sets the
|
||||
gap to the specified number of milliseconds and ``z=negative number`` creates a
|
||||
*gapless* frame. Gapless frames are not displayed to the user since they are
|
||||
instantly skipped over, however they can be useful as the base data for
|
||||
subsequent frames. For example, for an animation where the background remains
|
||||
the same and a small object or two move.
|
||||
ignored, ``z=positive number`` sets the gap to the specified number of
|
||||
milliseconds and ``z=negative number`` creates a *gapless* frame. Gapless
|
||||
frames are not displayed to the user since they are instantly skipped over,
|
||||
however they can be useful as the base data for subsequent frames. For example,
|
||||
for an animation where the background remains the same and a small object or two
|
||||
move.
|
||||
|
||||
Controlling animations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -964,9 +921,9 @@ animation. ``s=2`` runs the animation, but in *loading* mode, in this mode when
|
||||
reaching the last frame, instead of looping, the terminal will wait for the
|
||||
arrival of more frames. ``s=3`` runs the animation normally, after the last
|
||||
frame, the terminal loops back to the first frame. The number of loops can be
|
||||
controlled by the ``v`` key. ``v=0`` is ignored (acts as though ``v`` was not
|
||||
specified), ``v=1`` is loop infinitely, and any other positive number is loop
|
||||
``number - 1`` times. Note that stopping the animation resets the loop counter.
|
||||
controlled by the ``v`` key. ``v=0`` is ignored, ``v=1`` is loop infinitely,
|
||||
and any other positive number is loop ``number - 1`` times. Note that stopping
|
||||
the animation resets the loop counter.
|
||||
|
||||
Finally, the *gap* for frames can be set using the ``z`` key. This can be
|
||||
specified either when the frame is created as part of the transmit escape code
|
||||
@@ -1072,8 +1029,7 @@ Key Value Default Description
|
||||
``o`` Single character. ``null`` The type of data compression.
|
||||
``only z``
|
||||
``m`` zero or one ``0`` Whether there is more chunked data available.
|
||||
``N`` bitmask ``0`` Usage hints from the client to the terminal about the intended use of
|
||||
the image.
|
||||
|
||||
**Keys for image display**
|
||||
-----------------------------------------------------------
|
||||
``x`` Positive integer ``0`` The left edge (in pixels) of the image area to display
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
kitty
|
||||
==========================================================
|
||||
|
||||
*If you live in the terminal, kitty is made for YOU!*
|
||||
|
||||
The fast, feature-rich, GPU based terminal emulator.
|
||||
*The fast, feature-rich, GPU based terminal emulator*
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
@@ -12,7 +10,6 @@ The fast, feature-rich, GPU based terminal emulator.
|
||||
overview
|
||||
faq
|
||||
support
|
||||
sessions
|
||||
performance
|
||||
changelog
|
||||
integrations
|
||||
@@ -22,7 +19,7 @@ The fast, feature-rich, GPU based terminal emulator.
|
||||
|
||||
.. tab:: Fast
|
||||
|
||||
* Uses GPU and SIMD vector CPU instructions for :doc:`best in class performance <performance>`
|
||||
* Uses GPU and SIMD vector CPU instructions for :doc:`best in class <performance>`
|
||||
* Uses threaded rendering for :iss:`absolutely minimal latency <2701#issuecomment-636497270>`
|
||||
* Performance tradeoffs can be :ref:`tuned <conf-kitty-performance>`
|
||||
|
||||
|
||||
@@ -14,12 +14,6 @@ Image and document viewers
|
||||
Powered by kitty's :doc:`graphics-protocol` there exist many tools for viewing
|
||||
images and other types of documents directly in your terminal, even over SSH.
|
||||
|
||||
.. _tool_bookokrat:
|
||||
|
||||
`bookokrat <https://github.com/bugzmanov/bookokrat>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal PDF/EPUB viewer
|
||||
|
||||
.. _tool_termpdf:
|
||||
|
||||
`termpdf.py <https://github.com/dsanson/termpdf.py>`_
|
||||
@@ -50,11 +44,40 @@ A terminal PDF viewer with GUI-like usage and Vim-like keybindings written in Ru
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Display various types of files nicely formatted with images in the terminal
|
||||
|
||||
`dawn <https://github.com/andrewmd5/dawn>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
.. _tool_ranger:
|
||||
|
||||
A markdown editor that uses the text-sizing protocol for large headings and
|
||||
the graphics protocol for images.
|
||||
`ranger <https://github.com/ranger/ranger>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_nnn:
|
||||
|
||||
`nnn <https://github.com/jarun/nnn/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_yazi:
|
||||
|
||||
`Yazi <https://github.com/sxyazi/yazi>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Blazing fast terminal file manager, with built-in kitty graphics protocol support
|
||||
(implemented both Classic protocol and Unicode placeholders).
|
||||
|
||||
.. _tool_clifm:
|
||||
|
||||
`clifm <https://github.com/leo-arch/clifm>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The shell-like, command line terminal file manager, uses the kitty graphics and
|
||||
keyboard protocols.
|
||||
|
||||
.. _tool_hunter:
|
||||
|
||||
`hunter <https://github.com/rabite0/hunter>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_presentterm:
|
||||
|
||||
@@ -63,18 +86,6 @@ the graphics protocol for images.
|
||||
Show markdown based slides with images in your terminal, powered by the
|
||||
kitty graphics protocol.
|
||||
|
||||
.. _tool_mdfried:
|
||||
|
||||
`mdfried <https://github.com/benjajaja/mdfried>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Markdown viewer that can render big headers with the text-sizing-protocol, and
|
||||
also render images with the kitty graphics protocol.
|
||||
|
||||
`kmv <https://github.com/parf/Kitty-Markdown-Viewer>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Markdown viewer that can render big headers with the text-sizing-protocol, and
|
||||
also render images with the kitty graphics protocol.
|
||||
|
||||
.. _tool_term_image:
|
||||
|
||||
`term-image <https://github.com/AnonymouX47/term-image>`__
|
||||
@@ -128,10 +139,6 @@ images.
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A video player that can play videos in the terminal.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
mpv --profile=sw-fast --vo=kitty --vo-kitty-use-shm=yes --really-quiet video.mkv
|
||||
|
||||
.. _tool_timg:
|
||||
|
||||
`timg <https://github.com/hzeller/timg>`_
|
||||
@@ -141,52 +148,6 @@ plays videos. Fast multi-threaded loading, JPEG exif rotation, grid view and
|
||||
connecting to the webcam make it a versatile terminal utility.
|
||||
|
||||
|
||||
|
||||
File managers
|
||||
-------------------
|
||||
.. _tool_ranger:
|
||||
|
||||
`ranger <https://github.com/ranger/ranger>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_nnn:
|
||||
|
||||
`nnn <https://github.com/jarun/nnn/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_yazi:
|
||||
|
||||
`Yazi <https://github.com/sxyazi/yazi>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Blazing fast terminal file manager, with built-in kitty graphics protocol support
|
||||
(implemented both Classic protocol and Unicode placeholders).
|
||||
|
||||
.. _tool_clifm:
|
||||
|
||||
`clifm <https://github.com/leo-arch/clifm>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The shell-like, command line terminal file manager, uses the kitty graphics and
|
||||
keyboard protocols.
|
||||
|
||||
.. _tool_hunter:
|
||||
|
||||
`hunter <https://github.com/rabite0/hunter>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_far2l:
|
||||
|
||||
`far2l <https://github.com/elfmz/far2l>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Text-mode dual panel (orthodox) file manager and also terminal emulator, uses
|
||||
the kitty graphics and keyboard protocols (both as client and as terminal)
|
||||
|
||||
|
||||
System and data visualisation tools
|
||||
---------------------------------------
|
||||
|
||||
@@ -225,8 +186,28 @@ by kitty's graphics protocol for displaying plots
|
||||
`gnuplot <http://www.gnuplot.info/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A graphing and data visualization tool that has support for the kitty graphics
|
||||
protocol, with its ``kittygd`` and ``kittycairo`` backends.
|
||||
A graphing and data visualization tool that can be made to display its output in
|
||||
kitty with the following bash snippet:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
function iplot {
|
||||
cat <<EOF | gnuplot
|
||||
set terminal pngcairo enhanced font 'Fira Sans,10'
|
||||
set autoscale
|
||||
set samples 1000
|
||||
set output '|kitten icat --stdin yes'
|
||||
set object 1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb"#fdf6e3" behind
|
||||
plot $@
|
||||
set output '/dev/null'
|
||||
EOF
|
||||
}
|
||||
|
||||
Add this to bashrc and then to plot a function, simply do:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
iplot 'sin(x*3)*exp(x*.2)'
|
||||
|
||||
.. _tool_k-nine:
|
||||
|
||||
@@ -273,7 +254,6 @@ View and manage the system clipboard under Wayland in your kitty terminal
|
||||
TUI for QEMU used to manage virtual machines, can display the Virtual Machine
|
||||
in the terminal using the kitty graphics protocol.
|
||||
|
||||
|
||||
Editor integration
|
||||
-----------------------
|
||||
|
||||
@@ -287,14 +267,6 @@ features such a split windows, previews, REPLs etc.
|
||||
Integrates with kitty to use native kitty windows for its windows/panels and
|
||||
REPLs.
|
||||
|
||||
.. _tool_orbiton:
|
||||
|
||||
`orbiton <https://github.com/xyproto/orbiton/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal text editor that uses kitty's graphics protocol to render Markdown
|
||||
documents with fonts and images inline (use the ``-B`` flag for a word
|
||||
processor-like book mode), and to preview images in its built-in file browser.
|
||||
|
||||
.. tool_vim_slime:
|
||||
|
||||
`vim-slime <https://github.com/jpalardy/vim-slime#kitty>`_
|
||||
@@ -322,18 +294,10 @@ Various image viewing plugins for editors
|
||||
* `image.nvim <https://github.com/3rd/image.nvim>`_ - Bringing images to neovim
|
||||
* `image_preview.nvim <https://github.com/adelarsq/image_preview.nvim/>`_ - Image preview for neovim
|
||||
* `hologram.nvim <https://github.com/edluffy/hologram.nvim>`_ - view images inside nvim
|
||||
* `kitty-graphics.el <https://github.com/cashmeredev/kitty-graphics.el>`_ - view images in emacs
|
||||
|
||||
Scrollback manipulation
|
||||
-------------------------
|
||||
|
||||
.. tool_kitty_search_incremental:
|
||||
|
||||
`kitty-search-incremental <https://github.com/Mobinshahidi/kitty-search>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Incremental scrollback search with live results, regex and literal modes,
|
||||
case-sensitivity toggle, match counter, and auto-scroll to the matching line.
|
||||
|
||||
.. tool_kitty_scrollback_nvim:
|
||||
|
||||
`kitty-scrollback.nvim <https://github.com/mikesmithgh/kitty-scrollback.nvim>`_
|
||||
@@ -365,30 +329,9 @@ A system panel for Kitty terminal that displays real-time system metrics using t
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A kitten-panel based desktop panel for your desktop
|
||||
|
||||
Password managers
|
||||
---------------------
|
||||
|
||||
`1password <https://github.com/mm-zacharydavison/kitty-kitten-1password>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Allow injecting passwords from 1Password into kitty.
|
||||
|
||||
`BitWarden <https://github.com/dnanhkhoa/kitty-password-manager>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Inject passwords from BitWarden into kitty
|
||||
|
||||
Miscellaneous
|
||||
------------------
|
||||
|
||||
.. tool_doom:
|
||||
|
||||
DOOM
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Play the classic shooter DOOM in `kitty <https://github.com/cryptocode/terminal-doom>`__ or even inside `neovim inside kitty
|
||||
<https://github.com/seandewar/actually-doom.nvim>`__.
|
||||
|
||||
.. tool_gattino:
|
||||
|
||||
`gattino <https://github.com/salvozappa/gattino>`__
|
||||
|
||||
@@ -35,15 +35,11 @@ inside the kitty terminal to report key events.
|
||||
In addition to kitty, this protocol is also implemented in:
|
||||
|
||||
* The `alacritty terminal <https://github.com/alacritty/alacritty/pull/7125>`__
|
||||
* The `foot terminal <https://codeberg.org/dnkl/foot/issues/319>`__
|
||||
* The `ghostty terminal <https://ghostty.org>`__
|
||||
* The `foot terminal <https://codeberg.org/dnkl/foot/issues/319>`__
|
||||
* The `iTerm2 terminal <https://gitlab.com/gnachman/iterm2/-/issues/10017>`__
|
||||
* The `Microsoft terminal <https://github.com/microsoft/terminal/pull/19817>`__
|
||||
* The `rio terminal <https://github.com/raphamorim/rio/commit/cd463ca37677a0fc48daa8795ea46dadc92b1e95>`__
|
||||
* The `TuiOS terminal (multiplexer) <https://github.com/Gaurav-Gosain/tuios/issues/26>`__
|
||||
* The `Warp terminal <https://github.com/warpdotdev/Warp/issues/8462#issuecomment-3857779488>`__
|
||||
* The `WezTerm terminal <https://wezfurlong.org/wezterm/config/lua/config/enable_kitty_keyboard.html>`__
|
||||
* The `xterm.js terminal <https://github.com/xtermjs/xterm.js/pull/5600>`__
|
||||
|
||||
Libraries implementing this protocol:
|
||||
|
||||
@@ -51,9 +47,6 @@ Libraries implementing this protocol:
|
||||
* The `crossterm library <https://github.com/crossterm-rs/crossterm/pull/688>`__
|
||||
* The `textual library <https://github.com/Textualize/textual/pull/4631>`__
|
||||
* The vaxis library `go <https://sr.ht/~rockorager/vaxis/>`__ and `zig <https://github.com/rockorager/libvaxis/>`__
|
||||
* The `bubbletea library <https://github.com/charmbracelet/bubbletea/issues/869>`__
|
||||
* The `vtinput <https://unxed.github.com/vtinput>`__ and `vtui <https://github.com/unxed/vtui>`__ libraries
|
||||
* The `tcell library <https://github.com/gdamore/tcell/commit/c10909b991eb87c009554fe9b2dfa7276e2649c1>`__
|
||||
|
||||
Programs implementing this protocol:
|
||||
|
||||
@@ -63,8 +56,7 @@ Programs implementing this protocol:
|
||||
* The `kakoune text editor <https://github.com/mawww/kakoune/issues/4103>`__
|
||||
* The `dte text editor <https://gitlab.com/craigbarnes/dte/-/issues/138>`__
|
||||
* The `Helix text editor <https://github.com/helix-editor/helix/pull/4939>`__
|
||||
* The `Flow control editor <https://github.com/neurocyte/flow?tab=readme-ov-file#requirements>`__
|
||||
* The `far2l <https://github.com/elfmz/far2l/commit/e1f2ee0ef2b8332e5fa3ad7f2e4afefe7c96fc3b>`__ and `f4 <https://github.com/unxed/f4>`__ file managers
|
||||
* The `far2l file manager <https://github.com/elfmz/far2l/commit/e1f2ee0ef2b8332e5fa3ad7f2e4afefe7c96fc3b>`__
|
||||
* The `Yazi file manager <https://github.com/sxyazi/yazi>`__
|
||||
* The `awrit web browser <https://github.com/chase/awrit>`__
|
||||
* The `Turbo Vision <https://github.com/magiblot/tvision/commit/6e5a7b46c6634079feb2ac98f0b890bbed59f1ba>`__/`Free Vision <https://gitlab.com/freepascal.org/fpc/source/-/issues/40673#note_2061428120>`__ IDEs
|
||||
@@ -249,19 +241,13 @@ The terminal can optionally send the text associated with key events as a
|
||||
sequence of Unicode code points. This behavior is opt-in by the :ref:`progressive
|
||||
enhancement <progressive_enhancement>` mechanism described below. Some examples::
|
||||
|
||||
shift+a -> CSI 97 ; 2 ; 65 u # The text 'A' is reported as 65
|
||||
alt+a -> CSI 0 ; ; 229 u # The text 'å' is reported as 229
|
||||
shift+a -> CSI 97 ; 2 ; 65 u # The text 'A' is reported as 65
|
||||
option+a -> CSI 97 ; ; 229 u # The text 'å' is reported as 229
|
||||
|
||||
If multiple code points are present, they must be separated by colons. If no
|
||||
known key is associated with the text the key number ``0`` must be used. The
|
||||
associated text must not contain control codes (control codes are code points
|
||||
below U+0020 and codepoints in the C0 and C1 blocks). In the above example, the
|
||||
:kbd:`alt` modifier is consumed by the OS itself to produce the text å and not
|
||||
sent to the terminal emulator, which gets only a "text input" event and no
|
||||
information about modifiers, thus the event gets encoded with no modifiers.
|
||||
The exact behavior in these situations depends on the OS, keyboard layout, IME
|
||||
system in use and so on. In general, if the terminal emulator receives no key
|
||||
information, the key number 0 must be used to indicate a pure "text event".
|
||||
below U+0020 and codepoints in the C0 and C1 blocks).
|
||||
|
||||
|
||||
Non-Unicode keys
|
||||
@@ -368,7 +354,7 @@ are the :kbd:`Enter`, :kbd:`Tab` and :kbd:`Backspace` keys which still generate
|
||||
bytes as in legacy mode this is to allow the user to type and execute commands
|
||||
in the shell such as ``reset`` after a program that sets this mode crashes
|
||||
without clearing it. Note that the Lock modifiers are not reported for text
|
||||
producing keys, to keep them usable in legacy programs. To get lock modifiers
|
||||
producing keys, to keep them useable in legacy programs. To get lock modifiers
|
||||
for all keys use the :ref:`report_all_keys` enhancement.
|
||||
|
||||
.. _report_events:
|
||||
@@ -478,10 +464,7 @@ These keys are encoded using three schemes::
|
||||
|
||||
In the above, if there are no modifiers, the modifier parameter is omitted.
|
||||
The modifier value is encoded as described in the :ref:`modifiers` section,
|
||||
above, except that lock keys (such as :kbd:`Num lock` and :kbd:`Caps lock`)
|
||||
are not encoded as the legacy mode has no encoding for them.
|
||||
|
||||
When the second form is used, the number is always ``1`` and must be
|
||||
above. When the second form is used, the number is always ``1`` and must be
|
||||
omitted if the modifiers field is also absent. The third form becomes the
|
||||
second form when modifiers are present (``SS3 is the bytes 0x1b 0x4f``).
|
||||
|
||||
@@ -572,8 +555,8 @@ Any other combination of modifiers with these keys is output as the appropriate
|
||||
.. csv-table:: Example encodings
|
||||
:header: "Key", "Plain", "shift", "alt", "ctrl", "shift+alt", "alt+ctrl", "ctrl+shift"
|
||||
|
||||
"i", "i (105)", "I (73)", "ESC i", "\t (9)", "ESC I", "ESC \t", "CSI 105; 6 u"
|
||||
"3", "3 (51)", "# (35)", "ESC 3", "ESC (27)", "ESC #", "ESC ESC", "CSI 51; 6 u"
|
||||
"i", "i (105)", "I (73)", "ESC i", ") (41)", "ESC I", "ESC )", "CSI 105; 6 u"
|
||||
"3", "3 (51)", "# (35)", "ESC 3", "3 (51)", "ESC #", "ESC 3", "CSI 51; 6 u"
|
||||
";", "; (59)", ": (58)", "ESC ;", "; (59)", "ESC :", "ESC ;", "CSI 59; 6 u"
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
Selecting files, fast
|
||||
========================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
.. versionadded:: 0.45.0
|
||||
|
||||
.. only:: not man
|
||||
|
||||
.. figure:: /screenshots/choose-files.webp
|
||||
:alt: The choose files kitten, showing metadata and title from an e-book file
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
|
||||
The choose-files kitten is designed to allow you to select files, very fast,
|
||||
with just a few key strokes. It operates like `fzf
|
||||
<https://github.com/junegunn/fzf/>`__ and similar fuzzy finders, except that
|
||||
it is specialised for finding files. As such it supports features such as
|
||||
filtering by file type, file type icons, content previews and
|
||||
so on, out of the box. It can be used as a drop in (but much more efficient and
|
||||
keyboard friendly) replacement for the :guilabel:`File open and save`
|
||||
dialog boxes common to GUI programs. On Linux, with the help of the
|
||||
:doc:`desktop-ui </kittens/desktop-ui>` kitten, you can even convince
|
||||
most GUI programs on your computer to use this kitten instead of regular file
|
||||
dialogs.
|
||||
|
||||
Simply run it as::
|
||||
|
||||
kitten choose-files
|
||||
|
||||
to select a single file from the tree rooted at the current working directory.
|
||||
|
||||
Type a few letters from the filename and once it becomes the top selection,
|
||||
press :kbd:`Enter`. You can change the current directory by selecting a
|
||||
directory and pressing the :kbd:`Tab` key. :kbd:`Shift+Tab` goes up one
|
||||
directory level.
|
||||
|
||||
If you want to choose a file and insert it into your shell prompt at the
|
||||
current cursor position, press :sc:`insert_chosen_file` for files or
|
||||
:sc:`insert_chosen_directory` for directories. Similarly, to have a file
|
||||
chosen in a command line, use, for example::
|
||||
|
||||
some-command $(kitten choose-file)
|
||||
|
||||
Note that the above may not work in a complicated pipeline as it performs
|
||||
terminal I/O and needs exclusive access to the tty device while choosing a
|
||||
file.
|
||||
|
||||
.. note:: For content previews, this kitten uses some external programs. In
|
||||
particular `ffmpeg <https://www.ffmpeg.org/>`__ is needed for video
|
||||
previews and `calibre <https://calibre-ebook.com>`__ is needed
|
||||
for ebook metadata and cover preiews.
|
||||
|
||||
Creating shortcuts to favorite/frequently used directories
|
||||
------------------------------------------------------------
|
||||
|
||||
You can create keyboard shortcuts to quickly switch to any directory in
|
||||
:file:`choose-files.conf`. For example:
|
||||
|
||||
.. code-block:: conf
|
||||
|
||||
map ctrl+t cd /tmp
|
||||
map alt+p cd ~/my/project
|
||||
|
||||
Selecting multiple files
|
||||
-----------------------------
|
||||
|
||||
When you wish to select multiple files, start the kitten with :option:`--mode
|
||||
<kitty +kitten choose_files --mode>`:code:`=files`. Then instead of pressing
|
||||
:kbd:`Enter`, press :kbd:`Shift+Enter` instead and the file will be added to the list
|
||||
of selections. You can also hold the :kbd:`Ctrl` key and click on files to add
|
||||
them to the selections. Similarly, you can hold the :kbd:`Alt` key and click to
|
||||
select ranges of files (similar to using :kbd:`Shift+click` in a GUI app).
|
||||
Press :kbd:`Enter` on the last selected file to finish. The list of selected
|
||||
files is displayed at the bottom of the kitten and you can click on them
|
||||
to deselect a file. Similarly, pressing :kbd:`Shift+Enter` will un-select a
|
||||
previously selected file.
|
||||
|
||||
|
||||
Hidden and ignored files
|
||||
--------------------------
|
||||
|
||||
By default, the kitten does not process hidden files and directories (whose
|
||||
names start with a period). This can be :opt:`changed in the configuration <kitten-choose_files.show_hidden>`
|
||||
and also at runtime via the clickable link to the right of the search input.
|
||||
|
||||
Similarly, the kitten respects both :file:`.gitignore` and :file:`.ignore`
|
||||
files, by default. This can also be changed both :opt:`in configuration
|
||||
<kitten-choose_files.respect_ignores>` or at runtime. Note that
|
||||
:file:`.gitignore` files are only respected if there is also a :file:`.git`
|
||||
directory present. The kitten also supports the global :file:`.gitignore` file,
|
||||
though it applies only inside git working trees. You can specify :opt:`global ignore
|
||||
patterns <kitten-choose_files.ignore>`, that apply everywhere in :file:`choose-files.conf`.
|
||||
|
||||
|
||||
Selecting non-existent files (save file names)
|
||||
-------------------------------------------------
|
||||
|
||||
This kitten can also be used to select non-existent files, that is a new file
|
||||
for a :guilabel:`Save file` type of dialog using :option:`--mode <kitty +kitten
|
||||
choose_files --mode>`:code:`=save-file`. Once you have changed to the directory
|
||||
you want the file to be in (using the :kbd:`Tab` key),
|
||||
press :kbd:`Ctrl+Enter` and you will be able to type in the file name. If you
|
||||
wish to modify an existing file name use :kbd:`Alt+Enter` to modify the
|
||||
filename of the current top match instead.
|
||||
|
||||
|
||||
Selecting directories
|
||||
---------------------------
|
||||
|
||||
This kitten can also be used to select directories,
|
||||
for an :guilabel:`Open directory` type of dialog using :option:`--mode <kitty +kitten
|
||||
choose_files --mode>`:code:`=dir`. Once you have changed to the directory
|
||||
you want, press :kbd:`Ctrl+Enter` to accept it. Or if you are in a parent
|
||||
directory you can select a descendant directory by pressing :kbd:`Enter`, the
|
||||
same as you would for selecting a file to open.
|
||||
|
||||
|
||||
Configuration
|
||||
------------------------
|
||||
|
||||
You can configure various aspects of the kitten's operation by creating a
|
||||
:file:`choose-files.conf` in your :ref:`kitty config folder <confloc>`.
|
||||
See below for the supported configuration directives.
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitten-choose_files.rst
|
||||
|
||||
|
||||
.. include:: /generated/cli-kitten-choose_files.rst
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ that is, they are used to set the variable value for some font characteristic.
|
||||
<https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-feature-from-string>`__
|
||||
|
||||
``system``
|
||||
This can be used to pass an arbitrary string, usually a family or full name
|
||||
This can be used to pass an arbitrary string, usuall a family or full name
|
||||
to the OS font selection APIs. Should not be used in conjunction with any
|
||||
other keys. Is the same as specifying just the font name without any keys.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ clipboard
|
||||
Overview
|
||||
--------------
|
||||
|
||||
*Copy/paste to the system clipboard from shell scripts*
|
||||
*Copy/paste to the system clipboard from shell scripts*
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
Command palette
|
||||
=================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
The command palette lets you browse, search and trigger all keyboard shortcuts
|
||||
and actions in |kitty| from a single searchable overlay. Press
|
||||
:sc:`command_palette` to open it (default: :kbd:`Ctrl+Shift+F3`).
|
||||
|
||||
.. figure:: ../screenshots/command-palette.webp
|
||||
:alt: A screenshot of the command palette kitten
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
The command palette showing search results for ``win close``.
|
||||
|
||||
All mapped actions (those with a keyboard shortcut) and unmapped actions (those
|
||||
available but not bound to any key) are listed, organized by category. Mouse
|
||||
bindings are shown in a separate section. Simply type to search, select a
|
||||
result, and press :kbd:`Enter` to run it.
|
||||
|
||||
|
||||
Searching
|
||||
-----------
|
||||
|
||||
As you type into the search bar, the palette filters results in real time.
|
||||
Matching is case-insensitive and works across three columns simultaneously:
|
||||
the **key** (keyboard shortcut), the **action** name, and the **category**.
|
||||
Matched characters are highlighted so you can see exactly where each term hit.
|
||||
|
||||
**Multiple words**
|
||||
Separate your terms with spaces. Typing ``scroll page`` looks for items
|
||||
that contain *scroll* and *page* anywhere across the key, action, or
|
||||
category columns. Items that match more of your terms are ranked higher
|
||||
than those that match fewer.
|
||||
|
||||
**How individual words are matched**
|
||||
Each word in your query is compared against every word in the three
|
||||
columns. The best match wins and determines the item's score for that
|
||||
term:
|
||||
|
||||
- *Exact word* — the query word equals a column word exactly (highest score).
|
||||
- *Prefix* — the column word starts with the query word,
|
||||
e.g. ``scr`` matches ``scroll``.
|
||||
- *Typo tolerance* — for words of four characters or longer, a single
|
||||
typo (one character inserted, deleted, or substituted) still produces a
|
||||
match, and two typos give a lower-scoring match.
|
||||
|
||||
An item appears in the results as long as at least one query word matches
|
||||
something. Items where more query words match rank above those where fewer
|
||||
match.
|
||||
|
||||
**Compound names**
|
||||
Delimiters such as ``_``, ``+``, ``/``, and ``-`` are kept intact inside a
|
||||
query word, so you can search for compound action names as a unit.
|
||||
Typing ``mouse_selection`` first tries to find that exact substring in each
|
||||
column. If that fails, it splits the token into its parts (``mouse`` and
|
||||
``selection``) and matches each part independently against the column words.
|
||||
|
||||
**Ranking**
|
||||
When multiple items match the same query, they are sorted by:
|
||||
|
||||
1. Number of query words that matched (more is better).
|
||||
2. Score on the action column (action matches outrank key or category matches).
|
||||
3. Score on the key column.
|
||||
4. Score on the category column.
|
||||
5. Shorter action name as a tiebreaker (more specific results first).
|
||||
|
||||
|
||||
Keyboard controls
|
||||
-------------------
|
||||
|
||||
The following keys are available while the command palette is open:
|
||||
|
||||
.. list-table::
|
||||
:widths: auto
|
||||
:header-rows: 1
|
||||
|
||||
* - Key
|
||||
- Action
|
||||
* - Any text
|
||||
- Filter results by typing a search query
|
||||
* - :kbd:`Enter`
|
||||
- Run the selected action
|
||||
* - :kbd:`Escape`
|
||||
- Clear the search query, or close the palette if the query is already empty
|
||||
* - :kbd:`Up` / :kbd:`Ctrl+K` / :kbd:`Ctrl+P`
|
||||
- Move selection up
|
||||
* - :kbd:`Down` / :kbd:`Ctrl+J` / :kbd:`Ctrl+N`
|
||||
- Move selection down
|
||||
* - :kbd:`Page Up`
|
||||
- Move selection up by a page
|
||||
* - :kbd:`Page Down`
|
||||
- Move selection down by a page
|
||||
* - :kbd:`Home`
|
||||
- Jump to the first result
|
||||
* - :kbd:`End`
|
||||
- Jump to the last result
|
||||
* - :kbd:`Backspace`
|
||||
- Delete the last character from the query
|
||||
* - :kbd:`F12`
|
||||
- Toggle display of unmapped actions
|
||||
* - Mouse click
|
||||
- Select and run the clicked action
|
||||
|
||||
|
||||
Unmapped actions
|
||||
------------------
|
||||
|
||||
By default, the palette shows both mapped actions (those bound to a shortcut)
|
||||
and unmapped actions (those with no shortcut assigned). Unmapped actions appear
|
||||
with an ``(unmapped)`` label in the key column. Press :kbd:`F12` to toggle
|
||||
their visibility. This preference is remembered across sessions.
|
||||
|
||||
Unmapped actions are useful for discovering functionality that you may not have
|
||||
configured a shortcut for. You can run them directly from the palette, or note
|
||||
the action name and add a mapping in :file:`kitty.conf`.
|
||||
|
||||
|
||||
Custom keyboard modes
|
||||
-----------------------
|
||||
|
||||
If you have defined custom :ref:`keyboard modes <modal_mappings>` in your
|
||||
configuration, their bindings appear under separate mode headers in the palette.
|
||||
The ``push_keyboard_mode`` bindings are grouped with the target mode they
|
||||
activate, making it easy to see how to enter each mode alongside its shortcuts.
|
||||
|
||||
|
||||
Configuration
|
||||
--------------
|
||||
|
||||
The default mapping to open the command palette is::
|
||||
|
||||
map kitty_mod+f3 command_palette
|
||||
|
||||
You can change this in :file:`kitty.conf` like any other mapping. For example::
|
||||
|
||||
map ctrl+p command_palette
|
||||
@@ -122,9 +122,9 @@ the table below:
|
||||
.. table:: Types of input to kittens
|
||||
:align: left
|
||||
|
||||
=========================== ========================================================================================
|
||||
=========================== =======================================================================================================
|
||||
Keyword Type of :file:`STDIN` input
|
||||
=========================== ========================================================================================
|
||||
=========================== =======================================================================================================
|
||||
``text`` Plain text of active window
|
||||
``ansi`` Formatted text of active window
|
||||
``screen`` Plain text of active window with line wrap markers
|
||||
@@ -141,7 +141,7 @@ the table below:
|
||||
``output-screen-ansi`` Formatted text of the output from the last run command with wrap markers
|
||||
|
||||
``selection`` The text currently selected with the mouse
|
||||
=========================== ========================================================================================
|
||||
=========================== =======================================================================================================
|
||||
|
||||
In addition to ``output``, that gets the output of the last run command,
|
||||
``last_visited_output`` gives the output of the command last jumped to
|
||||
@@ -298,6 +298,107 @@ So if you run kitty from another kitty instance, the output will be visible
|
||||
in the first kitty instance.
|
||||
|
||||
|
||||
Adding options to kittens
|
||||
----------------------------
|
||||
|
||||
If you would like to use kitty's config framework to make your kittens
|
||||
configurable, you will need some boilerplate. Put the following files in the
|
||||
directory of your kitten.
|
||||
|
||||
:file:`kitten_options_definition.py`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from kitty.conf.types import Action, Definition
|
||||
|
||||
definition = Definition(
|
||||
'!kitten_options_utils',
|
||||
Action(
|
||||
'map', 'parse_map',
|
||||
{'key_definitions': 'kitty.conf.utils.KittensKeyMap'},
|
||||
['kitty.types.ParsedShortcut', 'kitty.conf.utils.KeyAction']
|
||||
),
|
||||
)
|
||||
|
||||
agr = definition.add_group
|
||||
egr = definition.end_group
|
||||
opt = definition.add_option
|
||||
map = definition.add_map
|
||||
|
||||
# main options {{{
|
||||
agr('main', 'Main')
|
||||
|
||||
opt('some_option', '33',
|
||||
option_type='some_option_parser',
|
||||
long_text='''
|
||||
Help text for this option
|
||||
'''
|
||||
)
|
||||
egr() # }}}
|
||||
|
||||
# shortcuts {{{
|
||||
agr('shortcuts', 'Keyboard shortcuts')
|
||||
|
||||
map('Quit', 'quit q quit')
|
||||
egr() # }}}
|
||||
|
||||
|
||||
:file:`kitten_options_utils.py`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from kitty.conf.utils import KittensKeyDefinition, key_func, parse_kittens_key
|
||||
|
||||
func_with_args, args_funcs = key_func()
|
||||
FuncArgsType = Tuple[str, Sequence[Any]]
|
||||
|
||||
def some_option_parser(val: str) -> int:
|
||||
return int(val) + 3000
|
||||
|
||||
def parse_map(val: str) -> Iterable[KittensKeyDefinition]:
|
||||
x = parse_kittens_key(val, args_funcs)
|
||||
if x is not None:
|
||||
yield x
|
||||
|
||||
Then run::
|
||||
|
||||
kitty +runpy 'from kitty.conf.generate import main; main()' /path/to/kitten_options_definition.py
|
||||
|
||||
You can parse and read the options in your kitten using the following code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from .kitten_options_types import Options, defaults
|
||||
from kitty.conf.utils import load_config as _load_config, parse_config_base
|
||||
from typing import Optional, Iterable, Dict, Any
|
||||
|
||||
def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> Options:
|
||||
from .kitten_options_parse import (
|
||||
create_result_dict, merge_result_dicts, parse_conf_item
|
||||
)
|
||||
|
||||
def parse_config(lines: Iterable[str]) -> Dict[str, Any]:
|
||||
ans: Dict[str, Any] = create_result_dict()
|
||||
parse_config_base(
|
||||
lines,
|
||||
parse_conf_item,
|
||||
ans,
|
||||
)
|
||||
return ans
|
||||
|
||||
overrides = tuple(overrides) if overrides is not None else ()
|
||||
opts_dict, found_paths = _load_config(defaults, parse_config, merge_result_dicts, *paths, overrides=overrides)
|
||||
opts = Options(opts_dict)
|
||||
opts.config_paths = found_paths
|
||||
opts.all_config_paths = paths
|
||||
opts.config_overrides = overrides
|
||||
return opts
|
||||
|
||||
See `the code <https://github.com/kovidgoyal/kitty/tree/master/kittens/diff>`__
|
||||
for the builtin :doc:`diff kitten </kittens/diff>` for examples of creating more
|
||||
options and keyboard shortcuts.
|
||||
|
||||
|
||||
Developing builtin kittens for inclusion with kitty
|
||||
----------------------------------------------------------
|
||||
|
||||
@@ -317,8 +418,6 @@ Kittens created by kitty users
|
||||
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
|
||||
Makes the kitty scroll bindings work in full screen applications
|
||||
|
||||
`kitty-tab-switcher <https://github.com/OsiPog/kitty-tab-switcher>`__
|
||||
Fuzzy finder for kitty tabs with previews
|
||||
|
||||
`gattino <https://github.com/salvozappa/gattino>`__
|
||||
Integrate kitty with an LLM to convert plain language prompts into shell commands.
|
||||
@@ -330,6 +429,3 @@ Kittens created by kitty users
|
||||
`weechat-hints <https://github.com/GermainZ/kitty-weechat-hints>`_
|
||||
URL hints kitten for WeeChat that works without having to use WeeChat's
|
||||
raw-mode.
|
||||
|
||||
`pdf-kitten <https://github.com/gelaechter/pdf-kitten>`__
|
||||
Allows you to export kitty's output to PDF, making use of weasyprint.
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
Using terminal programs to provide Linux desktop components
|
||||
===============================================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
.. versionadded:: 0.43.0
|
||||
|
||||
Power users of terminals on Linux also often like to use bare bones window
|
||||
managers instead of full fledged desktop environments. This kitten helps
|
||||
provide parts of the desktop environment that are missing from such setups,
|
||||
and does so using keyboard friendly, terminal first, UI components. Some of its
|
||||
features are:
|
||||
|
||||
* Replace the typical File Open/Save dialogs used in GUI programs with the
|
||||
fast and keyboard centric :doc:`choose-files </kittens/choose-files>` kitten
|
||||
running in a semi-transparent kitty overlay.
|
||||
|
||||
* Allow simple command line based management of the desktop light/dark modes.
|
||||
|
||||
|
||||
How to install
|
||||
-------------------
|
||||
|
||||
.. note::
|
||||
|
||||
This kitten relies on the :doc:`panel kitten </kittens/panel>`
|
||||
under the hood to supply UI components. Check :ref:`the documentation <panel_compat>`
|
||||
of that kitten to see if your window manager works with it.
|
||||
|
||||
First, run::
|
||||
|
||||
kitten desktop-ui enable-portal
|
||||
|
||||
Then, set the following two environment variables, *system wide*, that means in
|
||||
:file:`/etc/environment` or the equivalent for your distribution::
|
||||
|
||||
QT_QPA_PLATFORMTHEME=xdgdesktopportal
|
||||
GTK_USE_PORTAL=1
|
||||
|
||||
|
||||
Finally, reboot. Now, when you open a file dialog in most GUI applications, it
|
||||
should open the :doc:`choose-files kitten </kittens/choose-files>` instead
|
||||
of a normal file open dialog. You can change the current light/dark mode of
|
||||
your desktop by running::
|
||||
|
||||
kitten desktop-ui set-color-scheme dark
|
||||
kitten desktop-ui set-color-scheme light
|
||||
|
||||
Check the current value using::
|
||||
|
||||
dbus-send --session --print-reply --dest=org.freedesktop.portal.Desktop /org/freedesktop/portal/desktop org.freedesktop.portal.Settings.Read string:org.freedesktop.appearance string:color-scheme
|
||||
|
||||
How it works
|
||||
----------------
|
||||
|
||||
Modern Linux desktops have so called `portals
|
||||
<https://flatpak.github.io/xdg-desktop-portal/docs/index.html>`__ that were
|
||||
invented for sandboxed applications and provide various facilities to such
|
||||
applications over DBUS, including file open dialogs, common desktop settings,
|
||||
etc. This kitten works by implementing a backend for some of these services.
|
||||
|
||||
Normal GUI applications can then be told to make use of these services, thereby
|
||||
allowing us to replace parts of the desktop experience as needed.
|
||||
|
||||
There are multiple competing implementations of the backends. Each desktop
|
||||
environment like KDE or GNOME has it's own backend and many window managers
|
||||
provide implementations for some backends as well. Service discovery and
|
||||
configuring which backend to use happens via the :file:`xdg-desktop-portal`
|
||||
program, usually found at :file:`/usr/lib/xdg-desktop-portal`.
|
||||
|
||||
It can be configured by files in :file:`~/.local/share/xdg-desktop-portal`. See
|
||||
`man portals.conf <https://man.archlinux.org/man/portals.conf.5>`__. The
|
||||
``kitten desktop-ui enable-portal`` command takes care of the setup for you
|
||||
automatically. If you want to customize exactly which services to use this
|
||||
kitten for, run the command and then edit the conf file that the command says
|
||||
it has patched.
|
||||
|
||||
|
||||
Troubleshooting
|
||||
-------------------
|
||||
|
||||
First, ensure that DBUS is able to auto-start the kitten when it is needed. If
|
||||
the kitten is not already running, try the following command::
|
||||
|
||||
dbus-send --session --print-reply --dest=org.freedesktop.impl.portal.desktop.kitty \
|
||||
/net/kovidgoyal/kitty/portal org.freedesktop.DBus.Properties.GetAll \
|
||||
string:net.kovidgoyal.kitty.settings
|
||||
|
||||
If DBUS is able to start the kitten or if it is already running it will print
|
||||
out the version property, otherwise it will fail with an error. If it fails,
|
||||
check the file
|
||||
:file:`~/.local/share/dbus-1/services/org.freedesktop.impl.portal.desktop.kitty.service`
|
||||
that should have been created by the ``enable-portal`` command. It's ``Exec``
|
||||
key must point to the full path to the kitten executable.
|
||||
|
||||
Next, check that the XDG portal system is actually using this kitten for its
|
||||
settings backend. Run::
|
||||
|
||||
dbus-send --session --print-reply --dest=org.freedesktop.portal.Desktop \
|
||||
/org/freedesktop/portal/desktop org.freedesktop.portal.Settings.Read \
|
||||
string:net.kovidgoyal.kitty string:status
|
||||
|
||||
If this returns a reply then the kitten is being used, as expected. If it
|
||||
returns a not found error, then some other backend is being used for settings.
|
||||
|
||||
Read the ``portals.conf`` man page and run::
|
||||
|
||||
/usr/lib/xdg-desktop-portal -r v
|
||||
|
||||
this will output a lot of debug information, which should tell you which
|
||||
backend is chosen for which service. Read the debug output carefully to
|
||||
determine why the kitten is not being selected.
|
||||
|
||||
If some GUI applications are not using the choose-files kitten for their file
|
||||
select dialogs, then make sure the environment variables mentioned above are
|
||||
set, you can also try running the GUI application with them set explicitly,
|
||||
as::
|
||||
|
||||
QT_QPA_PLATFORMTHEME=xdgdesktopportal GTK_USE_PORTAL=1 my-gui-app
|
||||
|
||||
Note that not all applications use portals, so if some particular application
|
||||
is failing to use the portal but others work, report the issue to that
|
||||
applications' developers.
|
||||
|
||||
Configuration
|
||||
------------------------
|
||||
|
||||
You can configure various aspects of the kitten's operation by creating a
|
||||
:file:`desktop-ui-portal.conf` in your :ref:`kitty config folder <confloc>`.
|
||||
See below for the supported configuration directives.
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitten-desktop_ui.rst
|
||||
@@ -1,53 +0,0 @@
|
||||
Drag and Drop
|
||||
==================================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
*Drag and drop of files from the shell*
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
|
||||
The ``dnd`` kitten can be used to drag and drop files between
|
||||
the shell and arbitrary GUI programs, it even works over SSH, so you
|
||||
can easily and seamlessly transfer files from one computer to another,
|
||||
simply by dragging from one kitty window to another.
|
||||
Using it is as simple as::
|
||||
|
||||
kitten dnd file-to-drag.xyz
|
||||
|
||||
Then, start dragging with the mouse inside the window, and :file:`file-to-drag.xyz`
|
||||
will be dragged and you can drop it onto a GUI file manager or another window
|
||||
running this kitten. You can specify directories as well to drag entire trees.
|
||||
|
||||
Similarly, dropping works by running the kitten::
|
||||
|
||||
kitten dnd
|
||||
|
||||
Then, drag some files from a GUI file manager or another window running the dnd kitten
|
||||
and drop them onto this window. The files will be copied or moved (depending on
|
||||
which area you drop them) into the current working directory.
|
||||
|
||||
The best part is this works even over SSH. So if you just want to quickly
|
||||
transfer some files from one computer to another all you need to so is ssh into
|
||||
the remote computer::
|
||||
|
||||
kitten ssh remote-computer-name
|
||||
|
||||
Then, run the dnd kitten on the remote computer::
|
||||
|
||||
kitten dnd files-or-dirs-to-drag
|
||||
|
||||
That's it, you can now drag form or drop to the remote computer. See below for
|
||||
customising the behavior of the kitten via command line flags.
|
||||
|
||||
This kitten uses a new protocol developed by kitty to function, for details,
|
||||
see :doc:`/dnd-protocol`.
|
||||
|
||||
.. program:: kitty +kitten dnd
|
||||
|
||||
|
||||
.. include:: /generated/cli-kitten-dnd.rst
|
||||
@@ -9,7 +9,7 @@ Hyperlinked grep
|
||||
|
||||
.. note::
|
||||
|
||||
As of ripgrep versions newer than 13.0 it supports hyperlinks
|
||||
As of ripgrep versions newer that 13.0 it supports hyperlinks
|
||||
natively so you can just add the following alias in your shell rc file:
|
||||
``alias rg="rg --hyperlink-format=kitty"`` no need to use this kitten.
|
||||
But, see below for instructions on how to customize kitty to have it open
|
||||
@@ -45,7 +45,7 @@ Now, run a search with::
|
||||
Hold down the :kbd:`Ctrl+Shift` keys and click on any of the result lines, to
|
||||
open the file in :program:`vim` at the matching line. If you use some editor
|
||||
other than :program:`vim`, you should adjust the :file:`open-actions.conf` file
|
||||
accordingly. To open links with the keyboard instead, use
|
||||
accordingly. TO open links with the keyboard instead, use
|
||||
:sc:`open_selected_hyperlink`.
|
||||
|
||||
Finally, add an alias to your shell's rc files to invoke the kitten as
|
||||
@@ -67,7 +67,7 @@ which items are linked with a :code:`--kitten hyperlink` flag. For example,
|
||||
:code:`--kitten hyperlink=matching_lines` will only add hyperlinks to the
|
||||
match lines. :code:`--kitten hyperlink=file_headers,context_lines` will link
|
||||
file headers and context lines but not match lines. :code:`--kitten
|
||||
hyperlink=none` will cause the command line to be passed directly to
|
||||
hyperlink=none` will cause the command line to be passed to directly to
|
||||
:command:`rg` so no hyperlinking will be performed. :code:`--kitten hyperlink`
|
||||
may be specified multiple times.
|
||||
|
||||
|
||||
@@ -114,12 +114,11 @@ shell.
|
||||
|
||||
The Linux dock panel was::
|
||||
|
||||
wm bar
|
||||
kitten panel kitty +launch my-panel.py
|
||||
|
||||
This is a custom program I wrote for my personal use. It uses kitty's kitten
|
||||
infrastructure to implement the bar in a `few hundred lines of code
|
||||
<https://github.com/kovidgoyal/wm/blob/master/bar/main.go>`__.
|
||||
This was designed for my personal use only, but, there are :ref:`public projects implementing
|
||||
This creates the panel window and runs the ``my-panel.py`` script inside it
|
||||
using the Python interpreter that comes bundled with kitty. Unfortunately the
|
||||
actual script is not public, but there are :ref:`public projects implementing
|
||||
general purpose panels using kitty <panel_projects>`.
|
||||
|
||||
|
||||
@@ -139,7 +138,7 @@ Compatibility with various platforms
|
||||
.. tab:: Wayland
|
||||
|
||||
Below is a list of the status of various Wayland compositors. The panel kitten
|
||||
relies on the `wlr layer shell protocol
|
||||
relies of the `wlr layer shell protocol
|
||||
<https://wayland.app/protocols/wlr-layer-shell-unstable-v1#compositor-support>`__,
|
||||
which is technically supported by almost all Wayland compositors, but the
|
||||
implementation in some of them is quite buggy.
|
||||
@@ -147,24 +146,29 @@ Compatibility with various platforms
|
||||
🟢 **Hyprland**
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **labwc**
|
||||
🟢 **KDE** (kwin)
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **niri**
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **river**
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **Xfce**
|
||||
Fully working, no known issues
|
||||
|
||||
🟠 **KDE** (kwin)
|
||||
Mostly working, except that clicks outside background panels cause kwin to :iss:`erroneously hide the panel <8715>`. KDE uses an `undocumented mapping <https://invent.kde.org/plasma/kwin/-/blob/3dc5cee6b34792486b343098e55e7f2b90dfcd00/src/layershellv1window.cpp#L24>`__ under Wayland to set the window type from the :code:`kitten panel --app-id` flag. You might want to use :code:`--app-id=dock` so that KDE treats the window as a dock panel, and disables window appearing/disappearing animations for it.
|
||||
|
||||
🟠 **Sway**
|
||||
Renders its configured background over the background window instead of
|
||||
under it. This is because it uses the wlr protocol for backgrounds itself.
|
||||
Partially working. Issues include:
|
||||
* Renders its configured background over the background window instead of
|
||||
under it. This is likely because it uses the wlr protocol for
|
||||
backgrounds itself.
|
||||
* Hiding a dock panel (unmapping the window) does not release the space
|
||||
used by the dock.
|
||||
|
||||
🟠 **niri**
|
||||
Breaks when hiding (unmapping) layer shell windows. This means the quick
|
||||
access terminal is non-functional, but background and dock panels work.
|
||||
More technically, keyboard focus gets stuck in the hidden window and when trying
|
||||
to remap the hidden window niri never sends configure events for the remapped surface.
|
||||
|
||||
🟠 **labwc**
|
||||
Breaks when hiding (unmapping) layer shell windows. This means the quick
|
||||
access terminal is non-functional, but background and dock panels work.
|
||||
More technically, when unmapping the surface (attaching a NULL buffer to
|
||||
it) labwc continues to send configure events to the unmapped surface,
|
||||
leading to Wayland protocol errors and a crash of labwc.
|
||||
|
||||
🔴 **GNOME** (mutter)
|
||||
Does not implement the wlr protocol at all, nothing works.
|
||||
|
||||
@@ -13,10 +13,7 @@ Extend with kittens
|
||||
kittens/themes
|
||||
kittens/choose-fonts
|
||||
kittens/hints
|
||||
kittens/command-palette
|
||||
kittens/quick-access-terminal
|
||||
kittens/choose-files
|
||||
kittens/dnd
|
||||
kittens/panel
|
||||
kittens/remote_file
|
||||
kittens/hyperlinked_grep
|
||||
@@ -56,11 +53,6 @@ Some prominent kittens:
|
||||
filenames, words, lines, etc. from the terminal screen.
|
||||
|
||||
|
||||
:doc:`Command palette <kittens/command-palette>`
|
||||
Browse, search and trigger all keyboard shortcuts and actions from a
|
||||
single searchable overlay.
|
||||
|
||||
|
||||
:doc:`Quick access terminal <kittens/quick-access-terminal>`
|
||||
Get access to a quick access floating, semi-transparent kitty window
|
||||
with a single keypress.
|
||||
@@ -71,14 +63,6 @@ Some prominent kittens:
|
||||
terminal programs.
|
||||
|
||||
|
||||
:doc:`Choose files <kittens/choose-files>`
|
||||
Preview and select files at the speed of thought
|
||||
|
||||
|
||||
:doc:`Drag and drop from the shell <kittens/dnd>`
|
||||
Drag and drop files from/to GUI programs from your shell, even over SSH
|
||||
|
||||
|
||||
:doc:`Remote file <kittens/remote_file>`
|
||||
Edit, open, or download remote files over SSH easily, by simply clicking on
|
||||
the filename.
|
||||
@@ -107,6 +91,11 @@ Some prominent kittens:
|
||||
configuration to the remote host.
|
||||
|
||||
|
||||
:doc:`Panel <kittens/panel>`
|
||||
Draw a GPU accelerated dock panel on your desktop showing the output from an
|
||||
arbitrary terminal program.
|
||||
|
||||
|
||||
:doc:`Clipboard <kittens/clipboard>`
|
||||
Copy/paste to the clipboard from shell scripts, even over SSH.
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ create :file:`~/.config/kitty/mywatcher.py` and use :option:`launch --watcher` =
|
||||
|
||||
def on_load(boss: Boss, data: dict[str, Any]) -> None:
|
||||
# This is a special function that is called just once when this watcher
|
||||
# module is first loaded, can be used to perform any initialization/one
|
||||
# module is first loaded, can be used to perform any initializztion/one
|
||||
# time setup. Any exceptions in this function are printed to kitty's
|
||||
# STDERR but otherwise ignored.
|
||||
...
|
||||
@@ -175,25 +175,6 @@ create :file:`~/.config/kitty/mywatcher.py` and use :option:`launch --watcher` =
|
||||
# code received from the program running in the window
|
||||
...
|
||||
|
||||
def on_tab_bar_dirty(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
# called when any changes happen to the tab bar, such a new tabs being
|
||||
# created, tab titles changing, tabs moving, etc. Useful to display the
|
||||
# tab bar externally to kitty. This is called even if the tab bar is
|
||||
# hidden. Note that this is called only in *global watchers*, that is
|
||||
# watchers defined in kitty.conf or using the --watcher command line
|
||||
# flag. data contains tab_manager which is the object responsible for
|
||||
# managing all tabs in a single OS Window.
|
||||
...
|
||||
|
||||
def on_quit(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
# called when kitty is about to quit. This is called in *global watchers*
|
||||
# only. It is called twice: once before the quit confirmation dialog is
|
||||
# shown (data['confirmed'] will be False) and once after the user has
|
||||
# confirmed quitting (data['confirmed'] will be True). Setting
|
||||
# data['aborted'] to True will abort the quit in both cases.
|
||||
...
|
||||
|
||||
|
||||
Every callback is passed a reference to the global ``Boss`` object as well as
|
||||
the ``Window`` object the action is occurring on. The ``data`` object is a dict
|
||||
that contains event dependent data. You have full access to kitty internals in
|
||||
|
||||
@@ -184,36 +184,12 @@ define a few extra key bindings in :file:`kitty.conf`::
|
||||
# window's size.
|
||||
map ctrl+. layout_action bias 80
|
||||
|
||||
# Maximize the active window along the horizontal axis (fill full width),
|
||||
# keeping other windows visible in their vertical positions. Press again to
|
||||
# restore the original layout.
|
||||
map ctrl+shift+right layout_action maximize horizontal
|
||||
|
||||
# Maximize the active window along the vertical axis (fill full height),
|
||||
# keeping other windows visible in their horizontal positions. Press again
|
||||
# to restore the original layout.
|
||||
map ctrl+shift+up layout_action maximize vertical
|
||||
|
||||
# Equalize all splits so that windows share available space proportionally.
|
||||
map ctrl+shift+e layout_action equalize
|
||||
|
||||
|
||||
Windows can be resized using :ref:`window_resizing`. You can swap the windows
|
||||
in a split using the ``rotate`` action with an argument of ``180`` and rotate
|
||||
and swap with an argument of ``270``. The ``maximize`` action expands the active
|
||||
window to fill the maximum available space along a single axis while keeping
|
||||
the rest of the layout intact. Use ``maximize horizontal`` to fill the full
|
||||
width and ``maximize vertical`` to fill the full height. Calling it again
|
||||
restores the original split sizes. The ``equalize`` action redistributes space
|
||||
so that all windows along each split axis receive an equal share.
|
||||
and swap with an argument of ``270``.
|
||||
|
||||
This layout takes two options. ``equalize_on_close`` automatically equalizes
|
||||
split sizes whenever a window is closed, keeping remaining windows balanced
|
||||
without needing an explicit keybinding::
|
||||
|
||||
enabled_layouts splits:equalize_on_close=true
|
||||
|
||||
``split_axis`` controls whether new windows
|
||||
This layout takes one option, ``split_axis`` that controls whether new windows
|
||||
are placed into vertical or horizontal splits when a :option:`--location
|
||||
<launch --location>` is not specified. A value of ``horizontal`` (same as
|
||||
``--location=vsplit``) means when a new split is created the two windows will
|
||||
@@ -289,14 +265,7 @@ All windows are shown one below the other. This layout has no options::
|
||||
Resizing windows
|
||||
------------------
|
||||
|
||||
You can resize windows inside layouts. The easiest method is to simply drag the
|
||||
window borders using a mouse, controlled by the option :opt:`window_drag_tolerance`.
|
||||
Note that technically this resizes layout slots not actual windows, so it
|
||||
does not work exactly like resizing OS Windows on your desktop. Instead, the
|
||||
layout is changed and potentially multiple windows get resized when dragging a
|
||||
single border.
|
||||
|
||||
For keyboard friendly resizing, press :sc:`start_resizing_window` (also
|
||||
You can resize windows inside layouts. Press :sc:`start_resizing_window` (also
|
||||
:kbd:`⌘+r` on macOS) to enter resizing mode and follow the on-screen
|
||||
instructions. In a given window layout only some operations may be possible for
|
||||
a particular window. For example, in the *Tall* layout you can make the first
|
||||
|
||||
108
docs/mapping.rst
108
docs/mapping.rst
@@ -167,33 +167,6 @@ the program running in the terminal, map it to :ac:`discard_event`::
|
||||
|
||||
.. _conditional_mappings:
|
||||
|
||||
Configuring a timeout
|
||||
----------------------
|
||||
|
||||
You can also set a timeout for keyboard modes and multi-key mappings. If a
|
||||
timeout is set and you don't complete the key sequence or exit the mode within
|
||||
the specified time, the mode will be automatically cancelled. This is useful
|
||||
for multi-key mappings where you might accidentally press the first key and
|
||||
then change your mind. The timeout is specified in seconds and can be set
|
||||
globally using the :opt:`map_timeout` option or per-mode using ``--timeout``::
|
||||
|
||||
# Set a global 2 second timeout for all multi-key and modal mappings
|
||||
map_timeout 2.0
|
||||
|
||||
# This mode will have a 5 second timeout (overrides global setting)
|
||||
map --new-mode resize --timeout 5.0 kitty_mod+r
|
||||
map --mode resize h resize_window narrower
|
||||
map --mode resize l resize_window wider
|
||||
# ... more mappings
|
||||
|
||||
# Multi-key mapping with the global timeout
|
||||
map ctrl+a>h new_window
|
||||
|
||||
When a timeout occurs, the mode is exited and any buffered keys are discarded.
|
||||
A timeout value of zero disables the timeout. For multi-key sequences, the
|
||||
timeout is restarted after each valid key press in the sequence.
|
||||
|
||||
|
||||
Conditional mappings depending on the state of the focused window
|
||||
----------------------------------------------------------------------
|
||||
|
||||
@@ -221,14 +194,14 @@ running an editor::
|
||||
|
||||
map --when-focus-on var:in_editor kitty_mod+c
|
||||
|
||||
In order to make this work, you need to configure your editor as shown below:
|
||||
In order to make this work, you need to configure your editor as show below:
|
||||
|
||||
.. tab:: vim
|
||||
|
||||
In :file:`~/.vimrc` add:
|
||||
.. code-block:: vim
|
||||
|
||||
let &t_ti = &t_ti . "\033]1337;SetUserVar=in_editor=MQ==\007"
|
||||
let &t_ti = &t_ti . "\033]1337;SetUserVar=in_editor=MQo\007"
|
||||
let &t_te = &t_te . "\033]1337;SetUserVar=in_editor\007"
|
||||
|
||||
.. tab:: neovim
|
||||
@@ -237,25 +210,17 @@ In order to make this work, you need to configure your editor as shown below:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
vim.api.nvim_create_autocmd({ "VimEnter", "VimResume", "UIEnter" }, {
|
||||
vim.api.nvim_create_autocmd({ "VimEnter", "VimResume" }, {
|
||||
group = vim.api.nvim_create_augroup("KittySetVarVimEnter", { clear = true }),
|
||||
callback = function()
|
||||
if vim.api.nvim_ui_send then
|
||||
vim.api.nvim_ui_send("\x1b]1337;SetUserVar=in_editor=MQ==\007")
|
||||
else
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor=MQ==\007")
|
||||
end
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor=MQo\007")
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd({ "VimLeave", "VimSuspend" }, {
|
||||
group = vim.api.nvim_create_augroup("KittyUnsetVarVimLeave", { clear = true }),
|
||||
callback = function()
|
||||
if vim.api.nvim_ui_send then
|
||||
vim.api.nvim_ui_send("\x1b]1337;SetUserVar=in_editor\007")
|
||||
else
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor\007")
|
||||
end
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor\007")
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -265,67 +230,6 @@ copying to clipboard. In the editor, you can map it to copy to the clipboard,
|
||||
thereby allowing use of a common shortcut both inside and outside the editor
|
||||
for copying to clipboard.
|
||||
|
||||
.. note::
|
||||
|
||||
When using multi-key mappings, of the form :kbd:`k1>k2` or similar, the
|
||||
condition applies to the first key and you can have only one condition per
|
||||
key, the last in kitty.conf wins. In particular, this means you cannot have
|
||||
multiple conditions applying to multi-key mappings with the same first key
|
||||
and you cannot have mappings with and without conditions applying to multi-keys
|
||||
with the same first key.
|
||||
|
||||
|
||||
.. _mapping-fallback:
|
||||
|
||||
Non-Latin keyboard layout support
|
||||
--------------------------------------
|
||||
|
||||
When using a non-Latin keyboard layout (e.g. Russian, Arabic, Greek), letter-key
|
||||
shortcuts like :kbd:`Ctrl+C` stop working because the key produces a non-Latin
|
||||
character. kitty solves this with the ``--allow-fallback`` option on the ``map``
|
||||
directive, which controls how shortcuts fall back to the physical key position.
|
||||
|
||||
The ``--allow-fallback`` option accepts a comma-separated list of fallback types:
|
||||
|
||||
``shifted``
|
||||
Fall back to the *shifted key* — the character produced when Shift is held
|
||||
with the key. This is the default for all mappings and preserves the existing
|
||||
behavior.
|
||||
|
||||
``ascii``
|
||||
Fall back to the *alternate key* — the character that the physical key would
|
||||
produce in a standard US layout. This only triggers when the key produces a
|
||||
non-ASCII character, so it has no effect on Latin-based layouts like Dvorak
|
||||
or Colemak.
|
||||
|
||||
``none``
|
||||
Disable all fallback matching. The mapping will only match the exact key
|
||||
specified, ignoring both shifted and alternate key positions.
|
||||
|
||||
For example::
|
||||
|
||||
# Enable both shifted and ASCII fallback (used by default kitty shortcuts)
|
||||
map --allow-fallback=shifted,ascii kitty_mod+c copy_to_clipboard
|
||||
|
||||
# Only ASCII fallback, no shifted key fallback
|
||||
map --allow-fallback=ascii ctrl+s save_something
|
||||
|
||||
# Disable all fallback (neither shifted nor alternate key matching)
|
||||
map --allow-fallback=none ctrl+x some_action
|
||||
|
||||
All default kitty shortcuts use ``--allow-fallback=shifted,ascii``, so they work
|
||||
out of the box with non-Latin layouts. Custom mappings without an explicit
|
||||
``--allow-fallback`` get the default value of ``shifted``, which preserves
|
||||
backward compatibility.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``ascii`` fallback uses a non-ASCII guard: it only activates when
|
||||
the key produces a character with a Unicode code point above 127. This means
|
||||
alternative Latin layouts (Dvorak, Colemak, etc.) are never affected by the
|
||||
``ascii`` fallback — only non-Latin layouts trigger it.
|
||||
|
||||
|
||||
Sending arbitrary text or keys to the program running in kitty
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -406,7 +310,7 @@ below::
|
||||
|
||||
# Beep on unknown keys
|
||||
map --new-mode XXX --on-unknown beep ...
|
||||
# Ignore unknown keys silently
|
||||
# Ingore unknown keys silently
|
||||
map --new-mode XXX --on-unknown ignore ...
|
||||
# Beep and exit the keyboard mode on unknown key
|
||||
map --new-mode XXX --on-unknown end ...
|
||||
|
||||
@@ -29,28 +29,6 @@ there is only one number to reset these attributes, SGR 22, which resets both.
|
||||
There is no way to reset one and not the other. kitty uses 221 and 222 to reset
|
||||
bold and faint independently.
|
||||
|
||||
.. _mouse_leave_window:
|
||||
|
||||
Reporting when the mouse leaves the window
|
||||
----------------------------------------------
|
||||
|
||||
kitty extends the SGR Pixel mouse reporting protocol created by xterm to
|
||||
also report when the mouse leaves the window. This event is delivered
|
||||
encoded as a normal SGR pixel event except that the eight bit is set on the
|
||||
first number. Additionally, bit 5 is set to indicate this is a motion related event.
|
||||
The remaining bits 1-7 (except 5) are used to encode button and modifier information.
|
||||
When bit 8 is set it means the event is a mouse has left the window event,
|
||||
and all other bits should be ignored. The pixel position values must also
|
||||
be ignored as they may not be accurate.
|
||||
|
||||
An escape code to move the contents of the screen into the scrollback
|
||||
-------------------------------------------------------------------------------------
|
||||
|
||||
The escape code is ``\x1b [ 22 J`` (ignoring spaces present for clarity). It
|
||||
moves all screen contents (text and images) into the scrollback leaving the
|
||||
screen in the same state as it would be if the standard screen clear escape
|
||||
code had been used ``\x1b [ 2 J``.
|
||||
|
||||
|
||||
kitty specific private escape codes
|
||||
---------------------------------------
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
The multiple cursors protocol
|
||||
==============================================
|
||||
|
||||
.. versionadded:: 0.43.0
|
||||
|
||||
Many editors support something called *multiple cursors* in which you can make
|
||||
the same changes at multiple locations in a file and the editor shows you
|
||||
cursors at each of the locations. In a terminal context editors typically
|
||||
implement this by showing some Unicode glyph at each location instead of the
|
||||
actual cursor. This is sub-optimal since actual cursors implemented by the
|
||||
terminal have many niceties like smooth animation [anim]_, auto adjust colors [rv]_,
|
||||
etc. To address this and other use cases, this protocol allows terminal programs to
|
||||
request that the terminal display multiple cursors at specific locations on the
|
||||
screen.
|
||||
|
||||
Quickstart
|
||||
----------------
|
||||
|
||||
An example, showing how to use the protocol:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Show cursors of the same shape as the main cursor at y=4, x=5
|
||||
printf "\e[>29;2:4:5 q"
|
||||
# Show more cursors on the seventh line, of various shapes, the underline shape is shown twice
|
||||
printf "\e[>1;2:7:1 q\e[>2;2:7:3 q\e[>3;2:7:5;2:7:7 q"
|
||||
|
||||
|
||||
The escape code to show a cursor has the following structure (ignore spaces
|
||||
they are present for readability only)::
|
||||
|
||||
CSI > SHAPE;CO-ORD TYPE : CO-ORDINATES ; CO-ORD TYPE : CO-ORDINATES ... TRAILER
|
||||
|
||||
Here ``CSI`` is the two bytes ESC (``0x1b``) and [ (``0x5b``). ``SHAPE`` can be
|
||||
one of:
|
||||
|
||||
* ``0``: No cursor
|
||||
* ``1``: Block cursor
|
||||
* ``2``: Beam cursor
|
||||
* ``3``: Underline cursor
|
||||
* ``29``: Follow the shape of the main cursor
|
||||
* ``30``: Change the color of text under extra cursors
|
||||
* ``40``: Change the color of extra cursors
|
||||
* ``100``: Used for querying currently set cursors
|
||||
|
||||
``CO-ORD TYPE`` can be one of:
|
||||
|
||||
* ``0``: This refers to the position of the main cursor and has no following
|
||||
co-ordinates.
|
||||
|
||||
* ``2``: In this case the following co-ordinates are pairs of numbers pointing
|
||||
to cells in the form ``y:x`` with the origin in the top left corner at
|
||||
``1,1``. There can be any number of pairs, the terminal must treat each pair
|
||||
as a new location to set a cursor.
|
||||
|
||||
* ``4``: In this case the following co-ordinates are sets of four numbers that
|
||||
define a rectangle in the same co-ordinate system as above of the form:
|
||||
``top:left:bottom:right``. The shape is set on every cell in the rectangle
|
||||
from the top left cell to the bottom right cell, inclusive. If no numbers
|
||||
are provided, the rectangle is the full screen. There can be any number of
|
||||
rectangles, the terminal must treat each set of four numbers as a new
|
||||
rectangle.
|
||||
|
||||
The sequence of ``CO-ORD TYPE : CO-ORDINATES`` can be repeated any number of
|
||||
times separated by ``;``. The ``SHAPE`` will be set on the cells indicated by
|
||||
each such group. For example: ``-1;2:3:4;4:5:6:7:8`` will set the shape ``-1``
|
||||
at the cell ``(3, 2)`` and in the rectangle ``(6, 5)`` to ``(8, 7)`` inclusive.
|
||||
|
||||
Finally, the ``TRAILER`` terminates the sequence and is the bytes SPACE
|
||||
(``0x20``) and q (``0x71``).
|
||||
|
||||
Terminals **must** ignore cells that fall outside the screen. That means, for
|
||||
rectangle co-ordinates only the intersection of the rectangle with the screen
|
||||
must be considered, and point co-ordinates that fall outside of the screen are
|
||||
simply ignored, with no effect.
|
||||
|
||||
Terminals **must** ignore extra co-ordinates, that means if an odd number of
|
||||
co-ordinates are specified for type ``2`` the last co-ordinate is ignored.
|
||||
Similarly for type ``4`` if the number of co-ordinates is not a multiple of
|
||||
four, the last ``1 <= n <= 3`` co-ordinates are ignored, as if they were not
|
||||
specified.
|
||||
|
||||
Querying for support
|
||||
-------------------------
|
||||
|
||||
A terminal program can query the terminal emulator for support of this
|
||||
protocol by sending the escape code::
|
||||
|
||||
CSI > TRAILER
|
||||
|
||||
In this case a supporting terminal must reply with::
|
||||
|
||||
CSI > 1;2;3;29;30;40;100;101 TRAILER
|
||||
|
||||
Here, the list of numbers indicates the cursor shapes and other operations
|
||||
the terminal supports and can be any subset of the above. No numbers
|
||||
indicates the protocol is not supported. To avoid having to wait with a
|
||||
timeout for a response from the terminal, the client should send this
|
||||
query code immediately followed by a request for the
|
||||
`primary device attributes <https://vt100.net/docs/vt510-rm/DA1.html>`_.
|
||||
If the terminal responds with an answer for the device attributes without
|
||||
an answer for the *query* the terminal emulator does not support this protocol at all.
|
||||
|
||||
Terminals **must** respond to these queries in FIFO order, so that
|
||||
multiplexers that split a single screen know which split to send responses too.
|
||||
|
||||
Clearing previously set multi-cursors
|
||||
------------------------------------------
|
||||
|
||||
The cursor at a cell is cleared by setting its shape to ``0``.
|
||||
The most common operation is to clear all previously set multi-cursors. This is
|
||||
easily done using the *rectangle* co-ordinate system above, like this::
|
||||
|
||||
CSI > 0;4 TRAILER
|
||||
|
||||
For more precise control different co-ordinate types can be used. This is
|
||||
particularly important for multiplexers that split up the screen and therefore
|
||||
need to re-write these escape codes.
|
||||
|
||||
.. _extra_cursor_color:
|
||||
|
||||
Changing the color of extra cursors
|
||||
---------------------------------------
|
||||
|
||||
In order to visually distinguish extra cursors from the main cursor, it is
|
||||
possible to specify a color pair for extra cursors. Note that for performance
|
||||
reasons, there is only a single color pair that all extra cursors share.
|
||||
The color pair consists of the cursor color and the color for text in the cell
|
||||
the cursor is on.
|
||||
|
||||
To change this color pair use an escape code of the form::
|
||||
|
||||
CSI > WHICH ; COLOR_SPACE : COLOR_PARAMETER1 : COLOR_PARAMETER2 : ... TRAILER
|
||||
|
||||
Here, ``WHICH`` is ``30`` to set the color of text under the cursor and ``40``
|
||||
to set the color of the cursor itself (these numbers mimic the SGR codes for
|
||||
foreground and background respectively).
|
||||
|
||||
The ``COLOR_SPACE`` parameter sets the type of color, it can take values:
|
||||
|
||||
``0`` - unset color is same as for main cursor. No color parameters.
|
||||
``1`` - *special* which typically means some kind of reverse video effect, see below
|
||||
``2`` - sRGB color, with three color parameters, red, green and blue as numbers
|
||||
from 0 to 255
|
||||
``5`` - Indexed color with one color parameter which is an index into the color
|
||||
table from 0 to 255
|
||||
|
||||
When the cursor color is set to *special* via ``40`` it means the block cursor
|
||||
must be rendered with a reverse video effect where the cursor color becomes the
|
||||
foreground color of the cell under the cursor and the foreground color of the
|
||||
cell becomes its background color. Implementations are free to adjust these
|
||||
colors to ensure suitable contrast levels. In this case the text color set by
|
||||
``30`` must be ignored.
|
||||
|
||||
When the cursor color is not set to *special* but the text color via ``30`` is
|
||||
set to special, then that means the foreground color of the cell with the
|
||||
cursor must be changed to its background color for a partial reverse video
|
||||
effect.
|
||||
|
||||
When unset, aka, set to ``0`` the cursors must be the same color as the main
|
||||
cursor. In particular if the main color is using a reverse video effect, the
|
||||
extra cursors must use the exact same colors as the main cursor, not the colors
|
||||
of the cells they are on.
|
||||
|
||||
Querying for already set cursors
|
||||
--------------------------------------
|
||||
|
||||
Programs can ask the terminal what extra cursors are currently set, by sending
|
||||
the escape code::
|
||||
|
||||
CSI > 100 TRAILER
|
||||
|
||||
The terminal must respond with **one** escape code::
|
||||
|
||||
CSI > 100; SHAPE:CO-ORDINATE TYPE:CO-ORDINATES ; ... TRAILER
|
||||
|
||||
Here, the ``SHAPE:CO-ORDINATE TYPE:CO-ORDINATES`` block can be repeated any
|
||||
number of times, separated by ``;``. This response gives the set of shapes and
|
||||
positions currently active. If no cursors are currently active, there will be
|
||||
no blocks, just an empty response of the form::
|
||||
|
||||
CSI > 100 TRAILER
|
||||
|
||||
Again, terminals **must** respond in FIFO order so that multiplexers know where
|
||||
to direct the responses.
|
||||
|
||||
Querying for extra cursor colors
|
||||
-------------------------------------
|
||||
|
||||
Programs can ask the terminal what cursor colors are currently set, by sending
|
||||
escape code::
|
||||
|
||||
CSI > 101 TRAILER
|
||||
|
||||
The terminal must respond with **one** escape code::
|
||||
|
||||
CSI > 101 ; 30 : COLOR_SPACE : COLOR_PARAMETERS ; 40 : COLOR_SPACE : COLOR_PARAMETERS TRAILER
|
||||
|
||||
The number and type of ``COLOR_PARAMETERS`` depends on the preceding
|
||||
``COLOR_SPACE`` and can be omitted for some ``COLOR_SPACE`` values. See the
|
||||
section :ref:`extra_cursor_color` for details.
|
||||
|
||||
|
||||
Interaction with other terminal controls and state
|
||||
-------------------------------------------------------
|
||||
|
||||
**The main cursor**
|
||||
The extra cursors must all have the same color and opacity and blink state
|
||||
as the main cursor. The main cursor's visibility must not affect the
|
||||
visibility of the extra cursors. Their visibility and shape are controlled
|
||||
only by this protocol.
|
||||
|
||||
**Clearing the screen**
|
||||
The escape codes used to clear the screen (`ED <https://vt100.net/docs/vt510-rm/ED.html>`__)
|
||||
with parameters 2, 3 and 22 must remove all extra cursors,
|
||||
this is so that the clear command can be used by users to clear the screen of extra cursors.
|
||||
|
||||
**Reset***
|
||||
This must remove all extra cursors.
|
||||
|
||||
**Alternate screen***
|
||||
Switching between the main and alternate screens must remove all extra
|
||||
cursors.
|
||||
|
||||
**Scrolling**
|
||||
The index (IND) and reverse index (RI) escape codes that cause screen
|
||||
contents to scroll into scrollback or off screen must not affect
|
||||
the extra cursors in any way. They remain at exactly the same position.
|
||||
It is up to applications to manage extra cursor positions when using these
|
||||
escape codes if needed. There are not a lot of use cases for scrolling
|
||||
extra cursors with screen content, since extra cursors are meant to be
|
||||
ephemeral and on screen only, not in scrollback. This allows terminals
|
||||
to avoid the extra overhead of adjusting positions of the extra cursors
|
||||
on every scroll.
|
||||
|
||||
|
||||
Footnotes
|
||||
-------------
|
||||
|
||||
.. [anim] kitty allows the cursor blink to be :opt:`animated
|
||||
<cursor_blink_interval>` using any CSS easing function. This cannot be
|
||||
implemented using fake cursors.
|
||||
|
||||
.. [rv] kitty has a special "reverse video" color mode for cursors where the
|
||||
color of the cursor and the text under the cursor is adjusted based on the
|
||||
color of the cell under the cursor. This also cannot be implemented using
|
||||
fake cursors.
|
||||
@@ -48,7 +48,7 @@ action per entry if you like, for example:
|
||||
action change_font_size current -2
|
||||
|
||||
|
||||
In the launch specification you can expand environment variables, as shown in
|
||||
In the action specification you can expand environment variables, as shown in
|
||||
the examples above. In addition to regular environment variables, there are
|
||||
some special variables, documented below:
|
||||
|
||||
@@ -126,12 +126,11 @@ lines. The various available criteria are:
|
||||
|
||||
.. _launch_actions:
|
||||
|
||||
Scripting the opening of files with kitty
|
||||
Scripting the opening of files with kitty on macOS
|
||||
-------------------------------------------------------
|
||||
|
||||
On macOS you can use :guilabel:`Open With` in Finder or drag and drop files and
|
||||
URLs onto the kitty dock icon to open them with kitty. Similarly on Linux, you
|
||||
can associate certain files types to open in kitty. The default actions are:
|
||||
URLs onto the kitty dock icon to open them with kitty. The default actions are:
|
||||
|
||||
* Open text files in your editor and images using the icat kitten.
|
||||
* Run shell scripts in a shell
|
||||
|
||||
@@ -33,9 +33,6 @@ frames-per-second. Press :sc:`edit_config_file` in kitty to open its fully
|
||||
commented sample config file in your text editor. For details see the
|
||||
:doc:`configuration docs <conf>`.
|
||||
|
||||
You can quickly browse all available mappable actions by pressing
|
||||
:sc:`command_palette`, see :doc:`kittens/command-palette` for details.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
@@ -99,16 +96,12 @@ used to create programs that leverage kitty's powerful features, for example,
|
||||
You can :doc:`create your own kittens to scratch your own itches
|
||||
<kittens/custom>`.
|
||||
|
||||
For a list of all the builtin kittens, run ``kitten`` in kitty, or to browse
|
||||
some of the more prominent ones, see :ref:`see here <kittens>`.
|
||||
For a list of all the builtin kittens, :ref:`see here <kittens>`.
|
||||
|
||||
Additionally, you can use the :ref:`watchers <Watchers>` framework
|
||||
to create Python scripts that run in response to various events such as windows
|
||||
being resized, closing, having their titles changed, etc.
|
||||
|
||||
Finally, there is remote control which allows you to control kitty from
|
||||
anywhere, even across a network! See below for more about remote control.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
@@ -131,14 +124,88 @@ started.
|
||||
remote-control
|
||||
|
||||
|
||||
Sessions
|
||||
.. _sessions:
|
||||
|
||||
Startup Sessions
|
||||
------------------
|
||||
|
||||
You can control the :term:`tabs <tab>`, :term:`kitty window <window>` layout,
|
||||
working directory, startup programs, etc. by creating a *session* file and using
|
||||
the :option:`kitty --session` command line flag or the :opt:`startup_session`
|
||||
option in :file:`kitty.conf`. You can also easily switch between sessions with
|
||||
a keypress. See :doc:`sessions` for details.
|
||||
option in :file:`kitty.conf`. An example, showing all available commands:
|
||||
|
||||
.. code-block:: session
|
||||
|
||||
# Set the layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for windows in the current tab
|
||||
cd ~
|
||||
# Create a window and run the specified command in it
|
||||
launch zsh
|
||||
# Create a window with some environment variables set and run vim in it
|
||||
launch --env FOO=BAR vim
|
||||
# Set the title for the next window
|
||||
launch --title "Chat with x" irssi --profile x
|
||||
# Run a short lived command and see its output
|
||||
launch --hold message-of-the-day
|
||||
|
||||
# Create a new tab
|
||||
# The part after new_tab is the optional tab title which will be displayed in
|
||||
# the tab bar, if omitted, the title of the active window will be used instead.
|
||||
new_tab my tab
|
||||
cd ~/somewhere
|
||||
# Set the layouts allowed in this tab
|
||||
enabled_layouts tall,stack
|
||||
# Set the current layout
|
||||
layout stack
|
||||
launch zsh
|
||||
|
||||
# Create a new OS window
|
||||
# Any definitions specified before the first new_os_window will apply to first OS window.
|
||||
new_os_window
|
||||
# Set new window size to 80x24 cells
|
||||
os_window_size 80c 24c
|
||||
# Set the --class for the new OS window
|
||||
os_window_class mywindow
|
||||
# Set the --name for the new OS window
|
||||
os_window_name myname
|
||||
# Change the OS window state to normal, fullscreen, maximized or minimized
|
||||
os_window_state normal
|
||||
launch sh
|
||||
# Resize the current window (see the resize_window action for details)
|
||||
resize_window wider 2
|
||||
# Make the current window the active (focused) window in its tab
|
||||
focus
|
||||
# Make the current OS Window the globally active window (not supported on Wayland)
|
||||
focus_os_window
|
||||
launch emacs
|
||||
|
||||
# Create a complex layout using multiple splits. Creates two columns of
|
||||
# windows with two windows in each column. The windows in the first column are
|
||||
# split 50:50. In the second column the windows are not evenly split.
|
||||
new_tab complex tab
|
||||
layout splits
|
||||
# First window, set a user variable on it so we can focus it later
|
||||
launch --var window=first
|
||||
# Create the second column by splitting the first window vertically
|
||||
launch --location=vsplit
|
||||
# Create the third window in the second column by splitting the second window horizontally
|
||||
# Make it take 40% of the height instead of 50%
|
||||
launch --location=hsplit --bias=40
|
||||
# Go back to focusing the first window, so that we can split it
|
||||
focus_matching_window var:window=first
|
||||
# Create the final window in the first column
|
||||
launch --location=hsplit
|
||||
|
||||
|
||||
.. note::
|
||||
The :doc:`launch <launch>` command when used in a session file cannot create
|
||||
new OS windows, or tabs.
|
||||
|
||||
.. note::
|
||||
Environment variables of the form :code:`${NAME}` or :code:`$NAME` are
|
||||
expanded in the session file, except in the *arguments* (not options) to the
|
||||
launch command.
|
||||
|
||||
|
||||
Creating tabs/windows
|
||||
@@ -181,13 +248,6 @@ You can also customize what happens when clicking on :term:`hyperlinks` in
|
||||
kitty, having it open files in your editor, download remote files, open things
|
||||
in your browser, etc. For details, see :doc:`here <open_actions>`.
|
||||
|
||||
Additionally, various bits of the kitty UI itself work with the mouse. You can
|
||||
drag and drop tabs in the tab bar to re-order them or move them from one OS
|
||||
Window to another, or even pop them out into a new OS Window.
|
||||
You can drag window borders to resize windows. You can double click on empty regions
|
||||
of the tab bar to create new tabs or double click on an existing tab to rename
|
||||
it.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
@@ -211,10 +271,9 @@ The scrollback buffer
|
||||
-----------------------
|
||||
|
||||
|kitty| supports scrolling back to view history, just like most terminals. You
|
||||
can use either keyboard shortcuts or the mouse scroll wheel to do so. |kitty|
|
||||
displays an interactive :opt:`scrollbar` along the right edge
|
||||
of the window that shows your current position in the scrollback. You can click
|
||||
and drag the scrollbar to quickly navigate through the history.
|
||||
can use either keyboard shortcuts or the mouse scroll wheel to do so. While
|
||||
you are browsing the scrollback a :opt:`small indicator <scrollback_indicator_opacity>`
|
||||
is displayed along the right edge of the window to show how far back you are.
|
||||
|
||||
However, |kitty| has an extra, neat feature. Sometimes you need to explore the scrollback
|
||||
buffer in more detail, maybe search for some text or refer to it side-by-side
|
||||
@@ -233,7 +292,7 @@ arbitrary, command running in a new :term:`window`, :term:`tab` or
|
||||
Would open the scrollback buffer in a new :term:`window` when you press the
|
||||
:kbd:`F1` key. See :sc:`show_scrollback <show_scrollback>` for details.
|
||||
|
||||
If you want to use it with an editor such as :program:`nvim` to get more powerful
|
||||
If you want to use it with an editor such as :program:`vim` to get more powerful
|
||||
features, see for example, `kitty-scrollback.nvim
|
||||
<https://github.com/mikesmithgh/kitty-scrollback.nvim>`__ or `kitty-grab <https://github.com/yurikhan/kitty_grab>`__
|
||||
or see more tips for using various editor programs, in :iss:`this thread <719>`.
|
||||
|
||||
@@ -101,7 +101,7 @@ ASCII only text.
|
||||
|
||||
foot, iterm2 and Terminal.app are left out as they do not run under X11.
|
||||
Alacritty+tmux is included just to show the effect of putting a terminal
|
||||
multiplexer into the mix (halving throughput) and because alacritty isn't
|
||||
multiplexer into the mix (halving throughput) and because alacritty isnt
|
||||
remotely comparable to any of the other terminals feature wise without tmux.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -28,8 +28,6 @@ please do so by opening issues in the `GitHub bug tracker
|
||||
graphics-protocol
|
||||
keyboard-protocol
|
||||
text-sizing-protocol
|
||||
dnd-protocol
|
||||
multiple-cursors-protocol
|
||||
file-transfer-protocol
|
||||
desktop-notifications
|
||||
pointer-shapes
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
.. only:: not man
|
||||
|
||||
.. sidebar::
|
||||
|
||||
.. only:: not man
|
||||
.. sidebar::
|
||||
|
||||
**Screenshots**
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ Now, using this password, you can, in scripts run the command::
|
||||
Any script with access to the password can now change colors in kitty using
|
||||
remote control, but only that and nothing else. You can even supply the
|
||||
password via the :envvar:`KITTY_RC_PASSWORD` environment variable, or the
|
||||
file :file:`~/.config/kitty/rc-pass` to avoid having to type it repeatedly.
|
||||
file :file:`~/.config/kitty/rc-password` to avoid having to type it repeatedly.
|
||||
See :option:`kitten @ --password-file` and :option:`kitten @ --password-env`.
|
||||
|
||||
The :opt:`remote_control_password` can be specified multiple times to create
|
||||
@@ -262,12 +262,6 @@ as shown below:
|
||||
return True
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
The payloads for the different remote control commands are documented in the
|
||||
:doc:`remote control protocol specification <rc_protocol>`.
|
||||
|
||||
|
||||
.. _rc_mapping:
|
||||
|
||||
Mapping key presses to remote control commands
|
||||
@@ -298,8 +292,7 @@ control commands as you like and process their output.
|
||||
:ac:`launch` command with ``--type=background --allow-remote-control``.
|
||||
For more advanced usage, including fine grained permissions, setting
|
||||
env vars, command line interpolation, passing data to STDIN, etc.
|
||||
the :doc:`launch <launch>` command should be used. Relative paths to scripts
|
||||
are interpreted with respect to the kitty config directory.
|
||||
the :doc:`launch <launch>` command should be used.
|
||||
|
||||
.. note:: You do not need :opt:`allow_remote_control` to use these mappings,
|
||||
as they are not actual remote programs, but are simply a way to reuse the
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# sphinx-inline-tabs breaks with sphinx >= 9
|
||||
sphinx <= 8.2.3
|
||||
sphinx
|
||||
furo
|
||||
sphinx-copybutton
|
||||
sphinxext-opengraph
|
||||
sphinx-inline-tabs
|
||||
sphinx-autobuild
|
||||
matplotlib
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 94 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 110 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 304 KiB After Width: | Height: | Size: 460 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 290 KiB After Width: | Height: | Size: 2.7 MiB |
@@ -1,377 +0,0 @@
|
||||
.. _sessions:
|
||||
|
||||
Sessions
|
||||
=============
|
||||
|
||||
kitty has robust support for sessions. A session is basically a simple text
|
||||
file where you can define kitty windows, tabs and what programs to run in them
|
||||
as well as how to layout the windows. kitty also supports actions to easily
|
||||
:ac:`create and switch between existing sessions <goto_session>`, so that you
|
||||
can move seamlessly from working on one project to another with a couple of keystrokes.
|
||||
|
||||
Let's see a quick example to get a feel of how easy it is to create sessions. First,
|
||||
a session file to develop a project:
|
||||
|
||||
.. code-block:: session
|
||||
|
||||
# Set the layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for windows in the current tab
|
||||
cd ~/path/to/myproject
|
||||
# Create the "main" window and run an editor in it to edit the project files
|
||||
launch --title "Edit My Project" /usr/bin/nvim
|
||||
# Create a side window to run a shell to build or test project
|
||||
launch --title "Build My Project"
|
||||
# Create another side window to keep an eye on some useful log file
|
||||
launch --title "Log for my project" /usr/bin/tail -f /path/to/project/log/file
|
||||
|
||||
Save this file as :file:`~/path/to/myproject/launch.kitty-session`. Now when
|
||||
you want to work on the project, simply run:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kitty --session ~/path/to/myproject/launch.kitty-session
|
||||
|
||||
You can also set the session in :file:`kitty.conf` via :opt:`startup_session`.
|
||||
|
||||
Thus, it is very easy to create sessions and work on projects. To learn how to
|
||||
create more complex sessions, see :ref:`complex_sessions`.
|
||||
|
||||
|
||||
.. _goto_session:
|
||||
|
||||
Creating/Switching to sessions with a keypress
|
||||
------------------------------------------------
|
||||
|
||||
If you like to manage multiple sessions within a single terminal and
|
||||
easily swap between them, kitty has you covered. You can use the
|
||||
:ac:`goto_session` action in kitty.conf, like this:
|
||||
|
||||
.. code-block:: conf
|
||||
|
||||
# Press F7 and then c to jump to the "cool" project
|
||||
map f7>c goto_session ~/path/to/cool/cool.kitty-session
|
||||
# Press F7 and then h to jump to the "hot" project
|
||||
map f7>h goto_session ~/path/to/hot/hot.kitty-session
|
||||
# Browse and select from the list of known projects defined via goto_session commands
|
||||
map f7>/ goto_session
|
||||
# Browse and select from the list of active projects defined via goto_session commands
|
||||
map f7>/ goto_session --active-only [=no]
|
||||
# Same as above, but the sessions are listed alphabetically instead of by most recent
|
||||
map f7>/ goto_session --sort-by=alphabetical
|
||||
# Browse session files inside a directory and pick one
|
||||
map f7>p goto_session ~/.local/share/kitty/sessions
|
||||
# Go to the previously active session (larger negative numbers jump further back in history)
|
||||
map f7>- goto_session -1
|
||||
|
||||
In this manner you can define as many projects/sessions as you like and easily
|
||||
switch between them with a keypress.
|
||||
|
||||
When a directory path is supplied to :ac:`goto_session`, kitty scans it for
|
||||
files ending in ``.kitty-session``, ``.kitty_session`` or ``.session`` and
|
||||
presents an interactive list. The ``--sort-by`` option controls the ordering of that list just like it does
|
||||
for globally known sessions.
|
||||
|
||||
You can also close sessions using the :ac:`close_session` action, which closes
|
||||
all windows in the session with a single keypress.
|
||||
|
||||
|
||||
Displaying the currently active session name
|
||||
----------------------------------------------
|
||||
|
||||
You can display the name of the currently active session file in the kitty tab
|
||||
bar using :opt:`tab_title_template`. For example, using the value::
|
||||
|
||||
{session_name} {title}
|
||||
|
||||
will show you the name of the session file the current tab was loaded from, as
|
||||
well as the normal tab title. Or alternatively, you can set the tab title
|
||||
directly to a project name in the session file itself when creating the tab,
|
||||
like this::
|
||||
|
||||
new_tab My Project Name
|
||||
|
||||
.. _complex_sessions:
|
||||
|
||||
More complex sessions
|
||||
-------------------------
|
||||
|
||||
If you want to create more complex sessions, with sophisticated layouts, such
|
||||
as :ref:`splits_layout`, the easiest way is to set up the state you want to
|
||||
save manually by first starting kitty like this:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kitty -o 'map f1 save_as_session --use-foreground-process --relocatable'
|
||||
|
||||
Now create whatever splits and tabs you need and start whatever programs such
|
||||
as editors, REPLs, debuggers, etc. you want to start in each of them. Once
|
||||
kitty is the way you want it, press the :kbd:`F1` key, and you will be prompted
|
||||
for a path at which to save the session file. Specify the path and the session
|
||||
will be saved there with the exact setup you created. The saved file will even
|
||||
be opened in your editor for you to review, automatically.
|
||||
|
||||
.. tip::
|
||||
If you want session files to be saved to a specific directory regardless of
|
||||
your current working directory, use the ``--base-dir`` option. For example::
|
||||
|
||||
map f7>s save_as_session --use-foreground-process --base-dir ~/.local/share/kitty/sessions
|
||||
|
||||
This is particularly useful when kitty is launched from system-wide shortcuts
|
||||
where the working directory might not be your home directory. Note that
|
||||
``--relocatable`` is typically not used with ``--base-dir``, since relocatable
|
||||
is meant for session files that are co-located with their project directories.
|
||||
|
||||
If instead, you want to create these by hand, see the example below which shows
|
||||
all the major keywords you can use in kitty session files:
|
||||
|
||||
.. code-block:: session
|
||||
|
||||
# Set the layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for windows in the current tab. Relative paths
|
||||
# are resolved with respect to the location of this session file.
|
||||
cd ~
|
||||
# Create a window and run the specified command in it
|
||||
launch zsh
|
||||
# Create a window with some environment variables set and run vim in it
|
||||
launch --env FOO=BAR vim
|
||||
# Set the title for the next window
|
||||
launch --title "Chat with x" irssi --profile x
|
||||
# Run a short lived command and see its output
|
||||
launch --hold message-of-the-day
|
||||
|
||||
# Create a new tab
|
||||
# The part after new_tab is the optional tab title which will be displayed in
|
||||
# the tab bar, if omitted, the title of the active window will be used instead.
|
||||
new_tab my tab
|
||||
cd somewhere
|
||||
# Set the layouts allowed in this tab
|
||||
enabled_layouts tall,stack
|
||||
# Set the current layout
|
||||
layout stack
|
||||
launch zsh
|
||||
|
||||
# Create a new OS window
|
||||
# Any definitions specified before the first new_os_window will apply to first OS window.
|
||||
new_os_window
|
||||
# Set new window size to 80x24 cells
|
||||
os_window_size 80c 24c
|
||||
# Set the --title for the new OS window
|
||||
os_window_title my fancy os window
|
||||
# Set the --class for the new OS window
|
||||
os_window_class mywindow
|
||||
# Set the --name for the new OS window
|
||||
os_window_name myname
|
||||
# Change the OS window state to normal, fullscreen, maximized or minimized
|
||||
os_window_state normal
|
||||
launch sh
|
||||
# Resize the current window (see the resize_window action for details)
|
||||
resize_window wider 2
|
||||
# Make the current window the active (focused) window in its tab
|
||||
focus
|
||||
# Make the current OS Window the globally active window
|
||||
focus_os_window
|
||||
launch emacs
|
||||
|
||||
# Create another tab
|
||||
new_tab logs
|
||||
launch tail -f /var/log/syslog
|
||||
|
||||
# Focus the first tab (index 0) when the session loads
|
||||
# You can also use a match expression like: focus_tab title:logs
|
||||
focus_tab 0
|
||||
|
||||
# Create a complex layout using multiple splits. Creates two columns of
|
||||
# windows with two windows in each column. The windows in the first column are
|
||||
# split 50:50. In the second column the windows are not evenly split.
|
||||
new_tab complex tab
|
||||
layout splits
|
||||
# First window, set a user variable on it so we can focus it later
|
||||
launch --var window=first
|
||||
# Create the second column by splitting the first window vertically
|
||||
launch --location=vsplit
|
||||
# Create the third window in the second column by splitting the second window horizontally
|
||||
# Make it take 40% of the height instead of 50%
|
||||
launch --location=hsplit --bias=40
|
||||
# Go back to focusing the first window, so that we can split it
|
||||
focus_matching_window var:window=first
|
||||
# Create the final window in the first column
|
||||
launch --location=hsplit
|
||||
|
||||
|
||||
.. note::
|
||||
The :doc:`launch <launch>` command when used in a session file cannot create
|
||||
new OS windows, or tabs.
|
||||
|
||||
.. note::
|
||||
Environment variables of the form :code:`${NAME}` or :code:`$NAME` are
|
||||
expanded in the session file, except in the *arguments* (not options) to the
|
||||
launch command. For example:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
launch --cwd=$THIS_IS_EXPANDED some-program $THIS_IS_NOT_EXPANDED
|
||||
|
||||
|
||||
Making newly created windows join an existing session
|
||||
---------------------------------------------------------
|
||||
|
||||
Normally, after activating a session, if you create new windows/tabs
|
||||
they don't belong to the session. If you would prefer to have them belong
|
||||
to the currently active session, you can use the :ac:`new_window_with_cwd`
|
||||
and :ac:`new_tab_with_cwd` actions instead, like this::
|
||||
|
||||
map kitty_mod+enter new_window_with_cwd
|
||||
map kitty_mod+t new_tab_with_cwd
|
||||
map kitty_mod+n new_os_window_with_cwd
|
||||
|
||||
This will cause newly created windows and tabs to belong to the currently active
|
||||
session, if any. Note that adding a window to a session in this way is
|
||||
temporary, it does not edit the session file. If you wish to update the
|
||||
session file of the currently active session, you can use the following
|
||||
mapping for it::
|
||||
|
||||
map f5 save_as_session --relocatable --use-foreground-process --match=session:. .
|
||||
|
||||
The two can be combined, using the :ac:`combine` action.
|
||||
For even more control of what session a window is added to use
|
||||
the :doc:`launch <launch>` command with the :option:`launch --add-to-session`
|
||||
flag.
|
||||
|
||||
|
||||
Sessions with remote connections
|
||||
-------------------------------------
|
||||
|
||||
If you use the :doc:`ssh kitten </kittens/ssh>` to connect to remote computers,
|
||||
:ac:`save_as_session` is smart enough to save the ssh kitten invocation to your
|
||||
session file, preserving the remote working directory and even the currently
|
||||
running program on the remote host! Try it, run kitty with::
|
||||
|
||||
kitty -o 'map f1 save_as_session --use-foreground-process --relocatable' --session <(echo "layout vertical\nlaunch\nlaunch")
|
||||
|
||||
Now in both windows, run::
|
||||
|
||||
kitten ssh localhost
|
||||
|
||||
To connect them both to a remote computer (replace ``localhost`` with another
|
||||
computer if you like). In one window change the directory to /tmp and in the
|
||||
other start some program. Then press :kbd:`F1` to save the session file.
|
||||
When you run the session file in another kitty instance you will see both
|
||||
windows re-created, as expected with the correct working directories and
|
||||
running programs.
|
||||
|
||||
Managing multi tab sessions in a single OS Window
|
||||
----------------------------------------------------
|
||||
|
||||
The natural way to organise sessions in kitty is one per :term:`os_window`.
|
||||
However, if you prefer to manage multiple sessions in a single OS Window, you
|
||||
can configure the kitty tab bar to only show tabs that belong to the currently
|
||||
active session. To do so, use :opt:`tab_bar_filter` in :file:`kitty.conf` set::
|
||||
|
||||
tab_bar_filter session:~ or session:^$
|
||||
|
||||
This will restrict the tab bar to only showing tabs from the currently active
|
||||
session as well tabs that do not belong to any session. Furthermore, when you
|
||||
are in a window or tab that does not belong to any session, the tab bar will
|
||||
show the tabs from the most recent active session, to maintain context.
|
||||
|
||||
Keyword reference
|
||||
---------------------
|
||||
|
||||
Below is the list of all supported keywords in session files along with
|
||||
documentation for them.
|
||||
|
||||
``cd [path]``
|
||||
Change the working directory for all windows in the current tab to
|
||||
``path``. Relative paths are resolved with respect to the directory
|
||||
containing the session file.
|
||||
|
||||
``focus``
|
||||
Give keyboard focus to the window created by the previous launch command
|
||||
|
||||
``focus_matching_window``
|
||||
Give keyboard focus to window that matches the specified expression. See
|
||||
:ref:`search_syntax` for the syntax for matching expressions.
|
||||
|
||||
``focus_os_window``
|
||||
Give keyboard focus to the current OS Window. This is guaranteed to work
|
||||
only is some other OS Window in the current kitty process has focus,
|
||||
otherwise the window manager might block changing focus to prevent *focus
|
||||
stealing*.
|
||||
|
||||
``focus_tab [tab specifier]``
|
||||
Set which tab should be active (focused) in the current OS Window. The tab
|
||||
specifier can be either a plain number (treated as a 0-based index) or a
|
||||
match expression. For example, ``focus_tab 0`` will focus the first tab,
|
||||
``focus_tab 1`` the second tab, and ``focus_tab title:logs`` will focus the
|
||||
tab whose title matches "logs". See :ref:`search_syntax` for the full syntax
|
||||
of match expressions. This is useful for session files that create multiple
|
||||
tabs and want to ensure a specific tab is active when the session is loaded.
|
||||
|
||||
``enabled_layouts comma separated list of layout names``
|
||||
Set the layouts allowed in the current tab. Same syntax as
|
||||
:opt:`enabled_layouts`.
|
||||
|
||||
``launch``
|
||||
Create a new window running the specified command or the default shell if
|
||||
no command is specified. See :doc:`launch` for details. Note that creating
|
||||
tabs and OS Windows using launch is not supported in session files, use the
|
||||
dedicated keywords for these.
|
||||
|
||||
``layout name``
|
||||
Set the layout for the current tab to the specified layout, including any
|
||||
specified options, see :doc:`layouts` for the available layouts and
|
||||
options.
|
||||
|
||||
``new_os_window``
|
||||
Create a new OS Window. Any OS window related keywords specified before the
|
||||
first ``new_os_window`` will apply to the first OS Window.
|
||||
|
||||
``new_tab [tab title]``
|
||||
Create a new tab with the specified title. If no title is specified, the
|
||||
title behaves just as for a regular tab in kitty.
|
||||
|
||||
``os_window_title``
|
||||
Set the title for the current OS Window. The OS Window will then always
|
||||
have this title, it will not change based on the title of the currently active
|
||||
window inside the OS Window.
|
||||
|
||||
``os_window_class``
|
||||
Set the class part of WM_CLASS or Wayland Application Id for the current OS Window
|
||||
|
||||
``os_window_name``
|
||||
Set the name part of WM_CLASS or Wayland Window tag for the current OS Window
|
||||
|
||||
``os_window_size``
|
||||
Set the size of the current OS Window, can be specified in pixels or cells.
|
||||
For example: 80c 24c is a window of width 80 cells by 24 cells.
|
||||
|
||||
``os_window_state``
|
||||
Set the state of the current OS Window, can be: ``normal``, ``fullscreen``, ``maximized`` or ``minimized``
|
||||
|
||||
``resize_window``
|
||||
Resize the current window. See the :ac:`resize_window` action for details.
|
||||
For example: resize_window wider 2
|
||||
|
||||
``set_layout_state``
|
||||
This keyword is only used in session files generated by the
|
||||
:ac:`save_as_session` action, it's syntax is undocumented and for internal
|
||||
use only.
|
||||
|
||||
``title``
|
||||
Set the title for the next window. Deprecated, use ``launch --title``
|
||||
instead.
|
||||
|
||||
|
||||
.. _save_as_session:
|
||||
|
||||
The save_as_session action
|
||||
------------------------------
|
||||
|
||||
This action can be mapped to a key press in :file:`kitty.conf`. It will save
|
||||
the currently open OS Windows, tabs, windows, running programs, working
|
||||
directories, etc. into a session file. It is a convenient way to
|
||||
:ref:`complex_sessions`. The options this action takes are documented below.
|
||||
|
||||
.. include:: generated/save-as-session.rst
|
||||
@@ -266,7 +266,7 @@ over SSH when using :doc:`kittens/ssh`.
|
||||
|
||||
The :command:`clone-in-kitty` command takes almost all the same arguments as the
|
||||
:doc:`launch <launch>` command, so you can open a new tab instead or a new OS
|
||||
window, etc. Arguments of launch that that don't
|
||||
window, etc. Arguments of launch that can cause code execution or that don't
|
||||
make sense when cloning are ignored. Most prominently, the following options are
|
||||
ignored: :option:`--allow-remote-control <launch --allow-remote-control>`,
|
||||
:option:`--copy-cmdline <launch --copy-cmdline>`, :option:`--copy-env <launch
|
||||
@@ -313,9 +313,7 @@ window, etc. Not all arguments are supported, see the discussion in the
|
||||
:ref:`clone_shell` section above.
|
||||
|
||||
In order to avoid remote code execution, kitty will only execute the configured
|
||||
editor and pass the file path to edit to it and it will strip all environment
|
||||
variables from the :command:`edit-in-kitty` command line. Additionally, parsing
|
||||
of colors is more limited, reading colors from config files is not allowed.
|
||||
editor and pass the file path to edit to it.
|
||||
|
||||
.. note:: To edit files using sudo the best method is to set the
|
||||
:code:`SUDO_EDITOR` environment variable to ``kitten edit-in-kitty`` and
|
||||
@@ -470,21 +468,13 @@ to control its behavior, separated by semi-colons. They are:
|
||||
this tells kitty that the secondary (PS2) prompt is starting at the
|
||||
current line.
|
||||
|
||||
``click_events=1|2``
|
||||
``click_events=1``
|
||||
this tells kitty that the shell is capable of handling
|
||||
mouse click events. kitty will thus send a click event to the shell when
|
||||
the user clicks somewhere in the prompt. The shell can then move the cursor
|
||||
to that position or perform some other appropriate action. Without this,
|
||||
kitty will instead generate a number of fake key events to move the cursor
|
||||
to the clicked location, which is not fully robust. A value of ``1`` will
|
||||
cause the click events to have absolute y co-ordinates, a value of ``2``
|
||||
will cause them to have y-coordinates relative to the top line of the
|
||||
current prompt. In relative mode, y is zero for cells on the top line of
|
||||
the current prompt. The current prompt here is either the secondary (PS2) or
|
||||
primary prompt. If the secondary prompt is on the same line or above the
|
||||
mouse position, then the reported y will be with respect to that, otherwise
|
||||
with respect to the primary prompt. The click event is encoded in the SGR
|
||||
encoding from xterm.
|
||||
to the clicked location, which is not fully robust.
|
||||
|
||||
kitty also optionally supports sending the cmdline going to be executed with ``<OSC>133;C`` as:
|
||||
|
||||
|
||||
@@ -77,9 +77,9 @@ There are only a handful of metadata keys, defined in the table below:
|
||||
|
||||
"d", "Integer from 0 to 15", "0", "The denominator for the fractional scale. Must be ``> n`` when non-zero."
|
||||
|
||||
"v", "Integer from 0 to 2", "0", "The vertical alignment to use for fractionally scaled text (n < d). ``0`` - top, ``1`` - bottom, ``2`` - centered"
|
||||
"v", "Integer from 0 to 2", "0", "The vertical alignment to use for fractionally scaled text. ``0`` - top, ``1`` - bottom, ``2`` - centered"
|
||||
|
||||
"h", "Integer from 0 to 2", "0", "The horizontal alignment to use for fractionally scaled text (n < d). ``0`` - left, ``1`` - right, ``2`` - centered"
|
||||
"h", "Integer from 0 to 2", "0", "The horizontal alignment to use for fractionally scaled text. ``0`` - left, ``1`` - right, ``2`` - centered"
|
||||
|
||||
|
||||
How it works
|
||||
@@ -126,7 +126,7 @@ and trailers)::
|
||||
|
||||
Note, in particular, how the last character, the cat emoji, ``🐈`` has ``w=2``.
|
||||
In practice client applications can assume that terminal emulators get the
|
||||
width of all ASCII code points correct and use the ``w=0`` form for efficient
|
||||
width of all ASCII characters correct and use the ``w=0`` form for efficient
|
||||
transmission, so that the above becomes::
|
||||
|
||||
cool- w=2:🐈
|
||||
@@ -160,11 +160,8 @@ The fractional scale **does not** affect the number of cells the text occupies,
|
||||
instead, it just adjusts the rendered font size within those cells.
|
||||
The fraction is specified using an integer numerator and denominator (``n`` and
|
||||
``d``). In addition, by using the ``v`` key one can vertically align the
|
||||
fractionally scaled render area at top, bottom or middle. Similarly, the ``h`` key
|
||||
does horizontal alignment — left, right or centered. Note that alignment
|
||||
here is not actual text alignment, it refers to how the fractionally scaled
|
||||
render area fits inside the full render area of size ``s * w`` by ``s`` cells.
|
||||
Thus, alignment only applies when ``n < d``.
|
||||
fractionally scaled text at top, bottom or middle. Similarly, the ``h`` key
|
||||
does horizontal alignment — left, right or centered.
|
||||
|
||||
When using fractional scaling one often wants to fit more than a single
|
||||
character per cell. To accommodate that, there is the ``w`` key. This specifies
|
||||
@@ -258,17 +255,17 @@ Detecting if the terminal supports this protocol
|
||||
-----------------------------------------------------
|
||||
|
||||
To detect support for this protocol use the `CPR (Cursor Position Report)
|
||||
<https://vt100.net/docs/vt510-rm/CPR.html>`__ escape code. Send a ``CR``
|
||||
(carriage return) followed by ``CPR`` followed by ``\e]_text_size_code;w=2; \a``
|
||||
which will draw a space character in two cells, followed by another ``CPR``.
|
||||
Then send ``\e]_text_size_code;s=2; \a`` which will draw a space in a ``2 by 2``
|
||||
block of cells, followed by another ``CPR``.
|
||||
<https://vt100.net/docs/vt510-rm/CPR.html>`__ escape code. Send a ``CPR``
|
||||
followed by ``\e]_text_size_code;w=2; \a`` which will draw a space character in
|
||||
two cells, followed by another ``CPR``. Then send ``\e]_text_size_code;s=2; \a``
|
||||
which will draw a space in a ``2 by 2`` block of cells, followed by another
|
||||
``CPR``.
|
||||
|
||||
Then wait for the three responses from the terminal to the three CPR queries.
|
||||
If the cursor position in the three responses is the same, the terminal does
|
||||
not support this protocol at all, if the second response has the cursor
|
||||
moved by two cells, then the width part is supported and if the third response has the
|
||||
cursor moved by another two cells, then the scale part is supported.
|
||||
not support this protocol at all, if the second response has a different cursor
|
||||
position then the width part is supported and if the third response has yet
|
||||
another position, the scale part is supported.
|
||||
|
||||
|
||||
Interaction with other terminal controls
|
||||
@@ -360,11 +357,11 @@ The algorithm for splitting text into cells
|
||||
<https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt>`__.
|
||||
|
||||
.. warning::
|
||||
This algorithm is under public discussion in :iss:`8533`. If serious issues
|
||||
are brought to light in that discussion, there may be small changes to the
|
||||
algorithm to address them. Additionally, in the future if the Unicode standard
|
||||
changes in ways that affect this algorithm, it will be updated. Currently the
|
||||
algorithm is based on Unicode version 16.
|
||||
This algorithm is under public discussion in :iss:`8533`. Until that issue
|
||||
is closed, it is subject to change based on feedback from the community.
|
||||
Additionally, in the future if the Unicode standard changes in ways that
|
||||
affect this algorithm, it will be updated. Currently the algorithm is based
|
||||
on Unicode version 16.
|
||||
|
||||
Here, we specify how a terminal must split up text into cells, where a cell is
|
||||
a width one unit in the character grid the terminal displays.
|
||||
@@ -372,24 +369,16 @@ a width one unit in the character grid the terminal displays.
|
||||
The basis for the algorithm is the
|
||||
`Grapheme segmentation algorithm <https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries>`__
|
||||
from the Unicode standard. However, that algorithm alone is insufficient to
|
||||
fully specify text handling for terminals. The full algorithm is specified below.
|
||||
fully specify text handling for terminals. The full algorithm is specified
|
||||
below. When a terminal receives a Unicode character:
|
||||
|
||||
A terminal using this algorithm must decode the bytes they receive
|
||||
into Unicode scalar values (i.e., code points except surrogates) using UTF-8.
|
||||
When it encounters any UTF-8 ill-formed subsequences,
|
||||
it must be replace each
|
||||
`maximal subpart of the ill-formed subsequence <https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G66453>`__
|
||||
with a :code:`U+FFFD REPLACEMENT CHARACTER` (<28>).
|
||||
#. First check if the character is an ASCII control code, and handle it
|
||||
appropriately. ASCII control codes are the characters less than 32 and the
|
||||
character 127 (DEL). The NUL character (0) must be discarded.
|
||||
|
||||
For each decoded code point:
|
||||
|
||||
#. First check if the code point is an ASCII control code, and handle it
|
||||
appropriately. ASCII control codes are the code points less than :code:`U+0032` and the
|
||||
code point :code:`U+0127 DEL`. The code point :code:`U+0000 NUL` must be discarded.
|
||||
|
||||
#. Next, check if the code point is *invalid*, and if it is, discard it
|
||||
and finish processing. Invalid code points are code points with Unicode category :code:`Cc or Cs`
|
||||
and 66 additional code points: :code:`[0xfdd0, 0xfdef]`, :code:`[0xfffe, 0x10ffff-1, 0x10000]`
|
||||
#. Next, check if the character is *invalid*, and if it is, discard it
|
||||
and finish processing. Invalid characters are characters with Unicode category :code:`Cc or Cs`
|
||||
and 66 additional characters: :code:`[0xfdd0, 0xfdef]`, :code:`[0xfffe, 0x10ffff-1, 0x10000]`
|
||||
and :code:`[0xffff, 0x10ffff, 0x10000]`.
|
||||
|
||||
#. Next, check if there is a previous cell before the
|
||||
@@ -398,31 +387,30 @@ For each decoded code point:
|
||||
the last cell of the previous line, provided there is no line break
|
||||
between the previous and current lines.
|
||||
|
||||
#. Next, calculate the width in cells of the received code point,
|
||||
which can be 0, 1, or 2 depending on the code point properties in
|
||||
#. Next, calculate the width in cells of the received
|
||||
character, which can be 0, 1, or 2 depending on the character properties in
|
||||
the Unicode standard.
|
||||
|
||||
#. If there is no previous cell and the code point's width is zero,
|
||||
the code point is discarded and its processing is finished.
|
||||
#. If there is no previous cell and the character width is zero, the character
|
||||
is discarded and processing of the character is finished.
|
||||
|
||||
#. If there is a previous cell, the
|
||||
`Grapheme segmentation algorithm UAX29-C1-1 <https://www.unicode.org/reports/tr29/#C1-1>`__
|
||||
is used to determine if there is a grapheme boundary between the previous cell
|
||||
and the current code point.
|
||||
is used to determine if there is a grapheme boundary between the previous cell and the current character.
|
||||
|
||||
#. If there is no boundary, the current code point is added to the previous
|
||||
cell and processing of the code point is finished. See the :ref:`var_select`
|
||||
#. If there is no boundary the current character is added to the previous
|
||||
cell and processing of the character is finished. See the :ref:`var_select`
|
||||
section below for handling of Unicode Variation selectors.
|
||||
|
||||
#. If there is a boundary, but the width of the current code point is zero,
|
||||
#. If there is a boundary, but the width of the current character is zero
|
||||
it is added to the previous cell and processing is finished.
|
||||
|
||||
#. The code point is added to the current cell and the cursor is moved forward
|
||||
(right) by either 1 or 2 cells depending on the width of the code point.
|
||||
#. The character is added to the current cell and the cursor is moved forward
|
||||
(right) by either 1 or 2 cells depending on the width of the character.
|
||||
|
||||
|
||||
It remains to specify how to calculate the width in cells of a code point.
|
||||
To do this, code points are divided into various classes, as
|
||||
It remains to specify how to calculate the width in cells of a Unicode
|
||||
character. To do this, characters are divided into various classes, as
|
||||
described by the rules below, in order of decreasing priority:
|
||||
|
||||
.. note::
|
||||
@@ -430,50 +418,49 @@ described by the rules below, in order of decreasing priority:
|
||||
to :code:`stop` in increments of :code:`step`. When the step is not
|
||||
specified, it defaults to one.
|
||||
|
||||
#. *Regional indicators*: 26 code points starting at :code:`0x1F1E6`. These all
|
||||
#. *Regional indicators*: 26 characters starting at :code:`0x1F1E6`. These all
|
||||
have width 2
|
||||
|
||||
#. *Doublewidth*: Parse `EastAsianWidth.txt
|
||||
<https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt>`__ from
|
||||
the Unicode standard. All code points marked :code:`W` or :code:`F` have
|
||||
width two. All code points in the following ranges have width two *unless*
|
||||
the Unicode standard. All characters marked :code:`W` or :code:`F` have
|
||||
width two. All characters in the following ranges have width two *unless*
|
||||
they are marked as :code:`A` in :code:`EastAsianWidth.txt`: :code:`[0x3400,
|
||||
0x4DBF], [0x4E00, 0x9FFF], [0xF900, 0xFAFF], [0x20000, 0x2FFFD], [0x30000, 0x3FFFD]`
|
||||
|
||||
#. *Wide emoji*: Parse `emoji-sequences.txt
|
||||
<https://www.unicode.org/Public/emoji/latest/emoji-sequences.txt>`__ from
|
||||
the Unicode standard. All :code:`Basic_Emoji` have width two unless they are
|
||||
followed by :code:`FE0F` in the file. The leading codepoints in all
|
||||
followed by :code:`FE0F` in the file. The leading copdepoints in all
|
||||
:code:`RGI_Emoji_Modifier_Sequence` and :code:`RGI_Emoji_Tag_Sequence` have width two.
|
||||
All code points in :code:`RGI_Emoji_Flag_Sequence` have width two.
|
||||
All codepoints in :code:`RGI_Emoji_Flag_Sequence` have width two.
|
||||
|
||||
#. *Marks*: These are all zero width code points. They are code points with Unicode
|
||||
#. *Marks*: These are all zero width characters. They are characters with Unicode
|
||||
categories whose first letter is :code:`M` or :code:`S`. Additionally,
|
||||
code points with Unicode category: :code:`Cf`. Finally, they include
|
||||
all modifier code points from :code:`RGI_Emoji_Modifier_Sequence` in the
|
||||
characters with Unicode category: :code:`Cf`. Finally, they include
|
||||
all modifier codepoints from :code:`RGI_Emoji_Modifier_Sequence` in the
|
||||
*Wide emoji* rule above.
|
||||
|
||||
#. All remaining code points have a width of one cell.
|
||||
#. All remaining codepoints have a width of one cell.
|
||||
|
||||
.. _var_select:
|
||||
|
||||
Unicode variation selectors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are two code points (:code:`U+FE0E` and :code:`U+FE0F`) that can actually
|
||||
`alter the width of the previous code point <https://www.unicode.org/reports/tr11/#ED4>`__
|
||||
by changing their presentation between ``Emoji_Presentation`` and ``Text_Presentation``.
|
||||
When adding a code point to the previous cell these have to be handled specially.
|
||||
There are two codepoints (:code:`U+FE0E` and :code:`U+FE0F`) that can actually
|
||||
alter the width of the previous codepoint. When adding a codepoint to the
|
||||
previous cell these have to be handled specially.
|
||||
|
||||
``U+FE0E`` - Variation Selector 15
|
||||
When the previous cell has width two and the last code point in the previous
|
||||
cell is one of the ``Basic_Emoji`` code points from the *Wide emoji* rule above
|
||||
When the previous cell has width two and the last character in the previous
|
||||
cell is one of the ``Basic_Emoji`` codepoints from the *Wide emoji* rule above
|
||||
that is *not* followed by ``FEOF`` then the width of the previous cell is
|
||||
decreased to one.
|
||||
|
||||
``U+FE0F`` - Variation Selector 16
|
||||
When the previous cell has width one and the last code point in the previous
|
||||
cell is one of the ``Basic_Emoji`` code points from the *Wide emoji* rule above
|
||||
When the previous cell has width one and the last character in the previous
|
||||
cell is one of the ``Basic_Emoji`` codepoints from the *Wide emoji* rule above
|
||||
that is followed by ``FEOF`` then the width of the
|
||||
previous cell is increased to two.
|
||||
|
||||
@@ -486,34 +473,4 @@ cell wide but it is *not* moved back to the previous line.
|
||||
|
||||
To avoid this issue, it is recommended applications detect when ``U+FE0E`` is
|
||||
present and in such cases use the width part of the text sizing protocol
|
||||
to control rendering. Alternately, applications can segment text into graphemes
|
||||
and given a list of graphemes and their widths it is possible to write a simple
|
||||
function that will output them to the terminal so as to avoid this issue. Below
|
||||
is such a function in the Python language:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Grapheme:
|
||||
text: str
|
||||
width: int
|
||||
|
||||
def output_one_line(iterator_over_graphemes):
|
||||
' Output graphemes so that they affect exactly wcswidth cells only (works for >= 2 graphemes) '
|
||||
graphemes = tuple(iterator_over_graphemes)
|
||||
if not graphemes:
|
||||
return
|
||||
yield graphemes[0].text
|
||||
for i in range(1, len(graphemes)):
|
||||
g = graphemes[i]
|
||||
if g is graphemes[-1]:
|
||||
prev_g = graphemes[i-1]
|
||||
yield f'\x1b[{prev_g.width}D' # move cursor back
|
||||
yield g.text
|
||||
yield f'\x1b[{g.width}D' # move cursor back
|
||||
yield f'\x1b[{prev_g.width}@' # insert cells
|
||||
yield prev_g.text
|
||||
yield f'\x1b[{g.width}C' # move cursor forward
|
||||
|
||||
Then, using ``wcswidth()`` the application can split long text into lines of
|
||||
width no more than the screen width and use the above function to write each
|
||||
line to the terminal robustly.
|
||||
to control rendering.
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
Wide gamut color formats
|
||||
=========================
|
||||
|
||||
kitty supports modern wide gamut color formats for precise color specification.
|
||||
These formats can be used anywhere a color value is accepted in the configuration
|
||||
(foreground, background, color0-color255, etc.).
|
||||
|
||||
OKLCH Colors
|
||||
------------
|
||||
|
||||
OKLCH is a perceptually uniform color space, ideal for creating color themes.
|
||||
The format is::
|
||||
|
||||
foreground oklch(0.9 0.05 140)
|
||||
color1 oklch(0.7 0.25 25)
|
||||
|
||||
Parameters:
|
||||
|
||||
- **L** (Lightness): 0 to 1, where 0 is black and 1 is white
|
||||
- **C** (Chroma): 0 to approximately 0.4, represents color saturation
|
||||
- **H** (Hue): 0 to 360 degrees (0=red, 120=green, 240=blue)
|
||||
|
||||
Benefits:
|
||||
|
||||
- Perceptually uniform - equal changes produce equal perceived differences
|
||||
- Adjusting lightness preserves hue (unlike HSL)
|
||||
- Industry standard for modern color design
|
||||
|
||||
Example::
|
||||
|
||||
foreground oklch(0.9 0.05 140)
|
||||
color1 oklch(0.65 0.25 29) # Vibrant red-orange
|
||||
color2 oklch(0.65 0.25 142) # Vibrant green
|
||||
color3 oklch(0.70 0.19 90) # Warm yellow
|
||||
|
||||
CIE LAB Colors
|
||||
--------------
|
||||
|
||||
CIE LAB is a device-independent color space designed to approximate human vision.
|
||||
|
||||
The format is::
|
||||
|
||||
background lab(20 5 -10)
|
||||
color4 lab(50 0 -50)
|
||||
|
||||
Parameters:
|
||||
|
||||
- **L**: Lightness, 0 to 100 (0 = black, 100 = white)
|
||||
- **a**: Green (-) to red (+), typically -100 to +100
|
||||
- **b**: Blue (-) to yellow (+), typically -100 to +100
|
||||
|
||||
Example::
|
||||
|
||||
background lab(10 0 0) # Very dark neutral gray
|
||||
foreground lab(90 0 0) # Very light neutral gray
|
||||
color1 lab(50 60 40) # Red
|
||||
color4 lab(50 0 -50) # Blue
|
||||
|
||||
Gamut Mapping
|
||||
-------------
|
||||
|
||||
When you specify colors in OKLCH or CIE LAB formats that are outside the sRGB
|
||||
color gamut, kitty automatically converts them using the CSS Color Module Level 4
|
||||
gamut mapping algorithm:
|
||||
|
||||
- Preserves the original lightness and hue as much as possible
|
||||
- Reduces chroma (saturation) until the color fits within the displayable range
|
||||
- Uses perceptual color difference (deltaE OK) to minimize visible changes
|
||||
- Maximizes color saturation while staying in gamut
|
||||
|
||||
This ensures that wide gamut colors gracefully degrade on standard sRGB displays while
|
||||
taking full advantage of wide gamut displays when available. The mapping happens
|
||||
automatically - you don't need to do anything special.
|
||||
|
||||
For example, :code:`oklch(0.7 0.4 25)` might be too saturated for sRGB but will be
|
||||
automatically adjusted to fit while preserving the perceived hue and lightness.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
- `CSS Color Module Level 4 <https://www.w3.org/TR/css-color-4/>`_
|
||||
- `OKLCH Color Space <https://bottosson.github.io/posts/oklab/>`_
|
||||
@@ -8,9 +8,6 @@ import (
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
//go:embed logo/kitty.png
|
||||
var KittyLogoAsPNGData []byte
|
||||
|
||||
//go:embed kitty_tests/GraphemeBreakTest.json
|
||||
var grapheme_break_test_data []byte
|
||||
|
||||
|
||||
@@ -34,9 +34,6 @@ def main(args: list[str]=sys.argv) -> None:
|
||||
elif which == 'cursors':
|
||||
from gen.cursors import main
|
||||
main(args)
|
||||
elif which == 'color-names':
|
||||
from gen.color_names import main
|
||||
main(args)
|
||||
else:
|
||||
raise SystemExit(f'Unknown which: {which}')
|
||||
|
||||
|
||||
@@ -114,7 +114,6 @@ def generate(
|
||||
payload_is_base64: bool = True,
|
||||
start_parsing_at: int = 1,
|
||||
field_sep: str = ',',
|
||||
post_init: str = '',
|
||||
) -> str:
|
||||
type_map = resolve_keys(keymap)
|
||||
keys_enum = enum(keymap)
|
||||
@@ -122,7 +121,6 @@ def generate(
|
||||
flag_keys = parse_flag(keymap, type_map, command_class)
|
||||
int_keys, uint_keys = parse_number(keymap)
|
||||
report_cmd = cmd_for_report(report_name, keymap, type_map, payload_allowed, payload_is_base64)
|
||||
post_init_line = f'\n {post_init}' if post_init else ''
|
||||
extra_init = ''
|
||||
if payload_allowed:
|
||||
payload_after_value = "case ';': state = PAYLOAD; break;"
|
||||
@@ -165,7 +163,7 @@ static inline void
|
||||
{extra_init}
|
||||
enum PARSER_STATES {{ KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE {payload} }};
|
||||
enum PARSER_STATES state = KEY, value_state = FLAG;
|
||||
{command_class} g = {{0}};{post_init_line}
|
||||
{command_class} g = {{0}};
|
||||
unsigned int i, code;
|
||||
uint64_t lcode; int64_t accumulator;
|
||||
bool is_negative; (void)is_negative;
|
||||
@@ -313,13 +311,11 @@ def parsers() -> None:
|
||||
'U': ('unicode_placement', 'uint'),
|
||||
'P': ('parent_id', 'uint'),
|
||||
'Q': ('parent_placement_id', 'uint'),
|
||||
'N': ('usage_hints', 'uint'),
|
||||
'H': ('offset_from_parent_x', 'int'),
|
||||
'V': ('offset_from_parent_y', 'int'),
|
||||
}
|
||||
text = generate('parse_graphics_code', 'screen_handle_graphics_command', 'graphics_command', keymap, 'GraphicsCommand')
|
||||
write_header(text, 'kitty/parse-graphics-command.h')
|
||||
|
||||
keymap = {
|
||||
'w': ('width', 'uint'),
|
||||
's': ('scale', 'uint'),
|
||||
@@ -333,21 +329,6 @@ def parsers() -> None:
|
||||
payload_is_base64=False, start_parsing_at=0, field_sep=':')
|
||||
write_header(text, 'kitty/parse-multicell-command.h')
|
||||
|
||||
keymap = {
|
||||
't': ('type', flag('aAmMrRopPqeEk')),
|
||||
'm': ('more', 'uint'),
|
||||
'i': ('client_id', 'uint'),
|
||||
'o': ('operation', 'uint'),
|
||||
'x': ('cell_x', 'int'),
|
||||
'y': ('cell_y', 'int'),
|
||||
'X': ('pixel_x', 'int'),
|
||||
'Y': ('pixel_y', 'int'),
|
||||
}
|
||||
text = generate(
|
||||
'parse_dnd_code', 'screen_handle_dnd_command', 'dnd_command', keymap, 'DnDCommand',
|
||||
payload_is_base64=False, start_parsing_at=0, field_sep=':')
|
||||
write_header(text, 'kitty/parse-dnd-command.h')
|
||||
|
||||
|
||||
def main(args: list[str]=sys.argv) -> None:
|
||||
parsers()
|
||||
|
||||
@@ -1,794 +0,0 @@
|
||||
#!./kitty/launcher/kitty +launch
|
||||
# License: GPLv3 Copyright: 2025, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
if __name__ == '__main__' and not __package__:
|
||||
import __main__
|
||||
__main__.__package__ = 'gen'
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
def Color(r: int, g: int, b: int) -> int:
|
||||
return (r << 16) | (g << 8) | b
|
||||
|
||||
# BEGIN_DATA_SECTION {{{
|
||||
color_names = {
|
||||
'alice blue': Color(240, 248, 255),
|
||||
'aliceblue': Color(240, 248, 255),
|
||||
'antique white': Color(250, 235, 215),
|
||||
'antiquewhite': Color(250, 235, 215),
|
||||
'antiquewhite1': Color(255, 239, 219),
|
||||
'antiquewhite2': Color(238, 223, 204),
|
||||
'antiquewhite3': Color(205, 192, 176),
|
||||
'antiquewhite4': Color(139, 131, 120),
|
||||
'aquamarine': Color(127, 255, 212),
|
||||
'aquamarine1': Color(127, 255, 212),
|
||||
'aquamarine2': Color(118, 238, 198),
|
||||
'aquamarine3': Color(102, 205, 170),
|
||||
'aquamarine4': Color(69, 139, 116),
|
||||
'azure': Color(240, 255, 255),
|
||||
'azure1': Color(240, 255, 255),
|
||||
'azure2': Color(224, 238, 238),
|
||||
'azure3': Color(193, 205, 205),
|
||||
'azure4': Color(131, 139, 139),
|
||||
'beige': Color(245, 245, 220),
|
||||
'bisque': Color(255, 228, 196),
|
||||
'bisque1': Color(255, 228, 196),
|
||||
'bisque2': Color(238, 213, 183),
|
||||
'bisque3': Color(205, 183, 158),
|
||||
'bisque4': Color(139, 125, 107),
|
||||
'black': Color(0, 0, 0),
|
||||
'blanched almond': Color(255, 235, 205),
|
||||
'blanchedalmond': Color(255, 235, 205),
|
||||
'blue': Color(0, 0, 255),
|
||||
'blue violet': Color(138, 43, 226),
|
||||
'blue1': Color(0, 0, 255),
|
||||
'blue2': Color(0, 0, 238),
|
||||
'blue3': Color(0, 0, 205),
|
||||
'blue4': Color(0, 0, 139),
|
||||
'blueviolet': Color(138, 43, 226),
|
||||
'brown': Color(165, 42, 42),
|
||||
'brown1': Color(255, 64, 64),
|
||||
'brown2': Color(238, 59, 59),
|
||||
'brown3': Color(205, 51, 51),
|
||||
'brown4': Color(139, 35, 35),
|
||||
'burlywood': Color(222, 184, 135),
|
||||
'burlywood1': Color(255, 211, 155),
|
||||
'burlywood2': Color(238, 197, 145),
|
||||
'burlywood3': Color(205, 170, 125),
|
||||
'burlywood4': Color(139, 115, 85),
|
||||
'cadet blue': Color(95, 158, 160),
|
||||
'cadetblue': Color(95, 158, 160),
|
||||
'cadetblue1': Color(152, 245, 255),
|
||||
'cadetblue2': Color(142, 229, 238),
|
||||
'cadetblue3': Color(122, 197, 205),
|
||||
'cadetblue4': Color(83, 134, 139),
|
||||
'chartreuse': Color(127, 255, 0),
|
||||
'chartreuse1': Color(127, 255, 0),
|
||||
'chartreuse2': Color(118, 238, 0),
|
||||
'chartreuse3': Color(102, 205, 0),
|
||||
'chartreuse4': Color(69, 139, 0),
|
||||
'chocolate': Color(210, 105, 30),
|
||||
'chocolate1': Color(255, 127, 36),
|
||||
'chocolate2': Color(238, 118, 33),
|
||||
'chocolate3': Color(205, 102, 29),
|
||||
'chocolate4': Color(139, 69, 19),
|
||||
'coral': Color(255, 127, 80),
|
||||
'coral1': Color(255, 114, 86),
|
||||
'coral2': Color(238, 106, 80),
|
||||
'coral3': Color(205, 91, 69),
|
||||
'coral4': Color(139, 62, 47),
|
||||
'cornflower blue': Color(100, 149, 237),
|
||||
'cornflowerblue': Color(100, 149, 237),
|
||||
'cornsilk': Color(255, 248, 220),
|
||||
'cornsilk1': Color(255, 248, 220),
|
||||
'cornsilk2': Color(238, 232, 205),
|
||||
'cornsilk3': Color(205, 200, 177),
|
||||
'cornsilk4': Color(139, 136, 120),
|
||||
'cyan': Color(0, 255, 255),
|
||||
'cyan1': Color(0, 255, 255),
|
||||
'cyan2': Color(0, 238, 238),
|
||||
'cyan3': Color(0, 205, 205),
|
||||
'cyan4': Color(0, 139, 139),
|
||||
'dark blue': Color(0, 0, 139),
|
||||
'dark cyan': Color(0, 139, 139),
|
||||
'dark goldenrod': Color(184, 134, 11),
|
||||
'dark gray': Color(169, 169, 169),
|
||||
'dark green': Color(0, 100, 0),
|
||||
'dark grey': Color(169, 169, 169),
|
||||
'dark khaki': Color(189, 183, 107),
|
||||
'dark magenta': Color(139, 0, 139),
|
||||
'dark olive green': Color(85, 107, 47),
|
||||
'dark orange': Color(255, 140, 0),
|
||||
'dark orchid': Color(153, 50, 204),
|
||||
'dark red': Color(139, 0, 0),
|
||||
'dark salmon': Color(233, 150, 122),
|
||||
'dark sea green': Color(143, 188, 143),
|
||||
'dark slate blue': Color(72, 61, 139),
|
||||
'dark slate gray': Color(47, 79, 79),
|
||||
'dark slate grey': Color(47, 79, 79),
|
||||
'dark turquoise': Color(0, 206, 209),
|
||||
'dark violet': Color(148, 0, 211),
|
||||
'darkblue': Color(0, 0, 139),
|
||||
'darkcyan': Color(0, 139, 139),
|
||||
'darkgoldenrod': Color(184, 134, 11),
|
||||
'darkgoldenrod1': Color(255, 185, 15),
|
||||
'darkgoldenrod2': Color(238, 173, 14),
|
||||
'darkgoldenrod3': Color(205, 149, 12),
|
||||
'darkgoldenrod4': Color(139, 101, 8),
|
||||
'darkgray': Color(169, 169, 169),
|
||||
'darkgreen': Color(0, 100, 0),
|
||||
'darkgrey': Color(169, 169, 169),
|
||||
'darkkhaki': Color(189, 183, 107),
|
||||
'darkmagenta': Color(139, 0, 139),
|
||||
'darkolivegreen': Color(85, 107, 47),
|
||||
'darkolivegreen1': Color(202, 255, 112),
|
||||
'darkolivegreen2': Color(188, 238, 104),
|
||||
'darkolivegreen3': Color(162, 205, 90),
|
||||
'darkolivegreen4': Color(110, 139, 61),
|
||||
'darkorange': Color(255, 140, 0),
|
||||
'darkorange1': Color(255, 127, 0),
|
||||
'darkorange2': Color(238, 118, 0),
|
||||
'darkorange3': Color(205, 102, 0),
|
||||
'darkorange4': Color(139, 69, 0),
|
||||
'darkorchid': Color(153, 50, 204),
|
||||
'darkorchid1': Color(191, 62, 255),
|
||||
'darkorchid2': Color(178, 58, 238),
|
||||
'darkorchid3': Color(154, 50, 205),
|
||||
'darkorchid4': Color(104, 34, 139),
|
||||
'darkred': Color(139, 0, 0),
|
||||
'darksalmon': Color(233, 150, 122),
|
||||
'darkseagreen': Color(143, 188, 143),
|
||||
'darkseagreen1': Color(193, 255, 193),
|
||||
'darkseagreen2': Color(180, 238, 180),
|
||||
'darkseagreen3': Color(155, 205, 155),
|
||||
'darkseagreen4': Color(105, 139, 105),
|
||||
'darkslateblue': Color(72, 61, 139),
|
||||
'darkslategray': Color(47, 79, 79),
|
||||
'darkslategray1': Color(151, 255, 255),
|
||||
'darkslategray2': Color(141, 238, 238),
|
||||
'darkslategray3': Color(121, 205, 205),
|
||||
'darkslategray4': Color(82, 139, 139),
|
||||
'darkslategrey': Color(47, 79, 79),
|
||||
'darkturquoise': Color(0, 206, 209),
|
||||
'darkviolet': Color(148, 0, 211),
|
||||
'debianred': Color(215, 7, 81),
|
||||
'deep pink': Color(255, 20, 147),
|
||||
'deep sky blue': Color(0, 191, 255),
|
||||
'deeppink': Color(255, 20, 147),
|
||||
'deeppink1': Color(255, 20, 147),
|
||||
'deeppink2': Color(238, 18, 137),
|
||||
'deeppink3': Color(205, 16, 118),
|
||||
'deeppink4': Color(139, 10, 80),
|
||||
'deepskyblue': Color(0, 191, 255),
|
||||
'deepskyblue1': Color(0, 191, 255),
|
||||
'deepskyblue2': Color(0, 178, 238),
|
||||
'deepskyblue3': Color(0, 154, 205),
|
||||
'deepskyblue4': Color(0, 104, 139),
|
||||
'dim gray': Color(105, 105, 105),
|
||||
'dim grey': Color(105, 105, 105),
|
||||
'dimgray': Color(105, 105, 105),
|
||||
'dimgrey': Color(105, 105, 105),
|
||||
'dodger blue': Color(30, 144, 255),
|
||||
'dodgerblue': Color(30, 144, 255),
|
||||
'dodgerblue1': Color(30, 144, 255),
|
||||
'dodgerblue2': Color(28, 134, 238),
|
||||
'dodgerblue3': Color(24, 116, 205),
|
||||
'dodgerblue4': Color(16, 78, 139),
|
||||
'firebrick': Color(178, 34, 34),
|
||||
'firebrick1': Color(255, 48, 48),
|
||||
'firebrick2': Color(238, 44, 44),
|
||||
'firebrick3': Color(205, 38, 38),
|
||||
'firebrick4': Color(139, 26, 26),
|
||||
'floral white': Color(255, 250, 240),
|
||||
'floralwhite': Color(255, 250, 240),
|
||||
'forest green': Color(34, 139, 34),
|
||||
'forestgreen': Color(34, 139, 34),
|
||||
'gainsboro': Color(220, 220, 220),
|
||||
'ghost white': Color(248, 248, 255),
|
||||
'ghostwhite': Color(248, 248, 255),
|
||||
'gold': Color(255, 215, 0),
|
||||
'gold1': Color(255, 215, 0),
|
||||
'gold2': Color(238, 201, 0),
|
||||
'gold3': Color(205, 173, 0),
|
||||
'gold4': Color(139, 117, 0),
|
||||
'goldenrod': Color(218, 165, 32),
|
||||
'goldenrod1': Color(255, 193, 37),
|
||||
'goldenrod2': Color(238, 180, 34),
|
||||
'goldenrod3': Color(205, 155, 29),
|
||||
'goldenrod4': Color(139, 105, 20),
|
||||
'gray': Color(190, 190, 190),
|
||||
'gray0': Color(0, 0, 0),
|
||||
'gray1': Color(3, 3, 3),
|
||||
'gray10': Color(26, 26, 26),
|
||||
'gray100': Color(255, 255, 255),
|
||||
'gray11': Color(28, 28, 28),
|
||||
'gray12': Color(31, 31, 31),
|
||||
'gray13': Color(33, 33, 33),
|
||||
'gray14': Color(36, 36, 36),
|
||||
'gray15': Color(38, 38, 38),
|
||||
'gray16': Color(41, 41, 41),
|
||||
'gray17': Color(43, 43, 43),
|
||||
'gray18': Color(46, 46, 46),
|
||||
'gray19': Color(48, 48, 48),
|
||||
'gray2': Color(5, 5, 5),
|
||||
'gray20': Color(51, 51, 51),
|
||||
'gray21': Color(54, 54, 54),
|
||||
'gray22': Color(56, 56, 56),
|
||||
'gray23': Color(59, 59, 59),
|
||||
'gray24': Color(61, 61, 61),
|
||||
'gray25': Color(64, 64, 64),
|
||||
'gray26': Color(66, 66, 66),
|
||||
'gray27': Color(69, 69, 69),
|
||||
'gray28': Color(71, 71, 71),
|
||||
'gray29': Color(74, 74, 74),
|
||||
'gray3': Color(8, 8, 8),
|
||||
'gray30': Color(77, 77, 77),
|
||||
'gray31': Color(79, 79, 79),
|
||||
'gray32': Color(82, 82, 82),
|
||||
'gray33': Color(84, 84, 84),
|
||||
'gray34': Color(87, 87, 87),
|
||||
'gray35': Color(89, 89, 89),
|
||||
'gray36': Color(92, 92, 92),
|
||||
'gray37': Color(94, 94, 94),
|
||||
'gray38': Color(97, 97, 97),
|
||||
'gray39': Color(99, 99, 99),
|
||||
'gray4': Color(10, 10, 10),
|
||||
'gray40': Color(102, 102, 102),
|
||||
'gray41': Color(105, 105, 105),
|
||||
'gray42': Color(107, 107, 107),
|
||||
'gray43': Color(110, 110, 110),
|
||||
'gray44': Color(112, 112, 112),
|
||||
'gray45': Color(115, 115, 115),
|
||||
'gray46': Color(117, 117, 117),
|
||||
'gray47': Color(120, 120, 120),
|
||||
'gray48': Color(122, 122, 122),
|
||||
'gray49': Color(125, 125, 125),
|
||||
'gray5': Color(13, 13, 13),
|
||||
'gray50': Color(127, 127, 127),
|
||||
'gray51': Color(130, 130, 130),
|
||||
'gray52': Color(133, 133, 133),
|
||||
'gray53': Color(135, 135, 135),
|
||||
'gray54': Color(138, 138, 138),
|
||||
'gray55': Color(140, 140, 140),
|
||||
'gray56': Color(143, 143, 143),
|
||||
'gray57': Color(145, 145, 145),
|
||||
'gray58': Color(148, 148, 148),
|
||||
'gray59': Color(150, 150, 150),
|
||||
'gray6': Color(15, 15, 15),
|
||||
'gray60': Color(153, 153, 153),
|
||||
'gray61': Color(156, 156, 156),
|
||||
'gray62': Color(158, 158, 158),
|
||||
'gray63': Color(161, 161, 161),
|
||||
'gray64': Color(163, 163, 163),
|
||||
'gray65': Color(166, 166, 166),
|
||||
'gray66': Color(168, 168, 168),
|
||||
'gray67': Color(171, 171, 171),
|
||||
'gray68': Color(173, 173, 173),
|
||||
'gray69': Color(176, 176, 176),
|
||||
'gray7': Color(18, 18, 18),
|
||||
'gray70': Color(179, 179, 179),
|
||||
'gray71': Color(181, 181, 181),
|
||||
'gray72': Color(184, 184, 184),
|
||||
'gray73': Color(186, 186, 186),
|
||||
'gray74': Color(189, 189, 189),
|
||||
'gray75': Color(191, 191, 191),
|
||||
'gray76': Color(194, 194, 194),
|
||||
'gray77': Color(196, 196, 196),
|
||||
'gray78': Color(199, 199, 199),
|
||||
'gray79': Color(201, 201, 201),
|
||||
'gray8': Color(20, 20, 20),
|
||||
'gray80': Color(204, 204, 204),
|
||||
'gray81': Color(207, 207, 207),
|
||||
'gray82': Color(209, 209, 209),
|
||||
'gray83': Color(212, 212, 212),
|
||||
'gray84': Color(214, 214, 214),
|
||||
'gray85': Color(217, 217, 217),
|
||||
'gray86': Color(219, 219, 219),
|
||||
'gray87': Color(222, 222, 222),
|
||||
'gray88': Color(224, 224, 224),
|
||||
'gray89': Color(227, 227, 227),
|
||||
'gray9': Color(23, 23, 23),
|
||||
'gray90': Color(229, 229, 229),
|
||||
'gray91': Color(232, 232, 232),
|
||||
'gray92': Color(235, 235, 235),
|
||||
'gray93': Color(237, 237, 237),
|
||||
'gray94': Color(240, 240, 240),
|
||||
'gray95': Color(242, 242, 242),
|
||||
'gray96': Color(245, 245, 245),
|
||||
'gray97': Color(247, 247, 247),
|
||||
'gray98': Color(250, 250, 250),
|
||||
'gray99': Color(252, 252, 252),
|
||||
'green': Color(0, 255, 0),
|
||||
'green yellow': Color(173, 255, 47),
|
||||
'green1': Color(0, 255, 0),
|
||||
'green2': Color(0, 238, 0),
|
||||
'green3': Color(0, 205, 0),
|
||||
'green4': Color(0, 139, 0),
|
||||
'greenyellow': Color(173, 255, 47),
|
||||
'grey': Color(190, 190, 190),
|
||||
'grey0': Color(0, 0, 0),
|
||||
'grey1': Color(3, 3, 3),
|
||||
'grey10': Color(26, 26, 26),
|
||||
'grey100': Color(255, 255, 255),
|
||||
'grey11': Color(28, 28, 28),
|
||||
'grey12': Color(31, 31, 31),
|
||||
'grey13': Color(33, 33, 33),
|
||||
'grey14': Color(36, 36, 36),
|
||||
'grey15': Color(38, 38, 38),
|
||||
'grey16': Color(41, 41, 41),
|
||||
'grey17': Color(43, 43, 43),
|
||||
'grey18': Color(46, 46, 46),
|
||||
'grey19': Color(48, 48, 48),
|
||||
'grey2': Color(5, 5, 5),
|
||||
'grey20': Color(51, 51, 51),
|
||||
'grey21': Color(54, 54, 54),
|
||||
'grey22': Color(56, 56, 56),
|
||||
'grey23': Color(59, 59, 59),
|
||||
'grey24': Color(61, 61, 61),
|
||||
'grey25': Color(64, 64, 64),
|
||||
'grey26': Color(66, 66, 66),
|
||||
'grey27': Color(69, 69, 69),
|
||||
'grey28': Color(71, 71, 71),
|
||||
'grey29': Color(74, 74, 74),
|
||||
'grey3': Color(8, 8, 8),
|
||||
'grey30': Color(77, 77, 77),
|
||||
'grey31': Color(79, 79, 79),
|
||||
'grey32': Color(82, 82, 82),
|
||||
'grey33': Color(84, 84, 84),
|
||||
'grey34': Color(87, 87, 87),
|
||||
'grey35': Color(89, 89, 89),
|
||||
'grey36': Color(92, 92, 92),
|
||||
'grey37': Color(94, 94, 94),
|
||||
'grey38': Color(97, 97, 97),
|
||||
'grey39': Color(99, 99, 99),
|
||||
'grey4': Color(10, 10, 10),
|
||||
'grey40': Color(102, 102, 102),
|
||||
'grey41': Color(105, 105, 105),
|
||||
'grey42': Color(107, 107, 107),
|
||||
'grey43': Color(110, 110, 110),
|
||||
'grey44': Color(112, 112, 112),
|
||||
'grey45': Color(115, 115, 115),
|
||||
'grey46': Color(117, 117, 117),
|
||||
'grey47': Color(120, 120, 120),
|
||||
'grey48': Color(122, 122, 122),
|
||||
'grey49': Color(125, 125, 125),
|
||||
'grey5': Color(13, 13, 13),
|
||||
'grey50': Color(127, 127, 127),
|
||||
'grey51': Color(130, 130, 130),
|
||||
'grey52': Color(133, 133, 133),
|
||||
'grey53': Color(135, 135, 135),
|
||||
'grey54': Color(138, 138, 138),
|
||||
'grey55': Color(140, 140, 140),
|
||||
'grey56': Color(143, 143, 143),
|
||||
'grey57': Color(145, 145, 145),
|
||||
'grey58': Color(148, 148, 148),
|
||||
'grey59': Color(150, 150, 150),
|
||||
'grey6': Color(15, 15, 15),
|
||||
'grey60': Color(153, 153, 153),
|
||||
'grey61': Color(156, 156, 156),
|
||||
'grey62': Color(158, 158, 158),
|
||||
'grey63': Color(161, 161, 161),
|
||||
'grey64': Color(163, 163, 163),
|
||||
'grey65': Color(166, 166, 166),
|
||||
'grey66': Color(168, 168, 168),
|
||||
'grey67': Color(171, 171, 171),
|
||||
'grey68': Color(173, 173, 173),
|
||||
'grey69': Color(176, 176, 176),
|
||||
'grey7': Color(18, 18, 18),
|
||||
'grey70': Color(179, 179, 179),
|
||||
'grey71': Color(181, 181, 181),
|
||||
'grey72': Color(184, 184, 184),
|
||||
'grey73': Color(186, 186, 186),
|
||||
'grey74': Color(189, 189, 189),
|
||||
'grey75': Color(191, 191, 191),
|
||||
'grey76': Color(194, 194, 194),
|
||||
'grey77': Color(196, 196, 196),
|
||||
'grey78': Color(199, 199, 199),
|
||||
'grey79': Color(201, 201, 201),
|
||||
'grey8': Color(20, 20, 20),
|
||||
'grey80': Color(204, 204, 204),
|
||||
'grey81': Color(207, 207, 207),
|
||||
'grey82': Color(209, 209, 209),
|
||||
'grey83': Color(212, 212, 212),
|
||||
'grey84': Color(214, 214, 214),
|
||||
'grey85': Color(217, 217, 217),
|
||||
'grey86': Color(219, 219, 219),
|
||||
'grey87': Color(222, 222, 222),
|
||||
'grey88': Color(224, 224, 224),
|
||||
'grey89': Color(227, 227, 227),
|
||||
'grey9': Color(23, 23, 23),
|
||||
'grey90': Color(229, 229, 229),
|
||||
'grey91': Color(232, 232, 232),
|
||||
'grey92': Color(235, 235, 235),
|
||||
'grey93': Color(237, 237, 237),
|
||||
'grey94': Color(240, 240, 240),
|
||||
'grey95': Color(242, 242, 242),
|
||||
'grey96': Color(245, 245, 245),
|
||||
'grey97': Color(247, 247, 247),
|
||||
'grey98': Color(250, 250, 250),
|
||||
'grey99': Color(252, 252, 252),
|
||||
'honeydew': Color(240, 255, 240),
|
||||
'honeydew1': Color(240, 255, 240),
|
||||
'honeydew2': Color(224, 238, 224),
|
||||
'honeydew3': Color(193, 205, 193),
|
||||
'honeydew4': Color(131, 139, 131),
|
||||
'hot pink': Color(255, 105, 180),
|
||||
'hotpink': Color(255, 105, 180),
|
||||
'hotpink1': Color(255, 110, 180),
|
||||
'hotpink2': Color(238, 106, 167),
|
||||
'hotpink3': Color(205, 96, 144),
|
||||
'hotpink4': Color(139, 58, 98),
|
||||
'indian red': Color(205, 92, 92),
|
||||
'indianred': Color(205, 92, 92),
|
||||
'indianred1': Color(255, 106, 106),
|
||||
'indianred2': Color(238, 99, 99),
|
||||
'indianred3': Color(205, 85, 85),
|
||||
'indianred4': Color(139, 58, 58),
|
||||
'ivory': Color(255, 255, 240),
|
||||
'ivory1': Color(255, 255, 240),
|
||||
'ivory2': Color(238, 238, 224),
|
||||
'ivory3': Color(205, 205, 193),
|
||||
'ivory4': Color(139, 139, 131),
|
||||
'khaki': Color(240, 230, 140),
|
||||
'khaki1': Color(255, 246, 143),
|
||||
'khaki2': Color(238, 230, 133),
|
||||
'khaki3': Color(205, 198, 115),
|
||||
'khaki4': Color(139, 134, 78),
|
||||
'lavender': Color(230, 230, 250),
|
||||
'lavender blush': Color(255, 240, 245),
|
||||
'lavenderblush': Color(255, 240, 245),
|
||||
'lavenderblush1': Color(255, 240, 245),
|
||||
'lavenderblush2': Color(238, 224, 229),
|
||||
'lavenderblush3': Color(205, 193, 197),
|
||||
'lavenderblush4': Color(139, 131, 134),
|
||||
'lawn green': Color(124, 252, 0),
|
||||
'lawngreen': Color(124, 252, 0),
|
||||
'lemon chiffon': Color(255, 250, 205),
|
||||
'lemonchiffon': Color(255, 250, 205),
|
||||
'lemonchiffon1': Color(255, 250, 205),
|
||||
'lemonchiffon2': Color(238, 233, 191),
|
||||
'lemonchiffon3': Color(205, 201, 165),
|
||||
'lemonchiffon4': Color(139, 137, 112),
|
||||
'light blue': Color(173, 216, 230),
|
||||
'light coral': Color(240, 128, 128),
|
||||
'light cyan': Color(224, 255, 255),
|
||||
'light goldenrod': Color(238, 221, 130),
|
||||
'light goldenrod yellow': Color(250, 250, 210),
|
||||
'light gray': Color(211, 211, 211),
|
||||
'light green': Color(144, 238, 144),
|
||||
'light grey': Color(211, 211, 211),
|
||||
'light pink': Color(255, 182, 193),
|
||||
'light salmon': Color(255, 160, 122),
|
||||
'light sea green': Color(32, 178, 170),
|
||||
'light sky blue': Color(135, 206, 250),
|
||||
'light slate blue': Color(132, 112, 255),
|
||||
'light slate gray': Color(119, 136, 153),
|
||||
'light slate grey': Color(119, 136, 153),
|
||||
'light steel blue': Color(176, 196, 222),
|
||||
'light yellow': Color(255, 255, 224),
|
||||
'lightblue': Color(173, 216, 230),
|
||||
'lightblue1': Color(191, 239, 255),
|
||||
'lightblue2': Color(178, 223, 238),
|
||||
'lightblue3': Color(154, 192, 205),
|
||||
'lightblue4': Color(104, 131, 139),
|
||||
'lightcoral': Color(240, 128, 128),
|
||||
'lightcyan': Color(224, 255, 255),
|
||||
'lightcyan1': Color(224, 255, 255),
|
||||
'lightcyan2': Color(209, 238, 238),
|
||||
'lightcyan3': Color(180, 205, 205),
|
||||
'lightcyan4': Color(122, 139, 139),
|
||||
'lightgoldenrod': Color(238, 221, 130),
|
||||
'lightgoldenrod1': Color(255, 236, 139),
|
||||
'lightgoldenrod2': Color(238, 220, 130),
|
||||
'lightgoldenrod3': Color(205, 190, 112),
|
||||
'lightgoldenrod4': Color(139, 129, 76),
|
||||
'lightgoldenrodyellow': Color(250, 250, 210),
|
||||
'lightgray': Color(211, 211, 211),
|
||||
'lightgreen': Color(144, 238, 144),
|
||||
'lightgrey': Color(211, 211, 211),
|
||||
'lightpink': Color(255, 182, 193),
|
||||
'lightpink1': Color(255, 174, 185),
|
||||
'lightpink2': Color(238, 162, 173),
|
||||
'lightpink3': Color(205, 140, 149),
|
||||
'lightpink4': Color(139, 95, 101),
|
||||
'lightsalmon': Color(255, 160, 122),
|
||||
'lightsalmon1': Color(255, 160, 122),
|
||||
'lightsalmon2': Color(238, 149, 114),
|
||||
'lightsalmon3': Color(205, 129, 98),
|
||||
'lightsalmon4': Color(139, 87, 66),
|
||||
'lightseagreen': Color(32, 178, 170),
|
||||
'lightskyblue': Color(135, 206, 250),
|
||||
'lightskyblue1': Color(176, 226, 255),
|
||||
'lightskyblue2': Color(164, 211, 238),
|
||||
'lightskyblue3': Color(141, 182, 205),
|
||||
'lightskyblue4': Color(96, 123, 139),
|
||||
'lightslateblue': Color(132, 112, 255),
|
||||
'lightslategray': Color(119, 136, 153),
|
||||
'lightslategrey': Color(119, 136, 153),
|
||||
'lightsteelblue': Color(176, 196, 222),
|
||||
'lightsteelblue1': Color(202, 225, 255),
|
||||
'lightsteelblue2': Color(188, 210, 238),
|
||||
'lightsteelblue3': Color(162, 181, 205),
|
||||
'lightsteelblue4': Color(110, 123, 139),
|
||||
'lightyellow': Color(255, 255, 224),
|
||||
'lightyellow1': Color(255, 255, 224),
|
||||
'lightyellow2': Color(238, 238, 209),
|
||||
'lightyellow3': Color(205, 205, 180),
|
||||
'lightyellow4': Color(139, 139, 122),
|
||||
'lime green': Color(50, 205, 50),
|
||||
'limegreen': Color(50, 205, 50),
|
||||
'linen': Color(250, 240, 230),
|
||||
'magenta': Color(255, 0, 255),
|
||||
'magenta1': Color(255, 0, 255),
|
||||
'magenta2': Color(238, 0, 238),
|
||||
'magenta3': Color(205, 0, 205),
|
||||
'magenta4': Color(139, 0, 139),
|
||||
'maroon': Color(176, 48, 96),
|
||||
'maroon1': Color(255, 52, 179),
|
||||
'maroon2': Color(238, 48, 167),
|
||||
'maroon3': Color(205, 41, 144),
|
||||
'maroon4': Color(139, 28, 98),
|
||||
'medium aquamarine': Color(102, 205, 170),
|
||||
'medium blue': Color(0, 0, 205),
|
||||
'medium orchid': Color(186, 85, 211),
|
||||
'medium purple': Color(147, 112, 219),
|
||||
'medium sea green': Color(60, 179, 113),
|
||||
'medium slate blue': Color(123, 104, 238),
|
||||
'medium spring green': Color(0, 250, 154),
|
||||
'medium turquoise': Color(72, 209, 204),
|
||||
'medium violet red': Color(199, 21, 133),
|
||||
'mediumaquamarine': Color(102, 205, 170),
|
||||
'mediumblue': Color(0, 0, 205),
|
||||
'mediumorchid': Color(186, 85, 211),
|
||||
'mediumorchid1': Color(224, 102, 255),
|
||||
'mediumorchid2': Color(209, 95, 238),
|
||||
'mediumorchid3': Color(180, 82, 205),
|
||||
'mediumorchid4': Color(122, 55, 139),
|
||||
'mediumpurple': Color(147, 112, 219),
|
||||
'mediumpurple1': Color(171, 130, 255),
|
||||
'mediumpurple2': Color(159, 121, 238),
|
||||
'mediumpurple3': Color(137, 104, 205),
|
||||
'mediumpurple4': Color(93, 71, 139),
|
||||
'mediumseagreen': Color(60, 179, 113),
|
||||
'mediumslateblue': Color(123, 104, 238),
|
||||
'mediumspringgreen': Color(0, 250, 154),
|
||||
'mediumturquoise': Color(72, 209, 204),
|
||||
'mediumvioletred': Color(199, 21, 133),
|
||||
'midnight blue': Color(25, 25, 112),
|
||||
'midnightblue': Color(25, 25, 112),
|
||||
'mint cream': Color(245, 255, 250),
|
||||
'mintcream': Color(245, 255, 250),
|
||||
'misty rose': Color(255, 228, 225),
|
||||
'mistyrose': Color(255, 228, 225),
|
||||
'mistyrose1': Color(255, 228, 225),
|
||||
'mistyrose2': Color(238, 213, 210),
|
||||
'mistyrose3': Color(205, 183, 181),
|
||||
'mistyrose4': Color(139, 125, 123),
|
||||
'moccasin': Color(255, 228, 181),
|
||||
'navajo white': Color(255, 222, 173),
|
||||
'navajowhite': Color(255, 222, 173),
|
||||
'navajowhite1': Color(255, 222, 173),
|
||||
'navajowhite2': Color(238, 207, 161),
|
||||
'navajowhite3': Color(205, 179, 139),
|
||||
'navajowhite4': Color(139, 121, 94),
|
||||
'navy': Color(0, 0, 128),
|
||||
'navy blue': Color(0, 0, 128),
|
||||
'navyblue': Color(0, 0, 128),
|
||||
'old lace': Color(253, 245, 230),
|
||||
'oldlace': Color(253, 245, 230),
|
||||
'olive drab': Color(107, 142, 35),
|
||||
'olivedrab': Color(107, 142, 35),
|
||||
'olivedrab1': Color(192, 255, 62),
|
||||
'olivedrab2': Color(179, 238, 58),
|
||||
'olivedrab3': Color(154, 205, 50),
|
||||
'olivedrab4': Color(105, 139, 34),
|
||||
'orange': Color(255, 165, 0),
|
||||
'orange red': Color(255, 69, 0),
|
||||
'orange1': Color(255, 165, 0),
|
||||
'orange2': Color(238, 154, 0),
|
||||
'orange3': Color(205, 133, 0),
|
||||
'orange4': Color(139, 90, 0),
|
||||
'orangered': Color(255, 69, 0),
|
||||
'orangered1': Color(255, 69, 0),
|
||||
'orangered2': Color(238, 64, 0),
|
||||
'orangered3': Color(205, 55, 0),
|
||||
'orangered4': Color(139, 37, 0),
|
||||
'orchid': Color(218, 112, 214),
|
||||
'orchid1': Color(255, 131, 250),
|
||||
'orchid2': Color(238, 122, 233),
|
||||
'orchid3': Color(205, 105, 201),
|
||||
'orchid4': Color(139, 71, 137),
|
||||
'pale goldenrod': Color(238, 232, 170),
|
||||
'pale green': Color(152, 251, 152),
|
||||
'pale turquoise': Color(175, 238, 238),
|
||||
'pale violet red': Color(219, 112, 147),
|
||||
'palegoldenrod': Color(238, 232, 170),
|
||||
'palegreen': Color(152, 251, 152),
|
||||
'palegreen1': Color(154, 255, 154),
|
||||
'palegreen2': Color(144, 238, 144),
|
||||
'palegreen3': Color(124, 205, 124),
|
||||
'palegreen4': Color(84, 139, 84),
|
||||
'paleturquoise': Color(175, 238, 238),
|
||||
'paleturquoise1': Color(187, 255, 255),
|
||||
'paleturquoise2': Color(174, 238, 238),
|
||||
'paleturquoise3': Color(150, 205, 205),
|
||||
'paleturquoise4': Color(102, 139, 139),
|
||||
'palevioletred': Color(219, 112, 147),
|
||||
'palevioletred1': Color(255, 130, 171),
|
||||
'palevioletred2': Color(238, 121, 159),
|
||||
'palevioletred3': Color(205, 104, 137),
|
||||
'palevioletred4': Color(139, 71, 93),
|
||||
'papaya whip': Color(255, 239, 213),
|
||||
'papayawhip': Color(255, 239, 213),
|
||||
'peach puff': Color(255, 218, 185),
|
||||
'peachpuff': Color(255, 218, 185),
|
||||
'peachpuff1': Color(255, 218, 185),
|
||||
'peachpuff2': Color(238, 203, 173),
|
||||
'peachpuff3': Color(205, 175, 149),
|
||||
'peachpuff4': Color(139, 119, 101),
|
||||
'peru': Color(205, 133, 63),
|
||||
'pink': Color(255, 192, 203),
|
||||
'pink1': Color(255, 181, 197),
|
||||
'pink2': Color(238, 169, 184),
|
||||
'pink3': Color(205, 145, 158),
|
||||
'pink4': Color(139, 99, 108),
|
||||
'plum': Color(221, 160, 221),
|
||||
'plum1': Color(255, 187, 255),
|
||||
'plum2': Color(238, 174, 238),
|
||||
'plum3': Color(205, 150, 205),
|
||||
'plum4': Color(139, 102, 139),
|
||||
'powder blue': Color(176, 224, 230),
|
||||
'powderblue': Color(176, 224, 230),
|
||||
'purple': Color(160, 32, 240),
|
||||
'purple1': Color(155, 48, 255),
|
||||
'purple2': Color(145, 44, 238),
|
||||
'purple3': Color(125, 38, 205),
|
||||
'purple4': Color(85, 26, 139),
|
||||
'red': Color(255, 0, 0),
|
||||
'red1': Color(255, 0, 0),
|
||||
'red2': Color(238, 0, 0),
|
||||
'red3': Color(205, 0, 0),
|
||||
'red4': Color(139, 0, 0),
|
||||
'rosy brown': Color(188, 143, 143),
|
||||
'rosybrown': Color(188, 143, 143),
|
||||
'rosybrown1': Color(255, 193, 193),
|
||||
'rosybrown2': Color(238, 180, 180),
|
||||
'rosybrown3': Color(205, 155, 155),
|
||||
'rosybrown4': Color(139, 105, 105),
|
||||
'royal blue': Color(65, 105, 225),
|
||||
'royalblue': Color(65, 105, 225),
|
||||
'royalblue1': Color(72, 118, 255),
|
||||
'royalblue2': Color(67, 110, 238),
|
||||
'royalblue3': Color(58, 95, 205),
|
||||
'royalblue4': Color(39, 64, 139),
|
||||
'saddle brown': Color(139, 69, 19),
|
||||
'saddlebrown': Color(139, 69, 19),
|
||||
'salmon': Color(250, 128, 114),
|
||||
'salmon1': Color(255, 140, 105),
|
||||
'salmon2': Color(238, 130, 98),
|
||||
'salmon3': Color(205, 112, 84),
|
||||
'salmon4': Color(139, 76, 57),
|
||||
'sandy brown': Color(244, 164, 96),
|
||||
'sandybrown': Color(244, 164, 96),
|
||||
'sea green': Color(46, 139, 87),
|
||||
'seagreen': Color(46, 139, 87),
|
||||
'seagreen1': Color(84, 255, 159),
|
||||
'seagreen2': Color(78, 238, 148),
|
||||
'seagreen3': Color(67, 205, 128),
|
||||
'seagreen4': Color(46, 139, 87),
|
||||
'seashell': Color(255, 245, 238),
|
||||
'seashell1': Color(255, 245, 238),
|
||||
'seashell2': Color(238, 229, 222),
|
||||
'seashell3': Color(205, 197, 191),
|
||||
'seashell4': Color(139, 134, 130),
|
||||
'sienna': Color(160, 82, 45),
|
||||
'sienna1': Color(255, 130, 71),
|
||||
'sienna2': Color(238, 121, 66),
|
||||
'sienna3': Color(205, 104, 57),
|
||||
'sienna4': Color(139, 71, 38),
|
||||
'sky blue': Color(135, 206, 235),
|
||||
'skyblue': Color(135, 206, 235),
|
||||
'skyblue1': Color(135, 206, 255),
|
||||
'skyblue2': Color(126, 192, 238),
|
||||
'skyblue3': Color(108, 166, 205),
|
||||
'skyblue4': Color(74, 112, 139),
|
||||
'slate blue': Color(106, 90, 205),
|
||||
'slate gray': Color(112, 128, 144),
|
||||
'slate grey': Color(112, 128, 144),
|
||||
'slateblue': Color(106, 90, 205),
|
||||
'slateblue1': Color(131, 111, 255),
|
||||
'slateblue2': Color(122, 103, 238),
|
||||
'slateblue3': Color(105, 89, 205),
|
||||
'slateblue4': Color(71, 60, 139),
|
||||
'slategray': Color(112, 128, 144),
|
||||
'slategray1': Color(198, 226, 255),
|
||||
'slategray2': Color(185, 211, 238),
|
||||
'slategray3': Color(159, 182, 205),
|
||||
'slategray4': Color(108, 123, 139),
|
||||
'slategrey': Color(112, 128, 144),
|
||||
'snow': Color(255, 250, 250),
|
||||
'snow1': Color(255, 250, 250),
|
||||
'snow2': Color(238, 233, 233),
|
||||
'snow3': Color(205, 201, 201),
|
||||
'snow4': Color(139, 137, 137),
|
||||
'spring green': Color(0, 255, 127),
|
||||
'springgreen': Color(0, 255, 127),
|
||||
'springgreen1': Color(0, 255, 127),
|
||||
'springgreen2': Color(0, 238, 118),
|
||||
'springgreen3': Color(0, 205, 102),
|
||||
'springgreen4': Color(0, 139, 69),
|
||||
'steel blue': Color(70, 130, 180),
|
||||
'steelblue': Color(70, 130, 180),
|
||||
'steelblue1': Color(99, 184, 255),
|
||||
'steelblue2': Color(92, 172, 238),
|
||||
'steelblue3': Color(79, 148, 205),
|
||||
'steelblue4': Color(54, 100, 139),
|
||||
'tan': Color(210, 180, 140),
|
||||
'tan1': Color(255, 165, 79),
|
||||
'tan2': Color(238, 154, 73),
|
||||
'tan3': Color(205, 133, 63),
|
||||
'tan4': Color(139, 90, 43),
|
||||
'thistle': Color(216, 191, 216),
|
||||
'thistle1': Color(255, 225, 255),
|
||||
'thistle2': Color(238, 210, 238),
|
||||
'thistle3': Color(205, 181, 205),
|
||||
'thistle4': Color(139, 123, 139),
|
||||
'tomato': Color(255, 99, 71),
|
||||
'tomato1': Color(255, 99, 71),
|
||||
'tomato2': Color(238, 92, 66),
|
||||
'tomato3': Color(205, 79, 57),
|
||||
'tomato4': Color(139, 54, 38),
|
||||
'turquoise': Color(64, 224, 208),
|
||||
'turquoise1': Color(0, 245, 255),
|
||||
'turquoise2': Color(0, 229, 238),
|
||||
'turquoise3': Color(0, 197, 205),
|
||||
'turquoise4': Color(0, 134, 139),
|
||||
'violet': Color(238, 130, 238),
|
||||
'violet red': Color(208, 32, 144),
|
||||
'violetred': Color(208, 32, 144),
|
||||
'violetred1': Color(255, 62, 150),
|
||||
'violetred2': Color(238, 58, 140),
|
||||
'violetred3': Color(205, 50, 120),
|
||||
'violetred4': Color(139, 34, 82),
|
||||
'wheat': Color(245, 222, 179),
|
||||
'wheat1': Color(255, 231, 186),
|
||||
'wheat2': Color(238, 216, 174),
|
||||
'wheat3': Color(205, 186, 150),
|
||||
'wheat4': Color(139, 126, 102),
|
||||
'white': Color(255, 255, 255),
|
||||
'white smoke': Color(245, 245, 245),
|
||||
'whitesmoke': Color(245, 245, 245),
|
||||
'yellow': Color(255, 255, 0),
|
||||
'yellow green': Color(154, 205, 50),
|
||||
'yellow1': Color(255, 255, 0),
|
||||
'yellow2': Color(238, 238, 0),
|
||||
'yellow3': Color(205, 205, 0),
|
||||
'yellow4': Color(139, 139, 0),
|
||||
'yellowgreen': Color(154, 205, 50)}
|
||||
# END_DATA_SECTION }}}
|
||||
|
||||
def main(args: list[str]=sys.argv) -> None:
|
||||
with tempfile.TemporaryFile(suffix='.gperf', mode='w+') as tf:
|
||||
print('struct Keyword { int name, value; };\n%%', file=tf)
|
||||
names = sorted(color_names)
|
||||
for name in names:
|
||||
print(f'{name}, {color_names[name]}', file=tf)
|
||||
print('%%', file=tf)
|
||||
tf.flush()
|
||||
tf.seek(0)
|
||||
with open('kitty/color-names.h', 'w') as header:
|
||||
subprocess.check_call(
|
||||
'gperf -m 2000 --struct-type --includes --readonly-tables --lookup-function-name in_color_name_set'
|
||||
' --global-table --null-strings --hash-function-name color_name_hash /dev/stdin'
|
||||
' --word-array-name color_names --pic --compare-strncmp'.split(), stdout=header, stdin=tf)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import runpy
|
||||
m = runpy.run_path(os.path.dirname(os.path.abspath(__file__)))
|
||||
m['main']([sys.executable, 'color-names'])
|
||||
@@ -43,29 +43,17 @@ def main(args: list[str]=sys.argv) -> None:
|
||||
from kitty.options.definition import definition
|
||||
nullable_colors = []
|
||||
all_colors = []
|
||||
special_colors = []
|
||||
for opt in definition.iter_all_options():
|
||||
if callable(opt.parser_func):
|
||||
match opt.parser_func.__name__:
|
||||
case 'to_color':
|
||||
all_colors.append(opt.name)
|
||||
case 'macos_titlebar_color' | 'titlebar_color' | 'scrollbar_color':
|
||||
all_colors.append(opt.name)
|
||||
special_colors.append(opt.name)
|
||||
case 'to_color_or_none' | 'cursor_text_color':
|
||||
all_colors.append(opt.name)
|
||||
nullable_colors.append(opt.name)
|
||||
|
||||
if opt.parser_func.__name__ in ('to_color_or_none', 'cursor_text_color'):
|
||||
nullable_colors.append(opt.name)
|
||||
all_colors.append(opt.name)
|
||||
elif opt.parser_func.__name__ in ('to_color', 'titlebar_color', 'macos_titlebar_color'):
|
||||
all_colors.append(opt.name)
|
||||
patch_color_list('tools/cmd/at/set_colors.go', nullable_colors, 'NULLABLE')
|
||||
patch_color_list('tools/themes/collection.go', all_colors, 'ALL')
|
||||
nc = ',\n '.join(f'{x!r}' for x in nullable_colors)
|
||||
sc = ',\n '.join(f'{x!r}' for x in special_colors)
|
||||
ac = ',\n '.join(f'{x!r}' for x in all_colors)
|
||||
write_output('kitty', definition,
|
||||
f'\nnullable_colors = frozenset({{\n {nc}\n}})\n'
|
||||
f'\nspecial_colors = frozenset({{\n {sc}\n}})\n'
|
||||
f'\nall_colors = frozenset({{\n {ac}\n}})\n'
|
||||
)
|
||||
write_output('kitty', definition, f'\nnullable_colors = frozenset({{\n {nc}\n}})\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -35,13 +35,13 @@ from kitty.cli import (
|
||||
from kitty.conf.generate import gen_go_code
|
||||
from kitty.conf.types import Definition
|
||||
from kitty.config import commented_out_default_config
|
||||
from kitty.fast_data_types import all_color_names
|
||||
from kitty.guess_mime_type import known_extensions, text_mimes
|
||||
from kitty.key_encoding import config_mod_map
|
||||
from kitty.key_names import character_key_name_aliases, functional_key_name_aliases
|
||||
from kitty.options.types import Options
|
||||
from kitty.rc.base import RemoteCommand, all_command_names, command_for_name
|
||||
from kitty.remote_control import global_options_spec
|
||||
from kitty.rgb import color_names
|
||||
from kitty.simple_cli_definitions import CompletionSpec, parse_option_spec, serialize_as_go_string
|
||||
|
||||
if __name__ == '__main__' and not __package__:
|
||||
@@ -201,7 +201,6 @@ def make_bitfields() -> None:
|
||||
)
|
||||
mb('tools/vt', 'CellColor', 'is_idx 1', 'red 8', 'green 8', 'blue 8')
|
||||
mb('tools/vt', 'LineAttrs', 'prompt_kind 2',)
|
||||
mb('kittens/choose_files', 'CombinedScore', 'score 16', 'length 16', 'index 32')
|
||||
# }}}
|
||||
|
||||
# Completions {{{
|
||||
@@ -247,7 +246,7 @@ def clone_safe_launch_opts() -> Sequence[GoOption]:
|
||||
ans = []
|
||||
allowed = clone_safe_opts()
|
||||
for o in go_options_for_seq(parse_option_spec(options_spec())[0]):
|
||||
if o.obj_defn.name in allowed:
|
||||
if o.obj_dict['name'] in allowed:
|
||||
ans.append(o)
|
||||
return tuple(ans)
|
||||
|
||||
@@ -260,9 +259,9 @@ def completion_for_launch_wrappers(*names: str) -> None:
|
||||
|
||||
def generate_completions_for_kitty() -> None:
|
||||
print('package completion\n')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cmd/tool"')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cmd/at"')
|
||||
print('import "kitty/tools/cli"')
|
||||
print('import "kitty/tools/cmd/tool"')
|
||||
print('import "kitty/tools/cmd/at"')
|
||||
|
||||
print('func kitty(root *cli.Command) {')
|
||||
|
||||
@@ -459,7 +458,7 @@ def generate_conf_parser(kitten: str, defn: Definition) -> None:
|
||||
|
||||
|
||||
def generate_extra_cli_parser(name: str, spec: str) -> None:
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('import "kitty/tools/cli"')
|
||||
go_opts = tuple(go_options_for_seq(parse_option_spec(spec)[0]))
|
||||
print(f'type {name}_options struct ''{')
|
||||
for opt in go_opts:
|
||||
@@ -509,7 +508,7 @@ def kitten_clis() -> None:
|
||||
has_underscore = '_' in kitten
|
||||
print(f'package {kitten}')
|
||||
print('import "fmt"')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('import "kitty/tools/cli"')
|
||||
print('var _ = fmt.Sprintf')
|
||||
print('func create_cmd(root *cli.Command, run_func func(*cli.Command, *Options, []string)(int, error)) {')
|
||||
print('ans := root.AddSubCommand(&cli.Command{')
|
||||
@@ -585,7 +584,7 @@ def generate_color_names() -> str:
|
||||
cursor = "" if Options.cursor is None else Options.cursor.as_sharp
|
||||
return 'package style\n\nvar ColorNames = map[string]RGBA{' + '\n'.join(
|
||||
f'\t"{name}": RGBA{{ Red:{val.red}, Green:{val.green}, Blue:{val.blue} }},'
|
||||
for name, val in all_color_names()
|
||||
for name, val in color_names.items()
|
||||
) + '\n}' + '\n\nvar ColorTable = [256]uint32{' + ', '.join(
|
||||
f'{x}' for x in Options.color_table) + '}\n' + f'''
|
||||
var DefaultColors = struct {{
|
||||
@@ -613,9 +612,8 @@ def generate_constants() -> str:
|
||||
from kittens.query_terminal.main import all_queries
|
||||
from kitty.colors import ThemeFile
|
||||
from kitty.config import option_names_for_completion
|
||||
from kitty.fast_data_types import DND_CODE, FILE_TRANSFER_CODE
|
||||
from kitty.fast_data_types import FILE_TRANSFER_CODE
|
||||
from kitty.options.utils import allowed_shell_integration_values, url_style_map
|
||||
from kitty.simple_cli_definitions import CONFIG_HELP
|
||||
del sys.modules['kittens.hints.main']
|
||||
del sys.modules['kittens.query_terminal.main']
|
||||
ref_map = load_ref_map()
|
||||
@@ -637,7 +635,6 @@ type VersionType struct {{
|
||||
const VersionString string = "{kc.str_version}"
|
||||
const WebsiteBaseURL string = "{kc.website_base_url}"
|
||||
const FileTransferCode int = {FILE_TRANSFER_CODE}
|
||||
const DndCode int = {DND_CODE}
|
||||
const ImagePlaceholderChar rune = {placeholder_char}
|
||||
const SSHControlMasterTemplate = "{kc.ssh_control_master_template}"
|
||||
const RC_ENCRYPTION_PROTOCOL_VERSION string = "{kc.RC_ENCRYPTION_PROTOCOL_VERSION}"
|
||||
@@ -649,7 +646,6 @@ const HintsDefaultRegex = `{DEFAULT_REGEX}`
|
||||
const DefaultTermName = `{Options.term}`
|
||||
const DefaultUrlStyle = `{url_style}`
|
||||
const DefaultUrlColor = `{Options.url_color.as_sharp}`
|
||||
const ConfigHelp = "{serialize_as_go_string(CONFIG_HELP)}"
|
||||
var Version VersionType = VersionType{{Major: {kc.version.major}, Minor: {kc.version.minor}, Patch: {kc.version.patch},}}
|
||||
var DefaultPager []string = []string{{ {dp} }}
|
||||
var FunctionalKeyNameAliases = map[string]string{serialize_go_dict(functional_key_name_aliases)}
|
||||
@@ -662,7 +658,7 @@ var QueryNames = []string{{ {query_names} }}
|
||||
var CommentedOutDefaultConfig = "{serialize_as_go_string(commented_out_default_config())}"
|
||||
var KittyConfigDefaults = struct {{
|
||||
Term, Shell_integration, Select_by_word_characters, Url_excluded_characters, Shell string
|
||||
Wheel_scroll_multiplier float64
|
||||
Wheel_scroll_multiplier int
|
||||
Url_prefixes []string
|
||||
}}{{
|
||||
Term: "{Options.term}", Shell_integration: "{' '.join(Options.shell_integration)}", Url_prefixes: []string{{ {url_prefixes} }},
|
||||
@@ -727,7 +723,7 @@ def update_at_commands() -> None:
|
||||
odef = '\n'.join(opt_def)
|
||||
code = f'''
|
||||
package at
|
||||
import "github.com/kovidgoyal/kitty/tools/cli"
|
||||
import "kitty/tools/cli"
|
||||
type rc_global_options struct {{
|
||||
{sdef}
|
||||
}}
|
||||
@@ -755,11 +751,10 @@ def update_completion() -> None:
|
||||
|
||||
with replace_if_needed('tools/cmd/edit_in_kitty/launch_generated.go'):
|
||||
print('package edit_in_kitty')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('import "kitty/tools/cli"')
|
||||
print('func AddCloneSafeOpts(cmd *cli.Command) {')
|
||||
completion_for_launch_wrappers('cmd')
|
||||
m = ','.join(text_mimes)
|
||||
print(''.join(CompletionSpec.from_string(f'type:file mime:text/*,{m} ext:bash,zsh group:"Text files"').as_go_code('cmd.ArgCompleter', ' = ')))
|
||||
print(''.join(CompletionSpec.from_string('type:file mime:text/* group:"Text files"').as_go_code('cmd.ArgCompleter', ' = ')))
|
||||
print('}')
|
||||
|
||||
|
||||
|
||||
11101
gen/nerd-fonts-glyphs.txt
Normal file
11101
gen/nerd-fonts-glyphs.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ def generate_srgb_lut(line_prefix: str = ' ') -> list[str]:
|
||||
lines: list[str] = []
|
||||
|
||||
for i in range(256):
|
||||
values.append(f'{to_linear(i / 255.0):1.8f}f')
|
||||
values.append(f'{to_linear(i / 255.0):1.5f}f')
|
||||
|
||||
for i in range(16):
|
||||
lines.append(line_prefix + ', '.join(values[i * 16:(i + 1) * 16]) + ',')
|
||||
|
||||
@@ -14,7 +14,18 @@ from functools import lru_cache, partial
|
||||
from html.entities import html5
|
||||
from io import StringIO
|
||||
from math import ceil, log
|
||||
from typing import Callable, DefaultDict, Iterator, Literal, NamedTuple, Optional, Protocol, Sequence, TypedDict, TypeVar, Union
|
||||
from typing import (
|
||||
Callable,
|
||||
DefaultDict,
|
||||
Iterator,
|
||||
Literal,
|
||||
NamedTuple,
|
||||
Optional,
|
||||
Protocol,
|
||||
Sequence,
|
||||
TypedDict,
|
||||
Union,
|
||||
)
|
||||
from urllib.request import urlopen
|
||||
|
||||
if __name__ == '__main__' and not __package__:
|
||||
@@ -32,7 +43,8 @@ if len(non_characters) != 66:
|
||||
emoji_skin_tone_modifiers = frozenset(range(0x1f3fb, 0x1F3FF + 1))
|
||||
|
||||
|
||||
def fetch_url(url: str) -> str:
|
||||
def get_data(fname: str, folder: str = 'UCD') -> Iterable[str]:
|
||||
url = f'https://www.unicode.org/Public/{folder}/latest/{fname}'
|
||||
bn = os.path.basename(url)
|
||||
local = os.path.join('/tmp', bn)
|
||||
if os.path.exists(local):
|
||||
@@ -42,12 +54,7 @@ def fetch_url(url: str) -> str:
|
||||
data = urlopen(url).read()
|
||||
with open(local, 'wb') as f:
|
||||
f.write(data)
|
||||
return data.decode()
|
||||
|
||||
|
||||
def get_data(fname: str, folder: str = 'UCD') -> Iterable[str]:
|
||||
url = f'https://www.unicode.org/Public/{folder}/latest/{fname}'
|
||||
for line in fetch_url(url).splitlines():
|
||||
for line in data.decode('utf-8').splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
yield line
|
||||
@@ -144,13 +151,13 @@ def parse_ucd() -> None:
|
||||
# the future.
|
||||
marks.add(codepoint)
|
||||
|
||||
gndata = fetch_url('https://raw.githubusercontent.com/ryanoasis/nerd-fonts/refs/heads/master/glyphnames.json')
|
||||
for name, val in json.loads(gndata).items():
|
||||
if name != 'METADATA':
|
||||
codepoint = int(val['code'], 16)
|
||||
category, sep, name = name.rpartition('-')
|
||||
name = name or category
|
||||
name = name.replace('_', ' ')
|
||||
with open('gen/nerd-fonts-glyphs.txt') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
code, category, name = line.split(' ', 2)
|
||||
codepoint = int(code, 16)
|
||||
if name and codepoint not in name_map:
|
||||
name_map[codepoint] = name.upper()
|
||||
for word in name.lower().split():
|
||||
@@ -455,9 +462,7 @@ def mask_for(bits: int) -> int:
|
||||
return ~((~0) << bits)
|
||||
|
||||
|
||||
HashableType = TypeVar('HashableType', bound=Hashable)
|
||||
|
||||
def splitbins(t: tuple[HashableType, ...], property_size: int, use_fixed_shift: int = 0) -> tuple[list[int], list[int], list[HashableType], int]:
|
||||
def splitbins[T: Hashable](t: tuple[T, ...], property_size: int, use_fixed_shift: int = 0) -> tuple[list[int], list[int], list[T], int]:
|
||||
if use_fixed_shift:
|
||||
candidates = range(use_fixed_shift, use_fixed_shift + 1)
|
||||
else:
|
||||
@@ -468,8 +473,8 @@ def splitbins(t: tuple[HashableType, ...], property_size: int, use_fixed_shift:
|
||||
n >>= 1
|
||||
maxshift += 1
|
||||
candidates = range(maxshift + 1)
|
||||
t3: list[HashableType] = []
|
||||
tmap: dict[HashableType, int] = {}
|
||||
t3: list[T] = []
|
||||
tmap: dict[T, int] = {}
|
||||
seen = set()
|
||||
for x in t:
|
||||
if x not in seen:
|
||||
|
||||
@@ -10,8 +10,7 @@ import subprocess
|
||||
|
||||
cmdline = (
|
||||
'glad --out-path {dest} --api gl:core=3.1 '
|
||||
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,'
|
||||
'GL_ARB_instanced_arrays,GL_KHR_debug,GL_ARB_framebuffer_sRGB,GL_EXT_framebuffer_sRGB '
|
||||
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,GL_ARB_instanced_arrays,GL_KHR_debug '
|
||||
'c --header-only --debug'
|
||||
)
|
||||
|
||||
|
||||
32
glfw/backend_utils.c
vendored
32
glfw/backend_utils.c
vendored
@@ -31,6 +31,7 @@ update_fds(EventLoopData *eld) {
|
||||
}
|
||||
}
|
||||
|
||||
static id_type watch_counter = 0;
|
||||
|
||||
id_type
|
||||
addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data) {
|
||||
@@ -38,7 +39,6 @@ addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled,
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many watches added");
|
||||
return 0;
|
||||
}
|
||||
static id_type watch_counter = 0;
|
||||
Watch *w = eld->watches + eld->watches_count++;
|
||||
w->name = name;
|
||||
w->fd = fd; w->events = events; w->enabled = enabled;
|
||||
@@ -234,12 +234,6 @@ mark_wakep_fd_ready(int fd UNUSED, int events UNUSED, void *data) {
|
||||
((EventLoopData*)(data))->wakeup_fd_ready = true;
|
||||
}
|
||||
|
||||
static void
|
||||
mark_key_repeat_fd_ready(int fd UNUSED, int events UNUSED, void *data) {
|
||||
((EventLoopData*)(data))->key_repeat_fd_ready = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
initPollData(EventLoopData *eld, int display_fd) {
|
||||
if (!addWatch(eld, "display", display_fd, POLLIN, 1, NULL, NULL)) return false;
|
||||
@@ -252,20 +246,6 @@ initPollData(EventLoopData *eld, int display_fd) {
|
||||
const int wakeup_fd = eld->wakeupFds[0];
|
||||
#endif
|
||||
if (!addWatch(eld, "wakeup", wakeup_fd, POLLIN, 1, mark_wakep_fd_ready, eld)) return false;
|
||||
|
||||
#ifdef HAS_TIMER_FD
|
||||
eld->key_repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
if (eld->key_repeat_fd < 0) return false;
|
||||
const int key_repeat_fd = eld->key_repeat_fd;
|
||||
#else
|
||||
if (pipe2(eld->key_repeat_fds, O_CLOEXEC | O_NONBLOCK) != 0) return false;
|
||||
const int key_repeat_fd = eld->key_repeat_fds[0];
|
||||
#endif
|
||||
#ifdef _GLFW_WAYLAND
|
||||
if (!addWatch(eld, "key_repeat", key_repeat_fd, POLLIN, 1, mark_key_repeat_fd_ready, eld)) return false;
|
||||
#else
|
||||
(void)key_repeat_fd; (void)mark_key_repeat_fd_ready;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -289,6 +269,7 @@ wakeupEventLoop(EventLoopData *eld) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAS_EVENT_FD
|
||||
static void
|
||||
closeFds(int *fds, size_t count) {
|
||||
while(count--) {
|
||||
@@ -299,20 +280,15 @@ closeFds(int *fds, size_t count) {
|
||||
fds++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
finalizePollData(EventLoopData *eld) {
|
||||
(void)closeFds;
|
||||
#ifdef HAS_EVENT_FD
|
||||
close(eld->wakeupFd); eld->wakeupFd = -1;
|
||||
#else
|
||||
closeFds(eld->wakeupFds, arraysz(eld->wakeupFds));
|
||||
#endif
|
||||
#ifdef HAS_TIMER_FD
|
||||
close(eld->key_repeat_fd); eld->key_repeat_fd = -1;
|
||||
#else
|
||||
closeFds(eld->key_repeat_fds, arraysz(eld->key_repeat_fds));
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
@@ -322,7 +298,7 @@ pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func displ
|
||||
EVDBG("pollForEvents final timeout: %.3f", monotonic_t_to_s_double(timeout));
|
||||
int result;
|
||||
monotonic_t end_time = monotonic() + timeout;
|
||||
eld->wakeup_fd_ready = false; eld->key_repeat_fd_ready = false;
|
||||
eld->wakeup_fd_ready = false;
|
||||
|
||||
while(1) {
|
||||
if (timeout >= 0) {
|
||||
|
||||
16
glfw/backend_utils.h
vendored
16
glfw/backend_utils.h
vendored
@@ -36,10 +36,6 @@
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
#if __has_include(<sys/timerfd.h>)
|
||||
#define HAS_TIMER_FD
|
||||
#include <sys/timerfd.h>
|
||||
#endif
|
||||
#else
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
@@ -69,23 +65,17 @@ typedef struct {
|
||||
bool repeats;
|
||||
} Timer;
|
||||
|
||||
#define MAX_NUM_OF_WATCHED_FDS 64
|
||||
|
||||
typedef struct {
|
||||
struct pollfd fds[MAX_NUM_OF_WATCHED_FDS];
|
||||
struct pollfd fds[32];
|
||||
#ifdef HAS_EVENT_FD
|
||||
int wakeupFd;
|
||||
#else
|
||||
int wakeupFds[2];
|
||||
#endif
|
||||
#ifdef HAS_TIMER_FD
|
||||
int key_repeat_fd;
|
||||
#else
|
||||
int key_repeat_fds[2];
|
||||
#endif
|
||||
bool wakeup_data_read, wakeup_fd_ready, key_repeat_fd_ready;
|
||||
bool wakeup_data_read, wakeup_fd_ready;
|
||||
nfds_t watches_count, timers_count;
|
||||
Watch watches[MAX_NUM_OF_WATCHED_FDS];
|
||||
Watch watches[32];
|
||||
Timer timers[128];
|
||||
} EventLoopData;
|
||||
|
||||
|
||||
@@ -10,36 +10,21 @@
|
||||
|
||||
#include "internal.h"
|
||||
#include <CoreVideo/CVDisplayLink.h>
|
||||
#include <os/lock.h>
|
||||
|
||||
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL s_to_monotonic_t(30ll)
|
||||
#define MAX_NUM_OF_DISPLAYS 256
|
||||
|
||||
typedef struct _GLFWDisplayLinkNS
|
||||
{
|
||||
CVDisplayLinkRef displayLink;
|
||||
CGDirectDisplayID displayID;
|
||||
monotonic_t lastRenderFrameRequestedAt, first_unserviced_render_frame_request_at;
|
||||
bool pending_dispatch;
|
||||
} _GLFWDisplayLinkNS;
|
||||
|
||||
static struct {
|
||||
_GLFWDisplayLinkNS entries[MAX_NUM_OF_DISPLAYS];
|
||||
os_unfair_lock locks[MAX_NUM_OF_DISPLAYS];
|
||||
bool locks_initialized[MAX_NUM_OF_DISPLAYS];
|
||||
_GLFWDisplayLinkNS entries[256];
|
||||
size_t count;
|
||||
} displayLinks = {0};
|
||||
|
||||
static inline size_t
|
||||
index_for_entry(_GLFWDisplayLinkNS *entry) {
|
||||
return (size_t)(entry - displayLinks.entries);
|
||||
}
|
||||
|
||||
static inline os_unfair_lock*
|
||||
lock_for_entry(_GLFWDisplayLinkNS *entry) {
|
||||
return &displayLinks.locks[index_for_entry(entry)];
|
||||
}
|
||||
|
||||
static CGDirectDisplayID
|
||||
displayIDForWindow(_GLFWwindow *w) {
|
||||
NSWindow *nw = w->ns.object;
|
||||
@@ -52,78 +37,48 @@ displayIDForWindow(_GLFWwindow *w) {
|
||||
void
|
||||
_glfwClearDisplayLinks(void) {
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *entry = &displayLinks.entries[i];
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
CVDisplayLinkRef link = entry->displayLink;
|
||||
entry->displayLink = NULL;
|
||||
entry->displayID = (CGDirectDisplayID)0;
|
||||
entry->lastRenderFrameRequestedAt = 0;
|
||||
entry->first_unserviced_render_frame_request_at = 0;
|
||||
entry->pending_dispatch = false;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
if (displayLinks.entries[i].displayLink) {
|
||||
CVDisplayLinkStop(displayLinks.entries[i].displayLink);
|
||||
CVDisplayLinkRelease(displayLinks.entries[i].displayLink);
|
||||
}
|
||||
}
|
||||
memset(displayLinks.entries, 0, sizeof(_GLFWDisplayLinkNS) * displayLinks.count);
|
||||
displayLinks.count = 0;
|
||||
}
|
||||
|
||||
static void _glfwDispatchRenderFrame(void *);
|
||||
|
||||
static CVReturn
|
||||
displayLinkCallback(
|
||||
CVDisplayLinkRef displayLink UNUSED,
|
||||
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
|
||||
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo) {
|
||||
_GLFWDisplayLinkNS *entry = (_GLFWDisplayLinkNS *)userInfo;
|
||||
if (entry) {
|
||||
os_unfair_lock *lock = lock_for_entry(entry);
|
||||
os_unfair_lock_lock(lock);
|
||||
const bool should_dispatch = entry->first_unserviced_render_frame_request_at &&
|
||||
!entry->pending_dispatch;
|
||||
CGDirectDisplayID displayID = entry->displayID;
|
||||
if (should_dispatch) entry->pending_dispatch = true;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (should_dispatch) dispatch_async_f(dispatch_get_main_queue(), (void*)(uintptr_t)displayID, _glfwDispatchRenderFrame);
|
||||
}
|
||||
CGDirectDisplayID displayID = (uintptr_t)userInfo;
|
||||
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
|
||||
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
|
||||
[arg release];
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
static void
|
||||
_glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
|
||||
CVDisplayLinkCreateWithCGDisplay(entry->displayID, &entry->displayLink);
|
||||
if (entry->displayLink) CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, entry);
|
||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_glfwCreateDisplayLink(CGDirectDisplayID displayID) {
|
||||
for (unsigned i = 0; i < displayLinks.count; i++) {
|
||||
os_unfair_lock *existing_lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(existing_lock);
|
||||
const bool already_created = displayLinks.entries[i].displayID == displayID;
|
||||
os_unfair_lock_unlock(existing_lock);
|
||||
if (already_created) return i;
|
||||
}
|
||||
if (displayLinks.count >= MAX_NUM_OF_DISPLAYS) {
|
||||
if (displayLinks.count >= arraysz(displayLinks.entries) - 1) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many monitors cannot create display link");
|
||||
return displayLinks.count;
|
||||
}
|
||||
unsigned idx = displayLinks.count;
|
||||
_GLFWDisplayLinkNS *entry = &displayLinks.entries[idx];
|
||||
if (!displayLinks.locks_initialized[idx]) {
|
||||
displayLinks.locks[idx] = OS_UNFAIR_LOCK_INIT;
|
||||
displayLinks.locks_initialized[idx] = true;
|
||||
for (unsigned i = 0; i < displayLinks.count; i++) {
|
||||
// already created in this run
|
||||
if (displayLinks.entries[i].displayID == displayID) return i;
|
||||
}
|
||||
os_unfair_lock *lock = &displayLinks.locks[idx];
|
||||
os_unfair_lock_lock(lock);
|
||||
memset(entry, 0, sizeof(entry[0]));
|
||||
_GLFWDisplayLinkNS *entry = &displayLinks.entries[displayLinks.count++];
|
||||
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
|
||||
entry->displayID = displayID;
|
||||
displayLinks.count++;
|
||||
_glfw_create_cv_display_link(entry);
|
||||
os_unfair_lock_unlock(lock);
|
||||
return idx;
|
||||
return displayLinks.count - 1;
|
||||
}
|
||||
|
||||
static unsigned long long display_link_shutdown_timer = 0;
|
||||
@@ -133,18 +88,9 @@ _glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data U
|
||||
display_link_shutdown_timer = 0;
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *dl = &displayLinks.entries[i];
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
CVDisplayLinkRef link = dl->displayLink;
|
||||
if (link) CVDisplayLinkRetain(link);
|
||||
if (dl->displayLink) CVDisplayLinkStop(dl->displayLink);
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
dl->first_unserviced_render_frame_request_at = 0;
|
||||
dl->pending_dispatch = false;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,89 +107,40 @@ _glfwRequestRenderFrame(_GLFWwindow *w) {
|
||||
_GLFWDisplayLinkNS *dl = NULL;
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
dl = &displayLinks.entries[i];
|
||||
bool need_start = false, need_stop = false, need_recreate = false;
|
||||
bool retain_link = false;
|
||||
CVDisplayLinkRef link = NULL;
|
||||
CVDisplayLinkRef new_link = NULL;
|
||||
bool new_link_retained = false;
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
link = dl->displayLink;
|
||||
if (dl->displayID == displayID) {
|
||||
found_display_link = true;
|
||||
monotonic_t first_unserviced = dl->first_unserviced_render_frame_request_at;
|
||||
dl->lastRenderFrameRequestedAt = now;
|
||||
if (!first_unserviced) {
|
||||
if (!dl->first_unserviced_render_frame_request_at) dl->first_unserviced_render_frame_request_at = now;
|
||||
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
||||
else if (now - dl->first_unserviced_render_frame_request_at > s_to_monotonic_t(1ll)) {
|
||||
// display link is stuck need to recreate it because Apple can't even
|
||||
// get a simple timer right
|
||||
CVDisplayLinkRelease(dl->displayLink); dl->displayLink = nil;
|
||||
dl->first_unserviced_render_frame_request_at = now;
|
||||
first_unserviced = now;
|
||||
_glfw_create_cv_display_link(dl);
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"CVDisplayLink stuck possibly because of sleep/screensaver + Apple's incompetence, recreating.");
|
||||
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
||||
}
|
||||
dl->pending_dispatch = false;
|
||||
if (link) {
|
||||
if (!CVDisplayLinkIsRunning(link)) {
|
||||
need_start = true;
|
||||
retain_link = true;
|
||||
} else if (now - first_unserviced > s_to_monotonic_t(1ll)) {
|
||||
need_recreate = true;
|
||||
dl->first_unserviced_render_frame_request_at = now;
|
||||
dl->displayLink = NULL;
|
||||
}
|
||||
}
|
||||
} else if (link && dl->lastRenderFrameRequestedAt && now - dl->lastRenderFrameRequestedAt >= DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL) {
|
||||
need_stop = true;
|
||||
retain_link = true;
|
||||
} else if (dl->displayLink && dl->lastRenderFrameRequestedAt && now - dl->lastRenderFrameRequestedAt >= DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL) {
|
||||
CVDisplayLinkStop(dl->displayLink);
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
dl->first_unserviced_render_frame_request_at = 0;
|
||||
dl->pending_dispatch = false;
|
||||
}
|
||||
if (retain_link && link) CVDisplayLinkRetain(link);
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (need_recreate && link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
os_unfair_lock_lock(lock);
|
||||
_glfw_create_cv_display_link(dl);
|
||||
new_link = dl->displayLink;
|
||||
if (new_link) {
|
||||
CVDisplayLinkRetain(new_link);
|
||||
new_link_retained = true;
|
||||
}
|
||||
dl->pending_dispatch = false;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (new_link) {
|
||||
if (!CVDisplayLinkIsRunning(new_link)) CVDisplayLinkStart(new_link);
|
||||
if (new_link_retained) CVDisplayLinkRelease(new_link);
|
||||
}
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"CVDisplayLink stuck possibly because of sleep/screensaver + Apple's incompetence, recreating.");
|
||||
} else {
|
||||
if (need_start && link) CVDisplayLinkStart(link);
|
||||
else if (need_stop && link) CVDisplayLinkStop(link);
|
||||
if (retain_link && link) CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
if (!found_display_link) {
|
||||
unsigned idx = _glfwCreateDisplayLink(displayID);
|
||||
if (idx < displayLinks.count) {
|
||||
dl = &displayLinks.entries[idx];
|
||||
os_unfair_lock *lock = &displayLinks.locks[idx];
|
||||
os_unfair_lock_lock(lock);
|
||||
dl->lastRenderFrameRequestedAt = now;
|
||||
dl->first_unserviced_render_frame_request_at = now;
|
||||
dl->pending_dispatch = false;
|
||||
CVDisplayLinkRef link = dl->displayLink;
|
||||
if (link) CVDisplayLinkRetain(link);
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (link) {
|
||||
if (!CVDisplayLinkIsRunning(link)) CVDisplayLinkStart(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_glfwDispatchRenderFrame(void *passed_in_data) {
|
||||
CGDirectDisplayID displayID = (uintptr_t)passed_in_data;
|
||||
void
|
||||
_glfwDispatchRenderFrame(CGDirectDisplayID displayID) {
|
||||
_GLFWwindow *w = _glfw.windowListHead;
|
||||
while (w) {
|
||||
if (w->ns.renderFrameRequested && displayID == displayIDForWindow(w)) {
|
||||
@@ -254,33 +151,10 @@ _glfwDispatchRenderFrame(void *passed_in_data) {
|
||||
}
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *dl = &displayLinks.entries[i];
|
||||
bool need_stop = false;
|
||||
CVDisplayLinkRef link = NULL;
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
if (dl->displayID == displayID) {
|
||||
dl->first_unserviced_render_frame_request_at = 0;
|
||||
dl->pending_dispatch = false;
|
||||
bool any_pending_request = false;
|
||||
_GLFWwindow *window = _glfw.windowListHead;
|
||||
while (window) {
|
||||
if (window->ns.renderFrameRequested && displayID == displayIDForWindow(window)) {
|
||||
any_pending_request = true;
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
}
|
||||
link = dl->displayLink;
|
||||
if (!any_pending_request && link && CVDisplayLinkIsRunning(link)) {
|
||||
need_stop = true;
|
||||
CVDisplayLinkRetain(link);
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
}
|
||||
}
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (need_stop && link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "internal.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
#include <sys/param.h> // For MAXPATHLEN
|
||||
#include <sys/sysctl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// Needed for _NSGetProgname
|
||||
@@ -298,37 +297,10 @@ static NSDictionary<NSString*,NSNumber*> *global_shortcuts = nil;
|
||||
// Delegate for application related notifications {{{
|
||||
|
||||
@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
|
||||
- (void)handleAppearanceChange;
|
||||
@end
|
||||
|
||||
@implementation GLFWApplicationDelegate
|
||||
|
||||
- (void)applicationDidActivate:(NSNotification *)notification {
|
||||
NSRunningApplication *app = notification.userInfo[NSWorkspaceApplicationKey];
|
||||
if (app && app.processIdentifier != getpid()) {
|
||||
_glfw.ns.previous_front_most_application = app.processIdentifier;
|
||||
debug_rendering("Front most application changed to: %s pid: %d\n", app.bundleIdentifier.UTF8String, app.processIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||
(void)notification;
|
||||
// When the application becomes active after switching spaces (e.g., swiping
|
||||
// back from a fullscreen app on another space), macOS may not send
|
||||
// windowDidBecomeKey: for the already-key window. This leaves GLFW thinking
|
||||
// no window has focus (since windowDidResignKey: was sent when leaving).
|
||||
// Ensure GLFW's focus state is updated to match the actual key window.
|
||||
NSWindow *keyWindow = [NSApp keyWindow];
|
||||
if (keyWindow && !_glfw.focusedWindowId) {
|
||||
for (_GLFWwindow *window = _glfw.windowListHead; window; window = window->next) {
|
||||
if (window->ns.object == keyWindow) {
|
||||
if (_glfw.focusedWindowId != window->id) _glfwInputWindowFocus(window, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
(void)sender;
|
||||
@@ -435,76 +407,20 @@ static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void *AppearanceObservationContext = &AppearanceObservationContext;
|
||||
static NSDate *application_finished_launching_at = nil;
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
[[NSApplication sharedApplication] addObserver:self
|
||||
forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
|
||||
context:AppearanceObservationContext];
|
||||
|
||||
if (finish_launching_callback) finish_launching_callback(true);
|
||||
(void)notification;
|
||||
[NSApp stop:nil];
|
||||
|
||||
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
||||
_glfwCocoaPostEmptyEvent();
|
||||
application_finished_launching_at = [NSDate date];
|
||||
}
|
||||
|
||||
GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized) {
|
||||
(void)query_if_unintialized;
|
||||
int theme_type = GLFW_COLOR_SCHEME_NO_PREFERENCE;
|
||||
NSAppearance *changedAppearance = NSApp.effectiveAppearance;
|
||||
NSAppearanceName newAppearance = [changedAppearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
|
||||
if([newAppearance isEqualToString:NSAppearanceNameDarkAqua]){
|
||||
theme_type = GLFW_COLOR_SCHEME_DARK;
|
||||
} else {
|
||||
theme_type = GLFW_COLOR_SCHEME_LIGHT;
|
||||
}
|
||||
return theme_type;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
|
||||
context:(void *)context {
|
||||
if (context == AppearanceObservationContext) {
|
||||
if ([keyPath isEqualToString:@"effectiveAppearance"]) {
|
||||
// The initial call (from NSKeyValueObservingOptionInitial) might happen on a background thread.
|
||||
// Dispatch to the main thread to be safe, especially if updating UI.
|
||||
__block __typeof__(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf handleAppearanceChange];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If the context doesn't match, pass the notification to the superclass.
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleAppearanceChange {
|
||||
static GLFWColorScheme previously_reported_appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE;
|
||||
GLFWColorScheme new_appearance = glfwGetCurrentSystemColorTheme(true);
|
||||
if (new_appearance != previously_reported_appearance) {
|
||||
previously_reported_appearance = new_appearance;
|
||||
_glfwInputColorScheme(new_appearance, false);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
(void)aNotification;
|
||||
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
|
||||
@try {
|
||||
[[NSApplication sharedApplication] removeObserver:self
|
||||
forKeyPath:@"effectiveAppearance"
|
||||
context:AppearanceObservationContext];
|
||||
} @catch (NSException * __unused exception) {
|
||||
// Ignore exceptions, which can happen if the observer was never added.
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidHide:(NSNotification *)notification
|
||||
@@ -522,6 +438,7 @@ GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialize
|
||||
|
||||
@interface GLFWApplication : NSApplication
|
||||
- (void)tick_callback;
|
||||
- (void)render_frame_received:(id)displayIDAsID;
|
||||
@end
|
||||
|
||||
@implementation GLFWApplication
|
||||
@@ -530,6 +447,11 @@ GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialize
|
||||
_glfwDispatchTickCallback();
|
||||
}
|
||||
|
||||
- (void)render_frame_received:(id)displayIDAsID
|
||||
{
|
||||
CGDirectDisplayID displayID = [(NSNumber*)displayIDAsID unsignedIntValue];
|
||||
_glfwDispatchRenderFrame(displayID);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@@ -857,24 +779,6 @@ is_apple_jis_layout_function_key(NSEvent *event) {
|
||||
return [event keyCode] == 0x66 /* kVK_JIS_Eisu */ || [event keyCode] == 0x68 /* kVK_JIS_Kana */;
|
||||
}
|
||||
|
||||
static bool
|
||||
has_apple_fn_global_shortcut(void) {
|
||||
NSDictionary *hitoolbox_settings = [[NSUserDefaults standardUserDefaults] persistentDomainForName:@"com.apple.HIToolbox"];
|
||||
id obj = [hitoolbox_settings objectForKey:@"AppleFnUsageType"];
|
||||
if (![obj isKindOfClass:[NSNumber class]]) return false;
|
||||
// Non-zero AppleFnUsageType means macOS has reserved Fn/Globe for a
|
||||
// system action such as input source switching, emoji picker, or dictation.
|
||||
return [obj integerValue] != 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_apple_fn_global_shortcut(NSEvent *event) {
|
||||
if ([event keyCode] != 0x3f /* kVK_Function */) return false;
|
||||
NSEventModifierFlags mods = USEFUL_MODS([event modifierFlags]);
|
||||
if (mods != 0 && mods != NSEventModifierFlagFunction) return false;
|
||||
return has_apple_fn_global_shortcut();
|
||||
}
|
||||
|
||||
GLFWAPI GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) {
|
||||
GLFWapplicationshouldhandlereopenfun previous = handle_reopen_callback;
|
||||
handle_reopen_callback = callback;
|
||||
@@ -912,11 +816,6 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
}
|
||||
|
||||
[NSApp setDelegate:_glfw.ns.delegate];
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter]
|
||||
addObserver:_glfw.ns.delegate
|
||||
selector:@selector(applicationDidActivate:)
|
||||
name:NSWorkspaceDidActivateApplicationNotification
|
||||
object:nil];
|
||||
static struct {
|
||||
unsigned short virtual_key_code;
|
||||
NSEventModifierFlags input_source_switch_modifiers;
|
||||
@@ -927,12 +826,12 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
|
||||
NSEvent* (^keydown_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
debug_input("---------------- key down -------------------\n");
|
||||
debug_input("%s\n", [[event description] UTF8String]);
|
||||
if (!_glfw.ignoreOSKeyboardProcessing && !_glfw.keyboard_grabbed) {
|
||||
debug_key("---------------- key down -------------------\n");
|
||||
debug_key("%s\n", [[event description] UTF8String]);
|
||||
if (!_glfw.ignoreOSKeyboardProcessing) {
|
||||
// first check if there is a global menu bar shortcut
|
||||
if ([[NSApp mainMenu] performKeyEquivalent:event]) {
|
||||
debug_input("keyDown triggered global menu bar action ignoring\n");
|
||||
debug_key("keyDown triggered global menu bar action ignoring\n");
|
||||
last_keydown_shortcut_event.virtual_key_code = [event keyCode];
|
||||
last_keydown_shortcut_event.input_source_switch_modifiers = 0;
|
||||
last_keydown_shortcut_event.timestamp = [event timestamp];
|
||||
@@ -941,7 +840,7 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
// now check if there is a useful apple shortcut
|
||||
int global_shortcut = is_active_apple_global_shortcut(event);
|
||||
if (is_useful_apple_global_shortcut(global_shortcut)) {
|
||||
debug_input("keyDown triggered global macOS shortcut ignoring\n");
|
||||
debug_key("keyDown triggered global macOS shortcut ignoring\n");
|
||||
last_keydown_shortcut_event.virtual_key_code = [event keyCode];
|
||||
// record the modifier keys if switching to the next input source
|
||||
last_keydown_shortcut_event.input_source_switch_modifiers = (global_shortcut == kSHKSelectNextSourceInInputMenu) ? USEFUL_MODS([event modifierFlags]) : 0;
|
||||
@@ -950,7 +849,7 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
}
|
||||
// check for JIS keyboard layout function keys
|
||||
if (is_apple_jis_layout_function_key(event)) {
|
||||
debug_input("keyDown triggered JIS layout function key ignoring\n");
|
||||
debug_key("keyDown triggered JIS layout function key ignoring\n");
|
||||
last_keydown_shortcut_event.virtual_key_code = [event keyCode];
|
||||
last_keydown_shortcut_event.input_source_switch_modifiers = 0;
|
||||
last_keydown_shortcut_event.timestamp = [event timestamp];
|
||||
@@ -960,35 +859,31 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
last_keydown_shortcut_event.virtual_key_code = 0xffff;
|
||||
NSWindow *kw = [NSApp keyWindow];
|
||||
if (kw && kw.contentView) [kw.contentView keyDown:event];
|
||||
else debug_input("keyDown ignored as no keyWindow present\n");
|
||||
else debug_key("keyDown ignored as no keyWindow present\n");
|
||||
return nil;
|
||||
};
|
||||
|
||||
NSEvent* (^keyup_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
debug_input("----------------- key up --------------------\n");
|
||||
debug_input("%s\n", [[event description] UTF8String]);
|
||||
debug_key("----------------- key up --------------------\n");
|
||||
debug_key("%s\n", [[event description] UTF8String]);
|
||||
if (last_keydown_shortcut_event.virtual_key_code != 0xffff && last_keydown_shortcut_event.virtual_key_code == [event keyCode]) {
|
||||
// ignore as the corresponding key down event triggered a menu bar or macOS shortcut
|
||||
last_keydown_shortcut_event.virtual_key_code = 0xffff;
|
||||
debug_input("keyUp ignored as corresponds to previous keyDown that triggered a shortcut\n");
|
||||
debug_key("keyUp ignored as corresponds to previous keyDown that triggered a shortcut\n");
|
||||
return nil;
|
||||
}
|
||||
NSWindow *kw = [NSApp keyWindow];
|
||||
if (kw && kw.contentView) [kw.contentView keyUp:event];
|
||||
else debug_input("keyUp ignored as no keyWindow present\n");
|
||||
else debug_key("keyUp ignored as no keyWindow present\n");
|
||||
return nil;
|
||||
};
|
||||
|
||||
NSEvent* (^flags_changed_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
debug_input("-------------- flags changed -----------------\n");
|
||||
debug_input("%s\n", [[event description] UTF8String]);
|
||||
debug_key("-------------- flags changed -----------------\n");
|
||||
debug_key("%s\n", [[event description] UTF8String]);
|
||||
last_keydown_shortcut_event.virtual_key_code = 0xffff;
|
||||
if (!_glfw.ignoreOSKeyboardProcessing && !_glfw.keyboard_grabbed && is_apple_fn_global_shortcut(event)) {
|
||||
debug_input("flagsChanged triggered global fn shortcut ignoring\n");
|
||||
return event;
|
||||
}
|
||||
// switching to the next input source is only confirmed when all modifier keys are released
|
||||
if (last_keydown_shortcut_event.input_source_switch_modifiers) {
|
||||
if (!([event modifierFlags] & last_keydown_shortcut_event.input_source_switch_modifiers))
|
||||
@@ -997,7 +892,7 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
}
|
||||
NSWindow *kw = [NSApp keyWindow];
|
||||
if (kw && kw.contentView) [kw.contentView flagsChanged:event];
|
||||
else debug_input("flagsChanged ignored as no keyWindow present\n");
|
||||
else debug_key("flagsChanged ignored as no keyWindow present\n");
|
||||
return nil;
|
||||
};
|
||||
|
||||
@@ -1014,16 +909,13 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
if (_glfw.hints.init.ns.chdir)
|
||||
changeToResourcesDirectory();
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
|
||||
NSDictionary* defaults = @{
|
||||
// Press and Hold prevents some keys from emitting repeated characters
|
||||
@"ApplePressAndHoldEnabled": @NO,
|
||||
// Dont generate openFile events from command line arguments
|
||||
@"NSTreatUnknownArgumentsAsOpen": @"NO",
|
||||
// This Tahoe nonsense causes slowdowns in some situations, see for example:
|
||||
// https://issues.chromium.org/issues/452372350 it doesnt affect
|
||||
// autofill via Edit->Autofill
|
||||
@"NSAutoFillHeuristicControllerEnabled" : @NO,
|
||||
}];
|
||||
};
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
|
||||
NSUserDefaults *apple_settings = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.symbolichotkeys"];
|
||||
[apple_settings addObserver:_glfw.ns.helper
|
||||
@@ -1052,47 +944,11 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
static NSDate*
|
||||
get_process_start_time(pid_t pid) {
|
||||
struct kinfo_proc kp;
|
||||
size_t len = sizeof(kp);
|
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
|
||||
|
||||
if (sysctl(mib, 4, &kp, &len, NULL, 0) == 0 && len == sizeof(kp)) {
|
||||
struct timeval start_tv = kp.kp_proc.p_starttime;
|
||||
time_t start_sec = start_tv.tv_sec;
|
||||
suseconds_t start_usec = start_tv.tv_usec;
|
||||
NSTimeInterval t = (NSTimeInterval)start_sec + ((NSTimeInterval)start_usec / 1000000.0);
|
||||
return [NSDate dateWithTimeIntervalSince1970:t];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
// Kill the AutoFill helper process that macOS Tahoe starts and fails to
|
||||
// shutdown on application exit, see https://github.com/kovidgoyal/kitty/issues/9299
|
||||
// Only kill helpers that were launched within a few seconds of this process to
|
||||
// avoid killing helpers from other processes. This is obviously not robust
|
||||
// but since Apple cant design its way out of a paper bag, it's the best we
|
||||
// can do.
|
||||
if (application_finished_launching_at != nil) {
|
||||
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
|
||||
if ([app.bundleIdentifier isEqualToString:@"com.apple.SafariPlatformSupport.Helper"] &&
|
||||
[[app.localizedName lowercaseString] containsString:@"autofill (kitty)"]) {
|
||||
NSDate *st = get_process_start_time(app.processIdentifier);
|
||||
if (st != nil) {
|
||||
NSTimeInterval timeDifference = [application_finished_launching_at timeIntervalSinceDate:st];
|
||||
[st release];
|
||||
if (fabs(timeDifference) <= 5) [app forceTerminate];
|
||||
}
|
||||
}
|
||||
}
|
||||
[application_finished_launching_at release]; application_finished_launching_at = nil;
|
||||
}
|
||||
|
||||
_glfwClearDisplayLinks();
|
||||
|
||||
if (_glfw.ns.inputSource)
|
||||
@@ -1288,4 +1144,3 @@ void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval,
|
||||
}
|
||||
|
||||
void _glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { }
|
||||
bool _glfwPlatformGrabKeyboard(bool grab UNUSED) { return true; /* directly uses _glfw.keyboard_grabbed */ }
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
#include <CoreVideo/CVBase.h>
|
||||
@@ -636,8 +635,6 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay);
|
||||
return monitor->ns.displayID;
|
||||
}
|
||||
|
||||
35
glfw/cocoa_platform.h
vendored
35
glfw/cocoa_platform.h
vendored
@@ -62,6 +62,8 @@ typedef void* id;
|
||||
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
||||
#endif
|
||||
|
||||
#define debug_key(...) if (_glfw.hints.init.debugKeyboard) { fprintf(stderr, __VA_ARGS__); fflush(stderr); }
|
||||
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandleurlopen)(const char*);
|
||||
@@ -114,21 +116,6 @@ typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
|
||||
typedef UInt8 (*PFN_LMGetKbdType)(void);
|
||||
#define LMGetKbdType _glfw.ns.tis.GetKbdType
|
||||
|
||||
typedef struct _GLFWDropData {
|
||||
const char **mimes; // Original MIME list; strings are owned here, never reordered
|
||||
size_t mimes_count;
|
||||
const char **copy_mimes; // Working copy passed to callbacks; pointers into mimes[]
|
||||
size_t copy_mimes_count; // Accepted count after last callback
|
||||
bool drag_accepted;
|
||||
struct {
|
||||
unsigned long long request_id;
|
||||
id temp_dir;
|
||||
id data_map; // map MIME to NSError or NSInputStream
|
||||
id path_map; // map MIME to NSError or NSInputStream or NSUrl
|
||||
id pending_requests;
|
||||
bool promises_loaded;
|
||||
} in_progress_drop;
|
||||
} _GLFWDropData;
|
||||
|
||||
// Cocoa-specific per-window data
|
||||
//
|
||||
@@ -143,23 +130,14 @@ typedef struct _GLFWwindowNS
|
||||
bool retina;
|
||||
bool in_traditional_fullscreen;
|
||||
bool in_fullscreen_transition;
|
||||
bool suppress_frame_constraints;
|
||||
id notch_cover_window;
|
||||
unsigned int notch_cover_color;
|
||||
float notch_cover_opacity;
|
||||
bool titlebar_hidden;
|
||||
unsigned long pre_full_screen_style_mask;
|
||||
CGRect pre_traditional_fullscreen_frame;
|
||||
|
||||
// Cached window properties to filter out duplicate events
|
||||
int width, height;
|
||||
int fbWidth, fbHeight;
|
||||
float xscale, yscale;
|
||||
int blur_radius;
|
||||
bool live_resize_in_progress;
|
||||
struct {
|
||||
struct { CGFloat red, green, blue, alpha; bool was_set; } color; bool transparent;
|
||||
} last_applied_titlebar_settings;
|
||||
|
||||
// The total sum of the distances the cursor has been warped
|
||||
// since the last cursor motion event was processed
|
||||
@@ -185,11 +163,6 @@ typedef struct _GLFWwindowNS
|
||||
// update cursor after switching desktops with Mission Control
|
||||
bool delayed_cursor_update_requested;
|
||||
GLFWcocoarenderframefun resizeCallback;
|
||||
|
||||
// Cached MIME types from drag enter (for move events)
|
||||
_GLFWDropData drop_data;
|
||||
unsigned long long drop_request_counter;
|
||||
|
||||
} _GLFWwindowNS;
|
||||
|
||||
// Cocoa-specific global data
|
||||
@@ -215,7 +188,6 @@ typedef struct _GLFWlibraryNS
|
||||
double restoreCursorPosX, restoreCursorPosY;
|
||||
// The window whose disabled cursor mode is active
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
pid_t previous_front_most_application;
|
||||
|
||||
struct {
|
||||
CFBundleRef bundle;
|
||||
@@ -228,8 +200,6 @@ typedef struct _GLFWlibraryNS
|
||||
// the callback to handle url open events
|
||||
GLFWhandleurlopen url_open_callback;
|
||||
|
||||
// Active drag session (NSDraggingSession*) and view (NSView*)
|
||||
id drag_session, drag_view, drag_image;
|
||||
} _GLFWlibraryNS;
|
||||
|
||||
// Cocoa-specific per-monitor data
|
||||
@@ -273,6 +243,7 @@ void* _glfwLoadLocalVulkanLoaderNS(void);
|
||||
void _glfwClearDisplayLinks(void);
|
||||
void _glfwRestartDisplayLinks(void);
|
||||
unsigned _glfwCreateDisplayLink(CGDirectDisplayID);
|
||||
void _glfwDispatchRenderFrame(CGDirectDisplayID);
|
||||
void _glfwRequestRenderFrame(_GLFWwindow *w);
|
||||
|
||||
// event loop
|
||||
|
||||
1995
glfw/cocoa_window.m
1995
glfw/cocoa_window.m
File diff suppressed because it is too large
Load Diff
32
glfw/egl_context.c
vendored
32
glfw/egl_context.c
vendored
@@ -223,7 +223,6 @@ static int extensionSupportedEGL(const char* extension)
|
||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
assert(window != NULL);
|
||||
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
@@ -388,7 +387,6 @@ bool _glfwInitEGL(void)
|
||||
}
|
||||
|
||||
_glfw.egl.platform = _glfwPlatformGetEGLPlatform(&attribs);
|
||||
_glfw.egl.display = EGL_NO_DISPLAY;
|
||||
if (_glfw.egl.platform)
|
||||
{
|
||||
_glfw.egl.display =
|
||||
@@ -396,18 +394,16 @@ bool _glfwInitEGL(void)
|
||||
_glfwPlatformGetEGLNativeDisplay(),
|
||||
attribs);
|
||||
}
|
||||
else
|
||||
_glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay());
|
||||
|
||||
free(attribs);
|
||||
|
||||
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
||||
_glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay());
|
||||
|
||||
|
||||
EGLint egl_err;
|
||||
if (_glfw.egl.display == EGL_NO_DISPLAY && (egl_err = eglGetError()) != EGL_SUCCESS)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to get EGL display: %s",
|
||||
getEGLErrorString(egl_err));
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return false;
|
||||
@@ -416,8 +412,8 @@ bool _glfwInitEGL(void)
|
||||
if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to initialize EGL: %s display_present: %d egl_platform_present: %d",
|
||||
getEGLErrorString(eglGetError()), _glfw.egl.display != EGL_NO_DISPLAY, _glfw.egl.platform != 0);
|
||||
"EGL: Failed to initialize EGL: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return false;
|
||||
@@ -546,18 +542,18 @@ bool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.egl.KHR_create_context_no_error)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, true);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||
|
||||
@@ -793,8 +789,6 @@ GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
|
||||
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
@@ -809,8 +803,6 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
|
||||
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
|
||||
227
glfw/glfw.py
227
glfw/glfw.py
@@ -2,13 +2,234 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Dict, List, NamedTuple, Optional, Sequence, Tuple
|
||||
|
||||
_plat = sys.platform.lower()
|
||||
is_linux = 'linux' in _plat
|
||||
is_openbsd = 'openbsd' in _plat
|
||||
base = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def null_func() -> None:
|
||||
return None
|
||||
|
||||
|
||||
class CompileKey(NamedTuple):
|
||||
src: str
|
||||
dest: str
|
||||
|
||||
|
||||
class Command(NamedTuple):
|
||||
desc: str
|
||||
cmd: Sequence[str]
|
||||
is_newer_func: Callable[[], bool]
|
||||
on_success: Callable[[], None] = null_func
|
||||
key: Optional[CompileKey] = None
|
||||
keyfile: Optional[str] = None
|
||||
|
||||
|
||||
class ISA(Enum):
|
||||
X86 = 0x03
|
||||
AMD64 = 0x3e
|
||||
ARM64 = 0xb7
|
||||
Other = 0x0
|
||||
|
||||
|
||||
class BinaryArch(NamedTuple):
|
||||
bits: int = 64
|
||||
isa: ISA = ISA.AMD64
|
||||
|
||||
|
||||
class CompilerType(Enum):
|
||||
gcc = 'gcc'
|
||||
clang = 'clang'
|
||||
unknown = 'unknown'
|
||||
|
||||
|
||||
class Env:
|
||||
|
||||
cc: List[str] = []
|
||||
cppflags: List[str] = []
|
||||
cflags: List[str] = []
|
||||
ldflags: List[str] = []
|
||||
library_paths: Dict[str, List[str]] = {}
|
||||
ldpaths: List[str] = []
|
||||
ccver: Tuple[int, int]
|
||||
vcs_rev: str = ''
|
||||
binary_arch: BinaryArch = BinaryArch()
|
||||
native_optimizations: bool = False
|
||||
primary_version: int = 0
|
||||
secondary_version: int = 0
|
||||
xt_version: str = ''
|
||||
has_copy_file_range: bool = False
|
||||
|
||||
# glfw stuff
|
||||
all_headers: List[str] = []
|
||||
sources: List[str] = []
|
||||
wayland_packagedir: str = ''
|
||||
wayland_scanner: str = ''
|
||||
wayland_scanner_code: str = ''
|
||||
wayland_protocols: Tuple[str, ...] = ()
|
||||
|
||||
def __init__(
|
||||
self, cc: List[str] = [], cppflags: List[str] = [], cflags: List[str] = [], ldflags: List[str] = [],
|
||||
library_paths: Dict[str, List[str]] = {}, ldpaths: Optional[List[str]] = None, ccver: Tuple[int, int] = (0, 0),
|
||||
vcs_rev: str = '', binary_arch: BinaryArch = BinaryArch(),
|
||||
native_optimizations: bool = False,
|
||||
):
|
||||
self.cc, self.cppflags, self.cflags, self.ldflags, self.library_paths = cc, cppflags, cflags, ldflags, library_paths
|
||||
self.ldpaths = ldpaths or []
|
||||
self.ccver = ccver
|
||||
self.vcs_rev = vcs_rev
|
||||
self.binary_arch = binary_arch
|
||||
self.native_optimizations = native_optimizations
|
||||
self._cc_version_string = ''
|
||||
self._compiler_type: Optional[CompilerType] = None
|
||||
|
||||
@property
|
||||
def cc_version_string(self) -> str:
|
||||
if not self._cc_version_string:
|
||||
self._cc_version_string = subprocess.check_output(self.cc + ['--version']).decode()
|
||||
return self._cc_version_string
|
||||
|
||||
@property
|
||||
def compiler_type(self) -> CompilerType:
|
||||
if self._compiler_type is None:
|
||||
raw = self.cc_version_string
|
||||
if 'Free Software Foundation' in raw:
|
||||
self._compiler_type = CompilerType.gcc
|
||||
elif 'clang' in raw.lower().split():
|
||||
self._compiler_type = CompilerType.clang
|
||||
else:
|
||||
self._compiler_type = CompilerType.unknown
|
||||
return self._compiler_type
|
||||
|
||||
def copy(self) -> 'Env':
|
||||
ans = Env(self.cc, list(self.cppflags), list(self.cflags), list(self.ldflags), dict(self.library_paths), list(self.ldpaths), self.ccver)
|
||||
ans.all_headers = list(self.all_headers)
|
||||
ans._cc_version_string = self._cc_version_string
|
||||
ans.sources = list(self.sources)
|
||||
ans.wayland_packagedir = self.wayland_packagedir
|
||||
ans.wayland_scanner = self.wayland_scanner
|
||||
ans.wayland_scanner_code = self.wayland_scanner_code
|
||||
ans.wayland_protocols = self.wayland_protocols
|
||||
ans.vcs_rev = self.vcs_rev
|
||||
ans.binary_arch = self.binary_arch
|
||||
ans.native_optimizations = self.native_optimizations
|
||||
ans.primary_version = self.primary_version
|
||||
ans.secondary_version = self.secondary_version
|
||||
ans.xt_version = self.xt_version
|
||||
ans.has_copy_file_range = self.has_copy_file_range
|
||||
return ans
|
||||
|
||||
|
||||
def wayland_protocol_file_name(base: str, ext: str = 'c') -> str:
|
||||
base = os.path.basename(base).rpartition('.')[0]
|
||||
return f'wayland-{base}-client-protocol.{ext}'
|
||||
|
||||
|
||||
def init_env(
|
||||
env: Env,
|
||||
pkg_config: Callable[..., List[str]],
|
||||
pkg_version: Callable[[str], Tuple[int, int]],
|
||||
at_least_version: Callable[..., None],
|
||||
test_compile: Callable[..., Any],
|
||||
module: str = 'x11'
|
||||
) -> Env:
|
||||
ans = env.copy()
|
||||
ans.cflags.append('-fPIC')
|
||||
ans.cppflags.append(f'-D_GLFW_{module.upper()}')
|
||||
ans.cppflags.append('-D_GLFW_BUILD_DLL')
|
||||
|
||||
with open(os.path.join(base, 'source-info.json')) as f:
|
||||
sinfo = json.load(f)
|
||||
module_sources = list(sinfo[module]['sources'])
|
||||
if module in ('x11', 'wayland'):
|
||||
remove = 'null_joystick.c' if is_linux else 'linux_joystick.c'
|
||||
module_sources.remove(remove)
|
||||
|
||||
ans.sources = sinfo['common']['sources'] + module_sources
|
||||
ans.all_headers = [x for x in os.listdir(base) if x.endswith('.h')]
|
||||
|
||||
if module in ('x11', 'wayland'):
|
||||
ans.cflags.append('-pthread')
|
||||
ans.ldpaths.extend('-pthread -lm'.split())
|
||||
if not is_openbsd:
|
||||
ans.ldpaths.extend('-lrt -ldl'.split())
|
||||
major, minor = pkg_version('xkbcommon')
|
||||
if (major, minor) < (0, 5):
|
||||
raise SystemExit('libxkbcommon >= 0.5 required')
|
||||
if major < 1:
|
||||
ans.cflags.append('-DXKB_HAS_NO_UTF32')
|
||||
|
||||
if module == 'x11':
|
||||
for dep in 'x11 xrandr xinerama xcursor xkbcommon xkbcommon-x11 x11-xcb dbus-1'.split():
|
||||
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||
|
||||
elif module == 'cocoa':
|
||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
||||
for f_ in 'Cocoa IOKit CoreFoundation CoreVideo UniformTypeIdentifiers'.split():
|
||||
ans.ldpaths.extend(('-framework', f_))
|
||||
|
||||
elif module == 'wayland':
|
||||
at_least_version('wayland-protocols', *sinfo['wayland_protocols'])
|
||||
ans.wayland_packagedir = os.path.abspath(pkg_config('wayland-protocols', '--variable=pkgdatadir')[0])
|
||||
ans.wayland_scanner = os.path.abspath(pkg_config('wayland-scanner', '--variable=wayland_scanner')[0])
|
||||
scanner_version = tuple(map(int, pkg_config('wayland-scanner', '--modversion')[0].strip().split('.')))
|
||||
ans.wayland_scanner_code = 'private-code' if scanner_version >= (1, 14, 91) else 'code'
|
||||
ans.wayland_protocols = tuple(sinfo[module]['protocols'])
|
||||
for p in ans.wayland_protocols:
|
||||
ans.sources.append(wayland_protocol_file_name(p))
|
||||
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
|
||||
for dep in 'wayland-client wayland-cursor xkbcommon dbus-1'.split():
|
||||
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||
has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
int main(void) {
|
||||
return syscall(__NR_memfd_create, "test", 0);
|
||||
}''')
|
||||
if has_memfd_create:
|
||||
ans.cppflags.append('-DHAS_MEMFD_CREATE')
|
||||
|
||||
return ans
|
||||
|
||||
|
||||
def build_wayland_protocols(
|
||||
env: Env,
|
||||
parallel_run: Callable[[List[Command]], None],
|
||||
emphasis: Callable[[str], str],
|
||||
newer: Callable[..., bool],
|
||||
dest_dir: str
|
||||
) -> None:
|
||||
items = []
|
||||
for protocol in env.wayland_protocols:
|
||||
if '/' in protocol:
|
||||
src = os.path.join(env.wayland_packagedir, protocol)
|
||||
if not os.path.exists(src):
|
||||
raise SystemExit(f'The wayland-protocols package on your system is missing the {protocol} protocol definition file')
|
||||
else:
|
||||
src = os.path.join(os.path.dirname(os.path.abspath(__file__)), protocol)
|
||||
if not os.path.exists(src):
|
||||
raise SystemExit(f'The local Wayland protocol {protocol} is missing from kitty sources')
|
||||
for ext in 'hc':
|
||||
dest = wayland_protocol_file_name(src, ext)
|
||||
dest = os.path.join(dest_dir, dest)
|
||||
if newer(dest, src):
|
||||
q = 'client-header' if ext == 'h' else env.wayland_scanner_code
|
||||
items.append(Command(
|
||||
f'Generating {emphasis(os.path.basename(dest))} ...',
|
||||
[env.wayland_scanner, q, src, dest], lambda: True))
|
||||
if items:
|
||||
parallel_run(items)
|
||||
|
||||
|
||||
class Arg:
|
||||
@@ -88,15 +309,12 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
|
||||
uint32_t glfwGetCocoaKeyEquivalent(uint32_t glfw_key, int glfw_mods, int* cocoa_mods)
|
||||
void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
||||
bool glfwCocoaRecreateGLDrawable(GLFWwindow *w)
|
||||
GLFWcocoarenderframefun glfwCocoaSetWindowResizeCallback(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
||||
void* glfwGetX11Display(void)
|
||||
unsigned long glfwGetX11Window(GLFWwindow* window)
|
||||
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
|
||||
void glfwCocoaCycleThroughOSWindows(bool backwards)
|
||||
void glfwCocoaSetWindowChrome(GLFWwindow* window, unsigned int color, bool use_system_color, unsigned int system_color,\
|
||||
int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable)
|
||||
void glfwCocoaRegisterMIMETypes(GLFWwindow *window, const char **mimes, size_t count)
|
||||
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
|
||||
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
|
||||
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
|
||||
@@ -104,12 +322,11 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
const char* glfwWaylandMissingCapabilities(void)
|
||||
void glfwWaylandRunWithActivationToken(GLFWwindow *handle, GLFWactivationcallback cb, void *cb_data)
|
||||
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
|
||||
void glfwWaylandSetTitlebarHidden(GLFWwindow *handle, bool hidden)
|
||||
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
|
||||
bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle)
|
||||
bool glfwWaylandBeep(GLFWwindow *handle)
|
||||
GLFWLayerShellConfig* glfwWaylandLayerShellConfig(GLFWwindow *handle)
|
||||
pid_t glfwWaylandCompositorPID(void)
|
||||
void glfwConfigureMomentumScroller(double friction, double min_velocity, double max_velocity, unsigned timer_interval)
|
||||
unsigned long long glfwDBusUserNotify(const GLFWDBUSNotificationData *n, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
int glfwSetX11LaunchCommand(GLFWwindow *handle, char **argv, int argc)
|
||||
|
||||
226
glfw/glfw3.h
vendored
226
glfw/glfw3.h
vendored
@@ -109,16 +109,6 @@ extern "C" {
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Include for ssize_t on POSIX systems. On Windows we define it if needed. */
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#if !defined(SSIZE_T_DEFINED)
|
||||
typedef intptr_t ssize_t;
|
||||
#define SSIZE_T_DEFINED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_INCLUDE_VULKAN)
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif /* Vulkan header */
|
||||
@@ -556,30 +546,6 @@ typedef enum GLFWColorScheme {
|
||||
GLFW_COLOR_SCHEME_LIGHT = 2
|
||||
} GLFWColorScheme;
|
||||
|
||||
typedef enum GLFWMomentumType {
|
||||
GLFW_NO_MOMENTUM_DATA = 0,
|
||||
GLFW_MOMENTUM_PHASE_BEGAN = 1,
|
||||
GLFW_MOMENTUM_PHASE_STATIONARY = 2,
|
||||
GLFW_MOMENTUM_PHASE_ACTIVE = 3,
|
||||
GLFW_MOMENTUM_PHASE_ENDED = 4,
|
||||
GLFW_MOMENTUM_PHASE_CANCELED = 5,
|
||||
GLFW_MOMENTUM_PHASE_MAY_BEGIN = 6,
|
||||
} GLFWMomentumType;
|
||||
|
||||
typedef enum GLFWOffsetType {
|
||||
GLFW_SCROLL_OFFSET_LINES = 0,
|
||||
GLFW_SCROLL_OFFEST_V120 = 1,
|
||||
GLFW_SCROLL_OFFEST_HIGHRES = 2,
|
||||
} GLFWOffsetType;
|
||||
|
||||
typedef struct GLFWScrollEvent {
|
||||
double x_offset, y_offset; // offsets are scaled by the window scale for HIGHRES
|
||||
struct { double x, y; } unscaled; // unscaled offsets, aka logical pixels
|
||||
GLFWMomentumType momentum_type;
|
||||
GLFWOffsetType offset_type;
|
||||
int keyboard_modifiers;
|
||||
} GLFWScrollEvent;
|
||||
|
||||
/*! @defgroup joysticks Joysticks
|
||||
* @brief Joystick IDs.
|
||||
*
|
||||
@@ -1090,7 +1056,6 @@ typedef enum {
|
||||
|
||||
#define GLFW_WAYLAND_APP_ID 0x00025001
|
||||
#define GLFW_WAYLAND_BGCOLOR 0x00025002
|
||||
#define GLFW_WAYLAND_WINDOW_TAG 0x00025003
|
||||
/*! @} */
|
||||
|
||||
#define GLFW_NO_API 0
|
||||
@@ -1277,20 +1242,6 @@ typedef struct GLFWwindow GLFWwindow;
|
||||
*/
|
||||
typedef struct GLFWcursor GLFWcursor;
|
||||
|
||||
/*! @brief Opaque drop data object.
|
||||
*
|
||||
* Opaque drop data object representing data from a drag and drop operation.
|
||||
* This object is passed to the drop callback and can be used to query
|
||||
* available MIME types and read the dropped data in chunks.
|
||||
*
|
||||
* @see @ref path_drop
|
||||
* @see @ref glfwGetDropMimeTypes
|
||||
* @see @ref glfwReadDropData
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef enum {
|
||||
GLFW_RELEASE = 0,
|
||||
GLFW_PRESS = 1,
|
||||
@@ -1351,19 +1302,14 @@ typedef struct GLFWkeyevent
|
||||
|
||||
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType;
|
||||
|
||||
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_CENTER, GLFW_EDGE_NONE, GLFW_EDGE_CENTER_SIZED } GLFWEdge;
|
||||
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_CENTER, GLFW_EDGE_NONE } GLFWEdge;
|
||||
|
||||
typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAND} GLFWFocusPolicy;
|
||||
|
||||
typedef struct GLFWLayerShellConfig {
|
||||
GLFWLayerShellType type;
|
||||
GLFWEdge edge;
|
||||
struct {
|
||||
GLFWEdge edge;
|
||||
int requested_top_margin, requested_left_margin, requested_bottom_margin, requested_right_margin;
|
||||
} previous;
|
||||
bool was_toggled_to_fullscreen;
|
||||
char output_name[128];
|
||||
char output_name[64];
|
||||
GLFWFocusPolicy focus_policy;
|
||||
unsigned x_size_in_cells, x_size_in_pixels;
|
||||
unsigned y_size_in_cells, y_size_in_pixels;
|
||||
@@ -1382,39 +1328,6 @@ typedef struct GLFWDBUSNotificationData {
|
||||
int32_t timeout; uint8_t urgency; uint32_t replaces; int muted;
|
||||
} GLFWDBUSNotificationData;
|
||||
|
||||
typedef enum { GLFW_DROP_ENTER, GLFW_DROP_MOVE, GLFW_DROP_LEAVE, GLFW_DROP_DROP, GLFW_DROP_STATUS_UPDATE, GLFW_DROP_DATA_AVAILABLE } GLFWDropEventType;
|
||||
|
||||
/*! @brief Drag operation types.
|
||||
*
|
||||
* These constants specify the type of drag operation (copy, move, or generic).
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef enum {
|
||||
GLFW_DRAG_OPERATION_NONE = 0, // no operation, drop was not accepted
|
||||
/*! Move the dragged data to the destination. */
|
||||
GLFW_DRAG_OPERATION_MOVE = 1,
|
||||
/*! Copy the dragged data to the destination. */
|
||||
GLFW_DRAG_OPERATION_COPY = 2,
|
||||
/*! Generic drag operation (platform decides semantics). */
|
||||
GLFW_DRAG_OPERATION_GENERIC = 4
|
||||
} GLFWDragOperationType;
|
||||
|
||||
|
||||
typedef struct GLFWDropEvent {
|
||||
GLFWDropEventType type;
|
||||
const char **mimes; size_t num_mimes;
|
||||
// Positions are only valid for GLFW_DROP_ENTER and GLFW_DROP_MOVE.
|
||||
// They are in window co-ordinates same as for mouse events
|
||||
double xpos, ypos;
|
||||
struct { GLFWDragOperationType preferred; int allowed, source_actions; } operation;
|
||||
bool from_self; // Only valid upto GLFW_DROP_DROP
|
||||
ssize_t (*read_data)(GLFWwindow *w, struct GLFWDropEvent* ev, char *buffer, size_t sz); // Only valid for GLFW_DROP_DATA_AVAILABLE
|
||||
void (*finish_drop)(GLFWwindow *w, GLFWDragOperationType op); // Only valid for GLFW_DROP_DROP and GLFW_DROP_DATA_AVAILABLE
|
||||
} GLFWDropEvent;
|
||||
typedef void (* GLFWdropeventfun)(GLFWwindow*, GLFWDropEvent *event);
|
||||
|
||||
|
||||
/*! @brief The function pointer type for error callbacks.
|
||||
*
|
||||
* This is the function pointer type for error callbacks. An error callback
|
||||
@@ -1779,7 +1692,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,const GLFWScrollEvent*);
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int);
|
||||
|
||||
/*! @brief The function pointer type for key callbacks.
|
||||
*
|
||||
@@ -1813,77 +1726,32 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,const GLFWScrollEvent*);
|
||||
*/
|
||||
typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
||||
|
||||
typedef enum {
|
||||
GLFW_DRAG_DATA_REQUEST, // request data for specified mime type
|
||||
GLFW_DRAG_CANCELLED,
|
||||
GLFW_DRAG_FINSHED,
|
||||
GLFW_DRAG_ACCEPTED, // mimetype was accepted or NULL if drag was accepted but no mime type specified
|
||||
GLFW_DRAG_ACTION_CHANGED, // action was changed 0 or GLFWDragOperationType
|
||||
GLFW_DRAG_DROPPED, // drop was performed but no data transferred yet
|
||||
} GLFWDragEventType;
|
||||
|
||||
typedef struct GLFWDragSourceItem {
|
||||
const char *mime_type;
|
||||
// Can be on null to provide data when the drag is started should be used only when the data is relatively small
|
||||
const char *optional_data;
|
||||
size_t data_size;
|
||||
bool is_remote_client;
|
||||
int type; // used for file promises type of entry 0 = regular, 1 = symlink, 2 = directory
|
||||
} GLFWDragSourceItem;
|
||||
|
||||
typedef struct GLFWDragEvent {
|
||||
GLFWDragEventType type;
|
||||
// When the drag event callback is called with a mimetype and no data, the
|
||||
// application should set the data ans data_sz and err_num fields.
|
||||
// Once glfw is done reading the data the drag event callback will be
|
||||
// called with the data pointer unchanged. The application is now free
|
||||
// to delete the data, as needed.
|
||||
const char *mime_type;
|
||||
const char *data; size_t data_sz;
|
||||
int err_num; // POSIX error code indicating failure fetching data
|
||||
GLFWDragOperationType action; // can be 0 indicating no action
|
||||
bool drop_maybe_a_cancel; // Happens on wayland compositors that dont implement top-level drag
|
||||
} GLFWDragEvent;
|
||||
|
||||
typedef void (* GLFWdragsourcefun)(GLFWwindow* window, GLFWDragEvent *ev);
|
||||
|
||||
/*! @brief The function pointer type for drag event callbacks.
|
||||
/*! @brief The function pointer type for drag and drop callbacks.
|
||||
*
|
||||
* This is the function pointer type for drag event callbacks. A drag event
|
||||
* This is the function pointer type for drop callbacks. A drop
|
||||
* callback function has the following signature:
|
||||
* @code
|
||||
* int function_name(GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int* mime_count)
|
||||
* int function_name(GLFWwindow* window, const char* mime, const char* text)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] window The window that received the drag event.
|
||||
* @param[in] event The drag event type: @ref GLFW_DRAG_ENTER, @ref GLFW_DRAG_MOVE,
|
||||
* or @ref GLFW_DRAG_LEAVE.
|
||||
* @param[in] xpos The x-coordinate of the drag position in window coordinates.
|
||||
* @param[in] ypos The y-coordinate of the drag position in window coordinates.
|
||||
* @param[in,out] mime_types A writable array of MIME type strings available from the drag source.
|
||||
* For @ref GLFW_DRAG_ENTER and @ref GLFW_DRAG_MOVE events this is non-NULL and contains all
|
||||
* available MIME types. The callback is responsible for sorting this list by priority and
|
||||
* keeping only the MIME types it wants to accept. The first MIME type in the sorted list
|
||||
* will be used for the drop operation. The strings are only valid for the duration of the
|
||||
* callback; if you need to store them, make copies. For @ref GLFW_DRAG_LEAVE events this
|
||||
* is `NULL`.
|
||||
* @param[in,out] mime_count Pointer to the number of MIME types in the array. The callback
|
||||
* should update this to reflect the new count after sorting and filtering. For
|
||||
* @ref GLFW_DRAG_LEAVE events this is `NULL`.
|
||||
* @return For @ref GLFW_DRAG_ENTER and @ref GLFW_DRAG_MOVE events, return non-zero
|
||||
* to accept the drag or zero to reject it. This allows the application to
|
||||
* dynamically accept or reject the drag based on the current position.
|
||||
* Return value is ignored for @ref GLFW_DRAG_LEAVE events.
|
||||
* @param[in] window The window that received the event.
|
||||
* @param[in] mime The UTF-8 encoded drop mime-type
|
||||
* @param[in] data The dropped data or NULL for drag enter events
|
||||
* @param[in] sz The size of the dropped data
|
||||
* @return For drag events should return the priority for the specified mime type. A priority of zero
|
||||
* or lower means the mime type is not accepted. Highest priority will be the finally accepted mime-type.
|
||||
*
|
||||
* @sa @ref drag_events
|
||||
* @sa @ref glfwSetDragCallback
|
||||
* @sa @ref glfwUpdateDragState
|
||||
* @pointer_lifetime The text is valid until the
|
||||
* callback function returns.
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
* @sa @ref path_drop
|
||||
* @sa @ref glfwSetDropCallback
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef int (* GLFWdragfun)(GLFWwindow*, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int* mime_count);
|
||||
typedef int (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||
|
||||
typedef void (* GLFWliveresizefun)(GLFWwindow*, bool);
|
||||
|
||||
@@ -2036,7 +1904,7 @@ typedef struct GLFWimage
|
||||
int height;
|
||||
/*! The pixel data of this image, arranged left-to-right, top-to-bottom.
|
||||
*/
|
||||
const unsigned char* pixels;
|
||||
unsigned char* pixels;
|
||||
} GLFWimage;
|
||||
|
||||
/*! @brief Gamepad input state
|
||||
@@ -2512,7 +2380,6 @@ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, flo
|
||||
* @ingroup monitor
|
||||
*/
|
||||
GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor);
|
||||
GLFWAPI const char* glfwGetMonitorDescription(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Sets the user pointer of the specified monitor.
|
||||
*
|
||||
@@ -3007,7 +2874,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G
|
||||
GLFWAPI bool glfwToggleFullscreen(GLFWwindow *window, unsigned int flags);
|
||||
GLFWAPI bool glfwIsFullscreen(GLFWwindow *window, unsigned int flags);
|
||||
GLFWAPI bool glfwAreSwapsAllowed(const GLFWwindow* window);
|
||||
GLFWAPI const GLFWLayerShellConfig* glfwGetLayerShellConfig(GLFWwindow* handle);
|
||||
GLFWAPI bool glfwSetLayerShellConfig(GLFWwindow* handle, const GLFWLayerShellConfig *value);
|
||||
|
||||
/*! @brief Destroys the specified window and its context.
|
||||
@@ -3705,7 +3571,7 @@ GLFWAPI void glfwMaximizeWindow(GLFWwindow* window);
|
||||
*
|
||||
* @ingroup window
|
||||
*/
|
||||
GLFWAPI void glfwShowWindow(GLFWwindow* window, bool move_to_active_screen);
|
||||
GLFWAPI void glfwShowWindow(GLFWwindow* window);
|
||||
|
||||
/*! @brief Hides the specified window.
|
||||
*
|
||||
@@ -4373,8 +4239,6 @@ GLFWAPI void glfwPostEmptyEvent(void);
|
||||
|
||||
GLFWAPI bool glfwGetIgnoreOSKeyboardProcessing(void);
|
||||
GLFWAPI void glfwSetIgnoreOSKeyboardProcessing(bool enabled);
|
||||
GLFWAPI bool glfwGrabKeyboard(int grab);
|
||||
GLFWAPI void glfwGetKeyboardRepeatDelay(monotonic_t *delay, monotonic_t *interval);
|
||||
|
||||
/*! @brief Returns the value of an input option for the specified window.
|
||||
*
|
||||
@@ -4978,20 +4842,44 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu
|
||||
*/
|
||||
GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback);
|
||||
|
||||
/*! @brief Sets the path drop callback.
|
||||
*
|
||||
* This function sets the path drop callback of the specified window, which is
|
||||
* called when one or more dragged paths are dropped on the window.
|
||||
*
|
||||
* Because the path array and its strings may have been generated specifically
|
||||
* for that event, they are not guaranteed to be valid after the callback has
|
||||
* returned. If you wish to use them after the callback returns, you need to
|
||||
* make a deep copy.
|
||||
*
|
||||
* @param[in] window The window whose callback to set.
|
||||
* @param[in] callback The new file drop callback, or `NULL` to remove the
|
||||
* currently set callback.
|
||||
* @return The previously set callback, or `NULL` if no callback was set or the
|
||||
* library had not been [initialized](@ref intro_init).
|
||||
*
|
||||
* @callback_signature
|
||||
* @code
|
||||
* void function_name(GLFWwindow* window, int path_count, const char* paths[])
|
||||
* @endcode
|
||||
* For more information about the callback parameters, see the
|
||||
* [function pointer type](@ref GLFWdropfun).
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @remark @wayland File drop is currently unimplemented.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref path_drop
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback);
|
||||
GLFWAPI GLFWliveresizefun glfwSetLiveResizeCallback(GLFWwindow* window, GLFWliveresizefun callback);
|
||||
|
||||
GLFWAPI GLFWdropeventfun glfwSetDropEventCallback(GLFWwindow *window, GLFWdropeventfun callback);
|
||||
// ask for update before GLFW_DROP_DROP happens
|
||||
GLFWAPI void glfwRequestDropUpdate(GLFWwindow *window);
|
||||
GLFWAPI int glfwRequestDropData(GLFWwindow *window, const char *mime);
|
||||
GLFWAPI void glfwEndDrop(GLFWwindow *window, GLFWDragOperationType op);
|
||||
GLFWAPI GLFWdragsourcefun glfwSetDragSourceCallback(GLFWwindow* window, GLFWdragsourcefun callback);
|
||||
|
||||
// Start a drag. If called with operations == -1 indicates that previously
|
||||
// requested data via GLFW_DRAG_DATA_REQUEST is ready. operations == -2 means
|
||||
// that the drag image is changed. operations == -3 cancels any existing drag.
|
||||
GLFWAPI int glfwStartDrag(GLFWwindow* window, const GLFWDragSourceItem *items, size_t mime_count, const GLFWimage* thumbnail, int operations, bool needs_toplevel_on_wayland);
|
||||
|
||||
/*! @brief Returns whether the specified joystick is present.
|
||||
*
|
||||
* This function returns whether the specified joystick is present.
|
||||
|
||||
4
glfw/glx_context.c
vendored
4
glfw/glx_context.c
vendored
@@ -658,8 +658,6 @@ bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig UNUSED,
|
||||
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
@@ -674,8 +672,6 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
|
||||
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(None);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
|
||||
4
glfw/ibus_glfw.c
vendored
4
glfw/ibus_glfw.c
vendored
@@ -287,9 +287,7 @@ get_ibus_address_file_name(void) {
|
||||
addr = getenv("IBUS_ADDRESS");
|
||||
int offset = 0;
|
||||
if (addr && addr[0]) {
|
||||
size_t len = GLFW_MIN(strlen(addr), sizeof(ans) - 1);
|
||||
memcpy(ans, addr, len);
|
||||
ans[len] = '\0';
|
||||
memcpy(ans, addr, GLFW_MIN(strlen(addr), sizeof(ans)));
|
||||
return ans;
|
||||
}
|
||||
const char* disp_num = NULL;
|
||||
|
||||
168
glfw/input.c
vendored
168
glfw/input.c
vendored
@@ -31,16 +31,11 @@
|
||||
#include "../kitty/monotonic.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NAME mime_dedup_set
|
||||
#define KEY_TY const char *
|
||||
#include "../3rdparty/verstable.h"
|
||||
|
||||
// Internal key state used for sticky keys
|
||||
#define _GLFW_STICK 3
|
||||
|
||||
@@ -358,10 +353,10 @@ void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
|
||||
|
||||
// Notifies shared code of a scroll event
|
||||
//
|
||||
void _glfwInputScroll(_GLFWwindow* window, const GLFWScrollEvent *ev)
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods)
|
||||
{
|
||||
if (window->callbacks.scroll)
|
||||
window->callbacks.scroll((GLFWwindow*) window, ev);
|
||||
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags, mods);
|
||||
}
|
||||
|
||||
// Notifies shared code of a mouse button click event
|
||||
@@ -406,58 +401,13 @@ void _glfwInputCursorEnter(_GLFWwindow* window, bool entered)
|
||||
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
|
||||
}
|
||||
|
||||
// Notifies shared code of a drop event.
|
||||
// The caller is responsible for passing a mutable working-copy of the mimes
|
||||
// array (reset to the full original list before each call) so that the
|
||||
// callback can sort/filter in-place without touching the backend's canonical
|
||||
// storage. The return value is ev.num_mimes after the callback returns,
|
||||
// i.e. the number of accepted (possibly reordered) mimes starting at
|
||||
// mimes[0].
|
||||
size_t _glfwInputDropEvent(_GLFWwindow *window, GLFWDropEventType type, double xpos, double ypos, const char** mimes, size_t num_mimes, bool from_self) {
|
||||
if (!window->callbacks.drop_event) return 0;
|
||||
if (num_mimes > 1) {
|
||||
mime_dedup_set seen;
|
||||
mime_dedup_set_init(&seen);
|
||||
size_t write_pos = 0;
|
||||
for (size_t i = 0; i < num_mimes; i++) {
|
||||
if (mime_dedup_set_is_end(mime_dedup_set_get(&seen, mimes[i]))) {
|
||||
if (mime_dedup_set_is_end(mime_dedup_set_insert(&seen, mimes[i]))) {
|
||||
// OOM: shift remaining entries to write_pos and stop deduplicating
|
||||
memmove(mimes + write_pos, mimes + i, (num_mimes - i) * sizeof(const char*));
|
||||
write_pos += num_mimes - i;
|
||||
break;
|
||||
}
|
||||
// Swap the unique entry into write_pos; the displaced entry moves to
|
||||
// position i where it will end up at or beyond the new num_mimes.
|
||||
if (write_pos != i) {
|
||||
const char *tmp = mimes[write_pos];
|
||||
mimes[write_pos] = mimes[i];
|
||||
mimes[i] = tmp;
|
||||
}
|
||||
write_pos++;
|
||||
}
|
||||
// duplicate: left in-place; will end up at a position >= new num_mimes
|
||||
}
|
||||
num_mimes = write_pos;
|
||||
mime_dedup_set_cleanup(&seen);
|
||||
}
|
||||
GLFWDropEvent ev = {
|
||||
.mimes=mimes, .type=type, .xpos=xpos, .ypos=ypos, .num_mimes=num_mimes, .from_self=from_self,
|
||||
.read_data=type == GLFW_DROP_DATA_AVAILABLE ? _glfwPlatformReadAvailableDropData : NULL,
|
||||
.finish_drop=type == GLFW_DROP_DATA_AVAILABLE || type == GLFW_DROP_DROP ? _glfwPlatformEndDrop : NULL,
|
||||
.operation.allowed = window->drop_operation.allowed, .operation.preferred = window->drop_operation.preferred,
|
||||
.operation.source_actions = window->drop_operation.source_actions,
|
||||
};
|
||||
window->callbacks.drop_event((GLFWwindow*)window, &ev);
|
||||
window->drop_operation.preferred = ev.operation.preferred; window->drop_operation.allowed = ev.operation.allowed;
|
||||
return ev.num_mimes;
|
||||
}
|
||||
|
||||
// Notifies shared code that the OS wants data for a MIME type from the drag source
|
||||
// Notifies shared code of files or directories dropped on a window
|
||||
//
|
||||
void _glfwInputDragSourceRequest(_GLFWwindow* window, GLFWDragEvent *ev) {
|
||||
if (window->callbacks.drag_source)
|
||||
window->callbacks.drag_source((GLFWwindow*) window, ev);
|
||||
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz)
|
||||
{
|
||||
if (window->callbacks.drop)
|
||||
return window->callbacks.drop((GLFWwindow*) window, mime, text, sz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Notifies shared code of a joystick connection or disconnection
|
||||
@@ -726,18 +676,6 @@ void _glfwCenterCursorInContentArea(_GLFWwindow* window)
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI int glfwRequestDropData(GLFWwindow *window, const char *mime) {
|
||||
return _glfwPlatformRequestDropData((_GLFWwindow*)window, mime);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwEndDrop(GLFWwindow *window, GLFWDragOperationType op) {
|
||||
_glfwPlatformEndDrop(window, op);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwRequestDropUpdate(GLFWwindow *window) {
|
||||
_glfwPlatformRequestDropUpdate((_GLFWwindow*)window);
|
||||
}
|
||||
|
||||
GLFWAPI bool glfwGetIgnoreOSKeyboardProcessing(void) {
|
||||
return _glfw.ignoreOSKeyboardProcessing;
|
||||
}
|
||||
@@ -746,20 +684,6 @@ GLFWAPI void glfwSetIgnoreOSKeyboardProcessing(bool enabled) {
|
||||
_glfw.ignoreOSKeyboardProcessing = enabled;
|
||||
}
|
||||
|
||||
GLFWAPI bool glfwGrabKeyboard(int grab) {
|
||||
if (grab == 0 || grab == 1) {
|
||||
if (_glfwPlatformGrabKeyboard(grab)) _glfw.keyboard_grabbed = grab;
|
||||
}
|
||||
return _glfw.keyboard_grabbed;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetKeyboardRepeatDelay(monotonic_t *delay, monotonic_t *interval) {
|
||||
_GLFW_REQUIRE_INIT();
|
||||
if (delay) *delay = ms_to_monotonic_t(500ll);
|
||||
if (interval) *interval = ms_to_monotonic_t(30ll);
|
||||
_glfwPlatformGetKeyboardRepeatDelay(delay, interval);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
@@ -1170,88 +1094,16 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWdropeventfun glfwSetDropEventCallback(GLFWwindow* handle, GLFWdropeventfun cbfun)
|
||||
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
_GLFW_SWAP_POINTERS(window->callbacks.drop_event, cbfun);
|
||||
_GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
|
||||
GLFWAPI GLFWdragsourcefun glfwSetDragSourceCallback(GLFWwindow* handle, GLFWdragsourcefun cbfun)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
_GLFW_SWAP_POINTERS(window->callbacks.drag_source, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
void
|
||||
_glfwFreeDragSourceData(void) {
|
||||
GLFWid drag_window_id = _glfw.drag.window_id;
|
||||
_glfwPlatformFreeDragSourceData();
|
||||
if (_glfw.drag.items) {
|
||||
for (size_t i = 0; i < _glfw.drag.item_count; i++) {
|
||||
free((void*)_glfw.drag.items[i].mime_type);
|
||||
free((void*)_glfw.drag.items[i].optional_data);
|
||||
}
|
||||
free(_glfw.drag.items);
|
||||
}
|
||||
GLFWid iid = _glfw.drag.instance_id;
|
||||
memset(&_glfw.drag, 0, sizeof(_glfw.drag));
|
||||
_glfw.drag.instance_id = iid;
|
||||
// Send a synthetic left button release to the drag source window if the
|
||||
// button is still marked as pressed. The focus-loss release was suppressed
|
||||
// while the drag was in progress, and on some platforms (Wayland, Cocoa)
|
||||
// the OS never sends a natural button release after the drag ends.
|
||||
if (drag_window_id) {
|
||||
_GLFWwindow* drag_window = _glfwWindowForId(drag_window_id);
|
||||
if (drag_window && drag_window->mouseButtons[GLFW_MOUSE_BUTTON_LEFT] == GLFW_PRESS)
|
||||
_glfwInputMouseClick(drag_window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
GLFWAPI int
|
||||
glfwStartDrag(GLFWwindow* handle, const GLFWDragSourceItem *items, size_t item_count, const GLFWimage* thumbnail, int operations, bool needs_toplevel_on_wayland) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EINVAL);
|
||||
if (operations == -1) return _glfwPlatformDragDataReady(items[0].mime_type, items[0].optional_data, items[0].data_size, items[0].type);
|
||||
if (operations == -2) return _glfwPlatformChangeDragImage(thumbnail);
|
||||
if (operations == -3) { _glfwPlatformCancelDrag(window); return 0; }
|
||||
_glfwFreeDragSourceData();
|
||||
_glfw.drag.instance_id++;
|
||||
if (!items || !item_count) return 0;
|
||||
_glfw.drag.items = calloc(item_count, sizeof(_glfw.drag.items[0]));
|
||||
if (!_glfw.drag.items) return ENOMEM;
|
||||
_glfw.drag.item_count = item_count;
|
||||
for (size_t i = 0; i < item_count; i++) {
|
||||
if (!items[i].mime_type || !items[i].mime_type[0]) {
|
||||
_glfwFreeDragSourceData(); return EINVAL;
|
||||
}
|
||||
_glfw.drag.items[i].mime_type = _glfw_strdup(items[i].mime_type);
|
||||
if (!_glfw.drag.items[i].mime_type) { _glfwFreeDragSourceData(); return ENOMEM; }
|
||||
if (items[i].optional_data) {
|
||||
_glfw.drag.items[i].optional_data = malloc(items[i].data_size);
|
||||
if (!_glfw.drag.items[i].optional_data) { _glfwFreeDragSourceData(); return ENOMEM; }
|
||||
memcpy((void*)_glfw.drag.items[i].optional_data, items[i].optional_data, items[i].data_size);
|
||||
}
|
||||
_glfw.drag.items[i].data_size = items[i].data_size;
|
||||
_glfw.drag.items[i].is_remote_client = items[i].is_remote_client;
|
||||
}
|
||||
_glfw.drag.window_id = window->id;
|
||||
_glfw.drag.operations = operations;
|
||||
_glfw.drag.needs_toplevel_on_wayland = needs_toplevel_on_wayland;
|
||||
int ans = _glfwPlatformStartDrag(window, thumbnail);
|
||||
if (ans != 0) _glfwFreeDragSourceData();
|
||||
return ans;
|
||||
}
|
||||
|
||||
GLFWAPI int glfwJoystickPresent(int jid)
|
||||
{
|
||||
_GLFWjoystick* js;
|
||||
|
||||
50
glfw/internal.h
vendored
50
glfw/internal.h
vendored
@@ -331,7 +331,7 @@ struct _GLFWwndconfig
|
||||
char instanceName[256];
|
||||
} x11;
|
||||
struct {
|
||||
char appId[256], windowTag[256];
|
||||
char appId[256];
|
||||
uint32_t bgcolor;
|
||||
} wl;
|
||||
};
|
||||
@@ -461,7 +461,6 @@ struct _GLFWwindow
|
||||
#else
|
||||
const bool swaps_disallowed;
|
||||
#endif
|
||||
struct { GLFWDragOperationType preferred; int allowed, source_actions; } drop_operation;
|
||||
|
||||
struct {
|
||||
GLFWwindowposfun pos;
|
||||
@@ -479,10 +478,8 @@ struct _GLFWwindow
|
||||
GLFWcursorenterfun cursorEnter;
|
||||
GLFWscrollfun scroll;
|
||||
GLFWkeyboardfun keyboard;
|
||||
GLFWdropfun drop;
|
||||
GLFWliveresizefun liveResize;
|
||||
|
||||
GLFWdragsourcefun drag_source;
|
||||
GLFWdropeventfun drop_event;
|
||||
} callbacks;
|
||||
|
||||
// This is defined in the window API's platform.h
|
||||
@@ -493,7 +490,7 @@ struct _GLFWwindow
|
||||
//
|
||||
struct _GLFWmonitor
|
||||
{
|
||||
const char *name, *description;
|
||||
char* name;
|
||||
void* userPointer;
|
||||
|
||||
// Physical dimensions in millimeters.
|
||||
@@ -619,7 +616,7 @@ struct _GLFWlibrary
|
||||
_GLFWtls contextSlot;
|
||||
_GLFWmutex errorLock;
|
||||
|
||||
bool ignoreOSKeyboardProcessing, keyboard_grabbed;
|
||||
bool ignoreOSKeyboardProcessing;
|
||||
|
||||
struct {
|
||||
bool available;
|
||||
@@ -665,12 +662,6 @@ struct _GLFWlibrary
|
||||
_GLFWlibraryEGL egl;
|
||||
// This is defined in osmesa_context.h
|
||||
_GLFWlibraryOSMesa osmesa;
|
||||
|
||||
struct {
|
||||
GLFWDragSourceItem *items; size_t item_count;
|
||||
GLFWid window_id, instance_id; int operations;
|
||||
bool needs_toplevel_on_wayland;
|
||||
} drag;
|
||||
};
|
||||
|
||||
// Global state shared between compilation units of GLFW
|
||||
@@ -728,7 +719,6 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title);
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images);
|
||||
bool _glfwPlatformSetLayerShellConfig(_GLFWwindow* window, const GLFWLayerShellConfig *value);
|
||||
const GLFWLayerShellConfig* _glfwPlatformGetLayerShellConfig(_GLFWwindow* window);
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos);
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos);
|
||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height);
|
||||
@@ -746,11 +736,10 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
float* xscale, float* yscale);
|
||||
monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window);
|
||||
void _glfwPlatformGetKeyboardRepeatDelay(monotonic_t *delay, monotonic_t *interval);
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformShowWindow(_GLFWwindow* window, bool move_to_active_screen);
|
||||
void _glfwPlatformShowWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformHideWindow(_GLFWwindow* window);
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window);
|
||||
int _glfwPlatformWindowBell(_GLFWwindow* window);
|
||||
@@ -824,26 +813,11 @@ void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
||||
|
||||
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
|
||||
void _glfwInputClipboardLost(GLFWClipboardType which);
|
||||
void _glfwInputScroll(_GLFWwindow* window, const GLFWScrollEvent *ev);
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods);
|
||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
|
||||
// Platform functions for drop data reading
|
||||
void _glfwPlatformRequestDropUpdate(_GLFWwindow* window);
|
||||
size_t _glfwInputDropEvent(_GLFWwindow *window, GLFWDropEventType type, double xpos, double ypos, const char** mimes, size_t num_mimes, bool from_self);
|
||||
ssize_t _glfwPlatformReadAvailableDropData(GLFWwindow *w, GLFWDropEvent *ev, char *buffer, size_t sz);
|
||||
void _glfwPlatformEndDrop(GLFWwindow *w, GLFWDragOperationType op);
|
||||
int _glfwPlatformRequestDropData(_GLFWwindow *window, const char *mime);
|
||||
// Platform functions for drag source
|
||||
int _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWimage* thumbnail);
|
||||
void _glfwPlatformCancelDrag(_GLFWwindow* window);
|
||||
void _glfwFreeDragSourceData(void);
|
||||
void _glfwPlatformFreeDragSourceData(void);
|
||||
void _glfwInputDragSourceRequest(_GLFWwindow* window, GLFWDragEvent *ev);
|
||||
int _glfwPlatformDragDataReady(const char *mime_type, const char *data, size_t sz, int type);
|
||||
int _glfwPlatformChangeDragImage(const GLFWimage *thumbnail);
|
||||
|
||||
|
||||
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz);
|
||||
void _glfwInputColorScheme(GLFWColorScheme, bool);
|
||||
void _glfwPlatformInputColorScheme(GLFWColorScheme);
|
||||
void _glfwInputJoystick(_GLFWjoystick* js, int event);
|
||||
@@ -909,15 +883,6 @@ void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval,
|
||||
void _glfwPlatformRemoveTimer(unsigned long long timer_id);
|
||||
int _glfwPlatformSetWindowBlur(_GLFWwindow* handle, int value);
|
||||
MonitorGeometry _glfwPlatformGetMonitorGeometry(_GLFWmonitor* monitor);
|
||||
bool _glfwPlatformGrabKeyboard(bool grab);
|
||||
void glfw_handle_scroll_event_for_momentum(_GLFWwindow *w, const GLFWScrollEvent *ev, bool stopped, bool is_finger_based);
|
||||
#define glfw_cancel_momentum_scroll() glfw_handle_scroll_event_for_momentum(NULL, NULL, false, false)
|
||||
#ifdef _GLFW_X11
|
||||
#define momentum_scroll_gesture_detection_timeout_ms 50
|
||||
#else
|
||||
#define momentum_scroll_gesture_detection_timeout_ms 0
|
||||
#endif
|
||||
bool glfw_is_momentum_scroll_enabled(void);
|
||||
|
||||
char* _glfw_strdup(const char* source);
|
||||
|
||||
@@ -925,4 +890,3 @@ void _glfw_free_clipboard_data(_GLFWClipboardData *cd);
|
||||
|
||||
#define debug_rendering(...) if (_glfw.hints.init.debugRendering) { timed_debug_print(__VA_ARGS__); }
|
||||
#define debug_input(...) if (_glfw.hints.init.debugKeyboard) { timed_debug_print(__VA_ARGS__); }
|
||||
#define safe_close(fd) do { errno = 0; close(fd); } while(errno == EINTR)
|
||||
|
||||
2
glfw/linux_desktop_settings.c
vendored
2
glfw/linux_desktop_settings.c
vendored
@@ -259,7 +259,7 @@ glfw_initialize_desktop_settings(void) {
|
||||
get_cursor_theme_from_env();
|
||||
DBusConnection *session_bus = glfw_dbus_session_bus();
|
||||
if (session_bus) {
|
||||
if (!read_desktop_settings(session_bus)) _glfwInputError(GLFW_PLATFORM_ERROR, "WARNING: Failed to read desktop settings, using defaults, make sure you have the desktop portal running.");
|
||||
if (!read_desktop_settings(session_bus)) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to read desktop settings, make sure you have the desktop portal running.");
|
||||
dbus_bus_add_match(session_bus, "type='signal',interface='" DESKTOP_INTERFACE "',member='SettingChanged'", NULL);
|
||||
dbus_connection_add_filter(session_bus, setting_changed, NULL, NULL);
|
||||
}
|
||||
|
||||
227
glfw/momentum-scroll.c
vendored
227
glfw/momentum-scroll.c
vendored
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
* momentum-scroll.c
|
||||
* Copyright (C) 2026 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
#include <math.h>
|
||||
|
||||
typedef struct ScrollSample {
|
||||
double dx, dy;
|
||||
monotonic_t timestamp;
|
||||
} ScrollSample;
|
||||
|
||||
#define DEQUE_DATA_TYPE ScrollSample
|
||||
#define DEQUE_NAME ScrollSamples
|
||||
#include "../kitty/fixed_size_deque.h"
|
||||
|
||||
typedef enum ScrollerState { NONE, PHYSICAL_EVENT_IN_PROGRESS, MOMENTUM_IN_PROGRESS } ScrollerState;
|
||||
|
||||
typedef struct MomentumScroller {
|
||||
double friction, // Deceleration inverse factor (0-1, higher = longer coast)
|
||||
min_velocity, // Minimum velocity before stopping
|
||||
max_velocity, // Maximum velocity to prevent runaway scrolling
|
||||
velocity_scale; // Scale factor for initial velocity
|
||||
monotonic_t timer_interval; // animation speed
|
||||
|
||||
GLFWid timer_id, window_id;
|
||||
ScrollSamples samples;
|
||||
ScrollerState state;
|
||||
double scale;
|
||||
struct { double x, y; } velocity;
|
||||
int keyboard_modifiers;
|
||||
struct {
|
||||
monotonic_t start, duration;
|
||||
struct { double x, y; } displacement;
|
||||
} physical_event;
|
||||
} MomentumScroller;
|
||||
|
||||
#define DEFAULTS { .friction = 0.96, .min_velocity = 0.5, .max_velocity = 100, .timer_interval = 10, }
|
||||
static const MomentumScroller defaults = DEFAULTS;
|
||||
static MomentumScroller s = DEFAULTS;
|
||||
#undef DEFAULTS
|
||||
|
||||
GLFWAPI void
|
||||
glfwConfigureMomentumScroller(double friction, double min_velocity, double max_velocity, unsigned timer_interval_ms) {
|
||||
s.timer_interval = timer_interval_ms ? ms_to_monotonic_t(timer_interval_ms) : defaults.timer_interval;
|
||||
s.friction = friction < 0 ? defaults.friction : MAX(0, MIN(friction, 1));
|
||||
#define S(w) s.w = w >= 0 ? w : defaults.w
|
||||
S(min_velocity); S(max_velocity);
|
||||
#undef S
|
||||
}
|
||||
|
||||
static void
|
||||
cancel_existing_scroll(bool reset_velocity) {
|
||||
if (s.timer_id) {
|
||||
glfwRemoveTimer(s.timer_id);
|
||||
s.timer_id = 0;
|
||||
}
|
||||
if (s.state == MOMENTUM_IN_PROGRESS) {
|
||||
_GLFWwindow *w = _glfwWindowForId(s.window_id);
|
||||
if (w) _glfwInputScroll(
|
||||
w, &(GLFWScrollEvent){.momentum_type=GLFW_MOMENTUM_PHASE_CANCELED, .keyboard_modifiers=s.keyboard_modifiers});
|
||||
}
|
||||
s.window_id = 0;
|
||||
s.keyboard_modifiers = 0;
|
||||
deque_clear(&s.samples);
|
||||
s.state = NONE;
|
||||
if (reset_velocity) { s.velocity.x = 0; s.velocity.y = 0; }
|
||||
}
|
||||
|
||||
static void
|
||||
add_sample(double dx, double dy, monotonic_t now) {
|
||||
deque_push_back(&s.samples, (ScrollSample){dx, dy, now}, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
last_sample_delta(double *dx, double *dy) {
|
||||
const ScrollSample *ss;
|
||||
if ((ss = deque_peek_back(&s.samples))) { *dx = ss->dx; *dy = ss->dy; }
|
||||
else { *dx = 0; *dy = 0; }
|
||||
}
|
||||
|
||||
static void
|
||||
trim_old_samples(monotonic_t now) {
|
||||
const ScrollSample *ss;
|
||||
while ((ss = deque_peek_front(&s.samples)) && (now - ss->timestamp) > ms_to_monotonic_t(150))
|
||||
deque_pop_front(&s.samples, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
add_velocity(double x, double y) {
|
||||
if (x == 0 || x * s.velocity.x >= 0) s.velocity.x += x;
|
||||
else s.velocity.x = x;
|
||||
if (y == 0 || y * s.velocity.y >= 0) s.velocity.y += y;
|
||||
else s.velocity.y = y;
|
||||
s.velocity.x = MAX(-s.max_velocity, MIN(s.velocity.x, s.max_velocity));
|
||||
s.velocity.y = MAX(-s.max_velocity, MIN(s.velocity.y, s.max_velocity));
|
||||
}
|
||||
|
||||
static void
|
||||
set_velocity_from_samples(monotonic_t now) {
|
||||
s.timer_interval = ms_to_monotonic_t(8);
|
||||
trim_old_samples(now);
|
||||
ScrollSample ss;
|
||||
switch (deque_size(&s.samples)) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
deque_pop_front(&s.samples, &ss);
|
||||
add_velocity(ss.dx, ss.dy);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use weighted average - more recent samples have higher weight
|
||||
double total_dx = 0.0, total_dy = 0.0, total_weight = 0.0;
|
||||
monotonic_t first_time = deque_peek_front(&s.samples)->timestamp;
|
||||
monotonic_t last_time = deque_peek_back(&s.samples)->timestamp;
|
||||
double time_span = MAX(1, last_time - first_time);
|
||||
for (size_t i = 0; i < deque_size(&s.samples); i++) {
|
||||
const ScrollSample *ss = deque_at(&s.samples, i);
|
||||
double weight = 1.0 + (ss->timestamp - first_time) / time_span;
|
||||
total_dx += ss->dx * weight; total_dy += ss->dy * weight;
|
||||
total_weight += weight;
|
||||
}
|
||||
deque_clear(&s.samples);
|
||||
if (total_weight <= 0) return;
|
||||
double dy = total_dy / total_weight, dx = total_dx / total_weight;
|
||||
add_velocity(dx, dy);
|
||||
if (false) timed_debug_print("momentum scroll: event velocity: %.1f final velocity: %.1f\n", dy, s.velocity.y);
|
||||
}
|
||||
|
||||
static void
|
||||
send_momentum_event(bool is_start) {
|
||||
_GLFWwindow *w = _glfwWindowForId(s.window_id);
|
||||
if (!w || w != _glfwFocusedWindow()) {
|
||||
cancel_existing_scroll(true);
|
||||
return;
|
||||
}
|
||||
s.velocity.x *= s.friction; s.velocity.y *= s.friction;
|
||||
if (fabs(s.velocity.x) < s.min_velocity) s.velocity.x = 0;
|
||||
if (fabs(s.velocity.y) < s.min_velocity) s.velocity.y = 0;
|
||||
|
||||
GLFWMomentumType m = is_start ? GLFW_MOMENTUM_PHASE_BEGAN : GLFW_MOMENTUM_PHASE_ACTIVE;
|
||||
if (s.velocity.x == 0 && s.velocity.y == 0 && !is_start) {
|
||||
m = GLFW_MOMENTUM_PHASE_ENDED;
|
||||
if (s.timer_id) glfwRemoveTimer(s.timer_id);
|
||||
s.timer_id = 0;
|
||||
s.state = NONE;
|
||||
}
|
||||
GLFWScrollEvent e = {
|
||||
.offset_type=GLFW_SCROLL_OFFEST_HIGHRES, .momentum_type=m, .unscaled.x=s.velocity.x, .unscaled.y=s.velocity.y,
|
||||
.x_offset=s.scale * s.velocity.x, .y_offset=s.scale * s.velocity.y, .keyboard_modifiers=s.keyboard_modifiers
|
||||
};
|
||||
_glfwInputScroll(w, &e);
|
||||
}
|
||||
|
||||
static void
|
||||
momentum_timer_fired(unsigned long long timer_id UNUSED, void *data UNUSED) {
|
||||
send_momentum_event(false);
|
||||
}
|
||||
|
||||
static void
|
||||
start_momentum_scroll(monotonic_t now) {
|
||||
set_velocity_from_samples(now);
|
||||
send_momentum_event(true);
|
||||
s.timer_id = glfwAddTimer(s.timer_interval, true, momentum_timer_fired, NULL, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_suitable_for_momentum(void) {
|
||||
return (
|
||||
MAX(fabs(s.physical_event.displacement.x), fabs(s.physical_event.displacement.y)) > 10 &&
|
||||
s.physical_event.duration > ms_to_monotonic_t(2)
|
||||
);
|
||||
}
|
||||
|
||||
bool
|
||||
glfw_is_momentum_scroll_enabled(void) {
|
||||
return s.friction > 0;
|
||||
}
|
||||
|
||||
void
|
||||
glfw_handle_scroll_event_for_momentum(
|
||||
_GLFWwindow *w, const GLFWScrollEvent *ev, bool stopped, bool is_finger_based
|
||||
) {
|
||||
const bool is_synthetic_momentum_start_event = stopped && momentum_scroll_gesture_detection_timeout_ms;
|
||||
if (!w) { cancel_existing_scroll(true); return; }
|
||||
if (!is_finger_based || ev->offset_type != GLFW_SCROLL_OFFEST_HIGHRES || !glfw_is_momentum_scroll_enabled()) {
|
||||
if (ev->x_offset != 0 || ev->y_offset != 0) _glfwInputScroll(w, ev);
|
||||
return;
|
||||
}
|
||||
monotonic_t now = monotonic();
|
||||
if (is_synthetic_momentum_start_event) now -= ms_to_monotonic_t(momentum_scroll_gesture_detection_timeout_ms);
|
||||
if (s.state == PHYSICAL_EVENT_IN_PROGRESS) {
|
||||
s.physical_event.displacement.x += ev->unscaled.x;
|
||||
s.physical_event.displacement.y += ev->unscaled.y;
|
||||
if (stopped) {
|
||||
s.physical_event.duration = now - s.physical_event.start;
|
||||
s.physical_event.start = 0;
|
||||
}
|
||||
} else {
|
||||
memset(&s.physical_event, 0, sizeof(s.physical_event));
|
||||
s.physical_event.start = now;
|
||||
}
|
||||
if (ev->unscaled.y > 0) s.scale = ev->y_offset / ev->unscaled.y;
|
||||
else if (ev->unscaled.x > 0) s.scale = ev->x_offset / ev->unscaled.x;
|
||||
if (s.window_id && s.window_id != w->id) cancel_existing_scroll(true);
|
||||
if (s.state != PHYSICAL_EVENT_IN_PROGRESS) cancel_existing_scroll(false);
|
||||
if (!is_synthetic_momentum_start_event) {
|
||||
// Check for change in direction
|
||||
double ldx, ldy; last_sample_delta(&ldx, &ldy);
|
||||
if (ldx * ev->x_offset < 0 || ldy * ev->y_offset < 0) cancel_existing_scroll(true);
|
||||
}
|
||||
s.window_id = w->id;
|
||||
s.keyboard_modifiers = ev->keyboard_modifiers;
|
||||
if (ev->offset_type == GLFW_SCROLL_OFFEST_HIGHRES) {
|
||||
if (!is_synthetic_momentum_start_event) add_sample(ev->unscaled.x, ev->unscaled.y, now);
|
||||
if (stopped) s.state = is_suitable_for_momentum() ? MOMENTUM_IN_PROGRESS : NONE;
|
||||
else s.state = PHYSICAL_EVENT_IN_PROGRESS;
|
||||
} else {
|
||||
s.state = stopped ? NONE : PHYSICAL_EVENT_IN_PROGRESS;
|
||||
}
|
||||
if (s.state == MOMENTUM_IN_PROGRESS) start_momentum_scroll(now);
|
||||
else _glfwInputScroll(w, ev);
|
||||
}
|
||||
15
glfw/monitor.c
vendored
15
glfw/monitor.c
vendored
@@ -186,8 +186,7 @@ void _glfwFreeMonitor(_GLFWmonitor* monitor)
|
||||
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||
|
||||
free(monitor->modes);
|
||||
free((void*)monitor->name);
|
||||
free((void*)monitor->description);
|
||||
free(monitor->name);
|
||||
free(monitor);
|
||||
}
|
||||
|
||||
@@ -394,19 +393,9 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->name ? monitor->name : "";
|
||||
return monitor->name;
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetMonitorDescription(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->description ? monitor->description : "";
|
||||
}
|
||||
|
||||
|
||||
GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
static void makeContextCurrentNSGL(_GLFWwindow* window)
|
||||
@@ -107,22 +106,12 @@ bool _glfwInitNSGL(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
// We use a globally shared context across all OS Windows so that
|
||||
// if all OS Windows are closed the context does not have to be recreated
|
||||
// with all associated data lost. On Apple kitty can remain running with no
|
||||
// OS Windows.
|
||||
static NSOpenGLContext* globally_shared_context = nil;
|
||||
|
||||
// Terminate OpenGL support
|
||||
//
|
||||
void _glfwTerminateNSGL(void) {
|
||||
if (globally_shared_context != nil) {
|
||||
[globally_shared_context release];
|
||||
globally_shared_context = nil;
|
||||
}
|
||||
void _glfwTerminateNSGL(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Create the OpenGL context
|
||||
//
|
||||
bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
@@ -282,7 +271,7 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
return false;
|
||||
}
|
||||
|
||||
NSOpenGLContext* share = globally_shared_context;
|
||||
NSOpenGLContext* share = nil;
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.nsgl.object;
|
||||
@@ -296,9 +285,6 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
"NSGL: Failed to create OpenGL context");
|
||||
return false;
|
||||
}
|
||||
if (globally_shared_context == nil) {
|
||||
globally_shared_context = [window->context.nsgl.object retain];
|
||||
}
|
||||
|
||||
if (fbconfig->transparent)
|
||||
{
|
||||
@@ -333,8 +319,6 @@ bool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(nil);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
@@ -345,48 +329,3 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
|
||||
|
||||
return window->context.nsgl.object;
|
||||
}
|
||||
|
||||
GLFWAPI bool
|
||||
glfwCocoaRecreateGLDrawable(GLFWwindow *w) {
|
||||
_GLFWwindow* window = (_GLFWwindow*)w;
|
||||
if (window->context.client == GLFW_NO_API) return false;
|
||||
@try {
|
||||
// Save current state
|
||||
NSOpenGLPixelFormat *pixelFormat = window->context.nsgl.pixelFormat;
|
||||
NSOpenGLContext *oldContext = window->context.nsgl.object;
|
||||
|
||||
// Create a new context sharing resources with the old one
|
||||
NSOpenGLContext *newContext = [[NSOpenGLContext alloc]
|
||||
initWithFormat:pixelFormat
|
||||
shareContext:oldContext];
|
||||
if (newContext == nil) return false;
|
||||
|
||||
// Copy settings from old context
|
||||
GLint opacity = 0;
|
||||
[oldContext getValues:&opacity forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
[newContext setValues:&opacity forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
GLint interval = 0;
|
||||
[newContext setValues:&interval forParameter:NSOpenGLContextParameterSwapInterval];
|
||||
|
||||
// Detach old context
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
[oldContext clearDrawable];
|
||||
|
||||
// Attach new context to the view
|
||||
[window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[newContext setView:window->ns.view];
|
||||
#pragma clang diagnostic pop
|
||||
[newContext makeCurrentContext];
|
||||
[newContext update];
|
||||
|
||||
// Replace context
|
||||
window->context.nsgl.object = newContext;
|
||||
[oldContext release];
|
||||
} @catch (NSException *e) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to recreate NSGL context: %s (%s)", [[e name] UTF8String], [[e reason] UTF8String]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
41
glfw/null_window.c
vendored
41
glfw/null_window.c
vendored
@@ -30,7 +30,6 @@
|
||||
#include "internal.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
|
||||
@@ -311,12 +310,6 @@ monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED)
|
||||
return ms_to_monotonic_t(500ll);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetKeyboardRepeatDelay(monotonic_t *delay, monotonic_t *interval)
|
||||
{
|
||||
if (delay) *delay = ms_to_monotonic_t(500ll);
|
||||
if (interval) *interval = ms_to_monotonic_t(30ll);
|
||||
}
|
||||
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (_glfw.null.focusedWindow == window)
|
||||
@@ -537,40 +530,6 @@ void _glfwPlatformSetCursor(_GLFWwindow* window UNUSED, _GLFWcursor* cursor UNUS
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformCancelDrag(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// No-op for null platform
|
||||
}
|
||||
int
|
||||
_glfwPlatformStartDrag(_GLFWwindow* window, const GLFWimage* thumbnail) {
|
||||
(void)window; (void)thumbnail;
|
||||
return ENOTSUP;
|
||||
}
|
||||
void _glfwPlatformFreeDragSourceData(void) {}
|
||||
int
|
||||
_glfwPlatformDragDataReady(const char *mime_type UNUSED, const char *data UNUSED, size_t sz UNUSED, int type UNUSED) { return 0; }
|
||||
int _glfwPlatformChangeDragImage(const GLFWimage *thumbnail) { (void)thumbnail; return 0; }
|
||||
|
||||
const char** _glfwPlatformGetDropMimeTypes(GLFWDropData* drop UNUSED, int* count)
|
||||
{
|
||||
if (count) *count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t _glfwPlatformReadDropData(GLFWDropData* drop UNUSED, const char* mime UNUSED,
|
||||
void* buffer UNUSED, size_t capacity UNUSED,
|
||||
monotonic_t timeout UNUSED)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
void _glfwPlatformFinishDrop(GLFWDropData* drop, GLFWDragOperationType operation UNUSED, bool success UNUSED)
|
||||
{
|
||||
if (!drop) return;
|
||||
// Free the heap-allocated drop data structure
|
||||
free(drop);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
char* copy = _glfw_strdup(string);
|
||||
|
||||
2
glfw/osmesa_context.c
vendored
2
glfw/osmesa_context.c
vendored
@@ -352,8 +352,6 @@ GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
|
||||
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
|
||||
@@ -84,13 +84,8 @@
|
||||
"staging/fractional-scale/fractional-scale-v1.xml",
|
||||
"staging/single-pixel-buffer/single-pixel-buffer-v1.xml",
|
||||
"unstable/idle-inhibit/idle-inhibit-unstable-v1.xml",
|
||||
"unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml",
|
||||
"staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml",
|
||||
"staging/xdg-system-bell/xdg-system-bell-v1.xml",
|
||||
"staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml",
|
||||
"staging/ext-background-effect/ext-background-effect-v1.xml",
|
||||
"staging/xdg-toplevel-drag/xdg-toplevel-drag-v1.xml",
|
||||
"unstable/pointer-gestures/pointer-gestures-unstable-v1.xml",
|
||||
|
||||
"kwin-blur-v1.xml",
|
||||
"wlr-layer-shell-unstable-v1.xml"
|
||||
@@ -112,7 +107,6 @@
|
||||
"linux_joystick.c",
|
||||
"linux_desktop_settings.c",
|
||||
"null_joystick.c",
|
||||
"momentum-scroll.c",
|
||||
"linux_notify.c"
|
||||
]
|
||||
},
|
||||
@@ -172,7 +166,6 @@
|
||||
"linux_joystick.c",
|
||||
"null_joystick.c",
|
||||
"linux_desktop_settings.c",
|
||||
"momentum-scroll.c",
|
||||
"linux_notify.c"
|
||||
]
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user