Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
115de36599 | ||
|
|
b01c3483de | ||
|
|
db7f566a0c | ||
|
|
9f806e76e7 | ||
|
|
12bdd4dddd | ||
|
|
72a1eb237d | ||
|
|
6a89289907 | ||
|
|
7ed835cf13 | ||
|
|
4621ff41d9 | ||
|
|
60e17d5224 | ||
|
|
1e2f7c705d | ||
|
|
1ebf0b95c4 | ||
|
|
c5acd94456 | ||
|
|
448ffe01c3 | ||
|
|
5c882f3290 | ||
|
|
70a4720bf9 | ||
|
|
c8aee8c881 | ||
|
|
c2ad0607b8 | ||
|
|
d1282b9f55 | ||
|
|
11ee317884 | ||
|
|
e69de2f968 | ||
|
|
2f4f3e3331 | ||
|
|
020f8a2047 | ||
|
|
b8faba2a16 | ||
|
|
0fcce6ec58 | ||
|
|
15f5ea92b8 | ||
|
|
2bbb5d25eb | ||
|
|
8d94285a5d | ||
|
|
eed11361c5 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,4 +1,4 @@
|
||||
kitty/wcwidth9.h linguist-generated=true
|
||||
kitty/wcwidth-std.h linguist-generated=true
|
||||
kitty/emoji.h linguist-generated=true
|
||||
kitty/keys.h linguist-generated=true
|
||||
kitty/charsets.c linguist-generated=true
|
||||
|
||||
@@ -56,7 +56,7 @@ matrix:
|
||||
env:
|
||||
- RUN_FLAKE=1 BUILD_PKG=1
|
||||
language: python
|
||||
python: "3.5"
|
||||
python: "3.6"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
@@ -123,6 +123,7 @@ before_script:
|
||||
- $PYTHON setup.py build --debug --verbose $SANITIZE_ARG;
|
||||
|
||||
script:
|
||||
- if grep -Inr '\s$' kitty kitty_tests *.py *.asciidoc .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
|
||||
- if [[ -z $SANITIZE_ARG ]]; then $PYTHON test.py; else ./asan-launcher test.py; fi
|
||||
- if [[ "$RUN_FLAKE" == "1" ]]; then flake8 --count .; fi
|
||||
- if [[ "$BUILD_PKG" == "1" ]]; then $PYTHON setup.py linux-package; fi
|
||||
|
||||
@@ -3,6 +3,34 @@ Changelog
|
||||
|
||||
kitty is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||
|
||||
version 0.6.1 [2017-12-28]
|
||||
---------------------------
|
||||
|
||||
- Add an option to fade the text in inactive windows
|
||||
|
||||
- Add new actions to open windows/tabs/etc. with the working directory set to
|
||||
the working directory of the current window.
|
||||
|
||||
- Automatically adjust cell size when DPI changes, for example when kitty is
|
||||
moved from one monitor to another with a different DPI
|
||||
|
||||
- Ensure underlines are rendered even for fonts with very poor metrics
|
||||
|
||||
- Fix some emoji glyphs not colored on Linux
|
||||
|
||||
- Internal wcwidth() implementation is now auto-generated from the unicode
|
||||
standard database
|
||||
|
||||
- Allow configuring the modifiers to use for rectangular selection with the
|
||||
mouse.
|
||||
|
||||
- Fix incorrect minimum wayland version in the build script
|
||||
|
||||
- Fix a crash when detecting a URL that ends at the end of the line
|
||||
|
||||
- Fix regression that broke drawing of hollow cursor when window loses focus
|
||||
|
||||
|
||||
version 0.6.0 [2017-12-18]
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ latency.
|
||||
|
||||
* Cross-platform support: kitty currently works on Linux and macOS, but because
|
||||
it uses only OpenGL for rendering, it should be trivial to port to other
|
||||
platforms.
|
||||
platforms.
|
||||
|
||||
* Allows you to open the scrollback buffer and window contents in a separate
|
||||
window using arbitrary programs of your choice. This is useful for browsing
|
||||
@@ -89,8 +89,8 @@ the following dependencies are installed first.
|
||||
=== Dependencies
|
||||
|
||||
* python >= 3.5
|
||||
* harfbuzz >= 1.5.0
|
||||
* libunistring
|
||||
* harfbuzz >= 1.5.0
|
||||
* libunistring
|
||||
* zlib
|
||||
* libpng
|
||||
* freetype (not needed on macOS)
|
||||
@@ -119,7 +119,9 @@ python3 /path/to/kitty/folder
|
||||
|
||||
=== Linux packages
|
||||
|
||||
* Arch linux: AUR git package https://aur.archlinux.org/packages/kitty-git/
|
||||
* Arch Linux: AUR git package https://aur.archlinux.org/packages/kitty-git/
|
||||
|
||||
* Arch Linux: AUR stable package https://aur.archlinux.org/packages/kitty/
|
||||
|
||||
* NixOS / nixpkgs: https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/misc/kitty/default.nix
|
||||
|
||||
@@ -222,7 +224,7 @@ windows are:
|
||||
|
||||
|Increase font size | {sc_increase_font_size}
|
||||
|Decrease font size | {sc_decrease_font_size}
|
||||
|Restore font size | {sc_restore_font_size}
|
||||
|Restore font size | {sc_restore_font_size}
|
||||
|Toggle fullscreen | {sc_toggle_fullscreen}
|
||||
|Pass current selection to program | {sc_pass_selection_to_program}
|
||||
|===
|
||||
@@ -337,14 +339,14 @@ render loop to reduce CPU usage. See the link:kitty/kitty.conf[config file] for
|
||||
You can generate detailed per-function performance data using
|
||||
link:https://github.com/gperftools/gperftools[gperftools]. Build kitty with the
|
||||
`--profile` flag which will create an executable called `kitty-profile`. Run
|
||||
that and perform the task you want to analyse, for example, scrolling a large
|
||||
that and perform the task you want to analyse, for example, scrolling a large
|
||||
file with `less`. After you quit, function call statistics will be printed to
|
||||
`stdout` and you can use tools like *kcachegrind* for more detailed analysis.
|
||||
|
||||
Here are some CPU usage numbers for the task of scrolling a file continuously in less.
|
||||
The CPU usage is for the terminal process and X together and is measured using htop.
|
||||
The measurements are taken at the same font and window size for all terminals on a
|
||||
`Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz` CPU with a
|
||||
The measurements are taken at the same font and window size for all terminals on a
|
||||
`Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz` CPU with a
|
||||
`Advanced Micro Devices, Inc. [AMD/ATI] Cape Verde XT [Radeon HD 7770/8760 / R7 250X]` GPU.
|
||||
|
||||
|===
|
||||
@@ -421,7 +423,7 @@ You dont need to build kitty.app to run kitty from source. Simply install the de
|
||||
listed above using brew/MacPorts or similar and then compile and run with:
|
||||
|
||||
```
|
||||
make
|
||||
make
|
||||
python3 .
|
||||
```
|
||||
|
||||
@@ -456,7 +458,7 @@ kitty, I ran headlong into more and more gnarly corners of terminal behavior.
|
||||
On all those occasions, either the excellent documentation at
|
||||
link:http://invisible-island.net/xterm/ctlseqs/ctlseqs.html[xterm-ctlseqs] or
|
||||
investigating the behavior and code of xterm or vttest were invaluable tools to
|
||||
aid my understanding.
|
||||
aid my understanding.
|
||||
|
||||
My achievements, if any, in developing kitty would not have been possible without
|
||||
his prior work and the generous sharing of knowledge accumulated over decades.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/bash
|
||||
cloc --exclude-list-file <(echo -e 'kitty/wcwidth9.h\nkitty/glfw.c\nkitty/keys.h\nkitty/charsets.c\nkitty/key_encoding.py\nkitty/rgb.py\nkitty/gl.h\nkitty/gl-wrapper.h\nkitty/gl-wrapper.c\nkitty/khrplatform.h\nkitty/glfw-wrapper.h\nkitty/glfw-wrapper.c\nkitty/emoji.h') kitty
|
||||
cloc --exclude-list-file <(echo -e 'kitty/wcwidth-std.h\nkitty/glfw.c\nkitty/keys.h\nkitty/charsets.c\nkitty/key_encoding.py\nkitty/rgb.py\nkitty/gl.h\nkitty/gl-wrapper.h\nkitty/gl-wrapper.c\nkitty/khrplatform.h\nkitty/glfw-wrapper.h\nkitty/glfw-wrapper.c\nkitty/emoji.h') kitty
|
||||
|
||||
75
gen-emoji.py
75
gen-emoji.py
@@ -1,75 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
from urllib.request import urlopen
|
||||
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
raw = urlopen('http://unicode.org/Public/emoji/5.0/emoji-data.txt').read().decode('utf-8')
|
||||
seen = set()
|
||||
cmap = defaultdict(set)
|
||||
for line in raw.splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
spec, rest = line.partition(';')[::2]
|
||||
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
||||
if '.' in spec:
|
||||
spec = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
||||
spec = set(range(spec[0], spec[1] + 1))
|
||||
else:
|
||||
spec = {int(spec, 16)}
|
||||
cmap[rest] |= spec
|
||||
seen |= spec
|
||||
items = list(seen)
|
||||
|
||||
|
||||
def get_ranges(items):
|
||||
items.sort()
|
||||
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
|
||||
group = tuple(map(itemgetter(1), g))
|
||||
a, b = group[0], group[-1]
|
||||
if a == b:
|
||||
yield a
|
||||
else:
|
||||
yield a, b
|
||||
|
||||
|
||||
def write_case(spec, p):
|
||||
if isinstance(spec, tuple):
|
||||
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
|
||||
else:
|
||||
p('\t\tcase 0x{:x}:'.format(spec))
|
||||
|
||||
|
||||
with open('kitty/emoji.h', 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
p('#pragma once')
|
||||
p('#include "data-types.h"\n')
|
||||
p('START_ALLOW_CASE_RANGE')
|
||||
p('static inline bool is_emoji(uint32_t code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(items):
|
||||
last = spec[1] if isinstance(spec, tuple) else spec
|
||||
if last < 0x231a:
|
||||
continue
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn false; \n}')
|
||||
p('static inline bool is_emoji_modifier(uint32_t code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(cmap['Emoji_Modifier'])):
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn false; \n}')
|
||||
p('END_ALLOW_CASE_RANGE')
|
||||
199
gen-wcwidth.py
Executable file
199
gen-wcwidth.py
Executable file
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from datetime import date
|
||||
from functools import partial
|
||||
from itertools import groupby
|
||||
from operator import itemgetter
|
||||
from urllib.request import urlopen
|
||||
|
||||
# We ignore the first few emojis as they are widely assumed to be single width
|
||||
# in legacy applications
|
||||
FIRST_EMOJI = 0x2194
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
def get_data(fname, folder='UCD'):
|
||||
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):
|
||||
data = open(local, 'rb').read()
|
||||
else:
|
||||
data = urlopen(url).read()
|
||||
open(local, 'wb').write(data)
|
||||
for line in data.decode('utf-8').splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
yield line
|
||||
|
||||
|
||||
# Map of class names to set of codepoints in class
|
||||
class_maps = {}
|
||||
combining_codepoints = set()
|
||||
not_assigned = set(range(0, sys.maxunicode))
|
||||
|
||||
|
||||
def parse_ucd():
|
||||
first = None
|
||||
for line in get_data('ucd/UnicodeData.txt'):
|
||||
parts = [x.strip() for x in line.split(';')]
|
||||
codepoint = int(parts[0], 16)
|
||||
category = parts[2]
|
||||
s = class_maps.setdefault(category, set())
|
||||
desc = parts[1]
|
||||
codepoints = (codepoint,)
|
||||
if first is None:
|
||||
if desc.endswith(', First>'):
|
||||
first = codepoint
|
||||
continue
|
||||
else:
|
||||
codepoints = range(first, codepoint + 1)
|
||||
first = None
|
||||
for codepoint in codepoints:
|
||||
s.add(codepoint)
|
||||
not_assigned.discard(codepoint)
|
||||
cc = parts[3]
|
||||
if cc and cc != '0':
|
||||
combining_codepoints.add(codepoint)
|
||||
|
||||
|
||||
def split_two(line):
|
||||
spec, rest = line.split(';', 1)
|
||||
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
||||
if '..' in spec:
|
||||
chars = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
||||
chars = set(range(chars[0], chars[1] + 1))
|
||||
else:
|
||||
chars = {int(spec, 16)}
|
||||
return chars, rest
|
||||
|
||||
|
||||
all_emoji = set()
|
||||
emoji_categories = {}
|
||||
|
||||
|
||||
def parse_emoji():
|
||||
for line in get_data('emoji-data.txt', 'emoji'):
|
||||
chars, rest = split_two(line)
|
||||
if max(chars) >= FIRST_EMOJI:
|
||||
s = emoji_categories.setdefault(rest, set())
|
||||
s |= chars
|
||||
all_emoji.update(chars)
|
||||
|
||||
|
||||
doublewidth, ambiguous = set(), set()
|
||||
|
||||
|
||||
def parse_eaw():
|
||||
global doublewidth, ambiguous
|
||||
seen = set()
|
||||
for line in get_data('ucd/EastAsianWidth.txt'):
|
||||
chars, eaw = split_two(line)
|
||||
if eaw == 'A':
|
||||
ambiguous |= chars
|
||||
seen |= chars
|
||||
elif eaw == 'W' or eaw == 'F':
|
||||
doublewidth |= chars
|
||||
seen |= chars
|
||||
doublewidth |= set(range(0x3400, 0x4DBF + 1)) - seen
|
||||
doublewidth |= set(range(0x4E00, 0x9FFF + 1)) - seen
|
||||
doublewidth |= set(range(0xF900, 0xFAFF + 1)) - seen
|
||||
doublewidth |= set(range(0x20000, 0x2FFFD + 1)) - seen
|
||||
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
|
||||
|
||||
|
||||
def get_ranges(items):
|
||||
items.sort()
|
||||
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
|
||||
group = tuple(map(itemgetter(1), g))
|
||||
a, b = group[0], group[-1]
|
||||
if a == b:
|
||||
yield a
|
||||
else:
|
||||
yield a, b
|
||||
|
||||
|
||||
def write_case(spec, p):
|
||||
if isinstance(spec, tuple):
|
||||
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
|
||||
else:
|
||||
p('\t\tcase 0x{:x}:'.format(spec))
|
||||
|
||||
|
||||
@contextmanager
|
||||
def create_header(path):
|
||||
f = open(path, 'w')
|
||||
p = partial(print, file=f)
|
||||
p('// unicode data, built from the unicode standard on:', date.today())
|
||||
p('// see gen-wcwidth.py')
|
||||
p('#pragma once')
|
||||
p('#include "data-types.h"\n')
|
||||
p('START_ALLOW_CASE_RANGE')
|
||||
p()
|
||||
yield p
|
||||
p()
|
||||
p('END_ALLOW_CASE_RANGE')
|
||||
f.close()
|
||||
|
||||
|
||||
def gen_emoji():
|
||||
with create_header('kitty/emoji.h') as p:
|
||||
p('static inline bool\nis_emoji(char_type code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(all_emoji)):
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn false;\n}')
|
||||
p('static inline bool\nis_emoji_modifier(char_type code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
|
||||
write_case(spec, p)
|
||||
p('\t\t\treturn true;')
|
||||
p('\t\tdefault: return false;')
|
||||
p('\t}')
|
||||
p('\treturn false;\n}')
|
||||
|
||||
|
||||
def gen_wcwidth():
|
||||
seen = set()
|
||||
|
||||
def add(p, comment, chars_, ret):
|
||||
chars = chars_ - seen
|
||||
seen.update(chars)
|
||||
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{{')
|
||||
for spec in get_ranges(list(chars)):
|
||||
write_case(spec, p)
|
||||
p(f'\t\t\treturn {ret};')
|
||||
p('\t\t// }}}\n')
|
||||
|
||||
with create_header('kitty/wcwidth-std.h') as p:
|
||||
p('static int\nwcwidth_std(int32_t code) {')
|
||||
p('\tswitch(code) {')
|
||||
|
||||
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
|
||||
add(p, 'Non-printing characters', non_printing, -1)
|
||||
add(p, 'Combining characters', combining_codepoints, -1)
|
||||
add(p, 'Private use', class_maps['Co'], -3)
|
||||
add(p, 'East Asian ambiguous width', ambiguous, -2)
|
||||
add(p, 'East Asian double width', doublewidth, 2)
|
||||
add(p, 'Emoji', all_emoji, 2)
|
||||
|
||||
add(p, 'Not assigned in the unicode character database', not_assigned, -1)
|
||||
|
||||
p('\t\tdefault: return 1;')
|
||||
p('\t}')
|
||||
p('\treturn 1;\n}')
|
||||
|
||||
|
||||
parse_ucd()
|
||||
parse_emoji()
|
||||
parse_eaw()
|
||||
gen_wcwidth()
|
||||
gen_emoji()
|
||||
@@ -43,6 +43,7 @@
|
||||
#define NSEventModifierFlagControl NSControlKeyMask
|
||||
#define NSEventModifierFlagOption NSAlternateKeyMask
|
||||
#define NSEventModifierFlagShift NSShiftKeyMask
|
||||
#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
|
||||
#define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
|
||||
#define NSEventMaskAny NSAnyEventMask
|
||||
#define NSEventTypeApplicationDefined NSApplicationDefined
|
||||
@@ -177,6 +178,8 @@ static int translateFlags(NSUInteger flags)
|
||||
mods |= GLFW_MOD_ALT;
|
||||
if (flags & NSEventModifierFlagCommand)
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
if (flags & NSEventModifierFlagCapsLock)
|
||||
mods |= GLFW_MOD_CAPS_LOCK;
|
||||
|
||||
return mods;
|
||||
}
|
||||
@@ -1087,8 +1090,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
||||
[window->ns.object zoom:nil];
|
||||
}
|
||||
|
||||
if (wndconfig->ns.frame)
|
||||
[window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->title]];
|
||||
if (strlen(wndconfig->ns.frameName))
|
||||
[window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->ns.frameName]];
|
||||
|
||||
window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ def init_env(env, pkg_config, at_least_version, module='x11'):
|
||||
ans.ldpaths.extend(('-framework', f))
|
||||
|
||||
elif module == 'wayland':
|
||||
at_least_version('wayland-protocols', 1, 1)
|
||||
at_least_version('wayland-protocols', 1, 6)
|
||||
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])
|
||||
ans.wayland_protocols = tuple(sinfo[module]['protocols'])
|
||||
@@ -69,6 +69,8 @@ def init_env(env, pkg_config, at_least_version, module='x11'):
|
||||
def build_wayland_protocols(env, run_tool, emphasis, newer, dest_dir):
|
||||
for protocol in env.wayland_protocols:
|
||||
src = os.path.join(env.wayland_packagedir, protocol)
|
||||
if not os.path.exists(src):
|
||||
raise SystemExit('The wayland-protocols package on your system is missing the {} protocol definition file'.format(protocol))
|
||||
for ext in 'hc':
|
||||
dest = wayland_protocol_file_name(src, ext)
|
||||
dest = os.path.join(dest_dir, dest)
|
||||
|
||||
277
glfw/glfw3.h
vendored
277
glfw/glfw3.h
vendored
@@ -493,17 +493,37 @@ extern "C" {
|
||||
* @{ */
|
||||
|
||||
/*! @brief If this bit is set one or more Shift keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Shift keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_SHIFT 0x0001
|
||||
/*! @brief If this bit is set one or more Control keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Control keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_CONTROL 0x0002
|
||||
/*! @brief If this bit is set one or more Alt keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Alt keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_ALT 0x0004
|
||||
/*! @brief If this bit is set one or more Super keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Super keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_SUPER 0x0008
|
||||
/*! @brief If this bit is set the Caps Lock key is enabled.
|
||||
*
|
||||
* If this bit is set the Caps Lock key is enabled and the @ref
|
||||
* GLFW_LOCK_KEY_MODS input mode is set.
|
||||
*/
|
||||
#define GLFW_MOD_CAPS_LOCK 0x0010
|
||||
/*! @brief If this bit is set the Num Lock key is enabled.
|
||||
*
|
||||
* If this bit is set the Num Lock key is enabled and the @ref
|
||||
* GLFW_LOCK_KEY_MODS input mode is set.
|
||||
*/
|
||||
#define GLFW_MOD_NUM_LOCK 0x0020
|
||||
|
||||
/*! @} */
|
||||
|
||||
@@ -944,8 +964,11 @@ extern "C" {
|
||||
#define GLFW_CONTEXT_CREATION_API 0x0002200B
|
||||
|
||||
#define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001
|
||||
#define GLFW_COCOA_FRAME_AUTOSAVE 0x00023002
|
||||
#define GLFW_COCOA_FRAME_NAME 0x00023002
|
||||
#define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003
|
||||
|
||||
#define GLFW_X11_CLASS_NAME 0x00024001
|
||||
#define GLFW_X11_INSTANCE_NAME 0x00024002
|
||||
/*! @} */
|
||||
|
||||
#define GLFW_NO_API 0
|
||||
@@ -963,6 +986,7 @@ extern "C" {
|
||||
#define GLFW_CURSOR 0x00033001
|
||||
#define GLFW_STICKY_KEYS 0x00033002
|
||||
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
|
||||
#define GLFW_LOCK_KEY_MODS 0x00033004
|
||||
|
||||
#define GLFW_CURSOR_NORMAL 0x00034001
|
||||
#define GLFW_CURSOR_HIDDEN 0x00034002
|
||||
@@ -1025,9 +1049,6 @@ extern "C" {
|
||||
|
||||
#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001
|
||||
#define GLFW_COCOA_MENUBAR 0x00051002
|
||||
|
||||
#define GLFW_X11_WM_CLASS_NAME 0x00052001
|
||||
#define GLFW_X11_WM_CLASS_CLASS 0x00052002
|
||||
/*! @} */
|
||||
|
||||
#define GLFW_DONT_CARE -1
|
||||
@@ -1046,7 +1067,7 @@ extern "C" {
|
||||
* @sa @ref glfwGetProcAddress
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
|
||||
*
|
||||
* @ingroup context
|
||||
*/
|
||||
typedef void (*GLFWglproc)(void);
|
||||
@@ -1623,8 +1644,7 @@ GLFWAPI void glfwTerminate(void);
|
||||
|
||||
/*! @brief Sets the specified init hint to the desired value.
|
||||
*
|
||||
* This function sets hints for the next initialization of GLFW. Only integer
|
||||
* type hints can be set with this function.
|
||||
* This function sets hints for the next initialization of GLFW.
|
||||
*
|
||||
* The values you set hints to are never reset by GLFW, but they only take
|
||||
* effect during initialization. Once GLFW has been initialized, any values
|
||||
@@ -1633,7 +1653,7 @@ GLFWAPI void glfwTerminate(void);
|
||||
*
|
||||
* Some hints are platform specific. These may be set on any platform but they
|
||||
* will only affect their specific platform. Other platforms will ignore them.
|
||||
* Setting these hints requires no platform specific headers or functions.
|
||||
* Setting these hints requires no platform specific headers or functions.
|
||||
*
|
||||
* @param[in] hint The [init hint](@ref init_hints) to set.
|
||||
* @param[in] value The new value of the init hint.
|
||||
@@ -1647,7 +1667,6 @@ GLFWAPI void glfwTerminate(void);
|
||||
*
|
||||
* @sa init_hints
|
||||
* @sa glfwInit
|
||||
* @sa glfwInitHintString
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
@@ -1655,40 +1674,6 @@ GLFWAPI void glfwTerminate(void);
|
||||
*/
|
||||
GLFWAPI void glfwInitHint(int hint, int value);
|
||||
|
||||
/*! @brief Sets the specified init hint to the desired value.
|
||||
*
|
||||
* This function sets hints for the next initialization of GLFW. Only string
|
||||
* type hints can be set with this function.
|
||||
*
|
||||
* The values you set hints to are never reset by GLFW, but they only take
|
||||
* effect during initialization. Once GLFW has been initialized, any values
|
||||
* you set will be ignored until the library is terminated and initialized
|
||||
* again.
|
||||
*
|
||||
* Some hints are platform specific. These may be set on any platform but they
|
||||
* will only affect their specific platform. Other platforms will ignore them.
|
||||
* Setting these hints requires no platform specific headers or functions.
|
||||
*
|
||||
* @param[in] hint The [init hint](@ref init_hints) to set.
|
||||
* @param[in] value The new value of the init hint.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref
|
||||
* GLFW_INVALID_VALUE.
|
||||
*
|
||||
* @remarks This function may be called before @ref glfwInit.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa init_hints
|
||||
* @sa glfwInit
|
||||
* @sa glfwInitHint
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup init
|
||||
*/
|
||||
GLFWAPI void glfwInitHintString(int hint, const char* value);
|
||||
|
||||
/*! @brief Retrieves the version of the GLFW library.
|
||||
*
|
||||
* This function retrieves the major, minor and revision numbers of the GLFW
|
||||
@@ -1985,6 +1970,56 @@ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, flo
|
||||
*/
|
||||
GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Sets the user pointer of the specified monitor.
|
||||
*
|
||||
* This function sets the user-defined pointer of the specified monitor. The
|
||||
* current value is retained until the monitor is disconnected. The initial
|
||||
* value is `NULL`.
|
||||
*
|
||||
* This function may be called from the monitor callback, even for a monitor
|
||||
* that is being disconnected.
|
||||
*
|
||||
* @param[in] monitor The monitor whose pointer to set.
|
||||
* @param[in] pointer The new value.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @sa @ref monitor_userptr
|
||||
* @sa @ref glfwGetMonitorUserPointer
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup monitor
|
||||
*/
|
||||
GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* monitor, void* pointer);
|
||||
|
||||
/*! @brief Returns the user pointer of the specified monitor.
|
||||
*
|
||||
* This function returns the current value of the user-defined pointer of the
|
||||
* specified monitor. The initial value is `NULL`.
|
||||
*
|
||||
* This function may be called from the monitor callback, even for a monitor
|
||||
* that is being disconnected.
|
||||
*
|
||||
* @param[in] monitor The monitor whose pointer to return.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @sa @ref monitor_userptr
|
||||
* @sa @ref glfwSetMonitorUserPointer
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup monitor
|
||||
*/
|
||||
GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Sets the monitor configuration callback.
|
||||
*
|
||||
* This function sets the monitor configuration callback, or removes the
|
||||
@@ -2184,6 +2219,7 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp);
|
||||
*
|
||||
* @sa @ref window_hints
|
||||
* @sa @ref glfwWindowHint
|
||||
* @sa @ref glfwWindowHintString
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
@@ -2194,14 +2230,20 @@ GLFWAPI void glfwDefaultWindowHints(void);
|
||||
/*! @brief Sets the specified window hint to the desired value.
|
||||
*
|
||||
* This function sets hints for the next call to @ref glfwCreateWindow. The
|
||||
* hints, once set, retain their values until changed by a call to @ref
|
||||
* glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is
|
||||
* terminated.
|
||||
* hints, once set, retain their values until changed by a call to this
|
||||
* function or @ref glfwDefaultWindowHints, or until the library is terminated.
|
||||
*
|
||||
* Only integer value hints can be set with this function. String value hints
|
||||
* are set with @ref glfwWindowHintString.
|
||||
*
|
||||
* This function does not check whether the specified hint values are valid.
|
||||
* If you set hints to invalid values this will instead be reported by the next
|
||||
* call to @ref glfwCreateWindow.
|
||||
*
|
||||
* Some hints are platform specific. These may be set on any platform but they
|
||||
* will only affect their specific platform. Other platforms will ignore them.
|
||||
* Setting these hints requires no platform specific headers or functions.
|
||||
*
|
||||
* @param[in] hint The [window hint](@ref window_hints) to set.
|
||||
* @param[in] value The new value of the window hint.
|
||||
*
|
||||
@@ -2211,6 +2253,7 @@ GLFWAPI void glfwDefaultWindowHints(void);
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref window_hints
|
||||
* @sa @ref glfwWindowHintString
|
||||
* @sa @ref glfwDefaultWindowHints
|
||||
*
|
||||
* @since Added in version 3.0. Replaces `glfwOpenWindowHint`.
|
||||
@@ -2219,6 +2262,44 @@ GLFWAPI void glfwDefaultWindowHints(void);
|
||||
*/
|
||||
GLFWAPI void glfwWindowHint(int hint, int value);
|
||||
|
||||
/*! @brief Sets the specified window hint to the desired value.
|
||||
*
|
||||
* This function sets hints for the next call to @ref glfwCreateWindow. The
|
||||
* hints, once set, retain their values until changed by a call to this
|
||||
* function or @ref glfwDefaultWindowHints, or until the library is terminated.
|
||||
*
|
||||
* Only string type hints can be set with this function. Integer value hints
|
||||
* are set with @ref glfwWindowHint.
|
||||
*
|
||||
* This function does not check whether the specified hint values are valid.
|
||||
* If you set hints to invalid values this will instead be reported by the next
|
||||
* call to @ref glfwCreateWindow.
|
||||
*
|
||||
* Some hints are platform specific. These may be set on any platform but they
|
||||
* will only affect their specific platform. Other platforms will ignore them.
|
||||
* Setting these hints requires no platform specific headers or functions.
|
||||
*
|
||||
* @param[in] hint The [window hint](@ref window_hints) to set.
|
||||
* @param[in] value The new value of the window hint.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_INVALID_ENUM.
|
||||
*
|
||||
* @pointer_lifetime The specified string is copied before this function
|
||||
* returns.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref window_hints
|
||||
* @sa @ref glfwWindowHint
|
||||
* @sa @ref glfwDefaultWindowHints
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup window
|
||||
*/
|
||||
GLFWAPI void glfwWindowHintString(int hint, const char* value);
|
||||
|
||||
/*! @brief Creates a window and its associated context.
|
||||
*
|
||||
* This function creates a window and its associated OpenGL or OpenGL ES
|
||||
@@ -2329,9 +2410,8 @@ GLFWAPI void glfwWindowHint(int hint, int value);
|
||||
* `CMake/MacOSXBundleInfo.plist.in` in the source tree.
|
||||
*
|
||||
* @remark @macos When activating frame autosaving with
|
||||
* [GLFW_COCOA_FRAME_AUTOSAVE](@ref GLFW_COCOA_FRAME_AUTOSAVE_hint), the
|
||||
* specified window size may be overriden by a previously saved size and
|
||||
* position.
|
||||
* [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified
|
||||
* window size and position may be overriden by previously saved values.
|
||||
*
|
||||
* @remark @x11 Some window managers will not respect the placement of
|
||||
* initially hidden windows.
|
||||
@@ -2341,15 +2421,12 @@ GLFWAPI void glfwWindowHint(int hint, int value);
|
||||
* query the final size, position or other attributes directly after window
|
||||
* creation.
|
||||
*
|
||||
* @remark @x11 The name and class of the `WM_CLASS` window property will by
|
||||
* default be set to the window title passed to this function. Set the @ref
|
||||
* GLFW_X11_WM_CLASS_NAME and @ref GLFW_X11_WM_CLASS_CLASS init hints before
|
||||
* initialization to override this. You can also set the title int he following
|
||||
* special format, which allows setting the two parts of the WM_CLASS property
|
||||
* and the window title independently:
|
||||
* <01> WM_CLASS name <30> WM_CLASS class <30> title
|
||||
* Here <01> refers to the byte value 01 (ASCII start-of-header) and <30> refers
|
||||
* to the byte value 30 (ASCII record separator).
|
||||
* @remark @x11 The class part of the `WM_CLASS` window property will by
|
||||
* default be set to the window title passed to this function. The instance
|
||||
* part will use the contents of the `RESOURCE_NAME` environment variable, if
|
||||
* present and not empty, or fall back to the window title. Set the @ref
|
||||
* GLFW_X11_CLASS_NAME and @ref GLFW_X11_INSTANCE_NAME window hints to override
|
||||
* this.
|
||||
*
|
||||
* @remark @wayland The window frame is currently unimplemented, as if
|
||||
* [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`.
|
||||
@@ -3237,7 +3314,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
|
||||
* The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib),
|
||||
* [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib),
|
||||
* [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) and
|
||||
* [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib).
|
||||
* [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib).
|
||||
*
|
||||
* Some of these attributes are ignored for full screen windows. The new
|
||||
* value will take effect if the window is later made windowed.
|
||||
@@ -3689,12 +3766,12 @@ GLFWAPI void glfwPostEmptyEvent(void);
|
||||
/*! @brief Returns the value of an input option for the specified window.
|
||||
*
|
||||
* This function returns the value of an input option for the specified window.
|
||||
* The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or
|
||||
* @ref GLFW_STICKY_MOUSE_BUTTONS.
|
||||
* The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
|
||||
* @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
|
||||
*
|
||||
* @param[in] window The window to query.
|
||||
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
|
||||
* `GLFW_STICKY_MOUSE_BUTTONS`.
|
||||
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
|
||||
* `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_INVALID_ENUM.
|
||||
@@ -3712,8 +3789,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
|
||||
/*! @brief Sets an input option for the specified window.
|
||||
*
|
||||
* This function sets an input mode option for the specified window. The mode
|
||||
* must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or
|
||||
* @ref GLFW_STICKY_MOUSE_BUTTONS.
|
||||
* must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
|
||||
* @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
|
||||
*
|
||||
* If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
|
||||
* modes:
|
||||
@@ -3739,9 +3816,15 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
|
||||
* you are only interested in whether mouse buttons have been pressed but not
|
||||
* when or in which order.
|
||||
*
|
||||
* If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to
|
||||
* enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled,
|
||||
* callbacks that receive modifier bits will also have the @ref
|
||||
* GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on,
|
||||
* and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on.
|
||||
*
|
||||
* @param[in] window The window whose input mode to set.
|
||||
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
|
||||
* `GLFW_STICKY_MOUSE_BUTTONS`.
|
||||
* @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
|
||||
* `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
|
||||
* @param[in] value The new value of the specified input mode.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||
@@ -4481,10 +4564,10 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count);
|
||||
* it with the corresponding direction.
|
||||
*
|
||||
* @code
|
||||
* if (hats[2] & GLFW_HAT_RIGHT)
|
||||
* {
|
||||
* // State of hat 2 could be right-up, right or right-down
|
||||
* }
|
||||
* if (hats[2] & GLFW_HAT_RIGHT)
|
||||
* {
|
||||
* // State of hat 2 could be right-up, right or right-down
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* If the specified joystick is not present this function will return `NULL`
|
||||
@@ -4588,6 +4671,56 @@ GLFWAPI const char* glfwGetJoystickName(int jid);
|
||||
*/
|
||||
GLFWAPI const char* glfwGetJoystickGUID(int jid);
|
||||
|
||||
/*! @brief Sets the user pointer of the specified joystick.
|
||||
*
|
||||
* This function sets the user-defined pointer of the specified joystick. The
|
||||
* current value is retained until the joystick is disconnected. The initial
|
||||
* value is `NULL`.
|
||||
*
|
||||
* This function may be called from the joystick callback, even for a joystick
|
||||
* that is being disconnected.
|
||||
*
|
||||
* @param[in] joystick The joystick whose pointer to set.
|
||||
* @param[in] pointer The new value.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @sa @ref joystick_userptr
|
||||
* @sa @ref glfwGetJoystickUserPointer
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer);
|
||||
|
||||
/*! @brief Returns the user pointer of the specified joystick.
|
||||
*
|
||||
* This function returns the current value of the user-defined pointer of the
|
||||
* specified joystick. The initial value is `NULL`.
|
||||
*
|
||||
* This function may be called from the joystick callback, even for a joystick
|
||||
* that is being disconnected.
|
||||
*
|
||||
* @param[in] joystick The joystick whose pointer to return.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @sa @ref joystick_userptr
|
||||
* @sa @ref glfwSetJoystickUserPointer
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI void* glfwGetJoystickUserPointer(int jid);
|
||||
|
||||
/*! @brief Returns whether the specified joystick has a gamepad mapping.
|
||||
*
|
||||
* This function returns whether the specified joystick is both present and has
|
||||
@@ -4864,7 +4997,7 @@ GLFWAPI void glfwSetTime(double time);
|
||||
* 1 / frequency seconds. To get the frequency, call @ref
|
||||
* glfwGetTimerFrequency.
|
||||
*
|
||||
* @return The value of the timer, or zero if an
|
||||
* @return The value of the timer, or zero if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
|
||||
26
glfw/init.c
vendored
26
glfw/init.c
vendored
@@ -53,10 +53,6 @@ static _GLFWinitconfig _glfwInitHints =
|
||||
{
|
||||
GLFW_TRUE, // macOS menu bar
|
||||
GLFW_TRUE // macOS bundle chdir
|
||||
},
|
||||
{
|
||||
"", // X11 WM_CLASS name
|
||||
"" // X11 WM_CLASS class
|
||||
}
|
||||
};
|
||||
|
||||
@@ -260,27 +256,7 @@ GLFWAPI void glfwInitHint(int hint, int value)
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid integer type init hint 0x%08X", hint);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwInitHintString(int hint, const char* value)
|
||||
{
|
||||
assert(value != NULL);
|
||||
|
||||
switch (hint)
|
||||
{
|
||||
case GLFW_X11_WM_CLASS_NAME:
|
||||
strncpy(_glfwInitHints.x11.className, value,
|
||||
sizeof(_glfwInitHints.x11.className) - 1);
|
||||
return;
|
||||
case GLFW_X11_WM_CLASS_CLASS:
|
||||
strncpy(_glfwInitHints.x11.classClass, value,
|
||||
sizeof(_glfwInitHints.x11.classClass) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid string type init hint 0x%08X", hint);
|
||||
"Invalid init hint 0x%08X", hint);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)
|
||||
|
||||
109
glfw/input.c
vendored
109
glfw/input.c
vendored
@@ -57,6 +57,58 @@ static _GLFWmapping* findMapping(const char* guid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Checks whether a gamepad mapping element is present in the hardware
|
||||
//
|
||||
static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e,
|
||||
const _GLFWjoystick* js)
|
||||
{
|
||||
if (e->type == _GLFW_JOYSTICK_HATBIT && (e->value >> 4) >= js->hatCount)
|
||||
return GLFW_FALSE;
|
||||
else if (e->type == _GLFW_JOYSTICK_BUTTON && e->value >= js->buttonCount)
|
||||
return GLFW_FALSE;
|
||||
else if (e->type == _GLFW_JOYSTICK_AXIS && e->value >= js->axisCount)
|
||||
return GLFW_FALSE;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Finds a mapping based on joystick GUID and verifies element indices
|
||||
//
|
||||
static _GLFWmapping* findValidMapping(const _GLFWjoystick* js)
|
||||
{
|
||||
_GLFWmapping* mapping = findMapping(js->guid);
|
||||
if (mapping)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
|
||||
{
|
||||
if (!isValidElementForJoystick(mapping->buttons + i, js))
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid button in gamepad mapping %s (%s)",
|
||||
mapping->guid,
|
||||
mapping->name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++)
|
||||
{
|
||||
if (!isValidElementForJoystick(mapping->axes + i, js))
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid axis in gamepad mapping %s (%s)",
|
||||
mapping->guid,
|
||||
mapping->name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
// Parses an SDL_GameControllerDB line and adds it to the mapping list
|
||||
//
|
||||
static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
@@ -193,6 +245,9 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m
|
||||
action = GLFW_REPEAT;
|
||||
}
|
||||
|
||||
if (!window->lockKeyMods)
|
||||
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
|
||||
|
||||
if (window->callbacks.key)
|
||||
window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
|
||||
}
|
||||
@@ -202,6 +257,9 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb
|
||||
if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
|
||||
return;
|
||||
|
||||
if (!window->lockKeyMods)
|
||||
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
|
||||
|
||||
if (window->callbacks.charmods)
|
||||
window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
|
||||
|
||||
@@ -223,6 +281,9 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
|
||||
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
|
||||
return;
|
||||
|
||||
if (!window->lockKeyMods)
|
||||
mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
|
||||
|
||||
if (action == GLFW_RELEASE && window->stickyMouseButtons)
|
||||
window->mouseButtons[button] = _GLFW_STICK;
|
||||
else
|
||||
@@ -318,9 +379,9 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
|
||||
js->axisCount = axisCount;
|
||||
js->buttonCount = buttonCount;
|
||||
js->hatCount = hatCount;
|
||||
js->mapping = findMapping(guid);
|
||||
|
||||
strcpy(js->guid, guid);
|
||||
js->mapping = findValidMapping(js);
|
||||
|
||||
return js;
|
||||
}
|
||||
@@ -354,6 +415,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
|
||||
return window->stickyKeys;
|
||||
case GLFW_STICKY_MOUSE_BUTTONS:
|
||||
return window->stickyMouseButtons;
|
||||
case GLFW_LOCK_KEY_MODS:
|
||||
return window->lockKeyMods;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||
@@ -409,7 +472,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
}
|
||||
}
|
||||
|
||||
window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
window->stickyKeys = value;
|
||||
}
|
||||
else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
|
||||
{
|
||||
@@ -429,8 +492,10 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
}
|
||||
}
|
||||
|
||||
window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
window->stickyMouseButtons = value;
|
||||
}
|
||||
else if (mode == GLFW_LOCK_KEY_MODS)
|
||||
window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
else
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
|
||||
}
|
||||
@@ -914,6 +979,38 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid)
|
||||
return js->guid;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer)
|
||||
{
|
||||
_GLFWjoystick* js;
|
||||
|
||||
assert(jid >= GLFW_JOYSTICK_1);
|
||||
assert(jid <= GLFW_JOYSTICK_LAST);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return;
|
||||
|
||||
js->userPointer = pointer;
|
||||
}
|
||||
|
||||
GLFWAPI void* glfwGetJoystickUserPointer(int jid)
|
||||
{
|
||||
_GLFWjoystick* js;
|
||||
|
||||
assert(jid >= GLFW_JOYSTICK_1);
|
||||
assert(jid <= GLFW_JOYSTICK_LAST);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
js = _glfw.joysticks + jid;
|
||||
if (!js->present)
|
||||
return NULL;
|
||||
|
||||
return js->userPointer;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
@@ -973,7 +1070,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string)
|
||||
{
|
||||
_GLFWjoystick* js = _glfw.joysticks + jid;
|
||||
if (js->present)
|
||||
js->mapping = findMapping(js->guid);
|
||||
js->mapping = findValidMapping(js);
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
@@ -1085,8 +1182,8 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
||||
state->axes[i] = js->axes[js->mapping->axes[i].value];
|
||||
else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT)
|
||||
{
|
||||
const unsigned int hat = js->mapping->buttons[i].value >> 4;
|
||||
const unsigned int bit = js->mapping->buttons[i].value & 0xf;
|
||||
const unsigned int hat = js->mapping->axes[i].value >> 4;
|
||||
const unsigned int bit = js->mapping->axes[i].value & 0xf;
|
||||
if (js->hats[hat] & bit)
|
||||
state->axes[i] = 1.f;
|
||||
}
|
||||
|
||||
13
glfw/internal.h
vendored
13
glfw/internal.h
vendored
@@ -281,10 +281,6 @@ struct _GLFWinitconfig
|
||||
GLFWbool menubar;
|
||||
GLFWbool chdir;
|
||||
} ns;
|
||||
struct {
|
||||
char className[256];
|
||||
char classClass[256];
|
||||
} x11;
|
||||
};
|
||||
|
||||
/*! @brief Window configuration.
|
||||
@@ -308,8 +304,12 @@ struct _GLFWwndconfig
|
||||
GLFWbool centerCursor;
|
||||
struct {
|
||||
GLFWbool retina;
|
||||
GLFWbool frame;
|
||||
char frameName[256];
|
||||
} ns;
|
||||
struct {
|
||||
char className[256];
|
||||
char instanceName[256];
|
||||
} x11;
|
||||
};
|
||||
|
||||
/*! @brief Context configuration.
|
||||
@@ -419,6 +419,7 @@ struct _GLFWwindow
|
||||
|
||||
GLFWbool stickyKeys;
|
||||
GLFWbool stickyMouseButtons;
|
||||
GLFWbool lockKeyMods;
|
||||
int cursorMode;
|
||||
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
|
||||
char keys[GLFW_KEY_LAST + 1];
|
||||
@@ -455,6 +456,7 @@ struct _GLFWwindow
|
||||
struct _GLFWmonitor
|
||||
{
|
||||
char* name;
|
||||
void* userPointer;
|
||||
|
||||
// Physical dimensions in millimeters.
|
||||
int widthMM, heightMM;
|
||||
@@ -513,6 +515,7 @@ struct _GLFWjoystick
|
||||
unsigned char* hats;
|
||||
int hatCount;
|
||||
char* name;
|
||||
void* userPointer;
|
||||
char guid[33];
|
||||
_GLFWmapping* mapping;
|
||||
|
||||
|
||||
2
glfw/mappings.h
vendored
2
glfw/mappings.h
vendored
@@ -51,7 +51,7 @@
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
|
||||
28
glfw/monitor.c
vendored
28
glfw/monitor.c
vendored
@@ -351,6 +351,24 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
|
||||
return monitor->name;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
monitor->userPointer = pointer;
|
||||
}
|
||||
|
||||
GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->userPointer;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
@@ -406,16 +424,16 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
double value;
|
||||
float value;
|
||||
|
||||
// Calculate intensity
|
||||
value = i / 255.0;
|
||||
value = i / 255.f;
|
||||
// Apply gamma curve
|
||||
value = pow(value, 1.0 / gamma) * 65535.0 + 0.5;
|
||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||
|
||||
// Clamp to value range
|
||||
if (value > 65535.0)
|
||||
value = 65535.0;
|
||||
if (value > 65535.f)
|
||||
value = 65535.f;
|
||||
|
||||
values[i] = (unsigned short) value;
|
||||
}
|
||||
|
||||
11
glfw/win32_platform.h
vendored
11
glfw/win32_platform.h
vendored
@@ -105,12 +105,11 @@
|
||||
#endif
|
||||
|
||||
#if WINVER < 0x0601
|
||||
typedef struct tagCHANGEFILTERSTRUCT
|
||||
typedef struct
|
||||
{
|
||||
DWORD cbSize;
|
||||
DWORD ExtStatus;
|
||||
|
||||
} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT;
|
||||
} CHANGEFILTERSTRUCT;
|
||||
#ifndef MSGFLT_ALLOW
|
||||
#define MSGFLT_ALLOW 1
|
||||
#endif
|
||||
@@ -129,13 +128,13 @@ typedef struct
|
||||
#endif /*Windows Vista*/
|
||||
|
||||
#ifndef DPI_ENUMS_DECLARED
|
||||
typedef enum PROCESS_DPI_AWARENESS
|
||||
typedef enum
|
||||
{
|
||||
PROCESS_DPI_UNAWARE = 0,
|
||||
PROCESS_SYSTEM_DPI_AWARE = 1,
|
||||
PROCESS_PER_MONITOR_DPI_AWARE = 2
|
||||
} PROCESS_DPI_AWARENESS;
|
||||
typedef enum MONITOR_DPI_TYPE
|
||||
typedef enum
|
||||
{
|
||||
MDT_EFFECTIVE_DPI = 0,
|
||||
MDT_ANGULAR_DPI = 1,
|
||||
@@ -209,7 +208,7 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*
|
||||
|
||||
// user32.dll function pointer typedefs
|
||||
typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void);
|
||||
typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT);
|
||||
typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*);
|
||||
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
|
||||
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
|
||||
|
||||
|
||||
24
glfw/win32_window.c
vendored
24
glfw/win32_window.c
vendored
@@ -384,14 +384,18 @@ static int getKeyMods(void)
|
||||
{
|
||||
int mods = 0;
|
||||
|
||||
if (GetKeyState(VK_SHIFT) & (1 << 31))
|
||||
if (GetKeyState(VK_SHIFT) & 0x8000)
|
||||
mods |= GLFW_MOD_SHIFT;
|
||||
if (GetKeyState(VK_CONTROL) & (1 << 31))
|
||||
if (GetKeyState(VK_CONTROL) & 0x8000)
|
||||
mods |= GLFW_MOD_CONTROL;
|
||||
if (GetKeyState(VK_MENU) & (1 << 31))
|
||||
if (GetKeyState(VK_MENU) & 0x8000)
|
||||
mods |= GLFW_MOD_ALT;
|
||||
if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31))
|
||||
if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000)
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
if (GetKeyState(VK_CAPITAL) & 1)
|
||||
mods |= GLFW_MOD_CAPS_LOCK;
|
||||
if (GetKeyState(VK_NUMLOCK) & 1)
|
||||
mods |= GLFW_MOD_NUM_LOCK;
|
||||
|
||||
return mods;
|
||||
}
|
||||
@@ -402,14 +406,18 @@ static int getAsyncKeyMods(void)
|
||||
{
|
||||
int mods = 0;
|
||||
|
||||
if (GetAsyncKeyState(VK_SHIFT) & (1 << 31))
|
||||
if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
|
||||
mods |= GLFW_MOD_SHIFT;
|
||||
if (GetAsyncKeyState(VK_CONTROL) & (1 << 31))
|
||||
if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
|
||||
mods |= GLFW_MOD_CONTROL;
|
||||
if (GetAsyncKeyState(VK_MENU) & (1 << 31))
|
||||
if (GetAsyncKeyState(VK_MENU) & 0x8000)
|
||||
mods |= GLFW_MOD_ALT;
|
||||
if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31))
|
||||
if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000)
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
if (GetAsyncKeyState(VK_CAPITAL) & 1)
|
||||
mods |= GLFW_MOD_CAPS_LOCK;
|
||||
if (GetAsyncKeyState(VK_NUMLOCK) & 1)
|
||||
mods |= GLFW_MOD_NUM_LOCK;
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
28
glfw/window.c
vendored
28
glfw/window.c
vendored
@@ -349,9 +349,6 @@ GLFWAPI void glfwWindowHint(int hint, int value)
|
||||
case GLFW_COCOA_RETINA_FRAMEBUFFER:
|
||||
_glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
return;
|
||||
case GLFW_COCOA_FRAME_AUTOSAVE:
|
||||
_glfw.hints.window.ns.frame = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
return;
|
||||
case GLFW_COCOA_GRAPHICS_SWITCHING:
|
||||
_glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
return;
|
||||
@@ -396,6 +393,31 @@ GLFWAPI void glfwWindowHint(int hint, int value)
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwWindowHintString(int hint, const char* value)
|
||||
{
|
||||
assert(value != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
switch (hint)
|
||||
{
|
||||
case GLFW_COCOA_FRAME_NAME:
|
||||
strncpy(_glfw.hints.window.ns.frameName, value,
|
||||
sizeof(_glfw.hints.window.ns.frameName) - 1);
|
||||
return;
|
||||
case GLFW_X11_CLASS_NAME:
|
||||
strncpy(_glfw.hints.window.x11.className, value,
|
||||
sizeof(_glfw.hints.window.x11.className) - 1);
|
||||
return;
|
||||
case GLFW_X11_INSTANCE_NAME:
|
||||
strncpy(_glfw.hints.window.x11.instanceName, value,
|
||||
sizeof(_glfw.hints.window.x11.instanceName) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
|
||||
17
glfw/wl_init.c
vendored
17
glfw/wl_init.c
vendored
@@ -132,11 +132,14 @@ static void pointerHandleAxis(void* data,
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
double scrollFactor;
|
||||
double x = 0.0, y = 0.0;
|
||||
double x = 0, y = 0;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ||
|
||||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
|
||||
|
||||
/* Wayland scroll events are in pointer motion coordinate space (think
|
||||
* two finger scroll). The factor 10 is commonly used to convert to
|
||||
* "scroll step means 1.0. */
|
||||
@@ -152,9 +155,6 @@ static void pointerHandleAxis(void* data,
|
||||
x = 0.0;
|
||||
y = wl_fixed_to_double(value) * scrollFactor;
|
||||
break;
|
||||
default:
|
||||
assert(GLFW_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
_glfwInputScroll(window, x, y);
|
||||
@@ -264,6 +264,10 @@ static void keyboardHandleKeymap(void* data,
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
|
||||
_glfw.wl.xkb.superMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
|
||||
_glfw.wl.xkb.capsLockMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
|
||||
_glfw.wl.xkb.numLockMask =
|
||||
1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
|
||||
}
|
||||
|
||||
static void keyboardHandleEnter(void* data,
|
||||
@@ -409,6 +413,10 @@ static void keyboardHandleModifiers(void* data,
|
||||
modifiers |= GLFW_MOD_SHIFT;
|
||||
if (mask & _glfw.wl.xkb.superMask)
|
||||
modifiers |= GLFW_MOD_SUPER;
|
||||
if (mask & _glfw.wl.xkb.capsLockMask)
|
||||
modifiers |= GLFW_MOD_CAPS_LOCK;
|
||||
if (mask & _glfw.wl.xkb.numLockMask)
|
||||
modifiers |= GLFW_MOD_NUM_LOCK;
|
||||
_glfw.wl.xkb.modifiers = modifiers;
|
||||
}
|
||||
|
||||
@@ -818,4 +826,3 @@ const char* _glfwPlatformGetVersionString(void)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
2
glfw/wl_platform.h
vendored
2
glfw/wl_platform.h
vendored
@@ -183,6 +183,8 @@ typedef struct _GLFWlibraryWayland
|
||||
xkb_mod_mask_t altMask;
|
||||
xkb_mod_mask_t shiftMask;
|
||||
xkb_mod_mask_t superMask;
|
||||
xkb_mod_mask_t capsLockMask;
|
||||
xkb_mod_mask_t numLockMask;
|
||||
unsigned int modifiers;
|
||||
|
||||
PFN_xkb_context_new context_new;
|
||||
|
||||
54
glfw/x11_window.c
vendored
54
glfw/x11_window.c
vendored
@@ -212,6 +212,10 @@ static int translateState(int state)
|
||||
mods |= GLFW_MOD_ALT;
|
||||
if (state & Mod4Mask)
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
if (state & LockMask)
|
||||
mods |= GLFW_MOD_CAPS_LOCK;
|
||||
if (state & Mod2Mask)
|
||||
mods |= GLFW_MOD_NUM_LOCK;
|
||||
|
||||
return mods;
|
||||
}
|
||||
@@ -703,49 +707,34 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
||||
|
||||
updateNormalHints(window, wndconfig->width, wndconfig->height);
|
||||
|
||||
// Set ICCCM WM_CLASS property and window title
|
||||
// Set ICCCM WM_CLASS property
|
||||
{
|
||||
XClassHint* hint = XAllocClassHint();
|
||||
char *wm_cclass = NULL, *wm_cname = NULL;
|
||||
const char *real_title = wndconfig->title;
|
||||
|
||||
if (strlen(_glfw.hints.init.x11.className) &&
|
||||
strlen(_glfw.hints.init.x11.classClass))
|
||||
if (strlen(wndconfig->x11.instanceName) &&
|
||||
strlen(wndconfig->x11.className))
|
||||
{
|
||||
hint->res_name = (char*) _glfw.hints.init.x11.className;
|
||||
hint->res_class = (char*) _glfw.hints.init.x11.classClass;
|
||||
}
|
||||
else if (strlen(real_title))
|
||||
{
|
||||
if (*real_title == 1) {
|
||||
char *p = strchr(real_title, 30);
|
||||
if (p && p > real_title + 1) {
|
||||
wm_cname = calloc(p - real_title + 1, 1);
|
||||
if (wm_cname) memcpy(wm_cname, real_title + 1, p - real_title - 1);
|
||||
hint->res_name = wm_cname;
|
||||
char *q = strchr(p + 1, 30);
|
||||
if (q && q > p + 1) {
|
||||
wm_cclass = calloc(q - p + 1, 1);
|
||||
if (wm_cclass) memcpy(wm_cclass, p + 1, q - p - 1);
|
||||
hint->res_class = wm_cclass;
|
||||
real_title = q + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hint->res_name = (char*) real_title;
|
||||
hint->res_class = (char*) real_title;
|
||||
}
|
||||
hint->res_name = (char*) wndconfig->x11.instanceName;
|
||||
hint->res_class = (char*) wndconfig->x11.className;
|
||||
}
|
||||
else
|
||||
{
|
||||
hint->res_name = (char*) "glfw-application";
|
||||
hint->res_class = (char*) "GLFW-Application";
|
||||
const char* resourceName = getenv("RESOURCE_NAME");
|
||||
if (resourceName && strlen(resourceName))
|
||||
hint->res_name = (char*) resourceName;
|
||||
else if (strlen(wndconfig->title))
|
||||
hint->res_name = (char*) wndconfig->title;
|
||||
else
|
||||
hint->res_name = (char*) "glfw-application";
|
||||
|
||||
if (strlen(wndconfig->title))
|
||||
hint->res_class = (char*) wndconfig->title;
|
||||
else
|
||||
hint->res_class = (char*) "GLFW-Application";
|
||||
}
|
||||
|
||||
XSetClassHint(_glfw.x11.display, window->x11.handle, hint);
|
||||
XFree(hint);
|
||||
free(wm_cclass); free(wm_cname);
|
||||
_glfwPlatformSetWindowTitle(window, real_title);
|
||||
}
|
||||
|
||||
// Announce support for Xdnd (drag and drop)
|
||||
@@ -756,6 +745,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
||||
PropModeReplace, (unsigned char*) &version, 1);
|
||||
}
|
||||
|
||||
_glfwPlatformSetWindowTitle(window, wndconfig->title);
|
||||
|
||||
if (_glfw.x11.im)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ to render arbitrary pixel (raster) graphics to the screen of the terminal
|
||||
emulator. The major design goals are
|
||||
|
||||
* Should not require terminal emulators to understand image formats.
|
||||
* Should allow specifying graphics to be drawn at individual pixel positions.
|
||||
* Should allow specifying graphics to be drawn at individual pixel positions.
|
||||
* The graphics should integrate with the text, in particular it should be possible to draw graphics
|
||||
below as well as above the text, with alpha blending. The graphics should also scroll with the text, automatically.
|
||||
* Should use optimizations when the client is running on the same computer as the terminal emulator.
|
||||
@@ -21,7 +21,7 @@ To see a quick demo, inside a kitty terminal run:
|
||||
kitty icat path/to/some/image.png
|
||||
```
|
||||
|
||||
You can also see a screenshot with more sophisticated features such as alpha-blending and text over graphics
|
||||
You can also see a screenshot with more sophisticated features such as alpha-blending and text over graphics
|
||||
link:https://github.com/kovidgoyal/kitty/issues/33#issuecomment-334436100[here].
|
||||
|
||||
toc::[]
|
||||
@@ -33,7 +33,7 @@ window size in pixels and the number of cells per row and column. This can be do
|
||||
Some C code to demonstrate its use
|
||||
|
||||
```C
|
||||
struct ttysize ts;
|
||||
struct ttysize ts;
|
||||
ioctl(0, TIOCGWINSZ, &ts);
|
||||
printf("number of columns: %i, number of rows: %i, screen width: %i, screen height: %i\n", sz.ws_col, sz.ws_row, sz.ws_xpixel, sz.ws_ypixel);
|
||||
```
|
||||
@@ -50,7 +50,7 @@ All graphics escape codes are of the form:
|
||||
```
|
||||
|
||||
This is a so-called _Application Programming Command (APC)_. Most terminal
|
||||
emulators ignore APC codes, making it safe to use.
|
||||
emulators ignore APC codes, making it safe to use.
|
||||
|
||||
The control data is a comma-separated list of `key=value` pairs. The payload
|
||||
is arbitrary binary data, base64-encoded to prevent interoperation problems
|
||||
@@ -124,12 +124,12 @@ The transmission medium is specified using the `t` key. The `t` key defaults to
|
||||
and can take the values:
|
||||
|
||||
|===
|
||||
| Value of `t` | Meaning
|
||||
| Value of `t` | Meaning
|
||||
|
||||
| d | Direct (the data is transmitted within the escape code itself)
|
||||
| f | A simple file
|
||||
| t | A temporary file, the terminal emulator will delete the file after reading the pixel data
|
||||
| s | A http://man7.org/linux/man-pages/man7/shm_overview.7.html[POSIX shared memory object]. The terminal emulator will delete it after reading the pixel data
|
||||
| s | A http://man7.org/linux/man-pages/man7/shm_overview.7.html[POSIX shared memory object]. The terminal emulator will delete it after reading the pixel data
|
||||
|===
|
||||
|
||||
==== Local client
|
||||
@@ -175,9 +175,9 @@ if the data is split into three chunks, the client would send the following
|
||||
sequence of escape codes to the terminal emulator:
|
||||
|
||||
```
|
||||
<ESC>_Gs=100,v=30,m=1;<encoded pixel data first chunk><ESC>\
|
||||
<ESC>_Gm=1;<encoded pixel data second chunk><ESC>\
|
||||
<ESC>_Gm=0;<encoded pixel data last chunk><ESC>\
|
||||
<ESC>_Gs=100,v=30,m=1;<encoded pixel data first chunk><ESC>\
|
||||
<ESC>_Gm=1;<encoded pixel data second chunk><ESC>\
|
||||
<ESC>_Gm=0;<encoded pixel data last chunk><ESC>\
|
||||
```
|
||||
|
||||
Note that only the first escape code needs to have the full set of control
|
||||
@@ -189,7 +189,7 @@ before sending any other graphics related escape codes.
|
||||
=== Detecting available transmission mediums
|
||||
|
||||
Since a client has no a-priori knowledge of whether it shares a filesystem/shared memory
|
||||
with the terminal emulator, it can send an id with the control data, using the `i` key
|
||||
with the terminal emulator, it can send an id with the control data, using the `i` key
|
||||
(which can be an arbitrary positive integer up to 4294967295, it must not be zero).
|
||||
If it does so, the terminal emulator will reply after trying to load the image, saying
|
||||
whether loading was successful or not. For example:
|
||||
@@ -207,7 +207,7 @@ to which the terminal emulator will reply (after trying to load the data):
|
||||
Here the `i` value will be the same as was sent by the client in the original
|
||||
request. The message data will be a ASCII encoded string containing only
|
||||
printable characters and spaces. The string will be `OK` if reading the pixel
|
||||
data succeeded or an error message.
|
||||
data succeeded or an error message.
|
||||
|
||||
Sometimes, using an id is not appropriate, for example, if you do not want to
|
||||
replace a previously sent image with the same id, or if you are sending a dummy
|
||||
@@ -245,7 +245,7 @@ be re-transmitted.
|
||||
=== Controlling displayed image layout
|
||||
|
||||
The image is rendered at the current cursor position, from the upper left corner of
|
||||
the current cell. You can also specify extra `X=3` and `Y=4` pixel offsets to display from
|
||||
the current cell. You can also specify extra `X=3` and `Y=4` pixel offsets to display from
|
||||
a different origin within the cell. Note that the offsets must be smaller that the size of the cell.
|
||||
|
||||
By default, the entire image will be displayed (images wider than the available
|
||||
@@ -255,7 +255,7 @@ the top-left corner, width and height of the source rectangle.
|
||||
|
||||
You can also ask the terminal emulator to display the image in a specified rectangle
|
||||
(num of columns / num of lines), using the control codes `c,r`. `c` is the number of columns
|
||||
and `r` the number of rows. The image will be scaled (enlarged/shrunk) as needed to fit
|
||||
and `r` the number of rows. The image will be scaled (enlarged/shrunk) as needed to fit
|
||||
the specified area. Note that if you specify a start cell offset via the `X,Y` keys, it is not
|
||||
added to the number of rows/columns.
|
||||
|
||||
@@ -269,7 +269,7 @@ allows rendering of text on top of images.
|
||||
|
||||
Images can be deleted by using the delete action `a=d`. If specified without any
|
||||
other keys, it will delete all images visible on screen. To delete specific images,
|
||||
use the `d` key as described in the table below. Note that each value of d has
|
||||
use the `d` key as described in the table below. Note that each value of d has
|
||||
both a lowercase and an uppercase variant. The lowercase variant only deletes the
|
||||
images without necessarily freeing up the stored image data, so that the images can be
|
||||
re-displayed without needing to resend the data. The uppercase variants will delete
|
||||
@@ -278,7 +278,7 @@ scrollback buffer. The values of the `x` and `y` keys are the same as cursor pos
|
||||
x=1, y=1 is the top left cell).
|
||||
|
||||
|===
|
||||
| Value of `d` | Meaning
|
||||
| Value of `d` | Meaning
|
||||
|
||||
| `a` or `A` | Delete all images visible on screen
|
||||
| `i` or `I` | Delete all images with the specified id, specified using the `i` key.
|
||||
@@ -313,7 +313,7 @@ delete older images to make space for the new one.
|
||||
== Control data reference
|
||||
|
||||
The table below shows all the control data keys as well as what values they can
|
||||
take, and the default value they take when missing. All integers are 32-bit.
|
||||
take, and the default value they take when missing. All integers are 32-bit.
|
||||
|
||||
[cols="^1,<3,^1,<6"]
|
||||
|===
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
#define bottom -1.0f
|
||||
|
||||
const vec2 pos_map[] = vec2[4](
|
||||
vec2(right, top),
|
||||
vec2(right, bottom),
|
||||
vec2(left, bottom),
|
||||
vec2(left, top)
|
||||
vec2(right, top),
|
||||
vec2(right, bottom),
|
||||
vec2(left, bottom),
|
||||
vec2(left, top)
|
||||
);
|
||||
|
||||
out vec2 texcoord;
|
||||
|
||||
@@ -11,10 +11,10 @@ const int RIGHT = 2;
|
||||
const int BOTTOM = 3;
|
||||
|
||||
const uvec2 pos_map[] = uvec2[4](
|
||||
uvec2(RIGHT, TOP),
|
||||
uvec2(RIGHT, BOTTOM),
|
||||
uvec2(LEFT, BOTTOM),
|
||||
uvec2(LEFT, TOP)
|
||||
uvec2(RIGHT, TOP),
|
||||
uvec2(RIGHT, BOTTOM),
|
||||
uvec2(LEFT, BOTTOM),
|
||||
uvec2(LEFT, TOP)
|
||||
);
|
||||
|
||||
vec2 to_opengl(uint x, uint y) {
|
||||
|
||||
103
kitty/boss.py
103
kitty/boss.py
@@ -7,21 +7,20 @@ from weakref import WeakValueDictionary
|
||||
|
||||
from .cli import create_opts, parse_args
|
||||
from .config import MINIMUM_FONT_SIZE, cached_values, initial_window_size
|
||||
from .constants import set_boss, wakeup
|
||||
from .constants import appname, set_boss, wakeup
|
||||
from .fast_data_types import (
|
||||
ChildMonitor, create_os_window, current_os_window, destroy_global_data,
|
||||
destroy_sprite_map, get_clipboard_string, glfw_post_empty_event,
|
||||
layout_sprite_map, mark_os_window_for_close, show_window,
|
||||
toggle_fullscreen, viewport_for_window
|
||||
layout_sprite_map, mark_os_window_for_close, set_dpi_from_os_window,
|
||||
show_window, toggle_fullscreen, viewport_for_window
|
||||
)
|
||||
from .fonts.render import prerender, resize_fonts, set_font_family
|
||||
from .keys import get_shortcut
|
||||
from .session import create_session
|
||||
from .tabs import SpecialWindow, TabManager
|
||||
from .utils import (
|
||||
encode_wm_class, end_startup_notification, get_primary_selection,
|
||||
init_startup_notification, open_url, safe_print, set_primary_selection,
|
||||
single_instance
|
||||
end_startup_notification, get_primary_selection, init_startup_notification,
|
||||
open_url, safe_print, set_primary_selection, single_instance
|
||||
)
|
||||
|
||||
|
||||
@@ -79,18 +78,34 @@ class Boss:
|
||||
startup_session = create_session(opts, args)
|
||||
self.add_os_window(startup_session, os_window_id=os_window_id)
|
||||
|
||||
def add_os_window(self, startup_session, os_window_id=None, wclass=None, wname=None, size=None, visible=True):
|
||||
def add_os_window(self, startup_session, os_window_id=None, wclass=None, wname=None, size=None, startup_id=None):
|
||||
dpi_changed = False
|
||||
if os_window_id is None:
|
||||
w, h = initial_window_size(self.opts) if size is None else size
|
||||
os_window_id = create_os_window(w, h, encode_wm_class(wname or self.args.name, wclass or self.args.cls), visible)
|
||||
cls = wclass or self.args.cls or appname
|
||||
os_window_id = create_os_window(w, h, appname, wname or self.args.name or cls, cls)
|
||||
if startup_id:
|
||||
ctx = init_startup_notification(os_window_id, startup_id)
|
||||
dpi_changed = show_window(os_window_id)
|
||||
if startup_id:
|
||||
end_startup_notification(ctx)
|
||||
tm = TabManager(os_window_id, self.opts, self.args, startup_session)
|
||||
self.os_window_map[os_window_id] = tm
|
||||
return os_window_id
|
||||
if dpi_changed:
|
||||
self.on_dpi_change(os_window_id)
|
||||
|
||||
def _new_os_window(self, args, cwd_from=None):
|
||||
sw = self.args_to_special_window(args, cwd_from) if args else None
|
||||
startup_session = create_session(self.opts, special_window=sw, cwd_from=cwd_from)
|
||||
self.add_os_window(startup_session)
|
||||
|
||||
def new_os_window(self, *args):
|
||||
sw = self.args_to_special_window(args) if args else None
|
||||
startup_session = create_session(self.opts, special_window=sw)
|
||||
return self.add_os_window(startup_session)
|
||||
self._new_os_window(args)
|
||||
|
||||
def new_os_window_with_cwd(self, *args):
|
||||
w = self.active_window
|
||||
cwd_from = w.child.pid if w is not None else None
|
||||
self._new_os_window(args, cwd_from)
|
||||
|
||||
def add_child(self, window):
|
||||
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
||||
@@ -106,12 +121,7 @@ class Boss:
|
||||
args.args = rest
|
||||
opts = create_opts(args)
|
||||
session = create_session(opts, args)
|
||||
os_window_id = self.add_os_window(session, wclass=args.cls, wname=args.name, size=initial_window_size(opts), visible=False)
|
||||
if startup_id:
|
||||
ctx = init_startup_notification(os_window_id, startup_id)
|
||||
show_window(os_window_id)
|
||||
if startup_id:
|
||||
end_startup_notification(ctx)
|
||||
self.add_os_window(session, wclass=args.cls, wname=args.name, size=initial_window_size(opts), startup_id=startup_id)
|
||||
else:
|
||||
safe_print('Unknown message received from peer, ignoring')
|
||||
|
||||
@@ -162,10 +172,16 @@ class Boss:
|
||||
if tm is not None:
|
||||
tm.activate_tab_at(x)
|
||||
|
||||
def on_window_resize(self, os_window_id, w, h):
|
||||
def on_window_resize(self, os_window_id, w, h, dpi_changed):
|
||||
tm = self.os_window_map.get(os_window_id)
|
||||
if tm is not None:
|
||||
tm.resize()
|
||||
if dpi_changed:
|
||||
if set_dpi_from_os_window(os_window_id):
|
||||
self.on_dpi_change(os_window_id)
|
||||
else:
|
||||
tm.resize()
|
||||
else:
|
||||
tm.resize()
|
||||
|
||||
def increase_font_size(self):
|
||||
self.change_font_size(
|
||||
@@ -182,10 +198,9 @@ class Boss:
|
||||
def restore_font_size(self):
|
||||
self.change_font_size(self.opts.font_size)
|
||||
|
||||
def change_font_size(self, new_size):
|
||||
if new_size == self.current_font_size:
|
||||
return
|
||||
self.current_font_size = new_size
|
||||
def _change_font_size(self, new_size=None):
|
||||
if new_size is not None:
|
||||
self.current_font_size = new_size
|
||||
old_cell_width, old_cell_height = viewport_for_window()[-2:]
|
||||
windows = tuple(filter(None, self.window_id_map.values()))
|
||||
resize_fonts(self.current_font_size)
|
||||
@@ -199,6 +214,14 @@ class Boss:
|
||||
tm.refresh_sprite_positions()
|
||||
glfw_post_empty_event()
|
||||
|
||||
def change_font_size(self, new_size):
|
||||
if new_size == self.current_font_size:
|
||||
return
|
||||
self._change_font_size(new_size)
|
||||
|
||||
def on_dpi_change(self, os_window_id):
|
||||
self._change_font_size()
|
||||
|
||||
@property
|
||||
def active_tab_manager(self):
|
||||
os_window_id = current_os_window()
|
||||
@@ -342,7 +365,7 @@ class Boss:
|
||||
if tm is not None:
|
||||
tm.next_tab(-1)
|
||||
|
||||
def args_to_special_window(self, args):
|
||||
def args_to_special_window(self, args, cwd_from=None):
|
||||
args = list(args)
|
||||
stdin = None
|
||||
w = self.active_window
|
||||
@@ -368,23 +391,39 @@ class Boss:
|
||||
if not arg:
|
||||
continue
|
||||
cmd.append(arg)
|
||||
return SpecialWindow(cmd, stdin)
|
||||
return SpecialWindow(cmd, stdin, cwd_from=cwd_from)
|
||||
|
||||
def new_tab(self, *args):
|
||||
def _new_tab(self, args, cwd_from=None):
|
||||
special_window = None
|
||||
if args:
|
||||
special_window = self.args_to_special_window(args)
|
||||
special_window = self.args_to_special_window(args, cwd_from=cwd_from)
|
||||
tm = self.active_tab_manager
|
||||
if tm is not None:
|
||||
tm.new_tab(special_window=special_window)
|
||||
tm.new_tab(special_window=special_window, cwd_from=cwd_from)
|
||||
|
||||
def new_window(self, *args):
|
||||
def new_tab(self, *args):
|
||||
self._new_tab(args)
|
||||
|
||||
def new_tab_with_cwd(self, *args):
|
||||
w = self.active_window
|
||||
cwd_from = w.child.pid if w is not None else None
|
||||
self._new_tab(args, cwd_from=cwd_from)
|
||||
|
||||
def _new_window(self, args, cwd_from=None):
|
||||
tab = self.active_tab
|
||||
if tab is not None:
|
||||
if args:
|
||||
tab.new_special_window(self.args_to_special_window(args))
|
||||
tab.new_special_window(self.args_to_special_window(args, cwd_from=cwd_from))
|
||||
else:
|
||||
tab.new_window()
|
||||
tab.new_window(cwd_from=cwd_from)
|
||||
|
||||
def new_window(self, *args):
|
||||
self._new_window(args)
|
||||
|
||||
def new_window_with_cwd(self, *args):
|
||||
w = self.active_window
|
||||
cwd_from = w.child.pid if w is not None else None
|
||||
self._new_window(args, cwd_from=cwd_from)
|
||||
|
||||
def move_tab_forward(self):
|
||||
tm = self.active_tab_manager
|
||||
|
||||
@@ -19,6 +19,7 @@ in float bg_alpha;
|
||||
|
||||
#ifdef NEEDS_FOREGROUND
|
||||
uniform sampler2DArray sprites;
|
||||
uniform float inactive_text_alpha;
|
||||
in vec3 sprite_pos;
|
||||
in vec3 underline_pos;
|
||||
in vec3 strike_pos;
|
||||
@@ -34,7 +35,7 @@ vec4 alpha_blend(vec3 over, float over_alpha, vec3 under, float under_alpha) {
|
||||
// Alpha blend two colors returning the resulting color pre-multiplied by its alpha
|
||||
// and its alpha.
|
||||
// See https://en.wikipedia.org/wiki/Alpha_compositing
|
||||
float alpha = mix(under_alpha, 1.0f, over_alpha);
|
||||
float alpha = mix(under_alpha, 1.0f, over_alpha);
|
||||
vec3 combined_color = mix(under * under_alpha, over, over_alpha);
|
||||
return vec4(combined_color, alpha);
|
||||
}
|
||||
@@ -45,7 +46,7 @@ vec3 premul_blend(vec3 over, float over_alpha, vec3 under) {
|
||||
|
||||
vec4 alpha_blend_premul(vec3 over, float over_alpha, vec3 under, float under_alpha) {
|
||||
// Same as alpha_blend() except that it assumes over and under are both premultiplied.
|
||||
float alpha = mix(under_alpha, 1.0f, over_alpha);
|
||||
float alpha = mix(under_alpha, 1.0f, over_alpha);
|
||||
return vec4(premul_blend(over, over_alpha, under), alpha);
|
||||
}
|
||||
// }}}
|
||||
@@ -60,7 +61,7 @@ vec4 calculate_foreground() {
|
||||
// Since strike and text are the same color, we simply add the alpha values
|
||||
float combined_alpha = min(text_alpha + strike_alpha, 1.0f);
|
||||
// Underline color might be different, so alpha blend
|
||||
return alpha_blend(decoration_fg, underline_alpha, fg, combined_alpha);
|
||||
return alpha_blend(decoration_fg, underline_alpha * inactive_text_alpha, fg, combined_alpha * inactive_text_alpha);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -70,7 +71,7 @@ void main() {
|
||||
final_color = vec4(background.rgb * bg_alpha, bg_alpha);
|
||||
#else
|
||||
final_color = vec4(background.rgb, 1.0f);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SPECIAL
|
||||
@@ -78,10 +79,10 @@ void main() {
|
||||
final_color = vec4(background.rgb * bg_alpha, bg_alpha);
|
||||
#else
|
||||
final_color = vec4(background.rgb, bg_alpha);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(FOREGROUND) || defined(SIMPLE)
|
||||
#if defined(FOREGROUND) || defined(SIMPLE)
|
||||
// FOREGROUND or SIMPLE
|
||||
vec4 fg = calculate_foreground(); // pre-multiplied foreground
|
||||
|
||||
@@ -99,7 +100,7 @@ void main() {
|
||||
final_color = alpha_blend_premul(fg.rgb, fg.a, background * bg_alpha, bg_alpha);
|
||||
final_color = vec4(final_color.rgb / final_color.a, final_color.a);
|
||||
#else
|
||||
// since background alpha is 1.0, it is effectively premultipled
|
||||
// since background alpha is 1.0, it is effectively pre-multiplied
|
||||
final_color = vec4(premul_blend(fg.rgb, fg.a, background), 1.0f);
|
||||
final_color = vec4(final_color.rgb / final_color.a, final_color.a);
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@ layout(std140) uniform CellRenderData {
|
||||
|
||||
uint xnum, ynum, cursor_x, cursor_y, cursor_w;
|
||||
|
||||
uint color_table[256];
|
||||
uint color_table[256];
|
||||
};
|
||||
|
||||
// Have to use fixed locations here as all variants of the cell program share the same VAO
|
||||
@@ -21,7 +21,7 @@ layout(location=1) in uvec4 sprite_coords;
|
||||
layout(location=2) in uint is_selected;
|
||||
|
||||
|
||||
|
||||
|
||||
const uvec2 cell_pos_map[] = uvec2[4](
|
||||
uvec2(1, 0), // right, top
|
||||
uvec2(1, 1), // right, bottom
|
||||
@@ -118,27 +118,27 @@ float is_cursor(uint x, uint y) {
|
||||
void main() {
|
||||
|
||||
// set cell vertex position {{{
|
||||
uint instance_id = uint(gl_InstanceID);
|
||||
uint instance_id = uint(gl_InstanceID);
|
||||
/* The current cell being rendered */
|
||||
uint r = instance_id / xnum;
|
||||
uint c = instance_id - r * xnum;
|
||||
uint r = instance_id / xnum;
|
||||
uint c = instance_id - r * xnum;
|
||||
|
||||
/* The position of this vertex, at a corner of the cell */
|
||||
float left = xstart + c * dx;
|
||||
float top = ystart - r * dy;
|
||||
vec2 xpos = vec2(left, left + dx);
|
||||
vec2 ypos = vec2(top, top - dy);
|
||||
uvec2 pos = cell_pos_map[gl_VertexID];
|
||||
/* The position of this vertex, at a corner of the cell */
|
||||
float left = xstart + c * dx;
|
||||
float top = ystart - r * dy;
|
||||
vec2 xpos = vec2(left, left + dx);
|
||||
vec2 ypos = vec2(top, top - dy);
|
||||
uvec2 pos = cell_pos_map[gl_VertexID];
|
||||
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
|
||||
|
||||
// }}}
|
||||
|
||||
|
||||
// set cell color indices {{{
|
||||
uvec2 default_colors = uvec2(default_fg, default_bg);
|
||||
ivec2 color_indices = ivec2(color1, color2);
|
||||
uint text_attrs = sprite_coords[3];
|
||||
int fg_index = color_indices[(text_attrs >> 6) & REVERSE_MASK];
|
||||
int bg_index = color_indices[1 - fg_index];
|
||||
uvec2 default_colors = uvec2(default_fg, default_bg);
|
||||
ivec2 color_indices = ivec2(color1, color2);
|
||||
uint text_attrs = sprite_coords[3];
|
||||
int fg_index = color_indices[(text_attrs >> 6) & REVERSE_MASK];
|
||||
int bg_index = color_indices[1 - fg_index];
|
||||
float cursor = is_cursor(c, r);
|
||||
vec3 bg = to_color(colors[bg_index], default_colors[bg_index]);
|
||||
// }}}
|
||||
@@ -150,7 +150,7 @@ void main() {
|
||||
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & Z_MASK);
|
||||
colored_sprite = float((sprite_coords.z & COLOR_MASK) >> 14);
|
||||
|
||||
// Foreground
|
||||
// Foreground
|
||||
uint resolved_fg = resolve_color(colors[fg_index], default_colors[fg_index]);
|
||||
foreground = color_to_vec(resolved_fg);
|
||||
// Selection
|
||||
@@ -165,7 +165,7 @@ void main() {
|
||||
foreground = choose_color(cursor, bg, foreground);
|
||||
decoration_fg = choose_color(cursor, bg, decoration_fg);
|
||||
#endif
|
||||
// }}}
|
||||
// }}}
|
||||
|
||||
// Background {{{
|
||||
#ifdef NEEDS_BACKROUND
|
||||
|
||||
18
kitty/charsets.c
generated
18
kitty/charsets.c
generated
@@ -43,7 +43,7 @@ static uint32_t charset_translations[5][256] = {
|
||||
0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
|
||||
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
|
||||
0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
|
||||
},
|
||||
},
|
||||
/* VT100 graphics mapped to Unicode */
|
||||
{
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
@@ -81,7 +81,7 @@ static uint32_t charset_translations[5][256] = {
|
||||
},
|
||||
/* IBM Codepage 437 mapped to Unicode */
|
||||
{
|
||||
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
|
||||
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
|
||||
0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
|
||||
0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
|
||||
0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
|
||||
@@ -113,7 +113,7 @@ static uint32_t charset_translations[5][256] = {
|
||||
0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
|
||||
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
|
||||
0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
|
||||
},
|
||||
},
|
||||
// VAX 42 map
|
||||
{
|
||||
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
|
||||
@@ -183,13 +183,13 @@ static uint32_t charset_translations[5][256] = {
|
||||
0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
|
||||
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
|
||||
0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
uint32_t*
|
||||
uint32_t*
|
||||
translation_table(uint32_t which) {
|
||||
switch(which){
|
||||
switch(which){
|
||||
case 'B':
|
||||
return charset_translations[0];
|
||||
case '0':
|
||||
@@ -208,7 +208,7 @@ translation_table(uint32_t which) {
|
||||
uint32_t *latin1_charset = charset_translations[0];
|
||||
|
||||
// UTF-8 decode taken from: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||
|
||||
|
||||
static const uint8_t utf8_data[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
|
||||
@@ -226,7 +226,7 @@ static const uint8_t utf8_data[] = {
|
||||
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
|
||||
};
|
||||
|
||||
uint32_t
|
||||
uint32_t
|
||||
decode_utf8(uint32_t* state, uint32_t* codep, uint8_t byte) {
|
||||
uint32_t type = utf8_data[byte];
|
||||
|
||||
@@ -278,7 +278,7 @@ base64_decode(const uint32_t *src, size_t src_sz, uint8_t *dest, size_t dest_cap
|
||||
if (!src_sz) { *dest_sz = 0; return NULL; }
|
||||
if (src_sz % 4 != 0) return "base64 encoded data must have a length that is a multiple of four";
|
||||
*dest_sz = (src_sz / 4) * 3;
|
||||
if (src[src_sz - 1] == '=') (*dest_sz)--;
|
||||
if (src[src_sz - 1] == '=') (*dest_sz)--;
|
||||
if (src[src_sz - 2] == '=') (*dest_sz)--;
|
||||
if (*dest_sz > dest_capacity) return "output buffer too small";
|
||||
for (size_t i = 0, j = 0; i < src_sz;) {
|
||||
|
||||
@@ -95,7 +95,7 @@ set_thread_name(const char *name) {
|
||||
#define FREE_CHILD(x) \
|
||||
Py_CLEAR((x).screen); x = EMPTY_CHILD;
|
||||
|
||||
#define XREF_CHILD(x, OP) OP(x.screen);
|
||||
#define XREF_CHILD(x, OP) OP(x.screen);
|
||||
#define INCREF_CHILD(x) XREF_CHILD(x, Py_INCREF)
|
||||
#define DECREF_CHILD(x) XREF_CHILD(x, Py_DECREF)
|
||||
|
||||
@@ -138,12 +138,12 @@ self_pipe(int fds[2]) {
|
||||
static PyObject *
|
||||
new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
ChildMonitor *self;
|
||||
PyObject *dump_callback, *death_notify;
|
||||
PyObject *dump_callback, *death_notify;
|
||||
int talk_fd = -1;
|
||||
int ret;
|
||||
|
||||
if (the_monitor) { PyErr_SetString(PyExc_RuntimeError, "Can have only a single ChildMonitor instance"); return NULL; }
|
||||
if (!PyArg_ParseTuple(args, "OO|i", &death_notify, &dump_callback, &talk_fd)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "OO|i", &death_notify, &dump_callback, &talk_fd)) return NULL;
|
||||
if ((ret = pthread_mutex_init(&children_lock, NULL)) != 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Failed to create children_lock mutex: %s", strerror(ret));
|
||||
return NULL;
|
||||
@@ -163,7 +163,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
self->dump_callback = dump_callback; Py_INCREF(dump_callback);
|
||||
parse_func = parse_worker_dump;
|
||||
} else parse_func = parse_worker;
|
||||
self->count = 0;
|
||||
self->count = 0;
|
||||
fds[0].fd = wakeup_fds[0]; fds[1].fd = signal_fds[0];
|
||||
fds[0].events = POLLIN; fds[1].events = POLLIN;
|
||||
the_monitor = self;
|
||||
@@ -187,7 +187,7 @@ dealloc(ChildMonitor* self) {
|
||||
}
|
||||
close(wakeup_fds[0]);
|
||||
close(wakeup_fds[1]);
|
||||
close(signal_fds[0]);
|
||||
close(signal_fds[0]);
|
||||
close(signal_fds[1]);
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ add_child(ChildMonitor *self, PyObject *args) {
|
||||
#define A(attr) &add_queue[add_queue_count].attr
|
||||
if (!PyArg_ParseTuple(args, "kiiO", A(id), A(pid), A(fd), A(screen))) {
|
||||
children_mutex(unlock);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
#undef A
|
||||
INCREF_CHILD(add_queue[add_queue_count]);
|
||||
@@ -259,12 +259,12 @@ schedule_write_to_child(unsigned long id, const char *data, size_t sz) {
|
||||
bool found = false;
|
||||
children_mutex(lock);
|
||||
for (size_t i = 0; i < self->count; i++) {
|
||||
if (children[i].id == id) {
|
||||
if (children[i].id == id) {
|
||||
found = true;
|
||||
Screen *screen = children[i].screen;
|
||||
screen_mutex(lock, write);
|
||||
size_t space_left = screen->write_buf_sz - screen->write_buf_used;
|
||||
if (space_left < sz) {
|
||||
if (space_left < sz) {
|
||||
if (screen->write_buf_used + sz > 100 * 1024 * 1024) {
|
||||
fprintf(stderr, "Too much data being sent to child with id: %lu, ignoring it\n", id);
|
||||
screen_mutex(unlock, write);
|
||||
@@ -295,7 +295,7 @@ needs_write(ChildMonitor UNUSED *self, PyObject *args) {
|
||||
#define needs_write_doc "needs_write(id, data) -> Queue data to be written to child."
|
||||
unsigned long id, sz;
|
||||
const char *data;
|
||||
if (!PyArg_ParseTuple(args, "ks#", &id, &data, &sz)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "ks#", &id, &data, &sz)) return NULL;
|
||||
if (schedule_write_to_child(id, data, sz)) { Py_RETURN_TRUE; }
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
@@ -332,7 +332,7 @@ parse_input(ChildMonitor *self) {
|
||||
PyObject *msg = NULL;
|
||||
children_mutex(lock);
|
||||
while (remove_queue_count) {
|
||||
remove_queue_count--;
|
||||
remove_queue_count--;
|
||||
remove_notify[remove_count] = remove_queue[remove_queue_count].id;
|
||||
remove_count++;
|
||||
FREE_CHILD(remove_queue[remove_queue_count]);
|
||||
@@ -517,7 +517,8 @@ collect_cursor_info(CursorRenderInfo *ans, Window *w, double now, OSWindow *os_w
|
||||
ColorProfile *cp = rd->screen->color_profile;
|
||||
ans->shape = cursor->shape ? cursor->shape : OPT(cursor_shape);
|
||||
ans->color = colorprofile_to_color(cp, cp->overridden.cursor_color, cp->configured.cursor_color);
|
||||
if (ans->shape == CURSOR_BLOCK) return;
|
||||
ans->is_focused = os_window->is_focused;
|
||||
if (ans->shape == CURSOR_BLOCK && ans->is_focused) return;
|
||||
double left = rd->xstart + cursor->x * rd->dx;
|
||||
double top = rd->ystart - cursor->y * rd->dy;
|
||||
unsigned long mult = MAX(1, screen_current_char_width(rd->screen));
|
||||
@@ -544,13 +545,13 @@ update_window_title(Window *w, OSWindow *os_window) {
|
||||
static PyObject*
|
||||
simple_render_screen(PyObject UNUSED *self, PyObject *args) {
|
||||
#define simple_render_screen_doc "Render a Screen object, with no cursor"
|
||||
Screen *screen;
|
||||
Screen *screen;
|
||||
float xstart, ystart, dx, dy;
|
||||
static ssize_t vao_idx = -1, gvao_idx = -1;
|
||||
if (vao_idx == -1) vao_idx = create_cell_vao();
|
||||
if (gvao_idx == -1) gvao_idx = create_graphics_vao();
|
||||
if (!PyArg_ParseTuple(args, "O!ffff", &Screen_Type, &screen, &xstart, &ystart, &dx, &dy)) return NULL;
|
||||
draw_cells(vao_idx, gvao_idx, xstart, ystart, dx, dy, screen, current_os_window());
|
||||
draw_cells(vao_idx, gvao_idx, xstart, ystart, dx, dy, screen, current_os_window(), true);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -563,7 +564,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id
|
||||
#define WD w->render_data
|
||||
if (w->visible && WD.screen) {
|
||||
if (w->last_drag_scroll_at > 0) {
|
||||
if (now - w->last_drag_scroll_at >= 0.02) {
|
||||
if (now - w->last_drag_scroll_at >= 0.02) {
|
||||
if (drag_scroll(w, os_window)) {
|
||||
w->last_drag_scroll_at = now;
|
||||
set_maximum_wait(0.02);
|
||||
@@ -576,8 +577,8 @@ render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id
|
||||
collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
|
||||
update_window_title(w, os_window);
|
||||
} else WD.screen->cursor_render_info.is_visible = false;
|
||||
draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window);
|
||||
if (is_active_window && WD.screen->cursor_render_info.is_visible && WD.screen->cursor_render_info.shape != CURSOR_BLOCK) {
|
||||
draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window, is_active_window);
|
||||
if (is_active_window && WD.screen->cursor_render_info.is_visible && (!WD.screen->cursor_render_info.is_focused || WD.screen->cursor_render_info.shape != CURSOR_BLOCK)) {
|
||||
draw_cursor(&WD.screen->cursor_render_info, os_window->is_focused);
|
||||
}
|
||||
if (WD.screen->start_visual_bell_at != 0) {
|
||||
@@ -592,7 +593,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id
|
||||
static inline void
|
||||
render(double now) {
|
||||
double time_since_last_render = now - last_render_at;
|
||||
if (time_since_last_render < OPT(repaint_delay)) {
|
||||
if (time_since_last_render < OPT(repaint_delay)) {
|
||||
set_maximum_wait(OPT(repaint_delay) - time_since_last_render);
|
||||
return;
|
||||
}
|
||||
@@ -612,7 +613,7 @@ render(double now) {
|
||||
Tab *active_tab = w->tabs + w->active_tab;
|
||||
BorderRects *br = &active_tab->border_rects;
|
||||
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, w->viewport_width, w->viewport_height);
|
||||
if (TD.screen && w->num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, w);
|
||||
if (TD.screen && w->num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, w, true);
|
||||
swap_window_buffers(w);
|
||||
w->last_active_tab = w->active_tab; w->last_num_tabs = w->num_tabs; w->last_active_window_id = active_window_id;
|
||||
br->is_dirty = false;
|
||||
@@ -663,7 +664,7 @@ cm_thread_write(PyObject UNUSED *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, "is#", &fd, &buf, &sz)) return NULL;
|
||||
ThreadWriteData *data = alloc_twd(sz);
|
||||
if (data == NULL) return PyErr_NoMemory();
|
||||
data->fd = fd;
|
||||
data->fd = fd;
|
||||
memcpy(data->buf, buf, data->sz);
|
||||
int ret = pthread_create(&thread, NULL, thread_write, data);
|
||||
if (ret != 0) { free_twd(data); return PyErr_SetFromErrno(PyExc_OSError); }
|
||||
@@ -716,7 +717,7 @@ main_loop(ChildMonitor *self) {
|
||||
Tab *tab = os_window->tabs + t;
|
||||
for (size_t w = 0; w < tab->num_windows; w++) mark_child_for_close(self, tab->windows[w].id);
|
||||
}
|
||||
remove_os_window(os_window->id);
|
||||
remove_os_window(os_window->id);
|
||||
} else has_open_windows = true;
|
||||
}
|
||||
}
|
||||
@@ -748,7 +749,7 @@ hangup(pid_t pid) {
|
||||
if (errno == ESRCH) return;
|
||||
if (errno != 0) { perror("Failed to get process group id for child"); return; }
|
||||
if (killpg(pgid, SIGHUP) != 0) {
|
||||
if (errno != ESRCH) perror("Failed to kill child");
|
||||
if (errno != ESRCH) perror("Failed to kill child");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,7 +764,7 @@ cleanup_child(ssize_t i) {
|
||||
static inline void
|
||||
remove_children(ChildMonitor *self) {
|
||||
if (self->count > 0) {
|
||||
size_t count = 0;
|
||||
size_t count = 0;
|
||||
for (ssize_t i = self->count - 1; i >= 0; i--) {
|
||||
if (children[i].needs_removal) {
|
||||
count++;
|
||||
@@ -839,7 +840,7 @@ write_to_child(int fd, Screen *screen) {
|
||||
while (written < screen->write_buf_used) {
|
||||
ret = write(fd, screen->write_buf + written, screen->write_buf_used - written);
|
||||
if (ret > 0) { written += ret; }
|
||||
else if (ret == 0) {
|
||||
else if (ret == 0) {
|
||||
// could mean anything, ignore
|
||||
break;
|
||||
} else {
|
||||
@@ -858,7 +859,7 @@ io_loop(void *data) {
|
||||
// The I/O thread loop
|
||||
size_t i;
|
||||
int ret;
|
||||
bool has_more, data_received;
|
||||
bool has_more, data_received;
|
||||
Screen *screen;
|
||||
ChildMonitor *self = (ChildMonitor*)data;
|
||||
set_thread_name("KittyChildMon");
|
||||
@@ -880,7 +881,7 @@ io_loop(void *data) {
|
||||
ret = poll(fds, self->count + EXTRA_FDS, -1);
|
||||
if (ret > 0) {
|
||||
if (fds[0].revents && POLLIN) drain_fd(fds[0].fd); // wakeup
|
||||
if (fds[1].revents && POLLIN) {
|
||||
if (fds[1].revents && POLLIN) {
|
||||
data_received = true;
|
||||
drain_fd(fds[1].fd);
|
||||
children_mutex(lock);
|
||||
@@ -891,7 +892,7 @@ io_loop(void *data) {
|
||||
if (fds[EXTRA_FDS + i].revents & (POLLIN | POLLHUP)) {
|
||||
data_received = true;
|
||||
has_more = read_bytes(fds[EXTRA_FDS + i].fd, children[i].screen);
|
||||
if (!has_more) {
|
||||
if (!has_more) {
|
||||
// child is dead
|
||||
children_mutex(lock);
|
||||
children[i].needs_removal = true;
|
||||
@@ -968,7 +969,7 @@ handle_peer(ChildMonitor *self, int s) {
|
||||
static void*
|
||||
talk_loop(void *data) {
|
||||
// The I/O thread loop
|
||||
|
||||
|
||||
ChildMonitor *self = (ChildMonitor*)data;
|
||||
set_thread_name("KittyTalkMon");
|
||||
|
||||
@@ -986,7 +987,7 @@ talk_loop(void *data) {
|
||||
return 0;
|
||||
}
|
||||
// }}}
|
||||
|
||||
|
||||
// Boilerplate {{{
|
||||
static PyMethodDef methods[] = {
|
||||
METHOD(add_child, METH_VARARGS)
|
||||
@@ -1007,11 +1008,11 @@ PyTypeObject ChildMonitor_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.ChildMonitor",
|
||||
.tp_basicsize = sizeof(ChildMonitor),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "ChildMonitor",
|
||||
.tp_methods = methods,
|
||||
.tp_new = new,
|
||||
.tp_new = new,
|
||||
};
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
@@ -1023,10 +1024,9 @@ bool
|
||||
init_child_monitor(PyObject *module) {
|
||||
if (PyType_Ready(&ChildMonitor_Type) < 0) return false;
|
||||
if (PyModule_AddObject(module, "ChildMonitor", (PyObject *)&ChildMonitor_Type) != 0) return false;
|
||||
Py_INCREF(&ChildMonitor_Type);
|
||||
Py_INCREF(&ChildMonitor_Type);
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
|
||||
@@ -8,7 +8,16 @@ import sys
|
||||
|
||||
import kitty.fast_data_types as fast_data_types
|
||||
|
||||
from .constants import terminfo_dir
|
||||
from .constants import terminfo_dir, is_macos
|
||||
|
||||
|
||||
def cwd_of_process(pid):
|
||||
if is_macos:
|
||||
from kitty.fast_data_types import cwd_of_process
|
||||
ans = cwd_of_process(pid)
|
||||
else:
|
||||
ans = '/proc/{}/cwd'.format(pid)
|
||||
return os.path.realpath(ans)
|
||||
|
||||
|
||||
def remove_cloexec(fd):
|
||||
@@ -20,9 +29,17 @@ class Child:
|
||||
child_fd = pid = None
|
||||
forked = False
|
||||
|
||||
def __init__(self, argv, cwd, opts, stdin=None, env=None):
|
||||
def __init__(self, argv, cwd, opts, stdin=None, env=None, cwd_from=None):
|
||||
self.argv = argv
|
||||
self.cwd = os.path.abspath(os.path.expandvars(os.path.expanduser(cwd or os.getcwd())))
|
||||
if cwd_from is not None:
|
||||
try:
|
||||
cwd = cwd_of_process(cwd_from)
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
else:
|
||||
cwd = os.path.expandvars(os.path.expanduser(cwd or os.getcwd()))
|
||||
self.cwd = os.path.abspath(cwd)
|
||||
self.opts = opts
|
||||
self.stdin = stdin
|
||||
self.env = env or {}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <AvailabilityMacros.h>
|
||||
// Needed for _NSGetProgname
|
||||
#include <crt_externs.h>
|
||||
typedef void* rusage_info_t; // needed for libproc.h
|
||||
#include <libproc.h>
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101200)
|
||||
#define NSWindowStyleMaskResizable NSResizableWindowMask
|
||||
@@ -22,7 +24,7 @@
|
||||
|
||||
static NSMenuItem* title_menu = NULL;
|
||||
|
||||
static NSString*
|
||||
static NSString*
|
||||
find_app_name(void) {
|
||||
size_t i;
|
||||
NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
|
||||
@@ -141,7 +143,7 @@ cocoa_update_title(PyObject *pytitle) {
|
||||
bool
|
||||
cocoa_make_window_resizable(void *w) {
|
||||
NSWindow *window = (NSWindow*)w;
|
||||
|
||||
|
||||
@try {
|
||||
[window setStyleMask:
|
||||
[window styleMask] | NSWindowStyleMaskResizable];
|
||||
@@ -166,8 +168,19 @@ cocoa_get_lang(PyObject UNUSED *self) {
|
||||
return Py_BuildValue("s", [locale UTF8String]);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
cwd_of_process(PyObject *self UNUSED, PyObject *pid_) {
|
||||
long pid = PyLong_AsLong(pid_);
|
||||
struct proc_vnodepathinfo vpi;
|
||||
int ret = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));
|
||||
if (ret < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; }
|
||||
return PyUnicode_FromString(vpi.pvi_cdir.vip_path);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
||||
{"cwd_of_process", (PyCFunction)cwd_of_process, METH_O, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ PyObject* create_256_color_table() {
|
||||
uint8_t v = 8 + i * 10;
|
||||
FG_BG_256[j] = (v << 16) | (v << 8) | v;
|
||||
}
|
||||
|
||||
|
||||
PyObject *ans = PyTuple_New(255);
|
||||
if (ans == NULL) return PyErr_NoMemory();
|
||||
for (i=0; i < 255; i++) {
|
||||
@@ -62,7 +62,7 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
||||
if (FG_BG_256[255] == 0) create_256_color_table();
|
||||
memcpy(self->color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
memcpy(self->orig_color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
self->dirty = true;
|
||||
self->dirty = true;
|
||||
}
|
||||
return (PyObject*) self;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ update_ansi_color_table(ColorProfile *self, PyObject *val) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
color_type
|
||||
color_type
|
||||
colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval) {
|
||||
color_type t = entry & 0xFF, r;
|
||||
switch(t) {
|
||||
@@ -128,7 +128,7 @@ as_color(ColorProfile *self, PyObject *val) {
|
||||
default:
|
||||
ans = Py_None; Py_INCREF(Py_None);
|
||||
}
|
||||
if (ans == NULL) ans = Py_BuildValue("BBB", (unsigned char)(col >> 16), (unsigned char)((col >> 8) & 0xFF), (unsigned char)(col & 0xFF));
|
||||
if (ans == NULL) ans = Py_BuildValue("BBB", (unsigned char)(col >> 16), (unsigned char)((col >> 8) & 0xFF), (unsigned char)(col & 0xFF));
|
||||
return ans;
|
||||
}
|
||||
|
||||
@@ -177,13 +177,13 @@ copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size
|
||||
}
|
||||
self->dirty = false;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
color_table_address(ColorProfile *self) {
|
||||
#define color_table_address_doc "Pointer address to start of color table"
|
||||
return PyLong_FromVoidPtr((void*)self->color_table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Boilerplate {{{
|
||||
|
||||
@@ -227,13 +227,13 @@ PyTypeObject ColorProfile_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.ColorProfile",
|
||||
.tp_basicsize = sizeof(ColorProfile),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "ColorProfile",
|
||||
.tp_members = members,
|
||||
.tp_methods = methods,
|
||||
.tp_getset = getsetters,
|
||||
.tp_new = new,
|
||||
.tp_new = new,
|
||||
};
|
||||
|
||||
INIT_TYPE(ColorProfile)
|
||||
|
||||
@@ -94,7 +94,7 @@ def parse_shortcut(sc):
|
||||
|
||||
|
||||
KeyAction = namedtuple('KeyAction', 'func args')
|
||||
shlex_actions = {'pass_selection_to_program', 'new_window', 'new_tab'}
|
||||
shlex_actions = {'pass_selection_to_program', 'new_window', 'new_tab', 'new_os_window', 'new_window_with_cwd', 'new_tab_with_cwd', 'new_os_window_with_cwd'}
|
||||
|
||||
|
||||
def parse_key_action(action):
|
||||
@@ -195,7 +195,7 @@ def parse_send_text(val, keymap):
|
||||
return parse_key(key_str, keymap)
|
||||
|
||||
|
||||
def to_open_url_modifiers(val):
|
||||
def to_modifiers(val):
|
||||
return parse_mods(val.split('+'))
|
||||
|
||||
|
||||
@@ -264,7 +264,8 @@ type_map = {
|
||||
'font_size_delta': positive_float,
|
||||
'focus_follows_mouse': to_bool,
|
||||
'cursor_shape': to_cursor_shape,
|
||||
'open_url_modifiers': to_open_url_modifiers,
|
||||
'open_url_modifiers': to_modifiers,
|
||||
'rectangle_select_modifiers': to_modifiers,
|
||||
'repaint_delay': positive_int,
|
||||
'input_delay': positive_int,
|
||||
'window_border_width': positive_float,
|
||||
@@ -290,6 +291,7 @@ type_map = {
|
||||
'tab_separator': tab_separator,
|
||||
'active_tab_font_style': tab_font_style,
|
||||
'inactive_tab_font_style': tab_font_style,
|
||||
'inactive_text_alpha': unit_float,
|
||||
'url_style': url_style,
|
||||
'prefer_color_emoji': to_bool,
|
||||
}
|
||||
@@ -350,7 +352,9 @@ with open(
|
||||
defaults = parse_config(f.read().decode('utf-8').splitlines(), check_keys=False)
|
||||
Options = namedtuple('Defaults', ','.join(defaults.keys()))
|
||||
defaults = Options(**defaults)
|
||||
actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset({'combine', 'send_text', 'goto_tab'})
|
||||
actions = frozenset(a.func for a in defaults.keymap.values()) | frozenset(
|
||||
'combine send_text goto_tab new_tab_with_cwd new_window_with_cwd new_os_window_with_cwd'.split()
|
||||
)
|
||||
no_op_actions = frozenset({'noop', 'no-op', 'no_op'})
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from collections import namedtuple
|
||||
from .fast_data_types import set_boss as set_c_boss
|
||||
|
||||
appname = 'kitty'
|
||||
version = (0, 6, 0)
|
||||
version = (0, 6, 1)
|
||||
str_version = '.'.join(map(str, version))
|
||||
_plat = sys.platform.lower()
|
||||
is_macos = 'darwin' in _plat
|
||||
@@ -22,9 +22,8 @@ WindowGeometry = namedtuple('WindowGeometry', 'left top right bottom xnum ynum')
|
||||
|
||||
|
||||
def _get_config_dir():
|
||||
# This must be called before calling setApplicationName
|
||||
if 'KITTY_CONFIG_DIRECTORY' in os.environ:
|
||||
return os.path.abspath(os.path.expanduser(os.environ['VISE_CONFIG_DIRECTORY']))
|
||||
return os.path.abspath(os.path.expanduser(os.environ['KITTY_CONFIG_DIRECTORY']))
|
||||
|
||||
candidate = os.path.abspath(os.path.expanduser(os.environ.get('XDG_CONFIG_HOME') or ('~/Library/Preferences' if is_macos else '~/.config')))
|
||||
ans = os.path.join(candidate, appname)
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
// Sharp control codes
|
||||
// -------------------
|
||||
|
||||
// Align display
|
||||
// Align display
|
||||
#define DECALN '8'
|
||||
|
||||
// Esc control codes
|
||||
@@ -180,7 +180,7 @@
|
||||
|
||||
// Scroll down by the specified number of lines
|
||||
#define SD 'T'
|
||||
|
||||
|
||||
// *Erase character*: Erase the indicated # of characters on the
|
||||
// current line.
|
||||
#define ECH 'X'
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
// *Select graphics rendition*: The terminal can display the following
|
||||
// character attributes that change the character display without
|
||||
// changing the character
|
||||
// changing the character
|
||||
#define SGR 'm'
|
||||
|
||||
// *Device status report*.
|
||||
|
||||
@@ -86,7 +86,7 @@ dealloc(CTFace* self) {
|
||||
static PyObject*
|
||||
font_descriptor_to_python(CTFontDescriptorRef descriptor) {
|
||||
NSURL *url = (NSURL *) CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute);
|
||||
NSString *psName = (NSString *) CTFontDescriptorCopyAttribute(descriptor, kCTFontNameAttribute);
|
||||
NSString *psName = (NSString *) CTFontDescriptorCopyAttribute(descriptor, kCTFontNameAttribute);
|
||||
NSString *family = (NSString *) CTFontDescriptorCopyAttribute(descriptor, kCTFontFamilyNameAttribute);
|
||||
NSString *style = (NSString *) CTFontDescriptorCopyAttribute(descriptor, kCTFontStyleNameAttribute);
|
||||
NSDictionary *traits = (NSDictionary *) CTFontDescriptorCopyAttribute(descriptor, kCTFontTraitsAttribute);
|
||||
@@ -94,8 +94,8 @@ font_descriptor_to_python(CTFontDescriptorRef descriptor) {
|
||||
NSNumber *weightVal = traits[(id)kCTFontWeightTrait];
|
||||
NSNumber *widthVal = traits[(id)kCTFontWidthTrait];
|
||||
|
||||
PyObject *ans = Py_BuildValue("{ssssssss sOsOsO sfsfsI}",
|
||||
"path", [[url path] UTF8String],
|
||||
PyObject *ans = Py_BuildValue("{ssssssss sOsOsO sfsfsI}",
|
||||
"path", [[url path] UTF8String],
|
||||
"postscript_name", [psName UTF8String],
|
||||
"family", [family UTF8String],
|
||||
"style", [style UTF8String],
|
||||
@@ -148,7 +148,7 @@ static PyObject*
|
||||
coretext_all_fonts(PyObject UNUSED *_self) {
|
||||
static CTFontCollectionRef collection = NULL;
|
||||
if (collection == NULL) collection = CTFontCollectionCreateFromAvailableFonts(NULL);
|
||||
NSArray *matches = (NSArray *) CTFontCollectionCreateMatchingFontDescriptors(collection);
|
||||
NSArray *matches = (NSArray *) CTFontCollectionCreateMatchingFontDescriptors(collection);
|
||||
PyObject *ans = PyTuple_New([matches count]), *temp;
|
||||
if (ans == NULL) return PyErr_NoMemory();
|
||||
for (unsigned int i = 0; i < [matches count]; i++) {
|
||||
@@ -173,7 +173,7 @@ find_substitute_face(CFStringRef str, CTFontRef old_font) {
|
||||
if (new_font == old_font) { CFRelease(new_font); continue; }
|
||||
return new_font;
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "CoreText returned the same font as a fallback font");
|
||||
PyErr_SetString(PyExc_ValueError, "CoreText returned the same font as a fallback font");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ create_fallback_face(PyObject *base_face, Cell* cell, bool UNUSED bold, bool UNU
|
||||
return (PyObject*)ct_face(new_font);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
unsigned int
|
||||
glyph_id_for_codepoint(PyObject *s, char_type ch) {
|
||||
CTFace *self = (CTFace*)s;
|
||||
unichar chars[2] = {0};
|
||||
@@ -216,7 +216,7 @@ set_size_for_face(PyObject *s, unsigned int UNUSED desired_height, bool force) {
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_font_t*
|
||||
hb_font_t*
|
||||
harfbuzz_font_for_face(PyObject* s) {
|
||||
CTFace *self = (CTFace*)s;
|
||||
if (!self->hb_font) {
|
||||
@@ -227,7 +227,7 @@ harfbuzz_font_for_face(PyObject* s) {
|
||||
return self->hb_font;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness) {
|
||||
// See https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html
|
||||
CTFace *self = (CTFace*)s;
|
||||
@@ -241,10 +241,10 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
||||
if (glyphs[i]) {
|
||||
w = (unsigned int)(ceilf(
|
||||
CTFontGetAdvancesForGlyphs(self->ct_font, kCTFontOrientationHorizontal, glyphs+i, NULL, 1)));
|
||||
if (w > width) width = w;
|
||||
if (w > width) width = w;
|
||||
}
|
||||
}
|
||||
*cell_width = MAX(1, width);
|
||||
*cell_width = MAX(1, width);
|
||||
*underline_position = floor(self->ascent - self->underline_position + 0.5);
|
||||
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
||||
*baseline = (unsigned int)self->ascent;
|
||||
@@ -252,7 +252,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
||||
// Let CoreText's layout engine calculate the line height. Slower, but hopefully more accurate.
|
||||
CFStringRef ts = CFSTR("test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test");
|
||||
CFMutableAttributedStringRef test_string = CFAttributedStringCreateMutable(kCFAllocatorDefault, CFStringGetLength(ts));
|
||||
CFAttributedStringReplaceString(test_string, CFRangeMake(0, 0), ts);
|
||||
CFAttributedStringReplaceString(test_string, CFRangeMake(0, 0), ts);
|
||||
CFAttributedStringSetAttribute(test_string, CFRangeMake(0, CFStringGetLength(ts)), kCTFontAttributeName, self->ct_font);
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathAddRect(path, NULL, CGRectMake(10, 10, 200, 200));
|
||||
@@ -263,7 +263,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
||||
CTFrameGetLineOrigins(test_frame, CFRangeMake(0, 1), &origin1);
|
||||
CTFrameGetLineOrigins(test_frame, CFRangeMake(1, 1), &origin2);
|
||||
CGFloat line_height = origin1.y - origin2.y;
|
||||
CFRelease(test_frame); CFRelease(path); CFRelease(framesetter);
|
||||
CFRelease(test_frame); CFRelease(path); CFRelease(framesetter);
|
||||
*cell_height = MAX(4, (unsigned int)ceilf(line_height));
|
||||
#undef count
|
||||
}
|
||||
@@ -278,7 +278,7 @@ face_from_descriptor(PyObject *descriptor) {
|
||||
return (PyObject*) ct_face(font);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyObject*
|
||||
face_from_path(const char *path, int UNUSED index) {
|
||||
CFStringRef s = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
|
||||
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, s, kCFURLPOSIXPathStyle, false);
|
||||
@@ -315,7 +315,7 @@ render_color_glyph(CTFontRef font, uint8_t *buf, int glyph_id, unsigned int widt
|
||||
if (ctx == NULL) fatal("Out of memory");
|
||||
CGContextSetShouldAntialias(ctx, true);
|
||||
CGContextSetShouldSmoothFonts(ctx, true); // sub-pixel antialias
|
||||
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
|
||||
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
CGContextSetTextDrawingMode(ctx, kCGTextFill);
|
||||
CGGlyph glyph = glyph_id;
|
||||
@@ -353,7 +353,7 @@ render_glyphs(CTFontRef font, unsigned int width, unsigned int height, unsigned
|
||||
CGContextSetGrayFillColor(render_ctx, 1, 1); // white glyphs
|
||||
CGContextSetTextDrawingMode(render_ctx, kCGTextFill);
|
||||
CGContextSetTextMatrix(render_ctx, CGAffineTransformIdentity);
|
||||
CGContextSetTextPosition(render_ctx, 0, height - baseline);
|
||||
CGContextSetTextPosition(render_ctx, 0, height - baseline);
|
||||
CTFontDrawGlyphs(font, glyphs, positions, num_glyphs, render_ctx);
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ static PyMethodDef methods[] = {
|
||||
static PyObject *
|
||||
repr(CTFace *self) {
|
||||
char buf[1024] = {0};
|
||||
snprintf(buf, sizeof(buf)/sizeof(buf[0]), "ascent=%.1f, descent=%.1f, leading=%.1f, point_sz=%.1f, scaled_point_sz=%.1f, underline_position=%.1f underline_thickness=%.1f",
|
||||
snprintf(buf, sizeof(buf)/sizeof(buf[0]), "ascent=%.1f, descent=%.1f, leading=%.1f, point_sz=%.1f, scaled_point_sz=%.1f, underline_position=%.1f underline_thickness=%.1f",
|
||||
(self->ascent), (self->descent), (self->leading), (self->point_sz), (self->scaled_point_sz), (self->underline_position), (self->underline_thickness));
|
||||
return PyUnicode_FromFormat(
|
||||
"Face(family=%U, full_name=%U, postscript_name=%U, path=%U, units_per_em=%u, %s)",
|
||||
@@ -455,8 +455,8 @@ PyTypeObject CTFace_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.CTFace",
|
||||
.tp_basicsize = sizeof(CTFace),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "CoreText Font face",
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
@@ -465,10 +465,10 @@ PyTypeObject CTFace_Type = {
|
||||
|
||||
|
||||
|
||||
int
|
||||
int
|
||||
init_CoreText(PyObject *module) {
|
||||
if (PyType_Ready(&CTFace_Type) < 0) return 0;
|
||||
if (PyModule_AddObject(module, "CTFace", (PyObject *)&CTFace_Type) != 0) return 0;
|
||||
if (PyModule_AddObject(module, "CTFace", (PyObject *)&CTFace_Type) != 0) return 0;
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return 0;
|
||||
if (Py_AtExit(finalize) != 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to register the CoreText at exit handler");
|
||||
|
||||
@@ -39,7 +39,7 @@ repr(Cursor *self) {
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
cursor_reset_display_attrs(Cursor *self) {
|
||||
self->bg = 0; self->fg = 0; self->decoration_fg = 0;
|
||||
self->decoration = 0; self->bold = false; self->italic = false; self->reverse = false; self->strikethrough = false;
|
||||
@@ -50,25 +50,25 @@ static inline void
|
||||
parse_color(unsigned int *params, unsigned int *i, unsigned int count, uint32_t *result) {
|
||||
unsigned int attr;
|
||||
uint8_t r, g, b;
|
||||
if (*i < count) {
|
||||
if (*i < count) {
|
||||
attr = params[(*i)++];
|
||||
switch(attr) {
|
||||
case 5:
|
||||
if (*i < count) *result = (params[(*i)++] & 0xFF) << 8 | 1;
|
||||
break;
|
||||
switch(attr) {
|
||||
case 5:
|
||||
if (*i < count) *result = (params[(*i)++] & 0xFF) << 8 | 1;
|
||||
break;
|
||||
case 2: \
|
||||
if (*i < count - 2) {
|
||||
/* Ignore the first parameter in a four parameter RGB */
|
||||
/* sequence (unused color space id), see https://github.com/kovidgoyal/kitty/issues/227 */
|
||||
if (*i < count - 3) (*i)++;
|
||||
r = params[(*i)++] & 0xFF;
|
||||
g = params[(*i)++] & 0xFF;
|
||||
b = params[(*i)++] & 0xFF;
|
||||
*result = r << 24 | g << 16 | b << 8 | 2;
|
||||
if (*i < count - 2) {
|
||||
/* Ignore the first parameter in a four parameter RGB */
|
||||
/* sequence (unused color space id), see https://github.com/kovidgoyal/kitty/issues/227 */
|
||||
if (*i < count - 3) (*i)++;
|
||||
r = params[(*i)++] & 0xFF;
|
||||
g = params[(*i)++] & 0xFF;
|
||||
b = params[(*i)++] & 0xFF;
|
||||
*result = r << 24 | g << 16 | b << 8 | 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,13 +109,13 @@ START_ALLOW_CASE_RANGE
|
||||
self->strikethrough = false; break;
|
||||
case 30 ... 37:
|
||||
self->fg = ((attr - 30) << 8) | 1; break;
|
||||
case 38:
|
||||
case 38:
|
||||
SET_COLOR(fg);
|
||||
case 39:
|
||||
self->fg = 0; break;
|
||||
case 40 ... 47:
|
||||
self->bg = ((attr - 40) << 8) | 1; break;
|
||||
case 48:
|
||||
case 48:
|
||||
SET_COLOR(bg);
|
||||
case 49:
|
||||
self->bg = 0; break;
|
||||
@@ -124,7 +124,7 @@ START_ALLOW_CASE_RANGE
|
||||
case 100 ... 107:
|
||||
self->bg = ((attr - 100 + 8) << 8) | 1; break;
|
||||
case DECORATION_FG_CODE:
|
||||
SET_COLOR(decoration_fg);
|
||||
SET_COLOR(decoration_fg);
|
||||
case DECORATION_FG_CODE + 1:
|
||||
self->decoration_fg = 0; break;
|
||||
}
|
||||
@@ -149,7 +149,7 @@ apply_sgr_to_cells(Cell *first_cell, unsigned int cell_count, unsigned int *para
|
||||
attr = params[i++];
|
||||
switch(attr) {
|
||||
case 0:
|
||||
RANGE { cell->attrs &= WIDTH_MASK; cell->fg = 0; cell->bg = 0; cell->decoration_fg = 0; }
|
||||
RANGE { cell->attrs &= WIDTH_MASK; cell->fg = 0; cell->bg = 0; cell->decoration_fg = 0; }
|
||||
break;
|
||||
case 1:
|
||||
SET(BOLD_SHIFT);
|
||||
@@ -177,13 +177,13 @@ apply_sgr_to_cells(Cell *first_cell, unsigned int cell_count, unsigned int *para
|
||||
START_ALLOW_CASE_RANGE
|
||||
case 30 ... 37:
|
||||
SIMPLE(fg, ((attr - 30) << 8) | 1);
|
||||
case 38:
|
||||
case 38:
|
||||
SET_COLOR(fg);
|
||||
case 39:
|
||||
SIMPLE(fg, 0);
|
||||
case 40 ... 47:
|
||||
SIMPLE(bg, ((attr - 40) << 8) | 1);
|
||||
case 48:
|
||||
case 48:
|
||||
SET_COLOR(bg);
|
||||
case 49:
|
||||
SIMPLE(bg, 0);
|
||||
@@ -224,14 +224,14 @@ color_as_sgr(char *buf, size_t sz, unsigned long val, unsigned simple_code, unsi
|
||||
static inline const char*
|
||||
decoration_as_sgr(uint8_t decoration) {
|
||||
switch(decoration) {
|
||||
case 1: return "4";
|
||||
case 2: return "4:2";
|
||||
case 1: return "4";
|
||||
case 2: return "4:2";
|
||||
case 3: return "4:3";
|
||||
default: return "24";
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
const char*
|
||||
cursor_as_sgr(Cursor *self, Cursor *prev) {
|
||||
static char buf[128];
|
||||
#define SZ sizeof(buf) - (p - buf) - 2
|
||||
@@ -267,8 +267,8 @@ void cursor_reset(Cursor *self) {
|
||||
|
||||
void cursor_copy_to(Cursor *src, Cursor *dest) {
|
||||
#define CCY(x) dest->x = src->x;
|
||||
CCY(x); CCY(y); CCY(shape); CCY(blink);
|
||||
CCY(bold); CCY(italic); CCY(strikethrough); CCY(reverse); CCY(decoration); CCY(fg); CCY(bg); CCY(decoration_fg);
|
||||
CCY(x); CCY(y); CCY(shape); CCY(blink);
|
||||
CCY(bold); CCY(italic); CCY(strikethrough); CCY(reverse); CCY(decoration); CCY(fg); CCY(bg); CCY(decoration_fg);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@@ -317,21 +317,21 @@ PyTypeObject Cursor_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.Cursor",
|
||||
.tp_basicsize = sizeof(Cursor),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_repr = (reprfunc)repr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "Cursors",
|
||||
.tp_richcompare = richcmp,
|
||||
.tp_richcompare = richcmp,
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
.tp_members = members,
|
||||
.tp_getset = getseters,
|
||||
.tp_new = new,
|
||||
.tp_new = new,
|
||||
};
|
||||
|
||||
RICHCMP(Cursor)
|
||||
|
||||
// }}}
|
||||
|
||||
|
||||
Cursor*
|
||||
cursor_copy(Cursor *self) {
|
||||
Cursor* ans;
|
||||
|
||||
@@ -163,8 +163,8 @@ static PyMethodDef module_methods[] = {
|
||||
static struct PyModuleDef module = {
|
||||
.m_base = PyModuleDef_HEAD_INIT,
|
||||
.m_name = "fast_data_types", /* name of module */
|
||||
.m_doc = NULL,
|
||||
.m_size = -1,
|
||||
.m_doc = NULL,
|
||||
.m_size = -1,
|
||||
.m_methods = module_methods
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
||||
|
||||
#define CURSOR_TO_ATTRS(c, w) \
|
||||
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
|
||||
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT)))
|
||||
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT)))
|
||||
|
||||
#define ATTRS_TO_CURSOR(a, c) \
|
||||
(c)->decoration = (a >> DECORATION_SHIFT) & 3; (c)->bold = (a >> BOLD_SHIFT) & 1; (c)->italic = (a >> ITALIC_SHIFT) & 1; \
|
||||
@@ -181,7 +181,7 @@ typedef struct {
|
||||
} Cursor;
|
||||
|
||||
typedef struct {
|
||||
bool is_visible;
|
||||
bool is_visible, is_focused;
|
||||
CursorShape shape;
|
||||
unsigned int x, y;
|
||||
double left, right, top, bottom;
|
||||
@@ -221,7 +221,7 @@ typedef struct {
|
||||
#define PARSER_BUF_SZ (8 * 1024)
|
||||
#define READ_BUF_SZ (1024*1024)
|
||||
|
||||
#define clear_sprite_position(cell) (cell).sprite_x = 0; (cell).sprite_y = 0; (cell).sprite_z = 0;
|
||||
#define clear_sprite_position(cell) (cell).sprite_x = 0; (cell).sprite_y = 0; (cell).sprite_z = 0;
|
||||
|
||||
#define left_shift_line(line, at, num) \
|
||||
for(index_type __i__ = (at); __i__ < (line)->xnum - (num); __i__++) { \
|
||||
@@ -243,7 +243,7 @@ typedef struct {
|
||||
}
|
||||
|
||||
|
||||
// Global functions
|
||||
// Global functions
|
||||
const char* base64_decode(const uint32_t *src, size_t src_sz, uint8_t *dest, size_t dest_capacity, size_t *dest_sz);
|
||||
Line* alloc_line();
|
||||
Cursor* alloc_cursor();
|
||||
|
||||
18
kitty/emoji.h
generated
18
kitty/emoji.h
generated
@@ -1,9 +1,17 @@
|
||||
// unicode data, built from the unicode standard on: 2017-12-20
|
||||
// see gen-wcwidth.py
|
||||
#pragma once
|
||||
#include "data-types.h"
|
||||
|
||||
START_ALLOW_CASE_RANGE
|
||||
static inline bool is_emoji(uint32_t code) {
|
||||
|
||||
static inline bool
|
||||
is_emoji(char_type code) {
|
||||
switch(code) {
|
||||
case 0x2194 ... 0x2199:
|
||||
return true;
|
||||
case 0x21a9 ... 0x21aa:
|
||||
return true;
|
||||
case 0x231a ... 0x231b:
|
||||
return true;
|
||||
case 0x2328:
|
||||
@@ -274,14 +282,16 @@ static inline bool is_emoji(uint32_t code) {
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
static inline bool is_emoji_modifier(uint32_t code) {
|
||||
static inline bool
|
||||
is_emoji_modifier(char_type code) {
|
||||
switch(code) {
|
||||
case 0x1f3fb ... 0x1f3ff:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
END_ALLOW_CASE_RANGE
|
||||
|
||||
@@ -131,9 +131,9 @@ add_charset(FcPattern *pat, size_t num) {
|
||||
charset = FcCharSetCreate();
|
||||
if (charset == NULL) { PyErr_NoMemory(); goto end; }
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (!FcCharSetAddChar(charset, char_buf[i])) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to add character to fontconfig charset");
|
||||
goto end;
|
||||
if (!FcCharSetAddChar(charset, char_buf[i])) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to add character to fontconfig charset");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
AP(FcPatternAddCharSet, FC_CHARSET, charset, "charset");
|
||||
@@ -214,7 +214,7 @@ static PyMethodDef module_methods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
bool
|
||||
bool
|
||||
init_fontconfig_library(PyObject *module) {
|
||||
if (!FcInit()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to initialize the fontconfig library");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* vim:fileencoding=utf-8
|
||||
* fonts.c
|
||||
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
@@ -57,7 +58,7 @@ static char_type shape_buffer[2048] = {0};
|
||||
typedef struct {
|
||||
PyObject *face;
|
||||
// Map glyphs to sprite map co-ords
|
||||
SpritePosition sprite_map[1024];
|
||||
SpritePosition sprite_map[1024];
|
||||
SpecialGlyphCache special_glyph_cache[1024];
|
||||
bool bold, italic;
|
||||
} Font;
|
||||
@@ -79,7 +80,7 @@ static Fonts fonts = {0};
|
||||
|
||||
// Sprites {{{
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
sprite_map_set_error(int error) {
|
||||
switch(error) {
|
||||
case 1:
|
||||
@@ -163,7 +164,7 @@ special_glyph_cache_for(Font *font, glyph_index glyph) {
|
||||
}
|
||||
if (!s->next) {
|
||||
s->next = calloc(1, sizeof(SpecialGlyphCache));
|
||||
if (s->next == NULL) return NULL;
|
||||
if (s->next == NULL) return NULL;
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
@@ -211,7 +212,7 @@ clear_sprite_map(Font *font) {
|
||||
|
||||
void
|
||||
clear_special_glyph_cache(Font *font) {
|
||||
#define CLEAR(s) s->filled = false; s->glyph = 0;
|
||||
#define CLEAR(s) s->filled = false; s->glyph = 0;
|
||||
SpecialGlyphCache *s;
|
||||
for (size_t i = 0; i < sizeof(font->special_glyph_cache)/sizeof(font->special_glyph_cache[0]); i++) {
|
||||
s = font->special_glyph_cache + i;
|
||||
@@ -247,14 +248,14 @@ init_font(Font *f, PyObject *descriptor, bool bold, bool italic, bool is_face) {
|
||||
PyObject *face;
|
||||
if (is_face) { face = descriptor; Py_INCREF(face); }
|
||||
else { face = desc_to_face(descriptor); if (face == NULL) return false; }
|
||||
f->face = face;
|
||||
f->face = face;
|
||||
f->bold = bold; f->italic = italic;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
del_font(Font *f) {
|
||||
Py_CLEAR(f->face);
|
||||
del_font(Font *f) {
|
||||
Py_CLEAR(f->face);
|
||||
free_maps(f);
|
||||
f->bold = false; f->italic = false;
|
||||
}
|
||||
@@ -262,7 +263,7 @@ del_font(Font *f) {
|
||||
static unsigned int cell_width = 0, cell_height = 0, baseline = 0, underline_position = 0, underline_thickness = 0;
|
||||
static pixel *canvas = NULL;
|
||||
#define CELLS_IN_CANVAS ((MAX_NUM_EXTRA_GLYPHS + 1) * 3)
|
||||
static inline void
|
||||
static inline void
|
||||
clear_canvas(void) { memset(canvas, 0, CELLS_IN_CANVAS * cell_width * cell_height * sizeof(pixel)); }
|
||||
|
||||
static void
|
||||
@@ -289,6 +290,8 @@ update_cell_metrics() {
|
||||
if (cell_height < 4) { PyErr_SetString(PyExc_ValueError, "line height too small after adjustment"); return NULL; }
|
||||
if (cell_height > 1000) { PyErr_SetString(PyExc_ValueError, "line height too large after adjustment"); return NULL; }
|
||||
underline_position = MIN(cell_height - 1, underline_position);
|
||||
// ensure there is at least a couple of pixels available to render styled underlines
|
||||
while (underline_position > baseline + 1 && cell_height - underline_position < 2) underline_position--;
|
||||
if (line_height_adjustment > 1) {
|
||||
baseline += MIN(cell_height - 1, (unsigned)line_height_adjustment / 2);
|
||||
underline_position += MIN(cell_height - 1, (unsigned)line_height_adjustment / 2);
|
||||
@@ -318,7 +321,7 @@ face_has_codepoint(PyObject* face, char_type cp) {
|
||||
return glyph_id_for_codepoint(face, cp) > 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static inline bool
|
||||
has_cell_text(Font *self, Cell *cell) {
|
||||
if (!face_has_codepoint(self->face, cell->ch)) return false;
|
||||
if (cell->cc) {
|
||||
@@ -329,20 +332,11 @@ has_cell_text(Font *self, Cell *cell) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline ssize_t
|
||||
fallback_font(Cell *cell) {
|
||||
bool bold = (cell->attrs >> BOLD_SHIFT) & 1;
|
||||
bool italic = (cell->attrs >> ITALIC_SHIFT) & 1;
|
||||
ssize_t f;
|
||||
|
||||
for (size_t i = 0, j = fonts.first_fallback_font_idx; i < fonts.fallback_fonts_count; i++, j++) {
|
||||
Font *ff = fonts.fonts +j;
|
||||
if (ff->bold == bold && ff->italic == italic && has_cell_text(ff, cell)) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
load_fallback_font(Cell *cell, bool bold, bool italic) {
|
||||
if (fonts.fallback_fonts_count > 100) { fprintf(stderr, "Too many fallback fonts\n"); return MISSING_FONT; }
|
||||
ssize_t f;
|
||||
|
||||
if (bold) f = fonts.italic_font_idx > 0 ? fonts.bi_font_idx : fonts.bold_font_idx;
|
||||
else f = italic ? fonts.italic_font_idx : fonts.medium_font_idx;
|
||||
@@ -363,6 +357,31 @@ fallback_font(Cell *cell) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
static inline ssize_t
|
||||
fallback_font(Cell *cell) {
|
||||
bool bold = (cell->attrs >> BOLD_SHIFT) & 1;
|
||||
bool italic = (cell->attrs >> ITALIC_SHIFT) & 1;
|
||||
|
||||
// Load the emoji fallback font first as on Linux there are a bunch of
|
||||
// non-color fonts that provide some emoji glyphs.
|
||||
if (fonts.fallback_fonts_count < 1) {
|
||||
Cell c = {0};
|
||||
c.ch = 0x1f648; // 🙈
|
||||
load_fallback_font(&c, false, false);
|
||||
}
|
||||
|
||||
// Check if one of the existing fallback fonts has this text
|
||||
for (size_t i = 0, j = fonts.first_fallback_font_idx; i < fonts.fallback_fonts_count; i++, j++) {
|
||||
Font *ff = fonts.fonts +j;
|
||||
if (ff->bold == bold && ff->italic == italic && has_cell_text(ff, cell)) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
return load_fallback_font(cell, bold, italic);
|
||||
}
|
||||
|
||||
static inline ssize_t
|
||||
in_symbol_maps(char_type ch) {
|
||||
for (size_t i = 0; i < fonts.symbol_maps_count; i++) {
|
||||
@@ -441,7 +460,7 @@ render_alpha_mask(uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *de
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
render_box_cell(Cell *cell) {
|
||||
int error = 0;
|
||||
glyph_index glyph = box_glyph_id(cell->ch);
|
||||
@@ -467,7 +486,7 @@ render_box_cell(Cell *cell) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
load_hb_buffer(Cell *first_cell, index_type num_cells) {
|
||||
load_hb_buffer(Cell *first_cell, index_type num_cells) {
|
||||
index_type num;
|
||||
hb_buffer_clear_contents(harfbuzz_buffer);
|
||||
while (num_cells) {
|
||||
@@ -521,10 +540,10 @@ render_group(unsigned int num_cells, unsigned int num_glyphs, Cell *cells, hb_gl
|
||||
render_glyphs_in_cells(font->face, font->bold, font->italic, info, positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, &was_colored);
|
||||
if (PyErr_Occurred()) PyErr_Print();
|
||||
|
||||
for (unsigned int i = 0; i < num_cells; i++) {
|
||||
for (unsigned int i = 0; i < num_cells; i++) {
|
||||
sprite_position[i]->rendered = true;
|
||||
sprite_position[i]->colored = was_colored;
|
||||
set_cell_sprite(cells + i, sprite_position[i]);
|
||||
set_cell_sprite(cells + i, sprite_position[i]);
|
||||
pixel *buf = num_cells == 1 ? canvas : extract_cell_from_canvas(i, num_cells);
|
||||
current_send_sprite_to_gpu(sprite_position[i]->x, sprite_position[i]->y, sprite_position[i]->z, buf);
|
||||
}
|
||||
@@ -547,11 +566,11 @@ is_special_glyph(glyph_index glyph_id, Font *font, CellData* cell_data) {
|
||||
if (s == NULL) return false;
|
||||
if (!s->filled) {
|
||||
s->is_special = cell_data->current_codepoint ? (
|
||||
glyph_id != glyph_id_for_codepoint(font->face, cell_data->current_codepoint) ? true : false)
|
||||
glyph_id != glyph_id_for_codepoint(font->face, cell_data->current_codepoint) ? true : false)
|
||||
:
|
||||
false;
|
||||
s->filled = true;
|
||||
}
|
||||
}
|
||||
return s->is_special;
|
||||
}
|
||||
|
||||
@@ -599,7 +618,7 @@ next_group(Font *font, unsigned int *num_group_cells, unsigned int *num_group_gl
|
||||
// how to break text into cells. In addition, we have to deal with
|
||||
// monospace ligature fonts that use dummy glyphs of zero size to implement
|
||||
// their ligatures.
|
||||
|
||||
|
||||
CellData cell_data;
|
||||
cell_data.cell = cells; cell_data.num_codepoints = num_codepoints_in_cell(cells); cell_data.codepoints_consumed = 0; cell_data.current_codepoint = cells->ch;
|
||||
#define LIMIT (MAX_NUM_EXTRA_GLYPHS + 1)
|
||||
@@ -614,7 +633,7 @@ next_group(Font *font, unsigned int *num_group_cells, unsigned int *num_group_gl
|
||||
glyph_index glyph_id = info[nglyphs].codepoint;
|
||||
cluster = info[nglyphs].cluster;
|
||||
is_special = is_special_glyph(glyph_id, font, &cell_data);
|
||||
if (prev_was_special && !is_special) break;
|
||||
if (prev_was_special && !is_special) break;
|
||||
glyphs_in_group[nglyphs++] = glyph_id;
|
||||
// Soak up a number of codepoints indicated by the difference in cluster numbers.
|
||||
if (cluster > previous_cluster || nglyphs == 1) {
|
||||
@@ -691,14 +710,14 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
|
||||
if (face == NULL) return NULL;
|
||||
font = calloc(1, sizeof(Font));
|
||||
font->face = face;
|
||||
}
|
||||
}
|
||||
hb_glyph_info_t *info;
|
||||
hb_glyph_position_t *positions;
|
||||
unsigned int num_glyphs = shape(line->cells, num, harfbuzz_font_for_face(font->face), &info, &positions);
|
||||
|
||||
PyObject *ans = PyList_New(0);
|
||||
unsigned int run_pos = 0, cell_pos = 0, num_group_glyphs, num_group_cells;
|
||||
ExtraGlyphs extra_glyphs;
|
||||
ExtraGlyphs extra_glyphs;
|
||||
glyph_index first_glyph;
|
||||
while(run_pos < num_glyphs && cell_pos < num) {
|
||||
first_glyph = next_group(font, &num_group_cells, &num_group_glyphs, line->cells + cell_pos, info + run_pos, num_glyphs - run_pos, num - cell_pos, &extra_glyphs);
|
||||
@@ -711,7 +730,7 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
render_run(Cell *first_cell, index_type num_cells, ssize_t font_idx) {
|
||||
switch(font_idx) {
|
||||
default:
|
||||
@@ -761,7 +780,7 @@ set_font(PyObject UNUSED *m, PyObject *args) {
|
||||
for (size_t i = 0; i < fonts.fonts_count; i++) del_font(fonts.fonts + i);
|
||||
ensure_space_for(&fonts, fonts, Font, num_fonts, fonts_capacity, 5, true);
|
||||
fonts.fonts_count = 1;
|
||||
#define A(attr, bold, italic) { if(attr) { if (!init_font(&fonts.fonts[fonts.fonts_count], attr, bold, italic, false)) return NULL; fonts.attr##_font_idx = fonts.fonts_count++; } else fonts.attr##_font_idx = -1; }
|
||||
#define A(attr, bold, italic) { if(attr) { if (!init_font(&fonts.fonts[fonts.fonts_count], attr, bold, italic, false)) return NULL; fonts.attr##_font_idx = fonts.fonts_count++; } else fonts.attr##_font_idx = -1; }
|
||||
A(medium, false, false);
|
||||
A(bold, true, false); A(italic, false, true); A(bi, true, true);
|
||||
#undef A
|
||||
@@ -923,7 +942,7 @@ error:
|
||||
|
||||
static PyObject*
|
||||
get_fallback_font(PyObject UNUSED *self, PyObject *args) {
|
||||
PyObject *text;
|
||||
PyObject *text;
|
||||
int bold, italic;
|
||||
if (!PyArg_ParseTuple(args, "Upp", &text, &bold, &italic)) return NULL;
|
||||
static Py_UCS4 char_buf[16];
|
||||
@@ -956,7 +975,7 @@ static PyMethodDef module_methods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
bool
|
||||
bool
|
||||
init_fonts(PyObject *module) {
|
||||
if (Py_AtExit(finalize) != 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to register the fonts module at exit handler");
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
unsigned int glyph_id_for_codepoint(PyObject *, char_type);
|
||||
hb_font_t* harfbuzz_font_for_face(PyObject*);
|
||||
bool set_size_for_face(PyObject*, unsigned int, bool);
|
||||
void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
|
||||
void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
|
||||
bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored);
|
||||
PyObject* create_fallback_face(PyObject *base_face, Cell* cell, bool bold, bool italic);
|
||||
PyObject* specialize_font_descriptor(PyObject *base_descriptor);
|
||||
|
||||
@@ -73,7 +73,7 @@ def resize_fonts(new_sz):
|
||||
|
||||
def add_line(buf, cell_width, position, thickness, cell_height):
|
||||
y = position - thickness // 2
|
||||
while thickness > 0 and y > -1 and y < cell_height - 1:
|
||||
while thickness > 0 and y > -1 and y < cell_height:
|
||||
thickness -= 1
|
||||
ctypes.memset(ctypes.addressof(buf) + (cell_width * y), 255, cell_width)
|
||||
y += 1
|
||||
|
||||
@@ -38,7 +38,7 @@ PyTypeObject Face_Type;
|
||||
|
||||
static PyObject* FreeType_Exception = NULL;
|
||||
|
||||
void
|
||||
void
|
||||
set_freetype_error(const char* prefix, int err_code) {
|
||||
int i = 0;
|
||||
#undef FTERRORS_H_
|
||||
@@ -54,7 +54,7 @@ set_freetype_error(const char* prefix, int err_code) {
|
||||
|
||||
#ifdef FT_ERRORS_H
|
||||
#include FT_ERRORS_H
|
||||
#else
|
||||
#else
|
||||
FT_ERROR_START_LIST FT_ERROR_END_LIST
|
||||
#endif
|
||||
|
||||
@@ -121,8 +121,8 @@ set_font_size(Face *self, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt
|
||||
return true;
|
||||
}
|
||||
}
|
||||
set_freetype_error("Failed to set char size, with error:", error);
|
||||
return false;
|
||||
set_freetype_error("Failed to set char size, with error:", error);
|
||||
return false;
|
||||
}
|
||||
return !error;
|
||||
}
|
||||
@@ -170,7 +170,7 @@ init_ft_face(Face *self, PyObject *path, int hinting, int hintstyle) {
|
||||
PyObject*
|
||||
ft_face_from_data(const uint8_t* data, size_t sz, void *extra_data, free_extra_data_func fed, PyObject *path, int hinting, int hintstyle, float apple_leading) {
|
||||
Face *ans = (Face*)Face_Type.tp_alloc(&Face_Type, 0);
|
||||
if (ans == NULL) return NULL;
|
||||
if (ans == NULL) return NULL;
|
||||
int error = FT_New_Memory_Face(library, data, sz, 0, &ans->face);
|
||||
if(error) { set_freetype_error("Failed to load memory face, with error:", error); Py_CLEAR(ans); return NULL; }
|
||||
if (!init_ft_face(ans, path, hinting, hintstyle)) { Py_CLEAR(ans); return NULL; }
|
||||
@@ -232,7 +232,7 @@ face_from_descriptor(PyObject *descriptor) {
|
||||
}
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
|
||||
PyObject*
|
||||
face_from_path(const char *path, int index) {
|
||||
Face *ans = (Face*)Face_Type.tp_alloc(&Face_Type, 0);
|
||||
@@ -265,7 +265,7 @@ repr(Face *self) {
|
||||
}
|
||||
|
||||
|
||||
static inline bool
|
||||
static inline bool
|
||||
load_glyph(Face *self, int glyph_index, int load_type) {
|
||||
int flags = get_load_flags(self->hinting, self->hintstyle, load_type);
|
||||
int error = FT_Load_Glyph(self->face, glyph_index, flags);
|
||||
@@ -285,7 +285,7 @@ calc_cell_width(Face *self) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness) {
|
||||
Face *self = (Face*)s;
|
||||
*cell_width = calc_cell_width(self);
|
||||
@@ -295,7 +295,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
||||
*underline_thickness = MAX(1, font_units_to_pixels(self, self->underline_thickness));
|
||||
}
|
||||
|
||||
unsigned int
|
||||
unsigned int
|
||||
glyph_id_for_codepoint(PyObject *s, char_type cp) {
|
||||
return FT_Get_Char_Index(((Face*)s)->face, cp);
|
||||
}
|
||||
@@ -376,12 +376,12 @@ downsample_bitmap(ProcessedBitmap *bm, unsigned int width, unsigned int cell_hei
|
||||
for (unsigned int y=sr; y < MIN(sr + factor, bm->rows); y++) {
|
||||
uint8_t *p = bm->buf + (y * bm->stride) + sc * 4;
|
||||
for (unsigned int x=sc; x < MIN(sc + factor, bm->width); x++, count++) {
|
||||
b += *(p++); g += *(p++); r += *(p++); a += *(p++);
|
||||
b += *(p++); g += *(p++); r += *(p++); a += *(p++);
|
||||
}
|
||||
}
|
||||
if (count) {
|
||||
d[0] = b / count; d[1] = g / count; d[2] = r / count; d[3] = a / count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -506,7 +506,7 @@ render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *inf
|
||||
y = (float)positions[i].y_offset / 64.0f;
|
||||
if ((*was_colored || self->face->glyph->metrics.width > 0) && bm.width > 0) place_bitmap_in_canvas(canvas, &bm, canvas_width, cell_height, x_offset, y, &self->face->glyph->metrics, baseline);
|
||||
x += (float)positions[i].x_advance / 64.0f;
|
||||
if (bm.needs_free) free(bm.buf);
|
||||
if (bm.needs_free) free(bm.buf);
|
||||
}
|
||||
|
||||
// center the glyphs in the canvas
|
||||
@@ -560,8 +560,8 @@ PyTypeObject Face_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.Face",
|
||||
.tp_basicsize = sizeof(Face),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "FreeType Font face",
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
@@ -573,11 +573,11 @@ free_freetype() {
|
||||
FT_Done_FreeType(library);
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
init_freetype_library(PyObject *m) {
|
||||
if (PyType_Ready(&Face_Type) < 0) return 0;
|
||||
if (PyModule_AddObject(m, "Face", (PyObject *)&Face_Type) != 0) return 0;
|
||||
Py_INCREF(&Face_Type);
|
||||
if (PyModule_AddObject(m, "Face", (PyObject *)&Face_Type) != 0) return 0;
|
||||
Py_INCREF(&Face_Type);
|
||||
FreeType_Exception = PyErr_NewException("fast_data_types.FreeTypeError", NULL, NULL);
|
||||
if (FreeType_Exception == NULL) return false;
|
||||
if (PyModule_AddObject(m, "FreeTypeError", FreeType_Exception) != 0) return false;
|
||||
|
||||
1622
kitty/gl-wrapper.c
generated
1622
kitty/gl-wrapper.c
generated
File diff suppressed because it is too large
Load Diff
40
kitty/gl.h
40
kitty/gl.h
@@ -22,24 +22,24 @@ static void
|
||||
check_for_gl_error(const char *name, void UNUSED *funcptr, int UNUSED len_args, ...) {
|
||||
#define f(msg) fatal("OpenGL error: %s (calling function: %s)", msg, name); break;
|
||||
GLenum code = glad_glGetError();
|
||||
switch(code) {
|
||||
switch(code) {
|
||||
case GL_NO_ERROR: break;
|
||||
case GL_INVALID_ENUM:
|
||||
f("An enum value is invalid (GL_INVALID_ENUM)");
|
||||
case GL_INVALID_VALUE:
|
||||
f("An numeric value is invalid (GL_INVALID_VALUE)");
|
||||
case GL_INVALID_OPERATION:
|
||||
f("This operation is invalid (GL_INVALID_OPERATION)");
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
f("The framebuffer object is not complete (GL_INVALID_FRAMEBUFFER_OPERATION)");
|
||||
case GL_OUT_OF_MEMORY:
|
||||
f("There is not enough memory left to execute the command. (GL_OUT_OF_MEMORY)");
|
||||
case GL_STACK_UNDERFLOW:
|
||||
f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_UNDERFLOW)");
|
||||
case GL_STACK_OVERFLOW:
|
||||
f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_OVERFLOW)");
|
||||
default:
|
||||
fatal("An unknown OpenGL error occurred with code: %d (calling function: %s)", code, name);
|
||||
case GL_INVALID_ENUM:
|
||||
f("An enum value is invalid (GL_INVALID_ENUM)");
|
||||
case GL_INVALID_VALUE:
|
||||
f("An numeric value is invalid (GL_INVALID_VALUE)");
|
||||
case GL_INVALID_OPERATION:
|
||||
f("This operation is invalid (GL_INVALID_OPERATION)");
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
f("The framebuffer object is not complete (GL_INVALID_FRAMEBUFFER_OPERATION)");
|
||||
case GL_OUT_OF_MEMORY:
|
||||
f("There is not enough memory left to execute the command. (GL_OUT_OF_MEMORY)");
|
||||
case GL_STACK_UNDERFLOW:
|
||||
f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_UNDERFLOW)");
|
||||
case GL_STACK_OVERFLOW:
|
||||
f("An attempt has been made to perform an operation that would cause an internal stack to underflow. (GL_STACK_OVERFLOW)");
|
||||
default:
|
||||
fatal("An unknown OpenGL error occurred with code: %d (calling function: %s)", code, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ update_surface_size(int w, int h, GLuint offscreen_texture_id) {
|
||||
|
||||
void
|
||||
free_texture(GLuint *tex_id) {
|
||||
glDeleteTextures(1, tex_id);
|
||||
glDeleteTextures(1, tex_id);
|
||||
*tex_id = 0;
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ add_buffer_to_vao(ssize_t vao_idx, GLenum usage) {
|
||||
static void
|
||||
add_located_attribute_to_vao(ssize_t vao_idx, GLint aloc, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) {
|
||||
VAO *vao = vaos + vao_idx;
|
||||
if (!vao->num_buffers) fatal("You must create a buffer for this attribute first");
|
||||
if (!vao->num_buffers) fatal("You must create a buffer for this attribute first");
|
||||
ssize_t buf = vao->buffers[vao->num_buffers - 1];
|
||||
bind_buffer(buf);
|
||||
glEnableVertexAttribArray(aloc);
|
||||
@@ -315,7 +315,7 @@ add_located_attribute_to_vao(ssize_t vao_idx, GLint aloc, GLint size, GLenum dat
|
||||
static inline void
|
||||
add_attribute_to_vao(int p, ssize_t vao_idx, const char *name, GLint size, GLenum data_type, GLsizei stride, void *offset, GLuint divisor) {
|
||||
GLint aloc = attrib_location(p, name);
|
||||
if (aloc == -1) fatal("No attribute named: %s found in this program", name);
|
||||
if (aloc == -1) fatal("No attribute named: %s found in this program", name);
|
||||
add_located_attribute_to_vao(vao_idx, aloc, size, data_type, stride, offset, divisor);
|
||||
}
|
||||
|
||||
|
||||
18
kitty/glfw-wrapper.c
generated
18
kitty/glfw-wrapper.c
generated
@@ -23,9 +23,6 @@ load_glfw(const char* path) {
|
||||
*(void **) (&glfwInitHint_impl) = dlsym(handle, "glfwInitHint");
|
||||
if (glfwInitHint_impl == NULL) fail("Failed to load glfw function glfwInitHint with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwInitHintString_impl) = dlsym(handle, "glfwInitHintString");
|
||||
if (glfwInitHintString_impl == NULL) fail("Failed to load glfw function glfwInitHintString with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwGetVersion_impl) = dlsym(handle, "glfwGetVersion");
|
||||
if (glfwGetVersion_impl == NULL) fail("Failed to load glfw function glfwGetVersion with error: %s", dlerror());
|
||||
|
||||
@@ -56,6 +53,12 @@ load_glfw(const char* path) {
|
||||
*(void **) (&glfwGetMonitorName_impl) = dlsym(handle, "glfwGetMonitorName");
|
||||
if (glfwGetMonitorName_impl == NULL) fail("Failed to load glfw function glfwGetMonitorName with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwSetMonitorUserPointer_impl) = dlsym(handle, "glfwSetMonitorUserPointer");
|
||||
if (glfwSetMonitorUserPointer_impl == NULL) fail("Failed to load glfw function glfwSetMonitorUserPointer with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwGetMonitorUserPointer_impl) = dlsym(handle, "glfwGetMonitorUserPointer");
|
||||
if (glfwGetMonitorUserPointer_impl == NULL) fail("Failed to load glfw function glfwGetMonitorUserPointer with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwSetMonitorCallback_impl) = dlsym(handle, "glfwSetMonitorCallback");
|
||||
if (glfwSetMonitorCallback_impl == NULL) fail("Failed to load glfw function glfwSetMonitorCallback with error: %s", dlerror());
|
||||
|
||||
@@ -80,6 +83,9 @@ load_glfw(const char* path) {
|
||||
*(void **) (&glfwWindowHint_impl) = dlsym(handle, "glfwWindowHint");
|
||||
if (glfwWindowHint_impl == NULL) fail("Failed to load glfw function glfwWindowHint with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwWindowHintString_impl) = dlsym(handle, "glfwWindowHintString");
|
||||
if (glfwWindowHintString_impl == NULL) fail("Failed to load glfw function glfwWindowHintString with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwCreateWindow_impl) = dlsym(handle, "glfwCreateWindow");
|
||||
if (glfwCreateWindow_impl == NULL) fail("Failed to load glfw function glfwCreateWindow with error: %s", dlerror());
|
||||
|
||||
@@ -287,6 +293,12 @@ load_glfw(const char* path) {
|
||||
*(void **) (&glfwGetJoystickGUID_impl) = dlsym(handle, "glfwGetJoystickGUID");
|
||||
if (glfwGetJoystickGUID_impl == NULL) fail("Failed to load glfw function glfwGetJoystickGUID with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwSetJoystickUserPointer_impl) = dlsym(handle, "glfwSetJoystickUserPointer");
|
||||
if (glfwSetJoystickUserPointer_impl == NULL) fail("Failed to load glfw function glfwSetJoystickUserPointer with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwGetJoystickUserPointer_impl) = dlsym(handle, "glfwGetJoystickUserPointer");
|
||||
if (glfwGetJoystickUserPointer_impl == NULL) fail("Failed to load glfw function glfwGetJoystickUserPointer with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwJoystickIsGamepad_impl) = dlsym(handle, "glfwJoystickIsGamepad");
|
||||
if (glfwJoystickIsGamepad_impl == NULL) fail("Failed to load glfw function glfwJoystickIsGamepad with error: %s", dlerror());
|
||||
|
||||
|
||||
55
kitty/glfw-wrapper.h
generated
55
kitty/glfw-wrapper.h
generated
@@ -251,17 +251,37 @@
|
||||
* @{ */
|
||||
|
||||
/*! @brief If this bit is set one or more Shift keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Shift keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_SHIFT 0x0001
|
||||
/*! @brief If this bit is set one or more Control keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Control keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_CONTROL 0x0002
|
||||
/*! @brief If this bit is set one or more Alt keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Alt keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_ALT 0x0004
|
||||
/*! @brief If this bit is set one or more Super keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Super keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_SUPER 0x0008
|
||||
/*! @brief If this bit is set the Caps Lock key is enabled.
|
||||
*
|
||||
* If this bit is set the Caps Lock key is enabled and the @ref
|
||||
* GLFW_LOCK_KEY_MODS input mode is set.
|
||||
*/
|
||||
#define GLFW_MOD_CAPS_LOCK 0x0010
|
||||
/*! @brief If this bit is set the Num Lock key is enabled.
|
||||
*
|
||||
* If this bit is set the Num Lock key is enabled and the @ref
|
||||
* GLFW_LOCK_KEY_MODS input mode is set.
|
||||
*/
|
||||
#define GLFW_MOD_NUM_LOCK 0x0020
|
||||
|
||||
/*! @} */
|
||||
|
||||
@@ -702,8 +722,11 @@
|
||||
#define GLFW_CONTEXT_CREATION_API 0x0002200B
|
||||
|
||||
#define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001
|
||||
#define GLFW_COCOA_FRAME_AUTOSAVE 0x00023002
|
||||
#define GLFW_COCOA_FRAME_NAME 0x00023002
|
||||
#define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003
|
||||
|
||||
#define GLFW_X11_CLASS_NAME 0x00024001
|
||||
#define GLFW_X11_INSTANCE_NAME 0x00024002
|
||||
/*! @} */
|
||||
|
||||
#define GLFW_NO_API 0
|
||||
@@ -721,6 +744,7 @@
|
||||
#define GLFW_CURSOR 0x00033001
|
||||
#define GLFW_STICKY_KEYS 0x00033002
|
||||
#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003
|
||||
#define GLFW_LOCK_KEY_MODS 0x00033004
|
||||
|
||||
#define GLFW_CURSOR_NORMAL 0x00034001
|
||||
#define GLFW_CURSOR_HIDDEN 0x00034002
|
||||
@@ -783,9 +807,6 @@
|
||||
|
||||
#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001
|
||||
#define GLFW_COCOA_MENUBAR 0x00051002
|
||||
|
||||
#define GLFW_X11_WM_CLASS_NAME 0x00052001
|
||||
#define GLFW_X11_WM_CLASS_CLASS 0x00052002
|
||||
/*! @} */
|
||||
|
||||
#define GLFW_DONT_CARE -1
|
||||
@@ -804,7 +825,7 @@
|
||||
* @sa @ref glfwGetProcAddress
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
|
||||
*
|
||||
* @ingroup context
|
||||
*/
|
||||
typedef void (*GLFWglproc)(void);
|
||||
@@ -1359,10 +1380,6 @@ typedef void (*glfwInitHint_func)(int, int);
|
||||
glfwInitHint_func glfwInitHint_impl;
|
||||
#define glfwInitHint glfwInitHint_impl
|
||||
|
||||
typedef void (*glfwInitHintString_func)(int, const char*);
|
||||
glfwInitHintString_func glfwInitHintString_impl;
|
||||
#define glfwInitHintString glfwInitHintString_impl
|
||||
|
||||
typedef void (*glfwGetVersion_func)(int*, int*, int*);
|
||||
glfwGetVersion_func glfwGetVersion_impl;
|
||||
#define glfwGetVersion glfwGetVersion_impl
|
||||
@@ -1403,6 +1420,14 @@ typedef const char* (*glfwGetMonitorName_func)(GLFWmonitor*);
|
||||
glfwGetMonitorName_func glfwGetMonitorName_impl;
|
||||
#define glfwGetMonitorName glfwGetMonitorName_impl
|
||||
|
||||
typedef void (*glfwSetMonitorUserPointer_func)(GLFWmonitor*, void*);
|
||||
glfwSetMonitorUserPointer_func glfwSetMonitorUserPointer_impl;
|
||||
#define glfwSetMonitorUserPointer glfwSetMonitorUserPointer_impl
|
||||
|
||||
typedef void* (*glfwGetMonitorUserPointer_func)(GLFWmonitor*);
|
||||
glfwGetMonitorUserPointer_func glfwGetMonitorUserPointer_impl;
|
||||
#define glfwGetMonitorUserPointer glfwGetMonitorUserPointer_impl
|
||||
|
||||
typedef GLFWmonitorfun (*glfwSetMonitorCallback_func)(GLFWmonitorfun);
|
||||
glfwSetMonitorCallback_func glfwSetMonitorCallback_impl;
|
||||
#define glfwSetMonitorCallback glfwSetMonitorCallback_impl
|
||||
@@ -1435,6 +1460,10 @@ typedef void (*glfwWindowHint_func)(int, int);
|
||||
glfwWindowHint_func glfwWindowHint_impl;
|
||||
#define glfwWindowHint glfwWindowHint_impl
|
||||
|
||||
typedef void (*glfwWindowHintString_func)(int, const char*);
|
||||
glfwWindowHintString_func glfwWindowHintString_impl;
|
||||
#define glfwWindowHintString glfwWindowHintString_impl
|
||||
|
||||
typedef GLFWwindow* (*glfwCreateWindow_func)(int, int, const char*, GLFWmonitor*, GLFWwindow*);
|
||||
glfwCreateWindow_func glfwCreateWindow_impl;
|
||||
#define glfwCreateWindow glfwCreateWindow_impl
|
||||
@@ -1711,6 +1740,14 @@ typedef const char* (*glfwGetJoystickGUID_func)(int);
|
||||
glfwGetJoystickGUID_func glfwGetJoystickGUID_impl;
|
||||
#define glfwGetJoystickGUID glfwGetJoystickGUID_impl
|
||||
|
||||
typedef void (*glfwSetJoystickUserPointer_func)(int, void*);
|
||||
glfwSetJoystickUserPointer_func glfwSetJoystickUserPointer_impl;
|
||||
#define glfwSetJoystickUserPointer glfwSetJoystickUserPointer_impl
|
||||
|
||||
typedef void* (*glfwGetJoystickUserPointer_func)(int);
|
||||
glfwGetJoystickUserPointer_func glfwGetJoystickUserPointer_impl;
|
||||
#define glfwGetJoystickUserPointer glfwGetJoystickUserPointer_impl
|
||||
|
||||
typedef int (*glfwJoystickIsGamepad_func)(int);
|
||||
glfwJoystickIsGamepad_func glfwJoystickIsGamepad_impl;
|
||||
#define glfwJoystickIsGamepad glfwJoystickIsGamepad_impl
|
||||
|
||||
98
kitty/glfw.c
98
kitty/glfw.c
@@ -21,12 +21,14 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) {
|
||||
int w, h;
|
||||
glfwGetFramebufferSize(window->handle, &window->viewport_width, &window->viewport_height);
|
||||
glfwGetWindowSize(window->handle, &w, &h);
|
||||
double xr = window->viewport_x_ratio, yr = window->viewport_y_ratio;
|
||||
window->viewport_x_ratio = (double)window->viewport_width / (double)w;
|
||||
window->viewport_y_ratio = (double)window->viewport_height / (double)h;
|
||||
bool dpi_changed = (xr != 0.0 && xr != window->viewport_x_ratio) || (yr != 0.0 && yr != window->viewport_y_ratio);
|
||||
window->viewport_size_dirty = true;
|
||||
window->has_pending_resizes = false;
|
||||
if (notify_boss) {
|
||||
call_boss(on_window_resize, "Kii", window->id, window->viewport_width, window->viewport_height);
|
||||
call_boss(on_window_resize, "KiiO", window->id, window->viewport_width, window->viewport_height, dpi_changed ? Py_True : Py_False);
|
||||
}
|
||||
window->last_resize_at = monotonic();
|
||||
}
|
||||
@@ -34,7 +36,7 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) {
|
||||
|
||||
// callbacks {{{
|
||||
|
||||
void
|
||||
void
|
||||
update_os_window_references() {
|
||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||
OSWindow *w = global_state.os_windows + i;
|
||||
@@ -68,10 +70,10 @@ is_window_ready_for_callbacks() {
|
||||
|
||||
static inline void
|
||||
show_mouse_cursor(GLFWwindow *w) {
|
||||
if (glfwGetInputMode(w, GLFW_CURSOR) != GLFW_CURSOR_NORMAL) { glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL); }
|
||||
if (glfwGetInputMode(w, GLFW_CURSOR) != GLFW_CURSOR_NORMAL) { glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL); }
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
framebuffer_size_callback(GLFWwindow *w, int width, int height) {
|
||||
if (!set_callback_window(w)) return;
|
||||
if (width > 100 && height > 100) {
|
||||
@@ -86,7 +88,7 @@ framebuffer_size_callback(GLFWwindow *w, int width, int height) {
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
char_mods_callback(GLFWwindow *w, unsigned int codepoint, int mods) {
|
||||
if (!set_callback_window(w)) return;
|
||||
global_state.callback_os_window->cursor_blink_zero_time = monotonic();
|
||||
@@ -94,7 +96,7 @@ char_mods_callback(GLFWwindow *w, unsigned int codepoint, int mods) {
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
key_callback(GLFWwindow *w, int key, int scancode, int action, int mods) {
|
||||
if (!set_callback_window(w)) return;
|
||||
global_state.callback_os_window->cursor_blink_zero_time = monotonic();
|
||||
@@ -105,7 +107,7 @@ key_callback(GLFWwindow *w, int key, int scancode, int action, int mods) {
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
mouse_button_callback(GLFWwindow *w, int button, int action, int mods) {
|
||||
if (!set_callback_window(w)) return;
|
||||
show_mouse_cursor(w);
|
||||
@@ -118,7 +120,7 @@ mouse_button_callback(GLFWwindow *w, int button, int action, int mods) {
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
cursor_pos_callback(GLFWwindow *w, double x, double y) {
|
||||
if (!set_callback_window(w)) return;
|
||||
show_mouse_cursor(w);
|
||||
@@ -131,7 +133,7 @@ cursor_pos_callback(GLFWwindow *w, double x, double y) {
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
scroll_callback(GLFWwindow *w, double xoffset, double yoffset) {
|
||||
if (!set_callback_window(w)) return;
|
||||
show_mouse_cursor(w);
|
||||
@@ -141,12 +143,12 @@ scroll_callback(GLFWwindow *w, double xoffset, double yoffset) {
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
window_focus_callback(GLFWwindow *w, int focused) {
|
||||
if (!set_callback_window(w)) return;
|
||||
global_state.callback_os_window->is_focused = focused ? true : false;
|
||||
if (focused) {
|
||||
show_mouse_cursor(w);
|
||||
show_mouse_cursor(w);
|
||||
focus_in_event();
|
||||
}
|
||||
double now = monotonic();
|
||||
@@ -158,7 +160,7 @@ window_focus_callback(GLFWwindow *w, int focused) {
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
drop_callback(GLFWwindow *w, int count, const char **paths) {
|
||||
if (!set_callback_window(w)) return;
|
||||
PyObject *p = PyTuple_New(count);
|
||||
@@ -201,7 +203,7 @@ set_default_window_icon(PyObject UNUSED *self, PyObject *args) {
|
||||
|
||||
static GLFWwindow *current_os_window_ctx = NULL;
|
||||
|
||||
void
|
||||
void
|
||||
make_os_window_context_current(OSWindow *w) {
|
||||
if (w->handle != current_os_window_ctx) {
|
||||
current_os_window_ctx = w->handle;
|
||||
@@ -246,8 +248,8 @@ current_monitor(GLFWwindow *window) {
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
set_dpi_from_window(OSWindow *w) {
|
||||
void
|
||||
set_dpi_from_os_window(OSWindow *w) {
|
||||
GLFWmonitor *monitor = NULL;
|
||||
if (w) { monitor = current_monitor(w->handle); }
|
||||
if (monitor == NULL) monitor = glfwGetPrimaryMonitor();
|
||||
@@ -265,13 +267,14 @@ set_dpi_from_window(OSWindow *w) {
|
||||
|
||||
static PyObject*
|
||||
create_os_window(PyObject UNUSED *self, PyObject *args) {
|
||||
int width, height, visible = 1, swap_interval = 0, x = -1, y = -1;
|
||||
char *title;
|
||||
int width, height, swap_interval = 0, x = -1, y = -1;
|
||||
char *title, *wm_class_class, *wm_class_name;
|
||||
PyObject *load_programs = NULL;
|
||||
if (!PyArg_ParseTuple(args, "iis|pOiii", &width, &height, &title, &visible, &load_programs, &swap_interval, &x, &y)) return NULL;
|
||||
if (!PyArg_ParseTuple(args, "iisss|Oiii", &width, &height, &title, &wm_class_name, &wm_class_class, &load_programs, &swap_interval, &x, &y)) return NULL;
|
||||
bool is_first_window = standard_cursor == NULL;
|
||||
|
||||
if (is_first_window) {
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_REQUIRED_VERSION_MAJOR);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_REQUIRED_VERSION_MINOR);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
@@ -288,15 +291,19 @@ create_os_window(PyObject UNUSED *self, PyObject *args) {
|
||||
click_cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||
arrow_cursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
if (standard_cursor == NULL || click_cursor == NULL || arrow_cursor == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL;
|
||||
PyErr_SetString(PyExc_ValueError, "Failed to create standard mouse cursors"); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
glfwWindowHintString(GLFW_X11_INSTANCE_NAME, wm_class_name);
|
||||
glfwWindowHintString(GLFW_X11_CLASS_NAME, wm_class_class);
|
||||
#endif
|
||||
|
||||
if (global_state.num_os_windows >= MAX_CHILDREN) {
|
||||
PyErr_SetString(PyExc_ValueError, "Too many windows");
|
||||
return NULL;
|
||||
}
|
||||
glfwWindowHint(GLFW_VISIBLE, visible ? GLFW_TRUE : GLFW_FALSE);
|
||||
bool want_semi_transparent = (1.0 - OPT(background_opacity) > 0.1) ? true : false;
|
||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, want_semi_transparent);
|
||||
GLFWwindow *glfw_window = glfwCreateWindow(width, height, title, NULL, global_state.num_os_windows ? global_state.os_windows[0].handle : NULL);
|
||||
@@ -309,8 +316,8 @@ create_os_window(PyObject UNUSED *self, PyObject *args) {
|
||||
if (x != -1 && y != -1) glfwSetWindowPos(glfw_window, x, y);
|
||||
current_os_window_ctx = glfw_window;
|
||||
glfwSwapInterval(swap_interval); // a value of 1 makes mouse selection laggy
|
||||
if (is_first_window) {
|
||||
set_dpi_from_window(NULL);
|
||||
if (is_first_window) {
|
||||
set_dpi_from_os_window(NULL);
|
||||
gl_init();
|
||||
PyObject *ret = PyObject_CallFunction(load_programs, "i", glfwGetWindowAttrib(glfw_window, GLFW_TRANSPARENT_FRAMEBUFFER));
|
||||
if (ret == NULL) return NULL;
|
||||
@@ -364,28 +371,41 @@ static PyObject*
|
||||
show_window(PyObject UNUSED *self, PyObject *args) {
|
||||
id_type os_window_id;
|
||||
int yes = 1;
|
||||
bool dpi_changed = false;
|
||||
if (!PyArg_ParseTuple(args, "K|p", &os_window_id, &yes)) return NULL;
|
||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||
OSWindow *w = global_state.os_windows + i;
|
||||
if (w->id == os_window_id) {
|
||||
if (yes) glfwShowWindow(w->handle); else glfwHideWindow(w->handle);
|
||||
if (yes) {
|
||||
bool first_show = !w->shown_once;
|
||||
glfwShowWindow(w->handle);
|
||||
w->shown_once = true;
|
||||
if (first_show) {
|
||||
double before_x = global_state.logical_dpi_x, before_y = global_state.logical_dpi_y;
|
||||
set_dpi_from_os_window(w);
|
||||
dpi_changed = before_x != global_state.logical_dpi_x || before_y != global_state.logical_dpi_y;
|
||||
w->has_pending_resizes = true;
|
||||
global_state.has_pending_resizes = true;
|
||||
}
|
||||
} else glfwHideWindow(w->handle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
if (dpi_changed) Py_RETURN_TRUE;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
destroy_os_window(OSWindow *w) {
|
||||
if (w->handle) {
|
||||
glfwDestroyWindow(w->handle);
|
||||
glfwDestroyWindow(w->handle);
|
||||
if (current_os_window_ctx == w->handle) current_os_window_ctx = NULL;
|
||||
}
|
||||
w->handle = NULL;
|
||||
}
|
||||
|
||||
// Global functions {{{
|
||||
static void
|
||||
static void
|
||||
error_callback(int error, const char* description) {
|
||||
fprintf(stderr, "[glfw error %d]: %s\n", error, description);
|
||||
}
|
||||
@@ -522,11 +542,11 @@ toggle_fullscreen(PyObject UNUSED *self) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
ring_audio_bell(OSWindow *w) {
|
||||
static double last_bell_at = -1;
|
||||
double now = monotonic();
|
||||
if (now - last_bell_at <= 0.1) return;
|
||||
if (now - last_bell_at <= 0.1) return;
|
||||
last_bell_at = now;
|
||||
if (w->handle) {
|
||||
glfwWindowBell(w->handle, OPT(x11_bell_volume));
|
||||
@@ -555,7 +575,7 @@ hide_mouse(OSWindow *w) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
swap_window_buffers(OSWindow *w) {
|
||||
glfwSwapBuffers(w->handle);
|
||||
}
|
||||
@@ -571,7 +591,7 @@ wakeup_main_loop() {
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
mark_os_window_for_close(OSWindow* w, bool yes) {
|
||||
glfwSetWindowShouldClose(w->handle, yes);
|
||||
}
|
||||
@@ -694,14 +714,14 @@ static PyMethodDef module_methods[] = {
|
||||
METHODB(x11_window_id, METH_O),
|
||||
METHODB(set_primary_selection, METH_VARARGS),
|
||||
METHODB(glfw_poll_events, METH_NOARGS),
|
||||
{"glfw_init", (PyCFunction)glfw_init, METH_VARARGS, ""},
|
||||
{"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""},
|
||||
{"glfw_wait_events", (PyCFunction)glfw_wait_events, METH_VARARGS, ""},
|
||||
{"glfw_post_empty_event", (PyCFunction)glfw_post_empty_event, METH_NOARGS, ""},
|
||||
{"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""},
|
||||
{"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""},
|
||||
{"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""},
|
||||
{"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""},
|
||||
{"glfw_init", (PyCFunction)glfw_init, METH_VARARGS, ""},
|
||||
{"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""},
|
||||
{"glfw_wait_events", (PyCFunction)glfw_wait_events, METH_VARARGS, ""},
|
||||
{"glfw_post_empty_event", (PyCFunction)glfw_post_empty_event, METH_NOARGS, ""},
|
||||
{"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""},
|
||||
{"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""},
|
||||
{"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""},
|
||||
{"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@@ -710,8 +730,6 @@ bool
|
||||
init_glfw(PyObject *m) {
|
||||
if (PyModule_AddFunctions(m, module_methods) != 0) return false;
|
||||
#define ADDC(n) if(PyModule_AddIntConstant(m, #n, n) != 0) return false;
|
||||
ADDC(GLFW_X11_WM_CLASS_NAME)
|
||||
ADDC(GLFW_X11_WM_CLASS_CLASS)
|
||||
ADDC(GLFW_RELEASE);
|
||||
ADDC(GLFW_PRESS);
|
||||
ADDC(GLFW_REPEAT);
|
||||
|
||||
@@ -81,7 +81,7 @@ static inline void
|
||||
remove_from_array(void *array, size_t item_size, size_t idx, size_t array_count) {
|
||||
size_t num_to_right = array_count - 1 - idx;
|
||||
uint8_t *p = (uint8_t*)array;
|
||||
if (num_to_right > 0) memmove(p + (idx * item_size), p + ((idx + 1) * item_size), num_to_right * item_size);
|
||||
if (num_to_right > 0) memmove(p + (idx * item_size), p + ((idx + 1) * item_size), num_to_right * item_size);
|
||||
memset(p + (item_size * (array_count - 1)), 0, item_size);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ trim_predicate(Image *img) {
|
||||
static int
|
||||
oldest_last(const void* a, const void *b) {
|
||||
double ans = ((Image*)(b))->atime - ((Image*)(a))->atime;
|
||||
return ans < 0 ? -1 : (ans == 0 ? 0 : 1);
|
||||
return ans < 0 ? -1 : (ans == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -171,7 +171,7 @@ mmap_img_file(GraphicsManager UNUSED *self, Image *img, int fd, size_t sz, off_t
|
||||
sz = s.st_size;
|
||||
}
|
||||
void *addr = mmap(0, sz, PROT_READ, MAP_SHARED, fd, offset);
|
||||
if (addr == MAP_FAILED) ABRT(EBADF, "Failed to map image file fd: %d at offset: %zd with size: %zu with error: [%d] %s", fd, offset, sz, errno, strerror(errno));
|
||||
if (addr == MAP_FAILED) ABRT(EBADF, "Failed to map image file fd: %d at offset: %zd with size: %zu with error: [%d] %s", fd, offset, sz, errno, strerror(errno));
|
||||
img->load_data.mapped_file = addr;
|
||||
img->load_data.mapped_file_sz = sz;
|
||||
return true;
|
||||
@@ -267,7 +267,7 @@ inflate_png_inner(struct png_jmp_data *d, uint8_t *buf, size_t bufsz) {
|
||||
if (!info) ABRT(ENOMEM, "Failed to create PNG info structure");
|
||||
|
||||
if (setjmp(jb)) goto err;
|
||||
|
||||
|
||||
png_set_read_fn(png, &f, read_png_from_buffer);
|
||||
png_read_info(png, info);
|
||||
png_byte color_type, bit_depth;
|
||||
@@ -312,7 +312,7 @@ inflate_png(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz
|
||||
if (d.ok) {
|
||||
free_load_data(&img->load_data);
|
||||
img->load_data.buf = d.decompressed;
|
||||
img->load_data.buf_capacity = d.sz;
|
||||
img->load_data.buf_capacity = d.sz;
|
||||
img->load_data.buf_used = d.sz;
|
||||
img->load_data.data_sz = d.sz;
|
||||
img->width = d.width; img->height = d.height;
|
||||
@@ -376,7 +376,7 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
|
||||
img->atime = monotonic(); img->used_storage = 0;
|
||||
img->width = g->data_width; img->height = g->data_height;
|
||||
switch(fmt) {
|
||||
case PNG:
|
||||
case PNG:
|
||||
if (g->data_sz > MAX_DATA_SZ) ABRT(EINVAL, "PNG data size too large");
|
||||
img->load_data.is_4byte_aligned = true;
|
||||
img->load_data.is_opaque = false;
|
||||
@@ -513,7 +513,7 @@ create_add_response(GraphicsManager UNUSED *self, bool data_loaded, uint32_t iid
|
||||
if (iid) {
|
||||
if (!has_add_respose) {
|
||||
if (!data_loaded) return NULL;
|
||||
snprintf(add_response, 10, "OK");
|
||||
snprintf(add_response, 10, "OK");
|
||||
}
|
||||
snprintf(rbuf, sizeof(rbuf)/sizeof(rbuf[0]) - 1, "Gi=%u;%s", iid, add_response);
|
||||
return rbuf;
|
||||
@@ -541,18 +541,18 @@ update_dest_rect(ImageRef *ref, uint32_t num_cols, uint32_t num_rows) {
|
||||
t = ref->src_width + ref->cell_x_offset;
|
||||
num_cols = t / global_state.cell_width;
|
||||
if (t > num_cols * global_state.cell_width) num_cols += 1;
|
||||
}
|
||||
}
|
||||
if (num_rows == 0) {
|
||||
t = ref->src_height + ref->cell_y_offset;
|
||||
num_rows = t / global_state.cell_height;
|
||||
if (t > num_rows * global_state.cell_height) num_rows += 1;
|
||||
}
|
||||
}
|
||||
ref->effective_num_rows = num_rows;
|
||||
ref->effective_num_cols = num_cols;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static void
|
||||
handle_put_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c, bool *is_dirty, Image *img) {
|
||||
has_add_respose = false;
|
||||
if (img == NULL) img = img_by_client_id(self, g->id);
|
||||
@@ -584,12 +584,12 @@ handle_put_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c, b
|
||||
c->x += ref->effective_num_cols; c->y += ref->effective_num_rows - 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_by_zindex_and_image(const void *a_, const void *b_) {
|
||||
static int
|
||||
cmp_by_zindex_and_image(const void *a_, const void *b_) {
|
||||
const ImageRenderData *a = (const ImageRenderData*)a_, *b = (const ImageRenderData*)b_;
|
||||
int ans = a->z_index - b->z_index;
|
||||
if (ans == 0) ans = a->image_id - b->image_id;
|
||||
return ans;
|
||||
return ans;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -656,9 +656,9 @@ filter_refs(GraphicsManager *self, const void* data, bool free_images, bool (*fi
|
||||
size_t i, j;
|
||||
|
||||
if (self->image_count) {
|
||||
for (i = self->image_count; i-- > 0;) {
|
||||
for (i = self->image_count; i-- > 0;) {
|
||||
img = self->images + i;
|
||||
for (j = img->refcnt; j-- > 0;) {
|
||||
for (j = img->refcnt; j-- > 0;) {
|
||||
ref = img->refs + j;
|
||||
if (filter_func(ref, img, data)) {
|
||||
remove_from_array(img->refs, sizeof(ImageRef), j, img->refcnt--);
|
||||
@@ -718,7 +718,7 @@ scroll_filter_margins_func(ImageRef* ref, Image* img, const void* data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
grman_scroll_images(GraphicsManager *self, const ScrollData *data) {
|
||||
filter_refs(self, data, true, data->has_margins ? scroll_filter_margins_func : scroll_filter_func);
|
||||
}
|
||||
@@ -799,18 +799,18 @@ handle_delete_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c
|
||||
|
||||
// }}}
|
||||
|
||||
void
|
||||
void
|
||||
grman_resize(GraphicsManager *self, index_type UNUSED old_lines, index_type UNUSED lines, index_type UNUSED old_columns, index_type UNUSED columns) {
|
||||
self->layers_dirty = true;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
grman_rescale(GraphicsManager *self, unsigned int UNUSED old_cell_width, unsigned int UNUSED old_cell_height) {
|
||||
ImageRef *ref; Image *img;
|
||||
self->layers_dirty = true;
|
||||
for (size_t i = self->image_count; i-- > 0;) {
|
||||
for (size_t i = self->image_count; i-- > 0;) {
|
||||
img = self->images + i;
|
||||
for (size_t j = img->refcnt; j-- > 0;) {
|
||||
for (size_t j = img->refcnt; j-- > 0;) {
|
||||
ref = img->refs + j;
|
||||
ref->cell_x_offset = MIN(ref->cell_x_offset, global_state.cell_width - 1);
|
||||
ref->cell_y_offset = MIN(ref->cell_y_offset, global_state.cell_height - 1);
|
||||
@@ -925,7 +925,7 @@ W(update_layers) {
|
||||
for (size_t i = 0; i < self->count; i++) {
|
||||
ImageRenderData *r = self->render_data + i;
|
||||
#define R(offset) Py_BuildValue("{sf sf sf sf}", "left", r->vertices[offset + 8], "top", r->vertices[offset + 1], "right", r->vertices[offset], "bottom", r->vertices[offset + 5])
|
||||
PyTuple_SET_ITEM(ans, i,
|
||||
PyTuple_SET_ITEM(ans, i,
|
||||
Py_BuildValue("{sN sN sI si sI}", "src_rect", R(0), "dest_rect", R(2), "group_count", r->group_count, "z_index", r->z_index, "image_id", r->image_id)
|
||||
);
|
||||
#undef R
|
||||
@@ -950,10 +950,10 @@ PyTypeObject GraphicsManager_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.GraphicsManager",
|
||||
.tp_basicsize = sizeof(GraphicsManager),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "GraphicsManager",
|
||||
.tp_new = new,
|
||||
.tp_new = new,
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
};
|
||||
@@ -969,7 +969,7 @@ static PyMethodDef module_methods[] = {
|
||||
bool
|
||||
init_graphics(PyObject *module) {
|
||||
if (PyType_Ready(&GraphicsManager_Type) < 0) return false;
|
||||
if (PyModule_AddObject(module, "GraphicsManager", (PyObject *)&GraphicsManager_Type) != 0) return false;
|
||||
if (PyModule_AddObject(module, "GraphicsManager", (PyObject *)&GraphicsManager_Type) != 0) return false;
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
Py_INCREF(&GraphicsManager_Type);
|
||||
return true;
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
#define ALPHA_TYPE
|
||||
|
||||
uniform sampler2D image;
|
||||
uniform float inactive_text_alpha;
|
||||
|
||||
in vec2 texcoord;
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = texture(image, texcoord);
|
||||
color.a *= inactive_text_alpha;
|
||||
#ifdef PREMULT
|
||||
color = vec4(color.rgb * color.a, color.a);
|
||||
#endif
|
||||
|
||||
@@ -58,7 +58,7 @@ dealloc(HistoryBuf* self) {
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static inline index_type
|
||||
static inline index_type
|
||||
index_of(HistoryBuf *self, index_type lnum) {
|
||||
// The index (buffer position) of the line with line number lnum
|
||||
// This is reverse indexing, i.e. lnum = 0 corresponds to the *last* line in the buffer.
|
||||
@@ -67,7 +67,7 @@ index_of(HistoryBuf *self, index_type lnum) {
|
||||
return (self->start_of_data + idx) % self->ynum;
|
||||
}
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
init_line(HistoryBuf *self, index_type num, Line *l) {
|
||||
// Initialize the line l, setting its pointer to the offsets for the line at index (buffer position) num
|
||||
l->cells = lineptr(self, num);
|
||||
@@ -75,22 +75,22 @@ init_line(HistoryBuf *self, index_type num, Line *l) {
|
||||
l->has_dirty_text = self->line_attrs[num] & TEXT_DIRTY_MASK ? true : false;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
historybuf_init_line(HistoryBuf *self, index_type lnum, Line *l) {
|
||||
init_line(self, index_of(self, lnum), l);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
historybuf_mark_line_clean(HistoryBuf *self, index_type y) {
|
||||
self->line_attrs[index_of(self, y)] &= ~TEXT_DIRTY_MASK;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
historybuf_mark_line_dirty(HistoryBuf *self, index_type y) {
|
||||
self->line_attrs[index_of(self, y)] |= TEXT_DIRTY_MASK;
|
||||
}
|
||||
|
||||
static inline index_type
|
||||
static inline index_type
|
||||
historybuf_push(HistoryBuf *self) {
|
||||
index_type idx = (self->start_of_data + self->count) % self->ynum;
|
||||
init_line(self, idx, self->line);
|
||||
@@ -124,7 +124,7 @@ historybuf_resize(HistoryBuf *self, index_type lines) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
historybuf_add_line(HistoryBuf *self, const Line *line) {
|
||||
index_type idx = historybuf_push(self);
|
||||
copy_line(line, self->line);
|
||||
@@ -234,11 +234,11 @@ PyTypeObject HistoryBuf_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.HistoryBuf",
|
||||
.tp_basicsize = sizeof(HistoryBuf),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "History buffers",
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
.tp_members = members,
|
||||
.tp_str = (reprfunc)__str__,
|
||||
.tp_new = new
|
||||
};
|
||||
@@ -258,9 +258,9 @@ HistoryBuf *alloc_historybuf(unsigned int lines, unsigned int columns) {
|
||||
|
||||
#define is_src_line_continued(src_y) (map_src_index(src_y) < src->ynum - 1 ? (src->line_attrs[map_src_index(src_y + 1)] & CONTINUED_MASK) : false)
|
||||
|
||||
#define next_dest_line(cont) dest->line_attrs[historybuf_push(dest)] = cont & CONTINUED_MASK; dest->line->continued = cont;
|
||||
#define next_dest_line(cont) dest->line_attrs[historybuf_push(dest)] = cont & CONTINUED_MASK; dest->line->continued = cont;
|
||||
|
||||
#define first_dest_line next_dest_line(false);
|
||||
#define first_dest_line next_dest_line(false);
|
||||
|
||||
#include "rewrap.h"
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ static inline bool
|
||||
is_modifier_key(int key) {
|
||||
switch(key) {
|
||||
case GLFW_KEY_LEFT_SHIFT:
|
||||
case GLFW_KEY_RIGHT_SHIFT:
|
||||
case GLFW_KEY_RIGHT_SHIFT:
|
||||
case GLFW_KEY_LEFT_ALT:
|
||||
case GLFW_KEY_RIGHT_ALT:
|
||||
case GLFW_KEY_LEFT_CONTROL:
|
||||
@@ -83,7 +83,7 @@ get_localized_key(int key, int scancode) {
|
||||
// key names {{{
|
||||
K('A', A); K('a', A);
|
||||
K('B', B); K('b', B);
|
||||
K('C', C); K('c', C);
|
||||
K('C', C); K('c', C);
|
||||
K('D', D); K('d', D);
|
||||
K('E', E); K('e', E);
|
||||
K('F', F); K('f', F);
|
||||
@@ -209,7 +209,7 @@ PYWRAP1(key_to_bytes) {
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
M(key_to_bytes, METH_VARARGS),
|
||||
M(key_to_bytes, METH_VARARGS),
|
||||
{0}
|
||||
};
|
||||
|
||||
|
||||
20
kitty/keys.h
generated
20
kitty/keys.h
generated
@@ -487,12 +487,12 @@ static inline const char*
|
||||
key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
switch(mode) {
|
||||
case NORMAL:
|
||||
switch(action & 3) { case 3: return NULL;
|
||||
switch(action & 3) { case 3: return NULL;
|
||||
case 0: // RELEASE
|
||||
return NULL;
|
||||
|
||||
case 1: // PRESS
|
||||
switch (mods & 0xf) {
|
||||
switch (mods & 0xf) {
|
||||
case 0x0:
|
||||
switch(key & 0x7f) { default: return NULL;
|
||||
case 50: // ESCAPE
|
||||
@@ -1690,7 +1690,7 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
} // end switch(mods)
|
||||
|
||||
case 2: // REPEAT
|
||||
switch (mods & 0xf) {
|
||||
switch (mods & 0xf) {
|
||||
case 0x0:
|
||||
switch(key & 0x7f) { default: return NULL;
|
||||
case 50: // ESCAPE
|
||||
@@ -2891,12 +2891,12 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
|
||||
|
||||
case APPLICATION:
|
||||
switch(action & 3) { case 3: return NULL;
|
||||
switch(action & 3) { case 3: return NULL;
|
||||
case 0: // RELEASE
|
||||
return NULL;
|
||||
|
||||
case 1: // PRESS
|
||||
switch (mods & 0xf) {
|
||||
switch (mods & 0xf) {
|
||||
case 0x0:
|
||||
switch(key & 0x7f) { default: return NULL;
|
||||
case 50: // ESCAPE
|
||||
@@ -4094,7 +4094,7 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
} // end switch(mods)
|
||||
|
||||
case 2: // REPEAT
|
||||
switch (mods & 0xf) {
|
||||
switch (mods & 0xf) {
|
||||
case 0x0:
|
||||
switch(key & 0x7f) { default: return NULL;
|
||||
case 50: // ESCAPE
|
||||
@@ -5295,9 +5295,9 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
|
||||
|
||||
case EXTENDED:
|
||||
switch(action & 3) { case 3: return NULL;
|
||||
switch(action & 3) { case 3: return NULL;
|
||||
case 0: // RELEASE
|
||||
switch (mods & 0xf) {
|
||||
switch (mods & 0xf) {
|
||||
case 0x0:
|
||||
switch(key & 0x7f) { default: return NULL;
|
||||
case 0: // SPACE
|
||||
@@ -9061,7 +9061,7 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
} // end switch(mods)
|
||||
|
||||
case 1: // PRESS
|
||||
switch (mods & 0xf) {
|
||||
switch (mods & 0xf) {
|
||||
case 0x0:
|
||||
switch(key & 0x7f) { default: return NULL;
|
||||
case 0: // SPACE
|
||||
@@ -12825,7 +12825,7 @@ key_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {
|
||||
} // end switch(mods)
|
||||
|
||||
case 2: // REPEAT
|
||||
switch (mods & 0xf) {
|
||||
switch (mods & 0xf) {
|
||||
case 0x0:
|
||||
switch(key & 0x7f) { default: return NULL;
|
||||
case 0: // SPACE
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# bold_font Operator Mono Medium
|
||||
# italic_font Operator Mono Book Italic
|
||||
# bold_italic_font Operator Mono Medium Italic
|
||||
#
|
||||
#
|
||||
# You can get a list of full family names available on your computer by running
|
||||
# kitty list-fonts
|
||||
font_family monospace
|
||||
@@ -24,7 +24,7 @@ font_size 11.0
|
||||
font_size_delta 2
|
||||
|
||||
|
||||
# Adjust the line height.
|
||||
# Adjust the line height.
|
||||
# You can use either numbers, which are interpreted as pixels or percentages
|
||||
# (number followed by %), which are interpreted as percentages of the
|
||||
# unmodified line height. You can use negative pixels or percentages less than
|
||||
@@ -32,7 +32,7 @@ font_size_delta 2
|
||||
adjust_line_height 0
|
||||
|
||||
# Change the sizes of the lines used for the box drawing unicode characters
|
||||
# These values are in pts. They will be scaled by the monitor DPI to arrive at
|
||||
# These values are in pts. They will be scaled by the monitor DPI to arrive at
|
||||
# a pixel value. There must be four values corresponding to thin, normal, thick,
|
||||
# and very thick lines;
|
||||
box_drawing_scale 0.001, 1, 1.5, 2
|
||||
@@ -73,7 +73,7 @@ cursor #cccccc
|
||||
cursor_shape block
|
||||
|
||||
# The interval (in seconds) at which to blink the cursor. Set to zero to
|
||||
# disable blinking. Note that numbers smaller than repaint_delay will be
|
||||
# disable blinking. Note that numbers smaller than repaint_delay will be
|
||||
# limited to repaint_delay.
|
||||
cursor_blink_interval 0.5
|
||||
|
||||
@@ -149,6 +149,10 @@ open_url_modifiers ctrl+shift
|
||||
# use the operating system's default URL handler.
|
||||
open_url_with default
|
||||
|
||||
# The modifiers to use rectangular selection (i.e. to select text in a
|
||||
# rectangular block with the mouse)
|
||||
rectangle_select_modifiers ctrl+alt
|
||||
|
||||
# Choose whether to use the system implementation of wcwidth() (used to
|
||||
# control how many cells a character is rendered in). If you use the system
|
||||
# implementation, then kitty and any programs running in it will agree. The
|
||||
@@ -177,6 +181,10 @@ active_border_color #00ff00
|
||||
# The color for the border of inactive windows
|
||||
inactive_border_color #cccccc
|
||||
|
||||
# Fade the text in inactive windows by the specified amount (a number between
|
||||
# zero and one, with 0 being fully faded).
|
||||
inactive_text_alpha 1.0
|
||||
|
||||
# Tab-bar customization
|
||||
active_tab_foreground #000
|
||||
active_tab_background #eee
|
||||
@@ -226,10 +234,10 @@ color15 #ffffff
|
||||
# Key mapping
|
||||
# For a list of key names, see: http://www.glfw.org/docs/latest/group__keys.html
|
||||
# For a list of modifier names, see: http://www.glfw.org/docs/latest/group__mods.html
|
||||
#
|
||||
#
|
||||
# You can use the special action no_op to unmap a keyboard shortcut that is
|
||||
# assigned in the default configuration.
|
||||
#
|
||||
#
|
||||
# You can combine multiple actions to be triggered by a single shortcut, using the
|
||||
# syntax below:
|
||||
# map key combine <separator> action1 <separator> action2 <separator> action3 ...
|
||||
@@ -246,7 +254,7 @@ map shift+insert paste_from_selection
|
||||
# pass_selection_to_program. By default, the system's open program is used, but
|
||||
# you can specify your own, for example:
|
||||
# map ctrl+shift+o pass_selection_to_program firefox
|
||||
map ctrl+shift+o pass_selection_to_program
|
||||
map ctrl+shift+o pass_selection_to_program
|
||||
|
||||
# Scrolling
|
||||
map ctrl+shift+up scroll_line_up
|
||||
@@ -260,8 +268,8 @@ map ctrl+shift+end scroll_end
|
||||
map ctrl+shift+h show_scrollback
|
||||
|
||||
# Window management
|
||||
map ctrl+shift+enter new_window
|
||||
map ctrl+shift+n new_os_window
|
||||
map ctrl+shift+enter new_window
|
||||
map ctrl+shift+n new_os_window
|
||||
map ctrl+shift+w close_window
|
||||
map ctrl+shift+] next_window
|
||||
map ctrl+shift+[ previous_window
|
||||
@@ -278,14 +286,20 @@ map ctrl+shift+7 seventh_window
|
||||
map ctrl+shift+8 eighth_window
|
||||
map ctrl+shift+9 ninth_window
|
||||
map ctrl+shift+0 tenth_window
|
||||
# You can also open a new window running an arbitrary program, for example:
|
||||
# You can open a new window running an arbitrary program, for example:
|
||||
# map ctrl+shift+y new_window mutt
|
||||
# You can also pass the current selection to the new program by using the @selection placeholder
|
||||
#
|
||||
# You can pass the current selection to the new program by using the @selection placeholder
|
||||
# map ctrl+shift+y new_window less @selection
|
||||
# Finally, you can even send the contents of the current screen + history buffer as stdin using
|
||||
#
|
||||
# You can even send the contents of the current screen + history buffer as stdin using
|
||||
# the placeholders @text (which is the plain text) and @ansi (which includes text styling escape codes)
|
||||
# For example, the following command opens the scrollback buffer in less in a new window.
|
||||
# map ctrl+shift+y new_window @ansi less +G -R
|
||||
#
|
||||
# You can open a new window with the current working directory set to the
|
||||
# working directory of the current window using
|
||||
# map ctrl+alt+enter new_window_with_cwd
|
||||
|
||||
|
||||
# Tab management
|
||||
@@ -301,7 +315,7 @@ map ctrl+shift+, move_tab_backward
|
||||
# map ctrl+alt+2 goto_tab 2
|
||||
|
||||
# Just as with new_window above, you can also pass the name of arbitrary
|
||||
# commands to run when using new_tab.
|
||||
# commands to run when using new_tab and use new_tab_with_cwd.
|
||||
|
||||
|
||||
# Miscellaneous
|
||||
@@ -334,11 +348,11 @@ map ctrl+shift+f11 toggle_fullscreen
|
||||
# in hexadecimal>. You can specify multiple code points, separated by commas
|
||||
# and ranges separated by hyphens. symbol_map itself can be specified multiple times.
|
||||
# Syntax is:
|
||||
#
|
||||
#
|
||||
# symbol_map codepoints Font Family Name
|
||||
#
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
#
|
||||
# symbol_map U+E0A0-U+E0A2,U+E0B0-U+E0B3 PowerlineSymbols
|
||||
|
||||
|
||||
@@ -347,7 +361,7 @@ map ctrl+shift+f11 toggle_fullscreen
|
||||
# Hide the kitty window's title bar on macOS.
|
||||
macos_hide_titlebar no
|
||||
|
||||
# Use the option key as an alt key. With this set to no, kitty will use
|
||||
# Use the option key as an alt key. With this set to no, kitty will use
|
||||
# the macOS native Option+Key = unicode character behavior. This will
|
||||
# break any Alt+key keyboard shortcuts in your terminal programs, but you
|
||||
# can use the macOS unicode input technique.
|
||||
|
||||
@@ -22,7 +22,7 @@ clear_chars_to(LineBuf* linebuf, index_type y, char_type ch) {
|
||||
clear_chars_in_line(lineptr(linebuf, y), linebuf->xnum, ch);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_clear(LineBuf *self, char_type ch) {
|
||||
memset(self->buf, 0, self->xnum * self->ynum * sizeof(Cell));
|
||||
memset(self->line_attrs, 0, self->ynum * sizeof(line_attrs_type));
|
||||
@@ -97,8 +97,8 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
static void
|
||||
dealloc(LineBuf* self) {
|
||||
PyMem_Free(self->buf);
|
||||
PyMem_Free(self->line_map);
|
||||
PyMem_Free(self->line_attrs);
|
||||
PyMem_Free(self->line_map);
|
||||
PyMem_Free(self->line_attrs);
|
||||
PyMem_Free(self->scratch);
|
||||
Py_CLEAR(self->line);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
@@ -109,7 +109,7 @@ init_line(LineBuf *lb, Line *l, index_type ynum) {
|
||||
l->cells = lineptr(lb, ynum);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_init_line(LineBuf *self, index_type idx) {
|
||||
self->line->ynum = idx;
|
||||
self->line->xnum = self->xnum;
|
||||
@@ -131,12 +131,12 @@ line(LineBuf *self, PyObject *y) {
|
||||
return (PyObject*)self->line;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
unsigned int
|
||||
linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
|
||||
return (lineptr(self, self->line_map[y])[x].attrs) & WIDTH_MASK;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_set_attribute(LineBuf *self, unsigned int shift, unsigned int val) {
|
||||
for (index_type y = 0; y < self->ynum; y++) {
|
||||
set_attribute_on_line(lineptr(self, y), shift, val, self->xnum);
|
||||
@@ -192,7 +192,7 @@ allocate_line_storage(Line *line, bool initialize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline PyObject*
|
||||
static inline PyObject*
|
||||
create_line_copy_inner(LineBuf* self, index_type y) {
|
||||
Line src, *line;
|
||||
line = alloc_line();
|
||||
@@ -237,7 +237,7 @@ clear_line_(Line *l, index_type xnum) {
|
||||
l->has_dirty_text = false;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_clear_line(LineBuf *self, index_type y) {
|
||||
Line l;
|
||||
init_line(self, &l, self->line_map[y]);
|
||||
@@ -254,7 +254,7 @@ clear_line(LineBuf *self, PyObject *val) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_index(LineBuf* self, index_type top, index_type bottom) {
|
||||
if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) return;
|
||||
index_type old_top = self->line_map[top];
|
||||
@@ -276,7 +276,7 @@ pyw_index(LineBuf *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_reverse_index(LineBuf *self, index_type top, index_type bottom) {
|
||||
if (top >= self->ynum - 1 || bottom >= self->ynum || bottom <= top) return;
|
||||
index_type old_bottom = self->line_map[bottom];
|
||||
@@ -308,7 +308,7 @@ is_continued(LineBuf *self, PyObject *val) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom) {
|
||||
index_type i;
|
||||
if (y >= self->ynum || y > bottom || bottom >= self->ynum) return;
|
||||
@@ -344,7 +344,7 @@ insert_lines(LineBuf *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom) {
|
||||
index_type i;
|
||||
index_type ylimit = bottom + 1;
|
||||
@@ -368,7 +368,7 @@ linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bot
|
||||
self->line_attrs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
delete_lines(LineBuf *self, PyObject *args) {
|
||||
#define delete_lines_doc "delete_lines(num, y, bottom) -> Delete num lines at y, only changing lines in the range [y, bottom]."
|
||||
@@ -377,7 +377,7 @@ delete_lines(LineBuf *self, PyObject *args) {
|
||||
linebuf_delete_lines(self, num, y, bottom);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
as_ansi(LineBuf *self, PyObject *callback) {
|
||||
#define as_ansi_doc "as_ansi(callback) -> The contents of this buffer as ANSI escaped text. callback is called with each successive line."
|
||||
@@ -453,11 +453,11 @@ PyTypeObject LineBuf_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.LineBuf",
|
||||
.tp_basicsize = sizeof(LineBuf),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "Line buffers",
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
.tp_members = members,
|
||||
.tp_str = (reprfunc)__str__,
|
||||
.tp_new = new
|
||||
};
|
||||
@@ -485,7 +485,7 @@ copy_old(LineBuf *self, PyObject *y) {
|
||||
|
||||
#include "rewrap.h"
|
||||
|
||||
void
|
||||
void
|
||||
linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_before, index_type *num_content_lines_after, HistoryBuf *historybuf) {
|
||||
index_type first, i;
|
||||
bool is_empty = true;
|
||||
@@ -510,9 +510,9 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *num_content_lines_befo
|
||||
} while(is_empty && first > 0);
|
||||
|
||||
if (is_empty) { // All lines are empty
|
||||
*num_content_lines_after = 0;
|
||||
*num_content_lines_after = 0;
|
||||
*num_content_lines_before = 0;
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
rewrap_inner(self, other, first + 1, historybuf);
|
||||
|
||||
31
kitty/line.c
31
kitty/line.c
@@ -34,7 +34,7 @@ line_length(Line *self) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyObject*
|
||||
line_text_at(char_type ch, combining_type cc) {
|
||||
PyObject *ans;
|
||||
if (LIKELY(cc == 0)) {
|
||||
@@ -67,7 +67,7 @@ find_colon_slash(Line *self, index_type x, index_type limit) {
|
||||
if (!is_url_char(ch)) return false;
|
||||
switch(state) {
|
||||
case ANY:
|
||||
if (ch == '/') state = FIRST_SLASH;
|
||||
if (ch == '/') state = FIRST_SLASH;
|
||||
break;
|
||||
case FIRST_SLASH:
|
||||
state = ch == '/' ? SECOND_SLASH : ANY;
|
||||
@@ -139,7 +139,7 @@ line_url_end_at(Line *self, index_type x, bool check_short) {
|
||||
index_type ans = x;
|
||||
if (x >= self->xnum || (check_short && self->xnum <= MIN_URL_LEN + 3)) return 0;
|
||||
while (ans < self->xnum && is_url_char(self->cells[ans].ch)) ans++;
|
||||
ans--;
|
||||
if (ans) ans--;
|
||||
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch)) ans--;
|
||||
return ans;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ PyObject*
|
||||
unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc, char leading_char) {
|
||||
size_t n = 0;
|
||||
static Py_UCS4 buf[4096];
|
||||
if (leading_char) buf[n++] = leading_char;
|
||||
if (leading_char) buf[n++] = leading_char;
|
||||
char_type previous_width = 0;
|
||||
for(index_type i = start; i < limit && n < sizeof(buf)/sizeof(buf[0]) - 4; i++) {
|
||||
char_type ch = self->cells[i].ch;
|
||||
@@ -241,7 +241,7 @@ write_sgr(const char *val, Py_UCS4 *buf, index_type buflen, index_type *i) {
|
||||
index_type
|
||||
line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen) {
|
||||
#define WRITE_SGR(val) { if (!write_sgr(val, buf, buflen, &i)) return i; }
|
||||
#define WRITE_CH(val) if (i > buflen - 1) return i; buf[i++] = val;
|
||||
#define WRITE_CH(val) if (i > buflen - 1) return i; buf[i++] = val;
|
||||
|
||||
index_type limit = xlimit_for_line(self), i=0;
|
||||
char_type previous_width = 0;
|
||||
@@ -316,7 +316,7 @@ width(Line *self, PyObject *val) {
|
||||
return PyLong_FromUnsignedLong((unsigned long) (attrs & WIDTH_MASK));
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
line_add_combining_char(Line *self, uint32_t ch, unsigned int x) {
|
||||
if (!self->cells[x].ch) return; // dont allow adding combining chars to a null cell
|
||||
combining_type c = self->cells[x].cc;
|
||||
@@ -398,7 +398,7 @@ cursor_from(Line* self, PyObject *args) {
|
||||
return (PyObject*)ans;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch) {
|
||||
attrs_type width = ch ? 1 : 0;
|
||||
#define PREFIX \
|
||||
@@ -423,13 +423,13 @@ clear_text(Line* self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char) {
|
||||
char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
|
||||
color_type fg = (cursor->fg & COL_MASK), bg = (cursor->bg & COL_MASK);
|
||||
color_type dfg = cursor->decoration_fg & COL_MASK;
|
||||
if (!clear_char) attrs = attrs & ATTRS_MASK_WITHOUT_WIDTH;
|
||||
|
||||
|
||||
for (index_type i = at; i < self->xnum && i < at + num; i++) {
|
||||
if (clear_char) {
|
||||
self->cells[i].ch = BLANK_CHAR;
|
||||
@@ -496,8 +496,8 @@ left_shift(Line *self, PyObject *args) {
|
||||
if (num > 0) left_shift_line(self, at, num);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
void
|
||||
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, bool UNUSED is_second) {
|
||||
if (cursor == NULL) {
|
||||
self->cells[at].attrs = (self->cells[at].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
|
||||
@@ -556,7 +556,7 @@ richcmp(PyObject *obj1, PyObject *obj2, int op);
|
||||
|
||||
|
||||
static PySequenceMethods sequence_methods = {
|
||||
.sq_length = __len__,
|
||||
.sq_length = __len__,
|
||||
.sq_item = (ssizeargfunc)text_at
|
||||
};
|
||||
|
||||
@@ -577,7 +577,7 @@ static PyMethodDef methods[] = {
|
||||
METHOD(url_start_at, METH_O)
|
||||
METHOD(url_end_at, METH_O)
|
||||
METHOD(sprite_at, METH_O)
|
||||
|
||||
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@@ -590,7 +590,7 @@ PyTypeObject Line_Type = {
|
||||
.tp_str = (reprfunc)as_unicode,
|
||||
.tp_as_sequence = &sequence_methods,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_richcompare = richcmp,
|
||||
.tp_richcompare = richcmp,
|
||||
.tp_doc = "Lines",
|
||||
.tp_methods = methods,
|
||||
.tp_new = new
|
||||
@@ -605,7 +605,7 @@ Line *alloc_line() {
|
||||
RICHCMP(Line)
|
||||
INIT_TYPE(Line)
|
||||
// }}}
|
||||
|
||||
|
||||
static PyObject*
|
||||
copy_char(Line* self, PyObject *args) {
|
||||
unsigned int src, dest;
|
||||
@@ -618,4 +618,3 @@ copy_char(Line* self, PyObject *args) {
|
||||
COPY_CELL(self, src, to, dest);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ static inline void
|
||||
set_attribute_on_line(Cell *cells, uint32_t shift, uint32_t val, index_type xnum) {
|
||||
// Set a single attribute on all cells in the line
|
||||
attrs_type mask = shift == DECORATION_SHIFT ? 3 : 1;
|
||||
attrs_type aval = (val & mask) << shift;
|
||||
attrs_type aval = (val & mask) << shift;
|
||||
mask = ~(mask << shift);
|
||||
for (index_type i = 0; i < xnum; i++) cells[i].attrs = (cells[i].attrs & mask) | aval;
|
||||
}
|
||||
|
||||
@@ -12,15 +12,15 @@ from .borders import load_borders_program
|
||||
from .boss import Boss
|
||||
from .cli import create_opts, parse_args
|
||||
from .config import initial_window_size, load_cached_values, save_cached_values
|
||||
from .constants import glfw_path, is_macos, is_wayland, logo_data_file
|
||||
from .constants import appname, glfw_path, is_macos, is_wayland, logo_data_file
|
||||
from .fast_data_types import (
|
||||
change_wcwidth, create_os_window, glfw_init, glfw_terminate,
|
||||
install_sigchld_handler, set_default_window_icon, set_options, show_window
|
||||
)
|
||||
from .fonts.box_drawing import set_scale
|
||||
from .utils import (
|
||||
detach, encode_wm_class, end_startup_notification,
|
||||
init_startup_notification, single_instance
|
||||
detach, end_startup_notification, init_startup_notification,
|
||||
single_instance
|
||||
)
|
||||
from .window import load_shader_programs
|
||||
|
||||
@@ -42,7 +42,7 @@ def run_app(opts, args):
|
||||
set_options(opts, is_wayland, args.debug_gl)
|
||||
load_cached_values()
|
||||
w, h = initial_window_size(opts)
|
||||
window_id = create_os_window(w, h, encode_wm_class(args.name, args.cls), False, load_all_shaders)
|
||||
window_id = create_os_window(w, h, appname, args.name or args.cls or appname, args.cls or appname, load_all_shaders)
|
||||
startup_ctx = init_startup_notification(window_id)
|
||||
show_window(window_id)
|
||||
if not is_wayland and not is_macos: # no window icons on wayland
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
/* *Insert/Replace Mode*: When enabled, new display characters move
|
||||
old display characters to the right. Characters moved past the
|
||||
right margin are lost. Otherwise, new display characters replace
|
||||
old display characters at the cursor position.
|
||||
old display characters at the cursor position.
|
||||
*/
|
||||
#define IRM 4
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ encode_mouse_event(Window *w, int button, MouseAction action, int mods) {
|
||||
return snprintf(mouse_event_buf, sizeof(mouse_event_buf), "%d;%d;%dM", cb + 32, x, y);
|
||||
break;
|
||||
case UTF8_PROTOCOL:
|
||||
mouse_event_buf[0] = 'M'; mouse_event_buf[1] = cb + 32;
|
||||
mouse_event_buf[0] = 'M'; mouse_event_buf[1] = cb + 32;
|
||||
unsigned int sz = 2;
|
||||
sz += encode_utf8(x + 32, mouse_event_buf + sz);
|
||||
sz += encode_utf8(y + 32, mouse_event_buf + sz);
|
||||
@@ -111,7 +111,7 @@ update_drag(bool from_button, Window *w, bool is_release, int modifiers) {
|
||||
Screen *screen = w->render_data.screen;
|
||||
if (from_button) {
|
||||
if (is_release) screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, true);
|
||||
else screen_start_selection(screen, w->mouse_cell_x, w->mouse_cell_y, modifiers == (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||
else screen_start_selection(screen, w->mouse_cell_x, w->mouse_cell_y, modifiers == (int)OPT(rectangle_select_modifiers));
|
||||
} else if (screen->selection.in_progress) {
|
||||
screen_update_selection(screen, w->mouse_cell_x, w->mouse_cell_y, false);
|
||||
call_boss(set_primary_selection, NULL);
|
||||
@@ -264,7 +264,7 @@ HANDLER(handle_button_event) {
|
||||
Screen *screen = w->render_data.screen;
|
||||
if (!screen) return;
|
||||
bool handle_in_kitty = (
|
||||
modifiers == GLFW_MOD_SHIFT ||
|
||||
modifiers == GLFW_MOD_SHIFT ||
|
||||
screen->modes.mouse_tracking_mode == 0 ||
|
||||
button == GLFW_MOUSE_BUTTON_MIDDLE ||
|
||||
(modifiers == (int)OPT(open_url_modifiers) && button == GLFW_MOUSE_BUTTON_LEFT)
|
||||
@@ -297,7 +297,7 @@ HANDLER(handle_event) {
|
||||
for (int i = 0; i < GLFW_MOUSE_BUTTON_5; i++) { if (global_state.callback_os_window->mouse_button_pressed[i]) { button = i; break; } }
|
||||
handle_move_event(w, button, modifiers, window_idx);
|
||||
break;
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
case GLFW_MOUSE_BUTTON_RIGHT:
|
||||
case GLFW_MOUSE_BUTTON_MIDDLE:
|
||||
case GLFW_MOUSE_BUTTON_4:
|
||||
@@ -309,7 +309,7 @@ HANDLER(handle_event) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
handle_tab_bar_mouse(int button, int UNUSED modifiers) {
|
||||
if (button != GLFW_MOUSE_BUTTON_LEFT || !global_state.callback_os_window->mouse_button_pressed[button]) return;
|
||||
call_boss(activate_tab_at, "Kd", global_state.callback_os_window->id, global_state.callback_os_window->mouse_x);
|
||||
@@ -347,9 +347,9 @@ mouse_event(int button, int modifiers) {
|
||||
bool in_tab_bar;
|
||||
unsigned int window_idx = 0;
|
||||
Window *w = window_for_event(&window_idx, &in_tab_bar);
|
||||
if (in_tab_bar) {
|
||||
if (in_tab_bar) {
|
||||
mouse_cursor_shape = HAND;
|
||||
handle_tab_bar_mouse(button, modifiers);
|
||||
handle_tab_bar_mouse(button, modifiers);
|
||||
} else if(w) {
|
||||
handle_event(w, button, modifiers, window_idx);
|
||||
}
|
||||
|
||||
200
kitty/parser.c
200
kitty/parser.c
@@ -62,7 +62,7 @@ utf8(char_type codepoint) {
|
||||
|
||||
|
||||
#ifdef DUMP_COMMANDS
|
||||
static void
|
||||
static void
|
||||
_report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
@@ -74,7 +74,7 @@ _report_error(PyObject *dump_callback, const char *fmt, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
_report_params(PyObject *dump_callback, const char *name, unsigned int *params, unsigned int count, Region *r) {
|
||||
static char buf[MAX_PARAMS*3] = {0};
|
||||
unsigned int i, p=0;
|
||||
@@ -126,7 +126,7 @@ _report_params(PyObject *dump_callback, const char *name, unsigned int *params,
|
||||
#define REPORT_ERROR(...) fprintf(stderr, "%s ", ERROR_PREFIX); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");
|
||||
|
||||
#define REPORT_COMMAND(...)
|
||||
#define REPORT_VA_COMMAND(...)
|
||||
#define REPORT_VA_COMMAND(...)
|
||||
#define REPORT_DRAW(ch)
|
||||
#define REPORT_PARAMS(...)
|
||||
#define FLUSH_DRAW
|
||||
@@ -142,7 +142,7 @@ _report_params(PyObject *dump_callback, const char *name, unsigned int *params,
|
||||
static inline void
|
||||
screen_nel(Screen *screen) { screen_carriage_return(screen); screen_linefeed(screen); }
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
handle_normal_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) {
|
||||
#define CALL_SCREEN_HANDLER(name) REPORT_COMMAND(name); name(screen); break;
|
||||
switch(ch) {
|
||||
@@ -191,11 +191,11 @@ handle_normal_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_
|
||||
} // }}}
|
||||
|
||||
// Esc mode {{{
|
||||
static inline void
|
||||
static inline void
|
||||
handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) {
|
||||
#define CALL_ED(name) REPORT_COMMAND(name); name(screen); SET_STATE(0);
|
||||
#define CALL_ED1(name, ch) REPORT_COMMAND(name, ch); name(screen, ch); SET_STATE(0);
|
||||
#define CALL_ED2(name, a, b) REPORT_COMMAND(name, a, b); name(screen, a, b); SET_STATE(0);
|
||||
#define CALL_ED(name) REPORT_COMMAND(name); name(screen); SET_STATE(0);
|
||||
#define CALL_ED1(name, ch) REPORT_COMMAND(name, ch); name(screen, ch); SET_STATE(0);
|
||||
#define CALL_ED2(name, a, b) REPORT_COMMAND(name, a, b); name(screen, a, b); SET_STATE(0);
|
||||
switch(screen->parser_buf_pos) {
|
||||
case 0:
|
||||
switch (ch) {
|
||||
@@ -223,9 +223,9 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal
|
||||
CALL_ED(screen_save_cursor); break;
|
||||
case ESC_DECRC:
|
||||
CALL_ED(screen_restore_cursor); break;
|
||||
case ESC_DECPNM:
|
||||
case ESC_DECPNM:
|
||||
CALL_ED(screen_normal_keypad_mode); break;
|
||||
case ESC_DECPAM:
|
||||
case ESC_DECPAM:
|
||||
CALL_ED(screen_alternate_keypad_mode); break;
|
||||
case '%':
|
||||
case '(':
|
||||
@@ -240,7 +240,7 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal
|
||||
screen->parser_buf[screen->parser_buf_pos++] = ch;
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("%s0x%x", "Unknown char after ESC: ", ch);
|
||||
REPORT_ERROR("%s0x%x", "Unknown char after ESC: ", ch);
|
||||
SET_STATE(0); break;
|
||||
}
|
||||
break;
|
||||
@@ -363,11 +363,11 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
case '$':
|
||||
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
screen_cursor_up2(Screen *s, unsigned int count) { screen_cursor_up(s, count, false, -1); }
|
||||
static inline void
|
||||
static inline void
|
||||
screen_cursor_back1(Screen *s, unsigned int count) { screen_cursor_back(s, count, -1); }
|
||||
static inline void
|
||||
static inline void
|
||||
screen_tabn(Screen *s, unsigned int count) { for (index_type i=0; i < MAX(1, count); i++) screen_tab(s); }
|
||||
static inline void
|
||||
save_cursor(Screen *s, unsigned int UNUSED param, bool private) {
|
||||
@@ -481,8 +481,8 @@ parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, unsigned int *params,
|
||||
READ_PARAM;
|
||||
num_start = i + 1;
|
||||
break;
|
||||
case COLOR:
|
||||
case COLOR1:
|
||||
case COLOR:
|
||||
case COLOR1:
|
||||
case COLOR3:
|
||||
REPORT_ERROR("Invalid SGR code containing disallowed character: %s", utf8(buf[i]));
|
||||
return;
|
||||
@@ -510,7 +510,7 @@ parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, unsigned int *params,
|
||||
break;
|
||||
case COLOR3:
|
||||
if (i > num_start && num_params < MAX_PARAMS) READ_PARAM;
|
||||
if (num_params != 5) {
|
||||
if (num_params != 5) {
|
||||
REPORT_ERROR("Invalid SGR code containing incomplete semi-colon separated color sequence");
|
||||
break;
|
||||
}
|
||||
@@ -532,7 +532,7 @@ parse_region(Region *r, uint32_t *buf, unsigned int num) {
|
||||
default:
|
||||
if (i > start) params[num_params++] = utoi(buf + start, i - start);
|
||||
else if (i == start && buf[i] == ';') params[num_params++] = 0;
|
||||
start = i + 1;
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -541,16 +541,16 @@ parse_region(Region *r, uint32_t *buf, unsigned int num) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
r->top = params[0];
|
||||
r->top = params[0];
|
||||
break;
|
||||
case 2:
|
||||
r->top = params[0]; r->left = params[1];
|
||||
r->top = params[0]; r->left = params[1];
|
||||
break;
|
||||
case 3:
|
||||
r->top = params[0]; r->left = params[1]; r->bottom = params[2];
|
||||
r->top = params[0]; r->left = params[1]; r->bottom = params[2];
|
||||
break;
|
||||
default:
|
||||
r->top = params[0]; r->left = params[1]; r->bottom = params[2]; r->right = params[3];
|
||||
r->top = params[0]; r->left = params[1]; r->bottom = params[2]; r->right = params[3];
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
@@ -639,83 +639,83 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
}
|
||||
if (i > start) params[num_params++] = utoi(buf + start, i - start);
|
||||
switch(code) {
|
||||
case ICH:
|
||||
CALL_CSI_HANDLER1(screen_insert_characters, 1);
|
||||
case CUU:
|
||||
CALL_CSI_HANDLER1(screen_cursor_up2, 1);
|
||||
case CUD:
|
||||
case VPR:
|
||||
CALL_CSI_HANDLER1(screen_cursor_down, 1);
|
||||
case CUF:
|
||||
case HPR:
|
||||
CALL_CSI_HANDLER1(screen_cursor_forward, 1);
|
||||
case CUB:
|
||||
CALL_CSI_HANDLER1(screen_cursor_back1, 1);
|
||||
case CNL:
|
||||
CALL_CSI_HANDLER1(screen_cursor_down1, 1);
|
||||
case CPL:
|
||||
CALL_CSI_HANDLER1(screen_cursor_up1, 1);
|
||||
case CHA:
|
||||
case HPA:
|
||||
CALL_CSI_HANDLER1(screen_cursor_to_column, 1);
|
||||
case VPA:
|
||||
CALL_CSI_HANDLER1(screen_cursor_to_line, 1);
|
||||
case ICH:
|
||||
CALL_CSI_HANDLER1(screen_insert_characters, 1);
|
||||
case CUU:
|
||||
CALL_CSI_HANDLER1(screen_cursor_up2, 1);
|
||||
case CUD:
|
||||
case VPR:
|
||||
CALL_CSI_HANDLER1(screen_cursor_down, 1);
|
||||
case CUF:
|
||||
case HPR:
|
||||
CALL_CSI_HANDLER1(screen_cursor_forward, 1);
|
||||
case CUB:
|
||||
CALL_CSI_HANDLER1(screen_cursor_back1, 1);
|
||||
case CNL:
|
||||
CALL_CSI_HANDLER1(screen_cursor_down1, 1);
|
||||
case CPL:
|
||||
CALL_CSI_HANDLER1(screen_cursor_up1, 1);
|
||||
case CHA:
|
||||
case HPA:
|
||||
CALL_CSI_HANDLER1(screen_cursor_to_column, 1);
|
||||
case VPA:
|
||||
CALL_CSI_HANDLER1(screen_cursor_to_line, 1);
|
||||
case CBT:
|
||||
CALL_CSI_HANDLER1(screen_backtab, 1);
|
||||
CALL_CSI_HANDLER1(screen_backtab, 1);
|
||||
case CHT:
|
||||
CALL_CSI_HANDLER1(screen_tabn, 1);
|
||||
case CUP:
|
||||
case HVP:
|
||||
CALL_CSI_HANDLER2(screen_cursor_position, 1, 1);
|
||||
case ED:
|
||||
CALL_CSI_HANDLER1P(screen_erase_in_display, 0, '?');
|
||||
case EL:
|
||||
CALL_CSI_HANDLER1P(screen_erase_in_line, 0, '?');
|
||||
case IL:
|
||||
CALL_CSI_HANDLER1(screen_insert_lines, 1);
|
||||
case DL:
|
||||
CALL_CSI_HANDLER1(screen_delete_lines, 1);
|
||||
case DCH:
|
||||
CALL_CSI_HANDLER1(screen_delete_characters, 1);
|
||||
case ECH:
|
||||
CALL_CSI_HANDLER1(screen_erase_characters, 1);
|
||||
case DA:
|
||||
CALL_CSI_HANDLER1S(report_device_attributes, 0);
|
||||
case TBC:
|
||||
CALL_CSI_HANDLER1(screen_clear_tab_stop, 0);
|
||||
case SM:
|
||||
SET_MODE(screen_set_mode);
|
||||
case RM:
|
||||
SET_MODE(screen_reset_mode);
|
||||
case DSR:
|
||||
CALL_CSI_HANDLER1P(report_device_status, 0, '?');
|
||||
case SC:
|
||||
CALL_CSI_HANDLER1P(save_cursor, 0, '?');
|
||||
case RC:
|
||||
CALL_CSI_HANDLER1P(restore_cursor, 0, '?');
|
||||
case 'r':
|
||||
CALL_CSI_HANDLER1(screen_tabn, 1);
|
||||
case CUP:
|
||||
case HVP:
|
||||
CALL_CSI_HANDLER2(screen_cursor_position, 1, 1);
|
||||
case ED:
|
||||
CALL_CSI_HANDLER1P(screen_erase_in_display, 0, '?');
|
||||
case EL:
|
||||
CALL_CSI_HANDLER1P(screen_erase_in_line, 0, '?');
|
||||
case IL:
|
||||
CALL_CSI_HANDLER1(screen_insert_lines, 1);
|
||||
case DL:
|
||||
CALL_CSI_HANDLER1(screen_delete_lines, 1);
|
||||
case DCH:
|
||||
CALL_CSI_HANDLER1(screen_delete_characters, 1);
|
||||
case ECH:
|
||||
CALL_CSI_HANDLER1(screen_erase_characters, 1);
|
||||
case DA:
|
||||
CALL_CSI_HANDLER1S(report_device_attributes, 0);
|
||||
case TBC:
|
||||
CALL_CSI_HANDLER1(screen_clear_tab_stop, 0);
|
||||
case SM:
|
||||
SET_MODE(screen_set_mode);
|
||||
case RM:
|
||||
SET_MODE(screen_reset_mode);
|
||||
case DSR:
|
||||
CALL_CSI_HANDLER1P(report_device_status, 0, '?');
|
||||
case SC:
|
||||
CALL_CSI_HANDLER1P(save_cursor, 0, '?');
|
||||
case RC:
|
||||
CALL_CSI_HANDLER1P(restore_cursor, 0, '?');
|
||||
case 'r':
|
||||
if (!start_modifier && !end_modifier) {
|
||||
// DECSTBM
|
||||
CALL_CSI_HANDLER2(screen_set_margins, 0, 0);
|
||||
CALL_CSI_HANDLER2(screen_set_margins, 0, 0);
|
||||
}
|
||||
REPORT_ERROR("Unknown CSI r sequence with start and end modifiers: '%c' '%c'", start_modifier, end_modifier);
|
||||
break;
|
||||
case 'x':
|
||||
if (!start_modifier && end_modifier == '*') {
|
||||
CALL_CSI_HANDLER1(screen_decsace, 0);
|
||||
CALL_CSI_HANDLER1(screen_decsace, 0);
|
||||
}
|
||||
REPORT_ERROR("Unknown CSI x sequence with start and end modifiers: '%c' '%c'", start_modifier, end_modifier);
|
||||
break;
|
||||
case DECSCUSR:
|
||||
CALL_CSI_HANDLER1M(screen_set_cursor, 1);
|
||||
case DECSCUSR:
|
||||
CALL_CSI_HANDLER1M(screen_set_cursor, 1);
|
||||
case SU:
|
||||
CALL_CSI_HANDLER1(screen_scroll, 1);
|
||||
CALL_CSI_HANDLER1(screen_scroll, 1);
|
||||
case SD:
|
||||
CALL_CSI_HANDLER1(screen_reverse_scroll, 1);
|
||||
CALL_CSI_HANDLER1(screen_reverse_scroll, 1);
|
||||
case DECSTR:
|
||||
if (end_modifier == '$') {
|
||||
// DECRQM
|
||||
CALL_CSI_HANDLER1P(report_mode_status, 0, '?');
|
||||
CALL_CSI_HANDLER1P(report_mode_status, 0, '?');
|
||||
} else {
|
||||
REPORT_ERROR("Unknown DECSTR CSI sequence with start and end modifiers: '%c' '%c'", start_modifier, end_modifier);
|
||||
}
|
||||
@@ -758,19 +758,19 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
unsigned int pos = 1;
|
||||
enum GR_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD };
|
||||
enum GR_STATES state = KEY, value_state = FLAG;
|
||||
enum KEYS {
|
||||
action='a',
|
||||
enum KEYS {
|
||||
action='a',
|
||||
delete_action='d',
|
||||
transmission_type='t',
|
||||
compressed='o',
|
||||
format = 'f',
|
||||
more = 'm',
|
||||
id = 'i',
|
||||
width = 'w',
|
||||
width = 'w',
|
||||
height = 'h',
|
||||
x_offset = 'x',
|
||||
y_offset = 'y',
|
||||
data_height = 'v',
|
||||
data_height = 'v',
|
||||
data_width = 's',
|
||||
data_sz = 'S',
|
||||
data_offset = 'O',
|
||||
@@ -778,7 +778,7 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
num_lines = 'r',
|
||||
cell_x_offset = 'X',
|
||||
cell_y_offset = 'Y',
|
||||
z_index = 'z'
|
||||
z_index = 'z'
|
||||
};
|
||||
enum KEYS key = 'a';
|
||||
static GraphicsCommand g;
|
||||
@@ -840,8 +840,8 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
is_negative = false;
|
||||
if(screen->parser_buf[pos] == '-') { is_negative = true; pos++; }
|
||||
#define U(x) case x: g.x = is_negative ? 0 - (int32_t)code : (int32_t)code; break
|
||||
READ_UINT;
|
||||
switch(key) {
|
||||
READ_UINT;
|
||||
switch(key) {
|
||||
U(z_index);
|
||||
default: break;
|
||||
}
|
||||
@@ -851,9 +851,9 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
case UINT:
|
||||
READ_UINT;
|
||||
#define U(x) case x: g.x = code; break
|
||||
switch(key) {
|
||||
switch(key) {
|
||||
U(format); U(more); U(id); U(data_sz); U(data_offset); U(width); U(height); U(x_offset); U(y_offset); U(data_height); U(data_width); U(num_cells); U(num_lines); U(cell_x_offset); U(cell_y_offset);
|
||||
default: break;
|
||||
default: break;
|
||||
}
|
||||
state = AFTER_VALUE;
|
||||
break;
|
||||
@@ -869,7 +869,7 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
state = PAYLOAD;
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a comma or semi-colon after a value, found: 0x%x", screen->parser_buf[pos - 1]);
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a comma or semi-colon after a value, found: 0x%x", screen->parser_buf[pos - 1]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -879,7 +879,7 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
err = base64_decode(screen->parser_buf + pos, sz, payload, sizeof(payload), &g.payload_sz);
|
||||
if (err != NULL) { REPORT_ERROR("Failed to parse graphics command payload with error: %s", err); return; }
|
||||
pos = screen->parser_buf_pos;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(state) {
|
||||
@@ -887,16 +887,16 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
REPORT_ERROR("Malformed graphics control block, no = after key"); return;
|
||||
case INT:
|
||||
case UINT:
|
||||
REPORT_ERROR("Malformed graphics control block, expecting an integer value"); return;
|
||||
REPORT_ERROR("Malformed graphics control block, expecting an integer value"); return;
|
||||
case FLAG:
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a flag value"); return;
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a flag value"); return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#define A(x) #x, g.x
|
||||
#define U(x) #x, (unsigned int)(g.x)
|
||||
#define I(x) #x, (int)(g.x)
|
||||
REPORT_VA_COMMAND("s {sc sc sc sc sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI si} y#", "graphics_command",
|
||||
REPORT_VA_COMMAND("s {sc sc sc sc sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI sI si} y#", "graphics_command",
|
||||
A(action), A(delete_action), A(transmission_type), A(compressed),
|
||||
U(format), U(more), U(id), U(data_sz), U(data_offset),
|
||||
U(width), U(height), U(x_offset), U(y_offset), U(data_height), U(data_width), U(num_cells), U(num_lines), U(cell_x_offset), U(cell_y_offset),
|
||||
@@ -1027,7 +1027,7 @@ accumulate_csi(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback)
|
||||
REPORT_ERROR("CSI sequence too long, ignoring"); \
|
||||
SET_STATE(0); \
|
||||
return false; \
|
||||
}
|
||||
}
|
||||
|
||||
switch(ch) {
|
||||
IS_DIGIT
|
||||
@@ -1073,8 +1073,8 @@ END_ALLOW_CASE_RANGE
|
||||
case HTS:
|
||||
handle_normal_mode_char(screen, ch, dump_callback);
|
||||
break;
|
||||
case NUL:
|
||||
case DEL:
|
||||
case NUL:
|
||||
case DEL:
|
||||
break; // no-op
|
||||
default:
|
||||
REPORT_ERROR("Invalid character in CSI: 0x%x, ignoring the sequence", ch);
|
||||
@@ -1116,7 +1116,7 @@ dispatch_unicode_char(Screen *screen, uint32_t codepoint, PyObject DUMP_UNUSED *
|
||||
|
||||
extern uint32_t *latin1_charset;
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
_parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED *dump_callback) {
|
||||
uint32_t prev = screen->utf8_state;
|
||||
for (unsigned int i = 0; i < (unsigned int)len; i++) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef BufType
|
||||
#ifndef BufType
|
||||
#define BufType LineBuf
|
||||
#endif
|
||||
|
||||
@@ -41,13 +41,13 @@
|
||||
#define is_src_line_continued(src_y) (src_y < src->ynum - 1 ? (src->line_attrs[src_y + 1] & CONTINUED_MASK) : false)
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
copy_range(Line *src, index_type src_at, Line* dest, index_type dest_at, index_type num) {
|
||||
memcpy(dest->cells + dest_at, src->cells + src_at, num * sizeof(Cell));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static void
|
||||
rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf UNUSED *historybuf) {
|
||||
bool src_line_is_continued = false;
|
||||
index_type src_y = 0, src_x = 0, dest_x = 0, dest_y = 0, num = 0, src_x_limit = 0;
|
||||
@@ -60,7 +60,7 @@ rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf
|
||||
if (!src_line_is_continued) {
|
||||
// Trim trailing blanks since there is a hard line break at the end of this line
|
||||
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch) == BLANK_CHAR) src_x_limit--;
|
||||
|
||||
|
||||
}
|
||||
while (src_x < src_x_limit) {
|
||||
if (dest_x >= dest->xnum) { next_dest_line(true); dest_x = 0; }
|
||||
|
||||
204
kitty/screen.c
204
kitty/screen.c
@@ -13,12 +13,12 @@
|
||||
#include "screen.h"
|
||||
#include <structmember.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "unicode-data.h"
|
||||
#include "modes.h"
|
||||
#include "wcwidth9.h"
|
||||
#include "wcwidth-std.h"
|
||||
#include "control-codes.h"
|
||||
|
||||
static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true, .mDECARM=true};
|
||||
@@ -26,7 +26,7 @@ static Selection EMPTY_SELECTION = {0};
|
||||
|
||||
// Constructor/destructor {{{
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
init_tabstops(bool *tabstops, index_type count) {
|
||||
// In terminfo we specify the number of initial tabstops (it) as 8
|
||||
for (unsigned int t=0; t < count; t++) {
|
||||
@@ -40,7 +40,7 @@ init_tabstops(bool *tabstops, index_type count) {
|
||||
self->g_charset = self->g0_charset; \
|
||||
self->utf8_state = 0; \
|
||||
self->utf8_codepoint = 0; \
|
||||
self->use_latin1 = false;
|
||||
self->use_latin1 = false;
|
||||
#define CALLBACK(...) \
|
||||
if (self->callbacks != Py_None) { \
|
||||
PyObject *callback_ret = PyObject_CallMethod(self->callbacks, __VA_ARGS__); \
|
||||
@@ -84,7 +84,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns);
|
||||
self->linebuf = self->main_linebuf;
|
||||
self->historybuf = alloc_historybuf(MAX(scrollback, lines), columns);
|
||||
self->main_grman = grman_alloc();
|
||||
self->main_grman = grman_alloc();
|
||||
self->alt_grman = grman_alloc();
|
||||
self->grman = self->main_grman;
|
||||
self->main_tabstops = PyMem_Calloc(2 * self->columns, sizeof(bool));
|
||||
@@ -99,7 +99,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
||||
return (PyObject*) self;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_reset(Screen *self) {
|
||||
if (self->linebuf == self->alt_linebuf) screen_toggle_screen_buffer(self);
|
||||
linebuf_clear(self->linebuf, BLANK_CHAR);
|
||||
@@ -121,7 +121,7 @@ screen_reset(Screen *self) {
|
||||
set_color_table_color(self, 104, NULL);
|
||||
}
|
||||
|
||||
static inline HistoryBuf*
|
||||
static inline HistoryBuf*
|
||||
realloc_hb(HistoryBuf *old, unsigned int lines, unsigned int columns) {
|
||||
HistoryBuf *ans = alloc_historybuf(lines, columns);
|
||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
@@ -129,7 +129,7 @@ realloc_hb(HistoryBuf *old, unsigned int lines, unsigned int columns) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline LineBuf*
|
||||
static inline LineBuf*
|
||||
realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, index_type *nclb, index_type *ncla, HistoryBuf *hb) {
|
||||
LineBuf *ans = alloc_linebuf(lines, columns);
|
||||
if (ans == NULL) { PyErr_NoMemory(); return NULL; }
|
||||
@@ -137,7 +137,7 @@ realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, index_type *n
|
||||
return ans;
|
||||
}
|
||||
|
||||
static bool
|
||||
static bool
|
||||
screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
||||
lines = MAX(1, lines); columns = MAX(1, columns);
|
||||
|
||||
@@ -203,7 +203,7 @@ screen_rescale_images(Screen *self, unsigned int old_cell_width, unsigned int ol
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
static bool
|
||||
screen_change_scrollback_size(Screen *self, unsigned int size) {
|
||||
if (size != self->historybuf->ynum) return historybuf_resize(self->historybuf, size);
|
||||
return true;
|
||||
@@ -221,13 +221,13 @@ static void
|
||||
dealloc(Screen* self) {
|
||||
pthread_mutex_destroy(&self->read_buf_lock);
|
||||
pthread_mutex_destroy(&self->write_buf_lock);
|
||||
Py_CLEAR(self->main_grman);
|
||||
Py_CLEAR(self->main_grman);
|
||||
Py_CLEAR(self->alt_grman);
|
||||
PyMem_RawFree(self->write_buf);
|
||||
Py_CLEAR(self->callbacks);
|
||||
Py_CLEAR(self->test_child);
|
||||
Py_CLEAR(self->cursor);
|
||||
Py_CLEAR(self->main_linebuf);
|
||||
Py_CLEAR(self->cursor);
|
||||
Py_CLEAR(self->main_linebuf);
|
||||
Py_CLEAR(self->alt_linebuf);
|
||||
Py_CLEAR(self->historybuf);
|
||||
Py_CLEAR(self->color_profile);
|
||||
@@ -236,8 +236,8 @@ dealloc(Screen* self) {
|
||||
} // }}}
|
||||
|
||||
// Draw text {{{
|
||||
|
||||
void
|
||||
|
||||
void
|
||||
screen_change_charset(Screen *self, uint32_t which) {
|
||||
switch(which) {
|
||||
case 0:
|
||||
@@ -247,7 +247,7 @@ screen_change_charset(Screen *self, uint32_t which) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_designate_charset(Screen *self, uint32_t which, uint32_t as) {
|
||||
bool change_g = false;
|
||||
switch(which) {
|
||||
@@ -267,7 +267,7 @@ screen_designate_charset(Screen *self, uint32_t which, uint32_t as) {
|
||||
|
||||
static int (*wcwidth_impl)(wchar_t) = wcwidth;
|
||||
|
||||
unsigned int
|
||||
unsigned int
|
||||
safe_wcwidth(uint32_t ch) {
|
||||
int ans = wcwidth_impl(ch);
|
||||
if (ans < 0) ans = 1;
|
||||
@@ -275,8 +275,8 @@ safe_wcwidth(uint32_t ch) {
|
||||
}
|
||||
|
||||
void
|
||||
change_wcwidth(bool use9) {
|
||||
wcwidth_impl = (use9) ? wcwidth9 : wcwidth;
|
||||
change_wcwidth(bool use_std) {
|
||||
wcwidth_impl = use_std ? wcwidth_std : wcwidth;
|
||||
}
|
||||
|
||||
|
||||
@@ -334,9 +334,9 @@ screen_align(Screen *self) {
|
||||
|
||||
// Graphics {{{
|
||||
|
||||
void
|
||||
void
|
||||
screen_alignment_display(Screen *self) {
|
||||
// http://www.vt100.net/docs/vt510-rm/DECALN.html
|
||||
// http://www.vt100.net/docs/vt510-rm/DECALN.html
|
||||
screen_cursor_position(self, 1, 1);
|
||||
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
||||
for (unsigned int y = 0; y < self->linebuf->ynum; y++) {
|
||||
@@ -346,7 +346,7 @@ screen_alignment_display(Screen *self) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count, Region *region_) {
|
||||
if (region_) {
|
||||
Region region = *region_;
|
||||
@@ -418,7 +418,7 @@ screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const u
|
||||
if (response != NULL) write_escape_code_to_child(self, APC, response);
|
||||
if (x != self->cursor->x || y != self->cursor->y) {
|
||||
if (self->cursor->x >= self->columns) { self->cursor->x = 0; self->cursor->y++; }
|
||||
if (self->cursor->y > self->margin_bottom) screen_scroll(self, self->cursor->y - self->margin_bottom);
|
||||
if (self->cursor->y > self->margin_bottom) screen_scroll(self, self->cursor->y - self->margin_bottom);
|
||||
screen_ensure_bounds(self, false);
|
||||
}
|
||||
}
|
||||
@@ -427,7 +427,7 @@ screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const u
|
||||
// Modes {{{
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
screen_toggle_screen_buffer(Screen *self) {
|
||||
bool to_alt = self->linebuf == self->main_linebuf;
|
||||
grman_clear(self->alt_grman); // always clear the alt buffer graphics to free up resources, since it has to be cleared when switching back to it anyway
|
||||
@@ -452,7 +452,7 @@ screen_toggle_screen_buffer(Screen *self) {
|
||||
void screen_normal_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
||||
void screen_alternate_keypad_mode(Screen UNUSED *self) {} // Not implemented as this is handled by the GUI
|
||||
|
||||
static inline void
|
||||
static inline void
|
||||
set_mode_from_const(Screen *self, unsigned int mode, bool val) {
|
||||
#define SIMPLE_MODE(name) \
|
||||
case name: \
|
||||
@@ -481,40 +481,40 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
|
||||
case DECNRCM:
|
||||
break; // we ignore these modes
|
||||
case DECCKM:
|
||||
self->modes.mDECCKM = val;
|
||||
self->modes.mDECCKM = val;
|
||||
break;
|
||||
case DECTCEM:
|
||||
self->modes.mDECTCEM = val;
|
||||
case DECTCEM:
|
||||
self->modes.mDECTCEM = val;
|
||||
break;
|
||||
case DECSCNM:
|
||||
case DECSCNM:
|
||||
// Render screen in reverse video
|
||||
if (self->modes.mDECSCNM != val) {
|
||||
self->modes.mDECSCNM = val;
|
||||
self->modes.mDECSCNM = val;
|
||||
self->is_dirty = true;
|
||||
}
|
||||
break;
|
||||
case DECOM:
|
||||
self->modes.mDECOM = val;
|
||||
case DECOM:
|
||||
self->modes.mDECOM = val;
|
||||
// According to `vttest`, DECOM should also home the cursor, see
|
||||
// vttest/main.c:303.
|
||||
screen_cursor_position(self, 1, 1);
|
||||
break;
|
||||
case DECAWM:
|
||||
case DECAWM:
|
||||
self->modes.mDECAWM = val; break;
|
||||
case DECCOLM:
|
||||
case DECCOLM:
|
||||
// When DECCOLM mode is set, the screen is erased and the cursor
|
||||
// moves to the home position.
|
||||
self->modes.mDECCOLM = val;
|
||||
self->modes.mDECCOLM = val;
|
||||
screen_erase_in_display(self, 2, false);
|
||||
screen_cursor_position(self, 1, 1);
|
||||
break;
|
||||
case CONTROL_CURSOR_BLINK:
|
||||
self->cursor->blink = val;
|
||||
self->cursor->blink = val;
|
||||
break;
|
||||
case ALTERNATE_SCREEN:
|
||||
if (val && self->linebuf == self->main_linebuf) screen_toggle_screen_buffer(self);
|
||||
else if (!val && self->linebuf != self->main_linebuf) screen_toggle_screen_buffer(self);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
private = mode >= 1 << 5;
|
||||
if (private) mode >>= 5;
|
||||
@@ -524,7 +524,7 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
|
||||
#undef MOUSE_MODE
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_set_mode(Screen *self, unsigned int mode) {
|
||||
set_mode_from_const(self, mode, true);
|
||||
}
|
||||
@@ -534,7 +534,7 @@ screen_decsace(Screen *self, unsigned int val) {
|
||||
self->modes.mDECSACE = val == 2 ? true : false;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_reset_mode(Screen *self, unsigned int mode) {
|
||||
set_mode_from_const(self, mode, false);
|
||||
}
|
||||
@@ -561,12 +561,12 @@ screen_is_cursor_visible(Screen *self) {
|
||||
return self->modes.mDECTCEM;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_backspace(Screen *self) {
|
||||
screen_cursor_back(self, 1, -1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_tab(Screen *self) {
|
||||
// Move to the next tab space, or the end of the screen if there aren't anymore left.
|
||||
unsigned int found = 0;
|
||||
@@ -579,7 +579,7 @@ screen_tab(Screen *self) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_backtab(Screen *self, unsigned int count) {
|
||||
// Move back count tabs
|
||||
if (!count) count = 1;
|
||||
@@ -593,7 +593,7 @@ screen_backtab(Screen *self, unsigned int count) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_clear_tab_stop(Screen *self, unsigned int how) {
|
||||
switch(how) {
|
||||
case 0:
|
||||
@@ -610,13 +610,13 @@ screen_clear_tab_stop(Screen *self, unsigned int how) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_set_tab_stop(Screen *self) {
|
||||
if (self->cursor->x < self->columns)
|
||||
self->tabstops[self->cursor->x] = true;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_back(Screen *self, unsigned int count/*=1*/, int move_direction/*=-1*/) {
|
||||
if (count == 0) count = 1;
|
||||
if (move_direction < 0 && count > self->cursor->x) self->cursor->x = 0;
|
||||
@@ -624,12 +624,12 @@ screen_cursor_back(Screen *self, unsigned int count/*=1*/, int move_direction/*=
|
||||
screen_ensure_bounds(self, false);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_forward(Screen *self, unsigned int count/*=1*/) {
|
||||
screen_cursor_back(self, count, 1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_up(Screen *self, unsigned int count/*=1*/, bool do_carriage_return/*=false*/, int move_direction/*=-1*/) {
|
||||
if (count == 0) count = 1;
|
||||
if (move_direction < 0 && count > self->cursor->y) self->cursor->y = 0;
|
||||
@@ -638,22 +638,22 @@ screen_cursor_up(Screen *self, unsigned int count/*=1*/, bool do_carriage_return
|
||||
if (do_carriage_return) self->cursor->x = 0;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_up1(Screen *self, unsigned int count/*=1*/) {
|
||||
screen_cursor_up(self, count, true, -1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_down(Screen *self, unsigned int count/*=1*/) {
|
||||
screen_cursor_up(self, count, false, 1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_down1(Screen *self, unsigned int count/*=1*/) {
|
||||
screen_cursor_up(self, count, true, 1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_to_column(Screen *self, unsigned int column) {
|
||||
unsigned int x = MAX(column, 1) - 1;
|
||||
if (x != self->cursor->x) {
|
||||
@@ -683,7 +683,7 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
|
||||
linebuf_clear_line(self->linebuf, bottom); \
|
||||
self->is_dirty = true;
|
||||
|
||||
void
|
||||
void
|
||||
screen_index(Screen *self) {
|
||||
// Move cursor down one line, scrolling screen if needed
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
@@ -692,7 +692,7 @@ screen_index(Screen *self) {
|
||||
} else screen_cursor_down(self, 1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_scroll(Screen *self, unsigned int count) {
|
||||
// Scroll the screen up by count lines, not moving the cursor
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
@@ -708,7 +708,7 @@ screen_scroll(Screen *self, unsigned int count) {
|
||||
INDEX_GRAPHICS(1) \
|
||||
self->is_dirty = true;
|
||||
|
||||
void
|
||||
void
|
||||
screen_reverse_index(Screen *self) {
|
||||
// Move cursor up one line, scrolling screen if needed
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
@@ -717,7 +717,7 @@ screen_reverse_index(Screen *self) {
|
||||
} else screen_cursor_up(self, 1, false, -1);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_reverse_scroll(Screen *self, unsigned int count) {
|
||||
// Scroll the screen down by count lines, not moving the cursor
|
||||
count = MIN(self->lines, count);
|
||||
@@ -729,21 +729,21 @@ screen_reverse_scroll(Screen *self, unsigned int count) {
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
screen_carriage_return(Screen *self) {
|
||||
if (self->cursor->x != 0) {
|
||||
self->cursor->x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_linefeed(Screen *self) {
|
||||
screen_index(self);
|
||||
if (self->modes.mLNM) screen_carriage_return(self);
|
||||
screen_ensure_bounds(self, false);
|
||||
}
|
||||
|
||||
static inline Savepoint*
|
||||
static inline Savepoint*
|
||||
savepoints_push(SavepointBuffer *self) {
|
||||
Savepoint *ans = self->buf + ((self->start_of_data + self->count) % SAVEPOINTS_SZ);
|
||||
if (self->count == SAVEPOINTS_SZ) self->start_of_data = (self->start_of_data + 1) % SAVEPOINTS_SZ;
|
||||
@@ -751,7 +751,7 @@ savepoints_push(SavepointBuffer *self) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline Savepoint*
|
||||
static inline Savepoint*
|
||||
savepoints_pop(SavepointBuffer *self) {
|
||||
if (self->count == 0) return NULL;
|
||||
self->count--;
|
||||
@@ -766,7 +766,7 @@ savepoints_pop(SavepointBuffer *self) {
|
||||
sp->g_charset = self->g_charset; \
|
||||
sp->use_latin1 = self->use_latin1;
|
||||
|
||||
void
|
||||
void
|
||||
screen_save_cursor(Screen *self) {
|
||||
SavepointBuffer *pts = self->linebuf == self->main_linebuf ? &self->main_savepoints : &self->alt_savepoints;
|
||||
Savepoint *sp = savepoints_push(pts);
|
||||
@@ -777,7 +777,7 @@ screen_save_cursor(Screen *self) {
|
||||
COPY_CHARSETS(self, sp);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_restore_cursor(Screen *self) {
|
||||
SavepointBuffer *pts = self->linebuf == self->main_linebuf ? &self->main_savepoints : &self->alt_savepoints;
|
||||
Savepoint *sp = savepoints_pop(pts);
|
||||
@@ -796,7 +796,7 @@ screen_restore_cursor(Screen *self) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_ensure_bounds(Screen *self, bool force_use_margins/*=false*/) {
|
||||
unsigned int top, bottom;
|
||||
if (force_use_margins || self->modes.mDECOM) {
|
||||
@@ -808,7 +808,7 @@ screen_ensure_bounds(Screen *self, bool force_use_margins/*=false*/) {
|
||||
self->cursor->y = MAX(top, MIN(self->cursor->y, bottom));
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_position(Screen *self, unsigned int line, unsigned int column) {
|
||||
line = (line == 0 ? 1 : line) - 1;
|
||||
column = (column == 0 ? 1: column) - 1;
|
||||
@@ -820,7 +820,7 @@ screen_cursor_position(Screen *self, unsigned int line, unsigned int column) {
|
||||
screen_ensure_bounds(self, false);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_cursor_to_line(Screen *self, unsigned int line) {
|
||||
screen_cursor_position(self, line, self->cursor->x + 1);
|
||||
}
|
||||
@@ -829,7 +829,7 @@ screen_cursor_to_line(Screen *self, unsigned int line) {
|
||||
|
||||
// Editing {{{
|
||||
|
||||
void
|
||||
void
|
||||
screen_erase_in_line(Screen *self, unsigned int how, bool private) {
|
||||
/*Erases a line in a specific way.
|
||||
|
||||
@@ -870,7 +870,7 @@ screen_erase_in_line(Screen *self, unsigned int how, bool private) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_erase_in_display(Screen *self, unsigned int how, bool private) {
|
||||
/* Erases display in a specific way.
|
||||
|
||||
@@ -913,7 +913,7 @@ screen_erase_in_display(Screen *self, unsigned int how, bool private) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_insert_lines(Screen *self, unsigned int count) {
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
if (count == 0) count = 1;
|
||||
@@ -924,7 +924,7 @@ screen_insert_lines(Screen *self, unsigned int count) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_delete_lines(Screen *self, unsigned int count) {
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
if (count == 0) count = 1;
|
||||
@@ -935,7 +935,7 @@ screen_delete_lines(Screen *self, unsigned int count) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_insert_characters(Screen *self, unsigned int count) {
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
if (count == 0) count = 1;
|
||||
@@ -950,7 +950,7 @@ screen_insert_characters(Screen *self, unsigned int count) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_delete_characters(Screen *self, unsigned int count) {
|
||||
// Delete characters, later characters are moved left
|
||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||
@@ -966,7 +966,7 @@ screen_delete_characters(Screen *self, unsigned int count) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_erase_characters(Screen *self, unsigned int count) {
|
||||
// Delete characters replacing them by spaces
|
||||
if (count == 0) count = 1;
|
||||
@@ -984,7 +984,7 @@ screen_erase_characters(Screen *self, unsigned int count) {
|
||||
|
||||
void
|
||||
screen_use_latin1(Screen *self, bool on) {
|
||||
self->use_latin1 = on; self->utf8_state = 0; self->utf8_codepoint = 0;
|
||||
self->use_latin1 = on; self->utf8_state = 0; self->utf8_codepoint = 0;
|
||||
CALLBACK("use_utf8", "O", on ? Py_False : Py_True);
|
||||
}
|
||||
|
||||
@@ -999,12 +999,12 @@ screen_invert_colors(Screen *self) {
|
||||
return inverted;
|
||||
}
|
||||
|
||||
void
|
||||
screen_bell(Screen *self) {
|
||||
void
|
||||
screen_bell(Screen *self) {
|
||||
request_window_attention(self->window_id, OPT(enable_audio_bell));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
report_device_attributes(Screen *self, unsigned int mode, char start_modifier) {
|
||||
if (mode == 0) {
|
||||
switch(start_modifier) {
|
||||
@@ -1018,7 +1018,7 @@ report_device_attributes(Screen *self, unsigned int mode, char start_modifier) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
report_device_status(Screen *self, unsigned int which, bool private) {
|
||||
// We dont implement the private device status codes, since I haven't come
|
||||
// across any programs that use them
|
||||
@@ -1042,7 +1042,7 @@ report_device_status(Screen *self, unsigned int which, bool private) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
report_mode_status(Screen *self, unsigned int which, bool private) {
|
||||
unsigned int q = private ? which << 5 : which;
|
||||
unsigned int ans = 0;
|
||||
@@ -1071,7 +1071,7 @@ report_mode_status(Screen *self, unsigned int which, bool private) {
|
||||
if (sz > 0) write_escape_code_to_child(self, CSI, buf);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_set_margins(Screen *self, unsigned int top, unsigned int bottom) {
|
||||
if (!top) top = 1;
|
||||
if (!bottom) bottom = self->lines;
|
||||
@@ -1089,7 +1089,7 @@ screen_set_margins(Screen *self, unsigned int top, unsigned int bottom) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_set_cursor(Screen *self, unsigned int mode, uint8_t secondary) {
|
||||
uint8_t shape; bool blink;
|
||||
switch(secondary) {
|
||||
@@ -1110,29 +1110,29 @@ screen_set_cursor(Screen *self, unsigned int mode, uint8_t secondary) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
set_title(Screen *self, PyObject *title) {
|
||||
CALLBACK("title_changed", "O", title);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
set_icon(Screen *self, PyObject *icon) {
|
||||
CALLBACK("icon_changed", "O", icon);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
set_dynamic_color(Screen *self, unsigned int code, PyObject *color) {
|
||||
if (color == NULL) { CALLBACK("set_dynamic_color", "Is", code, ""); }
|
||||
else { CALLBACK("set_dynamic_color", "IO", code, color); }
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
set_color_table_color(Screen *self, unsigned int code, PyObject *color) {
|
||||
if (color == NULL) { CALLBACK("set_color_table_color", "Is", code, ""); }
|
||||
else { CALLBACK("set_color_table_color", "IO", code, color); }
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
screen_request_capabilities(Screen *self, char c, PyObject *q) {
|
||||
static char buf[128];
|
||||
int shape = 0;
|
||||
@@ -1252,7 +1252,7 @@ visual_line_(Screen *self, index_type y) {
|
||||
if (y < self->scrolled_by) {
|
||||
historybuf_init_line(self->historybuf, self->scrolled_by - 1 - y, self->historybuf->line);
|
||||
return self->historybuf->line;
|
||||
}
|
||||
}
|
||||
y -= self->scrolled_by;
|
||||
}
|
||||
linebuf_init_line(self->linebuf, y);
|
||||
@@ -1274,11 +1274,11 @@ visual_line_(Screen *self, index_type y) {
|
||||
index_type xlimit = xlimit_for_line(line); \
|
||||
if (y == end->y) xlimit = MIN(end->x + 1, xlimit); \
|
||||
index_type x_start = y == start->y ? start->x : 0;
|
||||
|
||||
|
||||
|
||||
static inline void
|
||||
apply_selection(Screen *self, uint8_t *data, SelectionBoundary *start, SelectionBoundary *end, uint8_t set_mask, bool rectangle_select) {
|
||||
if (is_selection_empty(self, start->x, start->y, end->x, end->y)) return;
|
||||
if (is_selection_empty(self, start->x, start->y, end->x, end->y)) return;
|
||||
if (rectangle_select) {
|
||||
iterate_over_rectangle(start, end)
|
||||
uint8_t *line_start = data + self->columns * y;
|
||||
@@ -1397,7 +1397,7 @@ visual_line(Screen *self, PyObject *args) {
|
||||
if (y >= self->lines) { Py_RETURN_NONE; }
|
||||
return Py_BuildValue("O", visual_line_(self, y));
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
draw(Screen *self, PyObject *src) {
|
||||
if (!PyUnicode_Check(src)) { PyErr_SetString(PyExc_TypeError, "A unicode string is required"); return NULL; }
|
||||
@@ -1418,7 +1418,7 @@ reset_mode(Screen *self, PyObject *args) {
|
||||
screen_reset_mode(self, mode);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static PyObject*
|
||||
_select_graphic_rendition(Screen *self, PyObject *args) {
|
||||
unsigned int params[256] = {0};
|
||||
@@ -1482,8 +1482,8 @@ WRAP2(rescale_images, 1, 1)
|
||||
|
||||
static PyObject*
|
||||
change_scrollback_size(Screen *self, PyObject *args) {
|
||||
unsigned int count = 1;
|
||||
if (!PyArg_ParseTuple(args, "|I", &count)) return NULL;
|
||||
unsigned int count = 1;
|
||||
if (!PyArg_ParseTuple(args, "|I", &count)) return NULL;
|
||||
if (!screen_change_scrollback_size(self, MAX(self->lines, count))) return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
@@ -1495,7 +1495,7 @@ text_for_selection(Screen *self) {
|
||||
if (is_selection_empty(self, start.x, start.y, end.x, end.y)) return PyTuple_New(0);
|
||||
return text_for_range(self, start, end, self->rectangle_select, true);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
screen_selection_range_for_line(Screen *self, index_type y, index_type *start, index_type *end) {
|
||||
if (y >= self->lines) { return false; }
|
||||
@@ -1526,7 +1526,7 @@ screen_selection_range_for_word(Screen *self, index_type x, index_type y, index_
|
||||
} else {
|
||||
start = x, end = x;
|
||||
while(start > 0 && is_ok(start - 1)) start--;
|
||||
while(end < self->columns - 1 && is_ok(end + 1)) end++;
|
||||
while(end < self->columns - 1 && is_ok(end + 1)) end++;
|
||||
}
|
||||
*s = start; *e = end;
|
||||
return true;
|
||||
@@ -1592,7 +1592,7 @@ screen_start_selection(Screen *self, index_type x, index_type y, bool rectangle_
|
||||
void
|
||||
screen_mark_url(Screen *self, index_type start_x, index_type start_y, index_type end_x, index_type end_y) {
|
||||
#define A(attr, val) self->url_range.attr = val;
|
||||
A(start_x, start_x); A(end_x, end_x); A(start_y, start_y); A(end_y, end_y); A(start_scrolled_by, self->scrolled_by); A(end_scrolled_by, self->scrolled_by);
|
||||
A(start_x, start_x); A(end_x, end_x); A(start_y, start_y); A(end_y, end_y); A(start_scrolled_by, self->scrolled_by); A(end_scrolled_by, self->scrolled_by);
|
||||
#undef A
|
||||
}
|
||||
|
||||
@@ -1602,19 +1602,19 @@ screen_update_selection(Screen *self, index_type x, index_type y, bool ended) {
|
||||
if (ended) self->selection.in_progress = false;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
static PyObject*
|
||||
mark_as_dirty(Screen *self) {
|
||||
self->is_dirty = true;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
static PyObject*
|
||||
current_char_width(Screen *self) {
|
||||
#define current_char_width_doc "The width of the character under the cursor"
|
||||
return PyLong_FromUnsignedLong(screen_current_char_width(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
static PyObject*
|
||||
is_main_linebuf(Screen *self) {
|
||||
PyObject *ans = (self->linebuf == self->main_linebuf) ? Py_True : Py_False;
|
||||
Py_INCREF(ans);
|
||||
@@ -1743,17 +1743,17 @@ static PyMemberDef members[] = {
|
||||
{"history_line_added_count", T_UINT, offsetof(Screen, history_line_added_count), 0, "history_line_added_count"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject Screen_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "fast_data_types.Screen",
|
||||
.tp_basicsize = sizeof(Screen),
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_dealloc = (destructor)dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "Screen",
|
||||
.tp_methods = methods,
|
||||
.tp_members = members,
|
||||
.tp_new = new,
|
||||
.tp_new = new,
|
||||
.tp_getset = getsetters,
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ typedef struct {
|
||||
unsigned int start_x, start_y, start_scrolled_by, end_x, end_y, end_scrolled_by;
|
||||
bool in_progress;
|
||||
} Selection;
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
@@ -75,8 +75,8 @@ void screen_erase_in_display(Screen *, unsigned int, bool);
|
||||
void screen_draw(Screen *screen, uint32_t codepoint);
|
||||
void screen_ensure_bounds(Screen *self, bool use_margins);
|
||||
void screen_toggle_screen_buffer(Screen *self);
|
||||
void screen_normal_keypad_mode(Screen *self);
|
||||
void screen_alternate_keypad_mode(Screen *self);
|
||||
void screen_normal_keypad_mode(Screen *self);
|
||||
void screen_alternate_keypad_mode(Screen *self);
|
||||
void screen_change_default_color(Screen *self, unsigned int which, uint32_t col);
|
||||
void screen_alignment_display(Screen *self);
|
||||
void screen_reverse_index(Screen *self);
|
||||
|
||||
@@ -85,7 +85,7 @@ def parse_session(raw, opts):
|
||||
return ans
|
||||
|
||||
|
||||
def create_session(opts, args=None, special_window=None):
|
||||
def create_session(opts, args=None, special_window=None, cwd_from=None):
|
||||
if args and args.session:
|
||||
with open(args.session) as f:
|
||||
return parse_session(f.read(), opts)
|
||||
@@ -100,11 +100,11 @@ def create_session(opts, args=None, special_window=None):
|
||||
ans.tabs[-1].layout = current_layout
|
||||
if special_window is None:
|
||||
cmd = args.args if args and args.args else [shell_path]
|
||||
from kitty.tabs import SpecialWindow
|
||||
if getattr(args, 'title', None):
|
||||
from kitty.tabs import SpecialWindow
|
||||
ans.add_window(SpecialWindow(cmd, override_title=args.title))
|
||||
ans.add_window(SpecialWindow(cmd, override_title=args.title, cwd_from=cwd_from))
|
||||
else:
|
||||
ans.add_window(cmd)
|
||||
ans.add_window(SpecialWindow(cmd, cwd_from=cwd_from))
|
||||
else:
|
||||
ans.add_special_window(special_window)
|
||||
return ans
|
||||
|
||||
180
kitty/shaders.c
180
kitty/shaders.c
@@ -35,14 +35,14 @@ copy_image_sub_data(GLuint src_texture_id, GLuint dest_texture_id, unsigned int
|
||||
size_t sz = width * height * num_levels;
|
||||
pixel *src = malloc(sz * sizeof(pixel));
|
||||
if (src == NULL) { fatal("Out of memory."); }
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture_id);
|
||||
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, src);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, dest_texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels, GL_RGBA, GL_UNSIGNED_BYTE, src);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture_id);
|
||||
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, src);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, dest_texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels, GL_RGBA, GL_UNSIGNED_BYTE, src);
|
||||
free(src);
|
||||
} else {
|
||||
glCopyImageSubData(src_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, dest_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels);
|
||||
glCopyImageSubData(src_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, dest_texture_id, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, num_levels);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,24 +50,24 @@ copy_image_sub_data(GLuint src_texture_id, GLuint dest_texture_id, unsigned int
|
||||
static void
|
||||
realloc_sprite_texture() {
|
||||
GLuint tex;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
|
||||
// We use GL_NEAREST otherwise glyphs that touch the edge of the cell
|
||||
// often show a border between cells
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
unsigned int xnum, ynum, z, znum, width, height, src_ynum;
|
||||
sprite_tracker_current_layout(&xnum, &ynum, &z);
|
||||
znum = z + 1;
|
||||
width = xnum * global_state.cell_width; height = ynum * global_state.cell_height;
|
||||
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, width, height, znum);
|
||||
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, width, height, znum);
|
||||
if (sprite_map.texture_id) {
|
||||
// need to re-alloc
|
||||
src_ynum = MAX(1, sprite_map.last_ynum);
|
||||
copy_image_sub_data(sprite_map.texture_id, tex, width, src_ynum * global_state.cell_height, sprite_map.last_num_of_layers);
|
||||
glDeleteTextures(1, &sprite_map.texture_id);
|
||||
glDeleteTextures(1, &sprite_map.texture_id);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||
sprite_map.last_num_of_layers = znum;
|
||||
@@ -80,40 +80,40 @@ ensure_sprite_map() {
|
||||
if (!sprite_map.texture_id) realloc_sprite_texture();
|
||||
// We have to rebind since we dont know if the texture was ever bound
|
||||
// in the context of the current OSWindow
|
||||
glActiveTexture(GL_TEXTURE0 + SPRITE_MAP_UNIT);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id);
|
||||
glActiveTexture(GL_TEXTURE0 + SPRITE_MAP_UNIT);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
send_sprite_to_gpu(unsigned int x, unsigned int y, unsigned int z, pixel *buf) {
|
||||
unsigned int xnum, ynum, znum;
|
||||
sprite_tracker_current_layout(&xnum, &ynum, &znum);
|
||||
if ((int)znum >= sprite_map.last_num_of_layers || (znum == 0 && (int)ynum > sprite_map.last_ynum)) realloc_sprite_texture();
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite_map.texture_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
x *= global_state.cell_width; y *= global_state.cell_height;
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, global_state.cell_width, global_state.cell_height, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buf);
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, x, y, z, global_state.cell_width, global_state.cell_height, 1, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, buf);
|
||||
}
|
||||
|
||||
void
|
||||
send_image_to_gpu(GLuint *tex_id, const void* data, GLsizei width, GLsizei height, bool is_opaque, bool is_4byte_aligned) {
|
||||
if (!(*tex_id)) { glGenTextures(1, tex_id); }
|
||||
glBindTexture(GL_TEXTURE_2D, *tex_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, is_4byte_aligned ? 4 : 1);
|
||||
glBindTexture(GL_TEXTURE_2D, *tex_id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, is_4byte_aligned ? 4 : 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, is_opaque ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, is_opaque ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
|
||||
static bool limits_updated = false;
|
||||
|
||||
static void
|
||||
static void
|
||||
layout_sprite_map() {
|
||||
if (!limits_updated) {
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &(sprite_map.max_texture_size));
|
||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &(sprite_map.max_array_texture_layers));
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &(sprite_map.max_texture_size));
|
||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &(sprite_map.max_array_texture_layers));
|
||||
#ifdef __APPLE__
|
||||
// Since on Apple we could have multiple GPUs, with different capabilities,
|
||||
// upper bound the values according to the data from http://developer.apple.com/graphicsimaging/opengl/capabilities/
|
||||
@@ -201,6 +201,14 @@ create_graphics_vao() {
|
||||
return vao_idx;
|
||||
}
|
||||
|
||||
struct CellUniformData {
|
||||
bool constants_set;
|
||||
GLint gploc, gpploc, cploc, cfploc;
|
||||
GLfloat prev_inactive_text_alpha;
|
||||
};
|
||||
|
||||
static struct CellUniformData cell_uniform_data = {0, .prev_inactive_text_alpha=-1};
|
||||
|
||||
static inline void
|
||||
cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, CursorRenderInfo *cursor, bool inverted) {
|
||||
struct CellRenderData {
|
||||
@@ -220,15 +228,15 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
|
||||
copy_color_table_to_buffer(screen->color_profile, (GLuint*)rd, cell_program_layouts[CELL_PROGRAM].color_table.offset / sizeof(GLuint), cell_program_layouts[CELL_PROGRAM].color_table.stride / sizeof(GLuint));
|
||||
}
|
||||
// Cursor position
|
||||
if (cursor->is_visible && cursor->shape == CURSOR_BLOCK) {
|
||||
rd->cursor_x = screen->cursor->x, rd->cursor_y = screen->cursor->y;
|
||||
if (cursor->is_visible && cursor->shape == CURSOR_BLOCK && cursor->is_focused) {
|
||||
rd->cursor_x = screen->cursor->x, rd->cursor_y = screen->cursor->y;
|
||||
} else {
|
||||
rd->cursor_x = screen->columns, rd->cursor_y = screen->lines;
|
||||
rd->cursor_x = screen->columns, rd->cursor_y = screen->lines;
|
||||
}
|
||||
rd->cursor_w = rd->cursor_x + MAX(1, screen_current_char_width(screen)) - 1;
|
||||
|
||||
rd->xnum = screen->columns; rd->ynum = screen->lines;
|
||||
|
||||
|
||||
rd->xstart = xstart; rd->ystart = ystart; rd->dx = dx; rd->dy = dy;
|
||||
unsigned int x, y, z;
|
||||
sprite_tracker_current_layout(&x, &y, &z);
|
||||
@@ -284,19 +292,13 @@ static void
|
||||
draw_graphics(int program, ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint start, GLuint count) {
|
||||
bind_program(program);
|
||||
bind_vertex_array(gvao_idx);
|
||||
static bool graphics_constants_set = false;
|
||||
if (!graphics_constants_set) {
|
||||
glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "image"), GRAPHICS_UNIT);
|
||||
glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PREMULT_PROGRAM), "image"), GRAPHICS_UNIT);
|
||||
graphics_constants_set = true;
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
|
||||
glActiveTexture(GL_TEXTURE0 + GRAPHICS_UNIT);
|
||||
|
||||
GLuint base = 4 * start;
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
for (GLuint i=0; i < count;) {
|
||||
ImageRenderData *rd = data + start + i;
|
||||
glBindTexture(GL_TEXTURE_2D, rd->texture_id);
|
||||
glBindTexture(GL_TEXTURE_2D, rd->texture_id);
|
||||
// You could reduce the number of draw calls by using
|
||||
// glDrawArraysInstancedBaseInstance but Apple chose to abandon OpenGL
|
||||
// before implementing it.
|
||||
@@ -311,8 +313,8 @@ draw_graphics(int program, ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *d
|
||||
|
||||
static void
|
||||
draw_cells_simple(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
|
||||
bind_program(CELL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
bind_program(CELL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
if (screen->grman->count) {
|
||||
glEnable(GL_BLEND);
|
||||
BLEND_ONTO_OPAQUE;
|
||||
@@ -323,18 +325,18 @@ draw_cells_simple(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
|
||||
|
||||
static void
|
||||
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
|
||||
bind_program(CELL_BG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
bind_program(CELL_BG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
glEnable(GL_BLEND);
|
||||
BLEND_ONTO_OPAQUE;
|
||||
|
||||
if (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_negative_refs);
|
||||
|
||||
bind_program(CELL_SPECIAL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
bind_program(CELL_SPECIAL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
|
||||
bind_program(CELL_FG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
bind_program(CELL_FG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
|
||||
if (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs);
|
||||
|
||||
@@ -350,25 +352,25 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, offscreen_framebuffer);
|
||||
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, os_window->offscreen_texture_id, 0);
|
||||
/* if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) fatal("offscreen framebuffer not complete"); */
|
||||
|
||||
bind_program(CELL_BG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
bind_program(CELL_BG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
glEnable(GL_BLEND);
|
||||
BLEND_PREMULT;
|
||||
|
||||
if (screen->grman->num_of_negative_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_negative_refs);
|
||||
|
||||
bind_program(CELL_SPECIAL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
bind_program(CELL_SPECIAL_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
|
||||
bind_program(CELL_FG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
bind_program(CELL_FG_PROGRAM);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||
|
||||
if (screen->grman->num_of_positive_refs) draw_graphics(GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs);
|
||||
|
||||
@@ -377,20 +379,41 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen
|
||||
|
||||
// Now render the framebuffer to the screen reversing alpha pre-multiplication
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
bind_program(BLIT_PROGRAM); bind_vertex_array(blit_vertex_array);
|
||||
bind_program(BLIT_PROGRAM); bind_vertex_array(blit_vertex_array);
|
||||
static bool blit_constants_set = false;
|
||||
if (!blit_constants_set) {
|
||||
glUniform1i(glGetUniformLocation(program_id(BLIT_PROGRAM), "image"), BLIT_UNIT);
|
||||
blit_constants_set = true;
|
||||
if (!blit_constants_set) {
|
||||
glUniform1i(glGetUniformLocation(program_id(BLIT_PROGRAM), "image"), BLIT_UNIT);
|
||||
blit_constants_set = true;
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0 + BLIT_UNIT);
|
||||
glBindTexture(GL_TEXTURE_2D, os_window->offscreen_texture_id);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glActiveTexture(GL_TEXTURE0 + BLIT_UNIT);
|
||||
glBindTexture(GL_TEXTURE_2D, os_window->offscreen_texture_id);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void
|
||||
draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window) {
|
||||
static inline void
|
||||
set_cell_uniforms(float current_inactive_text_alpha) {
|
||||
if (!cell_uniform_data.constants_set) {
|
||||
cell_uniform_data.gploc = glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "inactive_text_alpha");
|
||||
cell_uniform_data.gpploc = glGetUniformLocation(program_id(GRAPHICS_PREMULT_PROGRAM), "inactive_text_alpha");
|
||||
cell_uniform_data.cploc = glGetUniformLocation(program_id(CELL_PROGRAM), "inactive_text_alpha");
|
||||
cell_uniform_data.cfploc = glGetUniformLocation(program_id(CELL_FG_PROGRAM), "inactive_text_alpha");
|
||||
#define S(prog, name, val) { bind_program(prog); glUniform1i(glGetUniformLocation(program_id(prog), #name), val); }
|
||||
S(GRAPHICS_PROGRAM, image, GRAPHICS_UNIT); S(GRAPHICS_PREMULT_PROGRAM, image, GRAPHICS_UNIT);
|
||||
S(CELL_PROGRAM, sprites, SPRITE_MAP_UNIT); S(CELL_FG_PROGRAM, sprites, SPRITE_MAP_UNIT);
|
||||
#undef S
|
||||
cell_uniform_data.constants_set = true;
|
||||
}
|
||||
if (current_inactive_text_alpha != cell_uniform_data.prev_inactive_text_alpha) {
|
||||
cell_uniform_data.prev_inactive_text_alpha = current_inactive_text_alpha;
|
||||
#define S(prog, loc) { bind_program(prog); glUniform1f(cell_uniform_data.loc, current_inactive_text_alpha); }
|
||||
S(CELL_PROGRAM, cploc); S(CELL_FG_PROGRAM, cfploc); S(GRAPHICS_PROGRAM, gploc); S(GRAPHICS_PREMULT_PROGRAM, gpploc);
|
||||
#undef S
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window, bool is_active_window) {
|
||||
if (os_window->clear_count < 2) {
|
||||
os_window->clear_count++;
|
||||
#define C(shift) (((GLfloat)((OPT(background) >> shift) & 0xFF)) / 255.0f)
|
||||
@@ -400,22 +423,17 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL
|
||||
}
|
||||
|
||||
cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy);
|
||||
float current_inactive_text_alpha = screen->cursor_render_info.is_focused && is_active_window ? 1.0 : OPT(inactive_text_alpha);
|
||||
set_cell_uniforms(current_inactive_text_alpha);
|
||||
GLfloat w = (GLfloat)screen->columns * dx, h = (GLfloat)screen->lines * dy;
|
||||
#define SCALE(w, x) ((GLfloat)(os_window->viewport_##w) * (GLfloat)(x))
|
||||
glScissor(
|
||||
(GLint)(SCALE(width, (xstart + 1.0f) / 2.0f)),
|
||||
(GLint)(SCALE(width, (xstart + 1.0f) / 2.0f)),
|
||||
(GLint)(SCALE(height, ((ystart - h) + 1.0f) / 2.0f)),
|
||||
(GLsizei)(ceilf(SCALE(width, w / 2.0f))),
|
||||
(GLsizei)(ceilf(SCALE(height, h / 2.0f)))
|
||||
);
|
||||
#undef SCALE
|
||||
static bool cell_constants_set = false;
|
||||
if (!cell_constants_set) {
|
||||
bind_program(CELL_PROGRAM);
|
||||
glUniform1i(glGetUniformLocation(program_id(CELL_PROGRAM), "sprites"), SPRITE_MAP_UNIT);
|
||||
glUniform1i(glGetUniformLocation(program_id(CELL_FG_PROGRAM), "sprites"), SPRITE_MAP_UNIT);
|
||||
cell_constants_set = true;
|
||||
}
|
||||
if (os_window->is_semi_transparent) {
|
||||
if (screen->grman->count) draw_cells_interleaved_premult(vao_idx, gvao_idx, screen, os_window);
|
||||
else draw_cells_simple(vao_idx, gvao_idx, screen);
|
||||
@@ -446,12 +464,12 @@ init_cursor_program() {
|
||||
#undef SET_LOC
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
draw_cursor(CursorRenderInfo *cursor, bool is_focused) {
|
||||
bind_program(CURSOR_PROGRAM); bind_vertex_array(cursor_vertex_array);
|
||||
glUniform3f(cursor_uniform_locations[CURSOR_color], ((cursor->color >> 16) & 0xff) / 255.0, ((cursor->color >> 8) & 0xff) / 255.0, (cursor->color & 0xff) / 255.0);
|
||||
glUniform4f(cursor_uniform_locations[CURSOR_pos], cursor->left, cursor->top, cursor->right, cursor->bottom);
|
||||
glDrawArrays(is_focused ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, 4);
|
||||
bind_program(CURSOR_PROGRAM); bind_vertex_array(cursor_vertex_array);
|
||||
glUniform3f(cursor_uniform_locations[CURSOR_color], ((cursor->color >> 16) & 0xff) / 255.0, ((cursor->color >> 8) & 0xff) / 255.0, (cursor->color & 0xff) / 255.0);
|
||||
glUniform4f(cursor_uniform_locations[CURSOR_pos], cursor->left, cursor->top, cursor->right, cursor->bottom);
|
||||
glDrawArrays(is_focused ? GL_TRIANGLE_FAN : GL_LINE_LOOP, 0, 4);
|
||||
unbind_vertex_array(); unbind_program();
|
||||
}
|
||||
// }}}
|
||||
@@ -522,11 +540,11 @@ compile_program(PyObject UNUSED *self, PyObject *args) {
|
||||
if (which < 0 || which >= NUM_PROGRAMS) { PyErr_Format(PyExc_ValueError, "Unknown program: %d", which); return NULL; }
|
||||
if (programs[which].id != 0) { PyErr_SetString(PyExc_ValueError, "program already compiled"); return NULL; }
|
||||
programs[which].id = glCreateProgram();
|
||||
vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader);
|
||||
fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader);
|
||||
glAttachShader(programs[which].id, vertex_shader_id);
|
||||
glAttachShader(programs[which].id, fragment_shader_id);
|
||||
glLinkProgram(programs[which].id);
|
||||
vertex_shader_id = compile_shader(GL_VERTEX_SHADER, vertex_shader);
|
||||
fragment_shader_id = compile_shader(GL_FRAGMENT_SHADER, fragment_shader);
|
||||
glAttachShader(programs[which].id, vertex_shader_id);
|
||||
glAttachShader(programs[which].id, fragment_shader_id);
|
||||
glLinkProgram(programs[which].id);
|
||||
GLint ret = GL_FALSE;
|
||||
glGetProgramiv(programs[which].id, GL_LINK_STATUS, &ret);
|
||||
if (ret != GL_TRUE) {
|
||||
@@ -550,8 +568,8 @@ end:
|
||||
#define PYWRAP1(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args)
|
||||
#define PYWRAP2(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args, PyObject *kw)
|
||||
#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;
|
||||
#define ONE_INT(name) PYWRAP1(name) { name(PyLong_AsSsize_t(args)); Py_RETURN_NONE; }
|
||||
#define TWO_INT(name) PYWRAP1(name) { int a, b; PA("ii", &a, &b); name(a, b); Py_RETURN_NONE; }
|
||||
#define ONE_INT(name) PYWRAP1(name) { name(PyLong_AsSsize_t(args)); Py_RETURN_NONE; }
|
||||
#define TWO_INT(name) PYWRAP1(name) { int a, b; PA("ii", &a, &b); name(a, b); Py_RETURN_NONE; }
|
||||
#define NO_ARG(name) PYWRAP0(name) { name(); Py_RETURN_NONE; }
|
||||
#define NO_ARG_INT(name) PYWRAP0(name) { return PyLong_FromSsize_t(name()); }
|
||||
|
||||
@@ -622,7 +640,7 @@ init_shaders(PyObject *module) {
|
||||
C(GL_UNPACK_ALIGNMENT);
|
||||
C(GL_R8); C(GL_RED); C(GL_UNSIGNED_BYTE); C(GL_UNSIGNED_SHORT); C(GL_R32UI); C(GL_RGB32UI); C(GL_RGBA);
|
||||
C(GL_TEXTURE_BUFFER); C(GL_STATIC_DRAW); C(GL_STREAM_DRAW); C(GL_DYNAMIC_DRAW);
|
||||
C(GL_SRC_ALPHA); C(GL_ONE_MINUS_SRC_ALPHA);
|
||||
C(GL_SRC_ALPHA); C(GL_ONE_MINUS_SRC_ALPHA);
|
||||
C(GL_WRITE_ONLY); C(GL_READ_ONLY); C(GL_READ_WRITE);
|
||||
C(GL_BLEND); C(GL_FLOAT); C(GL_UNSIGNED_INT); C(GL_ARRAY_BUFFER); C(GL_UNIFORM_BUFFER);
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ GlobalState global_state = {{0}};
|
||||
(count)--; \
|
||||
break; \
|
||||
} \
|
||||
}}
|
||||
}}
|
||||
|
||||
#define WITH_OS_WINDOW(os_window_id) \
|
||||
for (size_t o = 0; o < global_state.num_os_windows; o++) { \
|
||||
OSWindow *os_window = global_state.os_windows + o; \
|
||||
if (os_window->id == os_window_id) {
|
||||
if (os_window->id == os_window_id) {
|
||||
#define END_WITH_OS_WINDOW break; }}
|
||||
|
||||
#define WITH_TAB(os_window_id, tab_id) \
|
||||
@@ -50,7 +50,7 @@ GlobalState global_state = {{0}};
|
||||
}}
|
||||
|
||||
|
||||
OSWindow*
|
||||
OSWindow*
|
||||
current_os_window() {
|
||||
if (global_state.callback_os_window) return global_state.callback_os_window;
|
||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||
@@ -187,7 +187,7 @@ remove_os_window(id_type os_window_id) {
|
||||
found = true;
|
||||
make_os_window_context_current(os_window);
|
||||
END_WITH_OS_WINDOW
|
||||
if (found) {
|
||||
if (found) {
|
||||
WITH_OS_WINDOW_REFS
|
||||
REMOVER(global_state.os_windows, os_window_id, global_state.num_os_windows, OSWindow, destroy_os_window_item, global_state.capacity);
|
||||
END_WITH_OS_WINDOW_REFS
|
||||
@@ -311,12 +311,14 @@ PYWRAP1(set_options) {
|
||||
S(cursor_blink_interval, PyFloat_AsDouble);
|
||||
S(cursor_stop_blinking_after, PyFloat_AsDouble);
|
||||
S(background_opacity, PyFloat_AsDouble);
|
||||
S(inactive_text_alpha, PyFloat_AsDouble);
|
||||
S(cursor_shape, PyLong_AsLong);
|
||||
S(url_style, PyLong_AsUnsignedLong);
|
||||
S(x11_bell_volume, PyLong_AsLong);
|
||||
S(mouse_hide_wait, PyFloat_AsDouble);
|
||||
S(wheel_scroll_multiplier, PyFloat_AsDouble);
|
||||
S(open_url_modifiers, PyLong_AsUnsignedLong);
|
||||
S(rectangle_select_modifiers, PyLong_AsUnsignedLong);
|
||||
S(click_interval, PyFloat_AsDouble);
|
||||
S(url_color, color_as_int);
|
||||
S(background, color_as_int);
|
||||
@@ -337,7 +339,7 @@ PYWRAP1(set_options) {
|
||||
Py_DECREF(ret); if (PyErr_Occurred()) return NULL;
|
||||
|
||||
PyObject *al = PyObject_GetAttrString(opts, "adjust_line_height");
|
||||
if (PyFloat_Check(al)) {
|
||||
if (PyFloat_Check(al)) {
|
||||
OPT(adjust_line_height_frac) = (float)PyFloat_AsDouble(al);
|
||||
OPT(adjust_line_height_px) = 0;
|
||||
} else {
|
||||
@@ -373,6 +375,15 @@ PYWRAP1(viewport_for_window) {
|
||||
return Py_BuildValue("iiII", 400, 400, global_state.cell_width, global_state.cell_height);
|
||||
}
|
||||
|
||||
PYWRAP1(set_dpi_from_os_window) {
|
||||
id_type os_window_id = PyLong_AsUnsignedLongLong(args);
|
||||
WITH_OS_WINDOW(os_window_id)
|
||||
set_dpi_from_os_window(os_window);
|
||||
Py_RETURN_TRUE;
|
||||
END_WITH_OS_WINDOW
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
PYWRAP1(mark_os_window_for_close) {
|
||||
id_type os_window_id;
|
||||
int yes = 1;
|
||||
@@ -476,6 +487,7 @@ static PyMethodDef module_methods[] = {
|
||||
MW(set_logical_dpi, METH_VARARGS),
|
||||
MW(pt_to_px, METH_O),
|
||||
MW(pt_to_px_ceil, METH_O),
|
||||
MW(set_dpi_from_os_window, METH_O),
|
||||
MW(add_tab, METH_O),
|
||||
MW(add_window, METH_VARARGS),
|
||||
MW(update_window_title, METH_VARARGS),
|
||||
@@ -498,7 +510,7 @@ static PyMethodDef module_methods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
bool
|
||||
bool
|
||||
init_state(PyObject *module) {
|
||||
global_state.cell_width = 1; global_state.cell_height = 1;
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
|
||||
@@ -15,6 +15,7 @@ typedef struct {
|
||||
bool enable_audio_bell;
|
||||
CursorShape cursor_shape;
|
||||
unsigned int open_url_modifiers;
|
||||
unsigned int rectangle_select_modifiers;
|
||||
unsigned int url_style;
|
||||
char_type select_by_word_characters[256]; size_t select_by_word_characters_count;
|
||||
color_type url_color, background;
|
||||
@@ -26,6 +27,7 @@ typedef struct {
|
||||
int x11_bell_volume;
|
||||
float adjust_line_height_frac;
|
||||
float background_opacity;
|
||||
float inactive_text_alpha;
|
||||
} Options;
|
||||
|
||||
typedef struct {
|
||||
@@ -105,6 +107,7 @@ typedef struct {
|
||||
double last_resize_at;
|
||||
bool has_pending_resizes;
|
||||
bool is_semi_transparent;
|
||||
bool shown_once;
|
||||
uint32_t offscreen_texture_id;
|
||||
unsigned int clear_count;
|
||||
} OSWindow;
|
||||
@@ -146,6 +149,7 @@ void mark_os_window_for_close(OSWindow* w, bool yes);
|
||||
void update_os_window_viewport(OSWindow *window, bool);
|
||||
bool should_os_window_close(OSWindow* w);
|
||||
bool should_os_window_be_rendered(OSWindow* w);
|
||||
void set_dpi_from_os_window(OSWindow *w);
|
||||
void wakeup_main_loop();
|
||||
void event_loop_wait(double timeout);
|
||||
void swap_window_buffers(OSWindow *w);
|
||||
@@ -161,7 +165,7 @@ void draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *re
|
||||
ssize_t create_cell_vao();
|
||||
ssize_t create_graphics_vao();
|
||||
ssize_t create_border_vao();
|
||||
void draw_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *);
|
||||
void draw_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *, bool);
|
||||
void draw_cursor(CursorRenderInfo *, bool);
|
||||
void update_surface_size(int, int, uint32_t);
|
||||
void free_texture(uint32_t*);
|
||||
|
||||
@@ -22,16 +22,16 @@ from .utils import color_as_int
|
||||
from .window import Window, calculate_gl_geometry
|
||||
|
||||
TabbarData = namedtuple('TabbarData', 'title is_active is_last')
|
||||
SpecialWindowInstance = namedtuple('SpecialWindow', 'cmd stdin override_title')
|
||||
SpecialWindowInstance = namedtuple('SpecialWindow', 'cmd stdin override_title cwd_from')
|
||||
|
||||
|
||||
def SpecialWindow(cmd, stdin=None, override_title=None):
|
||||
return SpecialWindowInstance(cmd, stdin, override_title)
|
||||
def SpecialWindow(cmd, stdin=None, override_title=None, cwd_from=None):
|
||||
return SpecialWindowInstance(cmd, stdin, override_title, cwd_from)
|
||||
|
||||
|
||||
class Tab: # {{{
|
||||
|
||||
def __init__(self, tab_manager, session_tab=None, special_window=None):
|
||||
def __init__(self, tab_manager, session_tab=None, special_window=None, cwd_from=None):
|
||||
self.tab_manager_ref = weakref.ref(tab_manager)
|
||||
self.os_window_id = tab_manager.os_window_id
|
||||
self.id = add_tab(self.os_window_id)
|
||||
@@ -50,7 +50,7 @@ class Tab: # {{{
|
||||
sl = self.enabled_layouts[0]
|
||||
self.current_layout = all_layouts[sl](self.os_window_id, self.opts, self.borders.border_width, self.windows)
|
||||
if special_window is None:
|
||||
self.new_window()
|
||||
self.new_window(cwd_from=cwd_from)
|
||||
else:
|
||||
self.new_special_window(special_window)
|
||||
else:
|
||||
@@ -109,7 +109,7 @@ class Tab: # {{{
|
||||
w.set_visible_in_layout(i, True)
|
||||
self.relayout()
|
||||
|
||||
def launch_child(self, use_shell=False, cmd=None, stdin=None):
|
||||
def launch_child(self, use_shell=False, cmd=None, stdin=None, cwd_from=None):
|
||||
if cmd is None:
|
||||
if use_shell:
|
||||
cmd = [shell_path]
|
||||
@@ -122,12 +122,12 @@ class Tab: # {{{
|
||||
except Exception:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
ans = Child(cmd, self.cwd, self.opts, stdin, env)
|
||||
ans = Child(cmd, self.cwd, self.opts, stdin, env, cwd_from)
|
||||
ans.fork()
|
||||
return ans
|
||||
|
||||
def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None):
|
||||
child = self.launch_child(use_shell=use_shell, cmd=cmd, stdin=stdin)
|
||||
def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None, cwd_from=None):
|
||||
child = self.launch_child(use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from)
|
||||
window = Window(self, child, self.opts, self.args, override_title=override_title)
|
||||
# Must add child before laying out so that resize_pty succeeds
|
||||
get_boss().add_child(window)
|
||||
@@ -401,10 +401,10 @@ class TabManager: # {{{
|
||||
def title_changed(self, new_title):
|
||||
self.update_tab_bar()
|
||||
|
||||
def new_tab(self, special_window=None):
|
||||
def new_tab(self, special_window=None, cwd_from=None):
|
||||
needs_resize = len(self.tabs) == 1
|
||||
idx = len(self.tabs)
|
||||
self._add_tab(Tab(self, special_window=special_window))
|
||||
self._add_tab(Tab(self, special_window=special_window, cwd_from=cwd_from))
|
||||
self._set_active_tab(idx)
|
||||
self.update_tab_bar()
|
||||
if needs_resize:
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
#include <unictype.h>
|
||||
#include <uninorm.h>
|
||||
|
||||
static inline bool
|
||||
static inline bool
|
||||
is_combining_char(uint32_t ch) {
|
||||
return uc_combining_class(ch) != UC_CCC_NR;
|
||||
}
|
||||
|
||||
|
||||
static inline bool
|
||||
|
||||
static inline bool
|
||||
is_ignored_char(uint32_t ch) {
|
||||
return uc_is_general_category_withtable(ch, UC_CATEGORY_MASK_Cc | UC_CATEGORY_MASK_Cf | UC_CATEGORY_MASK_Cs);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static inline bool
|
||||
is_word_char(uint32_t ch) {
|
||||
return uc_is_general_category_withtable(ch, UC_CATEGORY_MASK_L | UC_CATEGORY_MASK_N);
|
||||
}
|
||||
|
||||
@@ -264,9 +264,3 @@ def single_instance(group_id=None):
|
||||
s.set_inheritable(False)
|
||||
atexit.register(remove_socket_file, s)
|
||||
return True
|
||||
|
||||
|
||||
def encode_wm_class(name, cls, title=appname):
|
||||
if is_macos:
|
||||
return title
|
||||
return '\x01' + (name or cls) + '\x1e' + cls + '\x1e' + title
|
||||
|
||||
2435
kitty/wcwidth-std.h
generated
Normal file
2435
kitty/wcwidth-std.h
generated
Normal file
File diff suppressed because it is too large
Load Diff
1321
kitty/wcwidth9.h
1321
kitty/wcwidth9.h
File diff suppressed because it is too large
Load Diff
@@ -269,6 +269,9 @@ class TestDataTypes(BaseTest):
|
||||
no_url('http: //acme.com')
|
||||
no_url('http:/ /acme.com')
|
||||
|
||||
l4 = create(' xxxxxtekljhgdkjgd')
|
||||
self.ae(l4.url_end_at(0), 0)
|
||||
|
||||
def rewrap(self, lb, lb2):
|
||||
hb = HistoryBuf(lb2.ynum, lb2.xnum)
|
||||
cy = lb.rewrap(lb2, hb)
|
||||
|
||||
@@ -54,8 +54,8 @@ To reset the underline color (also previously reserved and unused):
|
||||
<ESC>[59m
|
||||
```
|
||||
|
||||
A client can query if the terminal emulator supports this underline extension using the
|
||||
standard link:http://vt100.net/docs/vt510-rm/DECRQM[DECRQM] escape sequence, with the
|
||||
A client can query if the terminal emulator supports this underline extension using the
|
||||
standard link:http://vt100.net/docs/vt510-rm/DECRQM[DECRQM] escape sequence, with the
|
||||
mode value `2016`, like this:
|
||||
|
||||
Client sends:
|
||||
@@ -86,8 +86,8 @@ include:
|
||||
* No way to use modifiers other than `Ctrl` and `Alt`
|
||||
* No way to use multiple modifier keys, other than, `Shift+Alt`.
|
||||
* No way to handle different types of keyboard events, such as press, release or repeat
|
||||
* No reliable way to distinguish single `Esc` keypresses from the
|
||||
start of a escape sequence. Currently, client programs use
|
||||
* No reliable way to distinguish single `Esc` keypresses from the
|
||||
start of a escape sequence. Currently, client programs use
|
||||
fragile timing related hacks for this, leading to bugs, for example:
|
||||
link:https://github.com/neovim/neovim/issues/2035[neovim #2035]
|
||||
|
||||
@@ -112,7 +112,7 @@ and to leave _full mode_, use DECRST
|
||||
```
|
||||
|
||||
The number `2017` above is not used for any existing modes, as far as I know.
|
||||
Client programs can query if the terminal emulator is in _full mode_ by using
|
||||
Client programs can query if the terminal emulator is in _full mode_ by using
|
||||
the standard link:http://vt100.net/docs/vt510-rm/DECRQM[DECRQM] escape sequence.
|
||||
|
||||
The new mode works as follows:
|
||||
@@ -135,7 +135,7 @@ The escape sequence encodes the following properties:
|
||||
|
||||
* Type of event: `press,repeat,release`
|
||||
* Modifiers pressed at the time of the event
|
||||
* The actual key being pressed
|
||||
* The actual key being pressed
|
||||
|
||||
```
|
||||
<ESC>_K<type><modifiers><key><ESC>\
|
||||
@@ -165,13 +165,13 @@ regions of the screen,
|
||||
link:https://vt100.net/docs/vt510-rm/DECCARA.html[DECCARA]. However, it is
|
||||
limited to only a few attributes. kitty extends this to work with *all* SGR
|
||||
attributes. So, for example, this can be used to set the background color in
|
||||
an arbitrary region of the screen.
|
||||
an arbitrary region of the screen.
|
||||
|
||||
The motivation for this extension is the various problems with the existing
|
||||
solution for erasing to background color, namely the *background color erase
|
||||
(bce)* capability. See
|
||||
(bce)* capability. See
|
||||
link:https://github.com/kovidgoyal/kitty/issues/160#issuecomment-346470545[this discussion]
|
||||
for a summary of problems with *bce*.
|
||||
for a summary of problems with *bce*.
|
||||
|
||||
For example, to set the background color to blue in a
|
||||
rectangular region of the screen from (3, 4) to (10, 11), you use:
|
||||
|
||||
7
setup.py
7
setup.py
@@ -401,7 +401,12 @@ def compile_glfw(incremental, compilation_database, all_keys):
|
||||
sources = [os.path.join('glfw', x) for x in genv.sources]
|
||||
all_headers = [os.path.join('glfw', x) for x in genv.all_headers]
|
||||
if module == 'wayland':
|
||||
glfw.build_wayland_protocols(genv, run_tool, emphasis, newer, os.path.join(base, 'glfw'))
|
||||
try:
|
||||
glfw.build_wayland_protocols(genv, run_tool, emphasis, newer, os.path.join(base, 'glfw'))
|
||||
except SystemExit as err:
|
||||
print(err, file=sys.stderr)
|
||||
print(error('Disabling building of wayland backend'), file=sys.stderr)
|
||||
continue
|
||||
compile_c_extension(genv, 'kitty/glfw-' + module, incremental, compilation_database, all_keys, sources, all_headers)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user