Compare commits

..

70 Commits

Author SHA1 Message Date
Kovid Goyal
20f7118432 version 0.14.4 2019-08-31 10:20:47 +05:30
Kovid Goyal
37e6c3f0cb Merge branch 'bool_indentation' of https://github.com/Luflosi/kitty 2019-08-30 19:08:46 +05:30
Luflosi
0459dda5c2 Fix bool indentation
The wrong indentation was caused by the removal of GLFWbool in fe62700825.
2019-08-30 15:32:20 +02:00
Kovid Goyal
a10c816c05 Merge branch 'fix_nslog_string_format' of https://github.com/Luflosi/kitty 2019-08-30 18:40:49 +05:30
Luflosi
c0c7cfacc2 Fix NSLog() printing of unicode format strings
See https://stackoverflow.com/questions/720052/nslog-incorrect-encoding.
The `%s` format placeholder for `NSLog()` expects an encoding other than UTF-8, which leads to garbled Unicode characters when trying to print a UTF-8 encoded string.
```Objective-C
NSLog(@"Ä %s %@", "Ä", @("Ä"));
```
prints `Ä √Ñ Ä`.

As can be seen in the example above, the workaround is to convert the UTF-8 encoded C-string to an `NSString` object and print that instead.
`debug_key()` calls `NSLog()`.
2019-08-30 15:03:51 +02:00
Kovid Goyal
8cdb6647ed Merge branch 'fix_update_encoding' of https://github.com/Luflosi/kitty 2019-08-30 16:20:42 +05:30
Luflosi
b68e3c85b9 Add missing MENU key to key_encoding.py 2019-08-30 12:37:23 +02:00
Luflosi
ef25d5bbd5 Fix update_encoding() not adding the last key 2019-08-30 12:36:37 +02:00
Kovid Goyal
278bf6e897 Fix #1937 2019-08-30 15:02:17 +05:30
Kovid Goyal
90a985b73a Make format_text() more secure 2019-08-28 05:41:20 +05:30
Kovid Goyal
b016353809 Some clarifications for the graphics protocol
See discussion on #33
2019-08-28 05:28:05 +05:30
Kovid Goyal
bc222af2e2 When dumping scrollback as ansi, reset SGR formatting at end of scrollback 2019-08-27 19:35:01 +05:30
Kovid Goyal
44599c9460 Merge branch 'simplify_compile_code' of https://github.com/Luflosi/kitty 2019-08-26 20:25:19 +05:30
Luflosi
902fc22670 Simplify GLFW compilation code
This commit removes the need for `is_macos` in `glfw/glfw.py` by moving a few lines of code. Instead of relying on the information that the compilation is or isn't happening on macOS, the code now does the right thing based on which `module` is being built.
This changes the order of the compilation flags slightly.
2019-08-26 16:47:19 +02:00
Kovid Goyal
d84e22fbf1 Merge branch 'fix_typos' of https://github.com/Luflosi/kitty 2019-08-26 16:34:54 +05:30
Luflosi
6cc720a350 Fix typos
Inspired by 4d3ee554b3.
Found using `codespell`.
2019-08-26 12:31:15 +02:00
Kovid Goyal
c905978874 Merge branch 'fix_issue_1924' of https://github.com/s1341/kitty
Fixes #1924
2019-08-26 10:19:50 +05:30
Kovid Goyal
bfe595a8e8 Merge branch '_glfwInputError_format' of https://github.com/Luflosi/kitty 2019-08-26 06:24:02 +05:30
Luflosi
94d56d1a9e Correct indentation for two _glfwInputError() messages
This commit changes the indentation of two error messages to match the indentation in the rest of the code.
2019-08-25 21:29:58 +02:00
s1341
bd3f0b5363 Properly handle all NULL cases 2019-08-25 17:22:06 +03:00
s1341
6fae3545c7 Fix null pointer deref 2019-08-25 16:39:39 +03:00
s1341
297963f6ab Fix issue #1924 by making prev_cell persistent across line_as_ansi calls 2019-08-25 16:25:36 +03:00
Kovid Goyal
a0ceba407e Merge branch 'drag_and_drop_text' of https://github.com/Luflosi/kitty 2019-08-24 08:39:27 +05:30
Kovid Goyal
35fa91fba2 When the OS returns a fallback font that does not actually contain glyphs for the text, do not exhaust the list of fallback fonts
Fixes #1918

Apparently fontconfig does this for Tangut components.
2019-08-24 08:27:54 +05:30
Kovid Goyal
a5d6cd169e Fix piping PNG images into the icat kitten not working
Fixes #1920
2019-08-24 08:04:04 +05:30
Luflosi
06c2263657 macOS: implement drag and drop of text into kitty
Closes #1368.
2019-08-24 01:29:33 +02:00
Kovid Goyal
472c6f6b8d When running kittens, use the colorscheme of the current window rather than the configured colorscheme
Fixes #1906
2019-08-18 18:27:44 +05:30
Kovid Goyal
afcaca85da Merge branch 'hints_regex_doc' of https://github.com/toonn/kitty 2019-08-18 07:41:14 +05:30
Toon Nolten
2575349ec2 Add expected regex syntax to hints kitten docs
The hints kitten's help documentation did not mention what syntax to use
for the regular expressions. I knew much of kitty was implemented in
python so I guessed correctly but not everyone might know this.

I also fixed some double-spaced sentences because most of them are
single-spaced.
2019-08-17 21:27:53 +02:00
Kovid Goyal
77054f688d Workaround for window managers like xmonad that in some circumstances set window size to zero. Fixes #1910 2019-08-17 18:04:08 +05:30
Kovid Goyal
c5cb24378f Merge branch 'fix_macos_show_window_title_in' of https://github.com/Luflosi/kitty 2019-08-14 06:36:25 +05:30
Luflosi
d66123dd14 Fix hiding the window title in macOS
In b5c2163238 I introduced a bug where only the window title of the first OS window would be hidden. This commit fixes that bug.
The bug was caused by the code hiding the window title being in an `if` statement that only executes once.
2019-08-13 21:02:28 +02:00
Kovid Goyal
4ef8f11f9e Merge branch 'add_frameworks_only_once' of https://github.com/Luflosi/kitty 2019-08-11 07:43:36 +05:30
Luflosi
599be7ddc9 Don't add Apple Frameworks twice
These Frameworks are added again a couple lines below in the check for `module == 'cocoa'`.
2019-08-11 02:26:12 +02:00
Kovid Goyal
685497fc8c Fix shaping test 2019-08-10 08:58:02 +05:30
Kovid Goyal
57542fc204 Only disable liga and dlig for nimbus mono 2019-08-10 08:22:36 +05:30
Kovid Goyal
8d9323aec6 Merge branch 'unnecessary_indentation' of https://github.com/Luflosi/kitty 2019-08-09 07:05:26 +05:30
Luflosi
4984a25b19 Remove unnecessary indentation 2019-08-09 03:27:22 +02:00
Kovid Goyal
3bdcb29e01 Merge branch 'trailing_whitespace' of https://github.com/Luflosi/kitty 2019-08-09 06:34:19 +05:30
Luflosi
b9ab8e6348 Remove trailing whitespace 2019-08-08 20:26:20 +02:00
Kovid Goyal
4a851701e9 Fix a regression that broke setting background_opacity via remote control
Fixes #1895
2019-08-07 15:09:04 +05:30
Kovid Goyal
eafd8af937 Merge branch 'glfw_3.4' of https://github.com/Luflosi/kitty 2019-08-03 07:38:14 +05:30
Luflosi
28bb123be8 Update the GLFW version number from 3.3 to 3.4
Closes https://github.com/kovidgoyal/kitty/issues/1884.
From a337c56848.
2019-08-02 11:00:16 -05:00
Kovid Goyal
8e1ed2f8c3 Update unicode data to 12.1 2019-08-02 14:48:18 +05:30
Kovid Goyal
4a0fcb3cff Merge branch 'macos_show_window_title_in' of https://github.com/Luflosi/kitty 2019-08-02 11:51:38 +05:30
Luflosi
b5c2163238 Add option to hide the window title on macOS
Deprecate `macos_show_window_title_in_menubar` and create a new option `macos_show_window_title_in`.
2019-08-02 00:20:43 -05:00
Kovid Goyal
d0ecdfb330 Add a :opt:kitten_alias option that can be used to alias kitten invocation for brevity and to change kitten option defaults globally
See #1879
2019-08-02 10:40:11 +05:30
Kovid Goyal
bdf7d98a36 hints kitten: Allow specifying :option:kitty +kitten hints --program multiple times to run multiple programs
See #1879
2019-08-02 10:03:04 +05:30
Kovid Goyal
e4b0980d15 DRYer 2019-08-02 07:18:42 +05:30
Kovid Goyal
d99c57aeae Merge branch 'open_context_manager' of https://github.com/Luflosi/kitty 2019-08-02 07:14:11 +05:30
Luflosi
5f855ce547 Use context managers to open files
Inspired by d50a6ddc1b.
2019-08-01 13:21:26 -05:00
Kovid Goyal
68f3b6fbeb Fix the decode_hint function to work with an arbitrary alphabet 2019-08-01 19:31:21 +05:30
Kovid Goyal
dc6d14943e Dont use a global variable for the hints alphabet 2019-08-01 19:24:09 +05:30
Kovid Goyal
05f7334db9 hints kitten: Add a :option:kitty +kitten hints --alphabet option to control what alphabets are used for hints
Fixes #1879
2019-08-01 16:25:54 +05:30
Kovid Goyal
cd707e9335 Merge branch 'wait_for_shell' of https://github.com/Luflosi/kitty 2019-08-01 12:56:12 +05:30
Luflosi
505ed5e43b Fix crash when the shell takes too long to start when reading the environment
According to https://docs.python.org/3/library/subprocess.html#subprocess.Popen.wait, `wait()` throws a `TimeoutExpired` exception when the process is not done after the timeout. I noticed this because kitty crashed for me.
The old code looks like it's trying to wait as long as it takes for the process to finish, which is what I implemented.
2019-08-01 02:03:08 -05:00
Kovid Goyal
9dc8bf5f62 Merge branch 'ignore_directories' of https://github.com/Luflosi/kitty 2019-08-01 06:38:34 +05:30
Luflosi
f8098662b6 Explicitly mark directories as such in .gitignore 2019-07-31 15:27:06 -05:00
Kovid Goyal
de7a0e86c4 Merge branch 'ignore_files_only_in_root' of https://github.com/Luflosi/kitty 2019-07-31 20:56:50 +05:30
Luflosi
ca55438fda Ignore several directories and files only in the root of the repo
These directories are always located in the root directory of the repository. Therefore it's better to only ignore these files in this location.
2019-07-31 10:16:19 -05:00
Kovid Goyal
a4b60e7eef Disable the `liga and dlig` OpenType features so that kitty works with "so-called" monospace fonts such as Nimbus Mono that have non-programming ligatures. 2019-07-31 20:02:48 +05:30
Kovid Goyal
5d22e07738 More details on login shell invocation 2019-07-31 12:20:02 +05:30
Kovid Goyal
bdade7e151 Use a new controlling terminal when reading shell environment
This is because some people do things in their rc files based
on checking the name of the controlling terminal.
2019-07-31 11:34:54 +05:30
Kovid Goyal
6958ded4c4 Dont fail to start if running the shell to read the EDITOR env var fails
Fixes #1869
2019-07-31 06:37:17 +05:30
Kovid Goyal
cc06104be6 Create FUNDING.yml
Add links to the various funding sources
2019-07-30 15:07:12 +05:30
Kovid Goyal
059c34c345 Add a version check to the installer on macOS 2019-07-30 15:01:07 +05:30
Kovid Goyal
9cbb726566 Fix #1865 2019-07-30 06:20:54 +05:30
Kovid Goyal
e8b4356a88 Merge branch 'ignore_build_only_in_root' of https://github.com/Luflosi/kitty 2019-07-29 11:37:36 +05:30
Kovid Goyal
634138cd3b Removed unused entry from .gitignore
Fixes #1859

tags is the file generated by ctags
2019-07-29 11:36:46 +05:30
Luflosi
3f6b07de81 Ignore the build directory only in the root of the repo
The `build` directory is always located at the root directory of the repository. Therefore it's better to only ignore `build` in this location.
2019-07-29 00:59:35 -05:00
110 changed files with 21405 additions and 21075 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
patreon: kovidgoyal
liberapay: kovidgoyal
custom: https://sw.kovidgoyal.net/kitty/support.html

27
.gitignore vendored
View File

@@ -1,18 +1,17 @@
*.so
*.pyc
*.pyo
tags
build
linux-package
kitty.app
compile_commands.json
link_commands.json
glad/out
kitty/launcher
*.dSYM
dev
__pycache__
glfw/wayland-*-client-protocol.[ch]
docs/_build
docs/generated
/tags
/build/
/linux-package/
/kitty.app/
/compile_commands.json
/link_commands.json
/glad/out/
/kitty/launcher/
/*.dSYM/
__pycache__/
/glfw/wayland-*-client-protocol.[ch]
/docs/_build/
/docs/generated/
.DS_Store

View File

@@ -1,8 +1,8 @@
ifdef V
VVAL=--verbose
VVAL=--verbose
endif
ifdef VERBOSE
VVAL=--verbose
VVAL=--verbose
endif
all:
@@ -28,7 +28,7 @@ asan:
profile:
python3 setup.py build $(VVAL) --profile
app:
app:
python3 setup.py kitty.app $(VVAL)
man:

View File

@@ -4,6 +4,45 @@ Changelog
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
To update |kitty|, :doc:`follow the instructions <binary>`.
0.14.4 [2019-08-31]
---------------------
- hints kitten: Add a :option:`kitty +kitten hints --alphabet` option to
control what alphabets are used for hints (:iss:`1879`)
- hints kitten: Allow specifying :option:`kitty +kitten hints --program`
multiple times to run multiple programs (:iss:`1879`)
- Add a :opt:`kitten_alias` option that can be used to alias kitten invocation
for brevity and to change kitten option defaults globally (:iss:`1879`)
- macOS: Add an option :opt:`macos_show_window_title_in` to control
showing the window title in the menubar/titlebar (:pull:`1837`)
- macOS: Allow drag and drop of text from other applications into kitty
(:pull:`1921`)
- When running kittens, use the colorscheme of the current window
rather than the configured colorscheme (:iss:`1906`)
- Don't fail to start if running the shell to read the EDITOR env var fails
(:iss:`1869`)
- Disable the ``liga`` and ``dlig`` OpenType features for broken fonts
such as Nimbus Mono.
- Fix a regression that broke setting background_opacity via remote control
(:iss:`1895`)
- Fix piping PNG images into the icat kitten not working (:iss:`1920`)
- When the OS returns a fallback font that does not actually contain glyphs
for the text, do not exhaust the list of fallback fonts (:iss:`1918`)
- Fix formatting attributes not reset across line boundaries when passing
buffer as ANSI (:iss:`1924`)
0.14.3 [2019-07-29]
---------------------
@@ -192,7 +231,7 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
- macOS: Fix :kbd:`cmd+period` key not working (:iss:`1318`)
- macOS: Add an option :opt:`macos_show_window_title_in_menubar` to not
- macOS: Add an option `macos_show_window_title_in_menubar` to not
show the current window title in the menu-bar (:iss:`1066`)
- macOS: Workaround for cocoa bug that could cause the mouse cursor to become

View File

@@ -107,7 +107,8 @@ features of the graphics protocol:
sys.stdout.flush()
cmd.clear()
write_chunked({'a': 'T', 'f': 100}, open(sys.argv[-1], 'rb').read())
with open(sys.argv[-1], 'rb') as f:
write_chunked({'a': 'T', 'f': 100}, f.read())
Save this script as :file:`png.py`, then you can use it to display any PNG
@@ -255,7 +256,10 @@ sequence of escape codes to the terminal emulator::
Note that only the first escape code needs to have the full set of control
codes such as width, height, format etc. Subsequent chunks must have
only the ``m`` key. The client **must** finish sending all chunks for a single image
before sending any other graphics related escape codes.
before sending any other graphics related escape codes. Note that the cursor
position used to display the image **must** be the position when the final chunk is
received. Finally, terminals must not display anything, until the entire sequence is
received and validated.
Detecting available transmission mediums

View File

@@ -20,6 +20,10 @@ import tempfile
py3 = sys.version_info[0] > 2
is64bit = platform.architecture()[0] == '64bit'
is_macos = 'darwin' in sys.platform.lower()
if is_macos:
mac_ver = tuple(map(int, platform.mac_ver()[0].split('.')))
if mac_ver[:2] < (10, 12):
raise SystemExit('Your version of macOS is too old, at least 10.12 is required')
try:
__file__
@@ -225,7 +229,8 @@ def script_launch():
def update_intaller_wrapper():
# To run: python3 -c "import runpy; runpy.run_path('installer.py', run_name='update_wrapper')" installer.sh
src = open(__file__, 'rb').read().decode('utf-8')
with open(__file__, 'rb') as f:
src = f.read().decode('utf-8')
wrapper = sys.argv[-1]
with open(wrapper, 'r+b') as f:
raw = f.read().decode('utf-8')

View File

@@ -2,7 +2,7 @@ Documentation for the kitty remote control protocol
======================================================
The kitty remote control protocol is a simple protocol that involves sending
data to kitty in the form of JSON. Any individual command ot kitty has the
data to kitty in the form of JSON. Any individual command of kitty has the
form::
<ESC>P@kitty-cmd<JSON object><ESC>\
@@ -21,7 +21,7 @@ standalone client, use the kitty version that you are developing against. Using
a version greater than the version of the kitty instance you are talking to,
will cause a failure.
Set ``no_response`` to True if you dont want a response from kitty.
Set ``no_response`` to True if you don't want a response from kitty.
The optional payload is a JSON object that is specific to the actual command being sent.
The fields in the object for every command are documented below.

View File

@@ -29,10 +29,12 @@ def get_data(fname, folder='UCD'):
bn = os.path.basename(url)
local = os.path.join('/tmp', bn)
if os.path.exists(local):
data = open(local, 'rb').read()
with open(local, 'rb') as f:
data = f.read()
else:
data = urlopen(url).read()
open(local, 'wb').write(data)
with open(local, 'wb') as f:
f.write(data)
for line in data.decode('utf-8').splitlines():
line = line.strip()
if line and not line.startswith('#'):
@@ -166,21 +168,20 @@ def write_case(spec, p):
@contextmanager
def create_header(path, include_data_types=True):
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')
if path.endswith('.h'):
p('#pragma once')
if include_data_types:
p('#include "data-types.h"\n')
p('START_ALLOW_CASE_RANGE')
p()
yield p
p()
if include_data_types:
p('END_ALLOW_CASE_RANGE')
f.close()
with open(path, 'w') as f:
p = partial(print, file=f)
p('// unicode data, built from the unicode standard on:', date.today())
p('// see gen-wcwidth.py')
if path.endswith('.h'):
p('#pragma once')
if include_data_types:
p('#include "data-types.h"\n')
p('START_ALLOW_CASE_RANGE')
p()
yield p
p()
if include_data_types:
p('END_ALLOW_CASE_RANGE')
def gen_emoji():
@@ -282,7 +283,9 @@ def gen_ucd():
p('combining_type mark_for_codepoint(char_type c) {')
rmap = codepoint_to_mark_map(p, mark_map)
p('}\n')
expected = int(re.search(r'^#define VS15 (\d+)', open('kitty/unicode-data.h').read(), re.M).group(1))
with open('kitty/unicode-data.h') as f:
unicode_data = f.read()
expected = int(re.search(r'^#define VS15 (\d+)', unicode_data, re.M).group(1))
if rmap[0xfe0e] != expected:
raise ValueError('The mark for 0xfe0e has changed, you have to update VS15 to {} and VS16 to {} in unicode-data.h'.format(
rmap[0xfe0e], rmap[0xfe0f]

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
// GLFW 3.4 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Cocoa - www.glfw.org
// GLFW 3.4 Cocoa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//

2
glfw/cocoa_time.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
//

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//
@@ -261,9 +261,13 @@ static inline const char*
format_text(const char *src) {
static char buf[256];
char *p = buf;
const char *last_char = buf + sizeof(buf) - 1;
if (!src[0]) return "<none>";
while (*src) {
p += snprintf(p, sizeof(buf) - (p - buf), "0x%x ", (unsigned char)*(src++));
int num = snprintf(p, sizeof(buf) - (p - buf), "0x%x ", (unsigned char)*(src++));
if (num < 0) return "<error>";
if (p + num >= last_char) break;
p += num;
}
if (p != buf) *(--p) = 0;
return buf;
@@ -630,7 +634,7 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
markedRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
[self updateTrackingAreas];
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL]];
[self registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
}
return self;
@@ -692,8 +696,8 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
[window->context.nsgl.object update];
} @catch (NSException *e) {
_glfwInputError(GLFW_PLATFORM_ERROR,
"Failed to update NSGL Context object with error: %s (%s)",
[[e name] UTF8String], [[e reason] UTF8String]);
"Failed to update NSGL Context object with error: %s (%s)",
[[e name] UTF8String], [[e reason] UTF8String]);
}
}
@@ -948,13 +952,13 @@ is_ascii_control_char(char x) {
&char_count,
text
) != noErr) {
debug_key(@"UCKeyTranslate failed for scancode: 0x%x (%s) %s\n",
scancode, safe_name_for_scancode(scancode), format_mods(mods));
debug_key(@"UCKeyTranslate failed for scancode: 0x%x (%@) %@\n",
scancode, @(safe_name_for_scancode(scancode)), @(format_mods(mods)));
window->ns.deadKeyState = 0;
return;
}
debug_key(@"scancode: 0x%x (%s) %schar_count: %lu deadKeyState: %u repeat: %d",
scancode, safe_name_for_scancode(scancode), format_mods(mods), char_count, window->ns.deadKeyState, event.ARepeat);
debug_key(@"scancode: 0x%x (%@) %@char_count: %lu deadKeyState: %u repeat: %d",
scancode, @(safe_name_for_scancode(scancode)), @(format_mods(mods)), char_count, window->ns.deadKeyState, event.ARepeat);
if (process_text) {
// this will call insertText which will fill up _glfw.ns.text
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
@@ -963,7 +967,7 @@ is_ascii_control_char(char x) {
}
if (window->ns.deadKeyState && (char_count == 0 || scancode == 0x75)) {
// 0x75 is the delete key which needs to be ignored during a compose sequence
debug_key(@"Sending pre-edit text for dead key (text: %s markedText: %@).\n", format_text(_glfw.ns.text), markedText);
debug_key(@"Sending pre-edit text for dead key (text: %@ markedText: %@).\n", @(format_text(_glfw.ns.text)), markedText);
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
[[markedText string] UTF8String], 1); // update pre-edit text
return;
@@ -975,8 +979,8 @@ is_ascii_control_char(char x) {
}
}
if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes
debug_key(@"text: %s glfw_key: %s marked_text: %@\n",
format_text(_glfw.ns.text), _glfwGetKeyName(key), markedText);
debug_key(@"text: %@ glfw_key: %@ marked_text: %@\n",
@(format_text(_glfw.ns.text)), @(_glfwGetKeyName(key)), markedText);
if (!window->ns.deadKeyState) {
if ([self hasMarkedText]) {
_glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods,
@@ -1073,16 +1077,27 @@ is_ascii_control_char(char x) {
NSPasteboard* pasteboard = [sender draggingPasteboard];
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
NSArray* objs = [pasteboard readObjectsForClasses:@[[NSURL class], [NSString class]]
options:options];
if (!urls) return NO;
const NSUInteger count = [urls count];
if (!objs) return NO;
const NSUInteger count = [objs count];
if (count)
{
char** paths = calloc(count, sizeof(char*));
for (NSUInteger i = 0; i < count; i++)
paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]);
{
id obj = objs[i];
if ([obj isKindOfClass:[NSURL class]]) {
paths[i] = _glfw_strdup([obj fileSystemRepresentation]);
} else if ([obj isKindOfClass:[NSString class]]) {
paths[i] = _glfw_strdup([obj UTF8String]);
} else {
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Object is neither a URL nor a string");
paths[i] = _glfw_strdup("");
}
}
_glfwInputDrop(window, (int) count, (const char**) paths);

2
glfw/context.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>

2
glfw/dbus_glfw.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//

2
glfw/dbus_glfw.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//

2
glfw/egl_context.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
// GLFW 3.4 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

2
glfw/egl_context.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 EGL - www.glfw.org
// GLFW 3.4 EGL - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -8,7 +8,6 @@ import re
import sys
_plat = sys.platform.lower()
is_macos = 'darwin' in _plat
is_freebsd = 'freebsd' in _plat
is_netbsd = 'netbsd' in _plat
is_dragonflybsd = 'dragonfly' in _plat
@@ -23,22 +22,12 @@ def wayland_protocol_file_name(base, ext='c'):
def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
ans = env.copy()
if not is_macos:
ans.cflags.append('-pthread')
ans.ldpaths.append('-pthread')
ans.cflags.append('-fpic')
ans.cppflags.append('-D_GLFW_' + module.upper())
ans.cppflags.append('-D_GLFW_BUILD_DLL')
if is_macos:
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
ans.ldpaths.extend(
"-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo".
split()
)
else:
ans.ldpaths.extend('-lrt -lm -ldl'.split())
sinfo = json.load(open(os.path.join(base, 'source-info.json')))
with open(os.path.join(base, 'source-info.json')) as f:
sinfo = json.load(f)
module_sources = list(sinfo[module]['sources'])
if module in ('x11', 'wayland'):
remove = 'linux_joystick.c' if is_bsd else 'null_joystick.c'
@@ -48,6 +37,9 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
ans.all_headers = [x for x in os.listdir(base) if x.endswith('.h')]
if module in ('x11', 'wayland'):
ans.cflags.append('-pthread')
ans.ldpaths.append('-pthread')
ans.ldpaths.extend('-lrt -lm -ldl'.split())
at_least_version('xkbcommon', 0, 5)
if module == 'x11':
@@ -56,6 +48,7 @@ def init_env(env, pkg_config, at_least_version, test_compile, module='x11'):
ans.ldpaths.extend(pkg_config(dep, '--libs'))
elif module == 'cocoa':
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
for f in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
ans.ldpaths.extend(('-framework', f))
@@ -157,7 +150,8 @@ class Function:
def generate_wrappers(glfw_header):
src = open(glfw_header).read()
with open(glfw_header) as f:
src = f.read()
functions = []
first = None
for m in re.finditer(r'^GLFWAPI\s+(.+[)]);\s*$', src, flags=re.MULTILINE):

18
glfw/glfw3.h vendored
View File

@@ -1,5 +1,5 @@
/*************************************************************************
* GLFW 3.3 - www.glfw.org
* GLFW 3.4 - www.glfw.org
* A library for OpenGL, window and input
*------------------------------------------------------------------------
* Copyright (c) 2002-2006 Marcus Geelnard
@@ -261,7 +261,7 @@ extern "C" {
* backward-compatible.
* @ingroup init
*/
#define GLFW_VERSION_MINOR 3
#define GLFW_VERSION_MINOR 4
/*! @brief The revision number of the GLFW library.
*
* This is incremented when a bug fix release is made that does not contain any
@@ -324,7 +324,7 @@ extern "C" {
*
* The naming of the key codes follow these rules:
* - The US keyboard layout is used
* - Names of printable alpha-numeric characters are used (e.g. "A", "R",
* - Names of printable alphanumeric characters are used (e.g. "A", "R",
* "3", etc.)
* - For non-alphanumeric characters, Unicode:ish names are used (e.g.
* "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not
@@ -2175,7 +2175,7 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
*
* @remark @wayland Gamma handling is a priviledged protocol, this function
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR.
*
* @thread_safety This function must only be called from the main thread.
@@ -2199,7 +2199,7 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland Gamma handling is a priviledged protocol, this function
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while
* returning `NULL`.
*
@@ -2243,7 +2243,7 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
*
* @remark @win32 The gamma ramp size must be 256.
*
* @remark @wayland Gamma handling is a priviledged protocol, this function
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR.
*
* @pointer_lifetime The specified gamma ramp is copied before this function
@@ -2462,7 +2462,7 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
*
* @remark @macos When activating frame autosaving with
* [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified
* window size and position may be overriden by previously saved values.
* window size and position may be overridden by previously saved values.
*
* @remark @x11 Some window managers will not respect the placement of
* initially hidden windows.
@@ -4524,7 +4524,7 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count);
*/
GLFWAPI const char* glfwGetJoystickName(int jid);
/*! @brief Returns the SDL comaptible GUID of the specified joystick.
/*! @brief Returns the SDL compatible GUID of the specified joystick.
*
* This function returns the SDL compatible GUID, as a UTF-8 encoded
* hexadecimal string, of the specified joystick. The returned string is
@@ -4738,7 +4738,7 @@ GLFWAPI const char* glfwGetGamepadName(int jid);
/*! @brief Retrieves the state of the specified joystick remapped as a gamepad.
*
* This function retrives the state of the specified joystick remapped to
* This function retrieves the state of the specified joystick remapped to
* an Xbox-like gamepad.
*
* If the specified joystick is not present or does not have a gamepad mapping

2
glfw/glx_context.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
// GLFW 3.4 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

26
glfw/glx_context.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 GLX - www.glfw.org
// GLFW 3.4 GLX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -153,18 +153,18 @@ typedef struct _GLFWlibraryGLX
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
bool SGI_swap_control;
bool EXT_swap_control;
bool MESA_swap_control;
bool ARB_multisample;
bool ARB_framebuffer_sRGB;
bool EXT_framebuffer_sRGB;
bool ARB_create_context;
bool ARB_create_context_profile;
bool ARB_create_context_robustness;
bool EXT_create_context_es2_profile;
bool ARB_create_context_no_error;
bool ARB_context_flush_control;
bool SGI_swap_control;
bool EXT_swap_control;
bool MESA_swap_control;
bool ARB_multisample;
bool ARB_framebuffer_sRGB;
bool EXT_framebuffer_sRGB;
bool ARB_create_context;
bool ARB_create_context_profile;
bool ARB_create_context_robustness;
bool EXT_create_context_es2_profile;
bool ARB_create_context_no_error;
bool ARB_context_flush_control;
} _GLFWlibraryGLX;

2
glfw/ibus_glfw.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//

2
glfw/ibus_glfw.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//

2
glfw/init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>

4
glfw/input.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -549,7 +549,7 @@ const char* _glfwGetKeyName(int key)
case GLFW_KEY_KP_8: return "KEYPAD 8";
case GLFW_KEY_KP_9: return "KEYPAD 9";
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTPLY";
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTIPLY";
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";

2
glfw/internal.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

12
glfw/linux_joystick.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
// GLFW 3.4 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -144,10 +144,10 @@ static bool openJoystickDevice(const char* path)
char absBits[(ABS_CNT + 7) / 8] = {0};
struct input_id id;
if (ioctl(linjs.fd, EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
ioctl(linjs.fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
ioctl(linjs.fd, EVIOCGID, &id) < 0)
if (ioctl(linjs.fd, (int32_t)EVIOCGBIT(0, sizeof(evBits)), evBits) < 0 ||
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) < 0 ||
ioctl(linjs.fd, (int32_t)EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) < 0 ||
ioctl(linjs.fd, (int32_t)EVIOCGID, &id) < 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Linux: Failed to query input device: %s",
@@ -165,7 +165,7 @@ static bool openJoystickDevice(const char* path)
char name[256] = "";
if (ioctl(linjs.fd, EVIOCGNAME(sizeof(name)), name) < 0)
if (ioctl(linjs.fd, (int32_t)EVIOCGNAME(sizeof(name)), name) < 0)
strncpy(name, "Unknown", sizeof(name));
char guid[33] = "";

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Linux - www.glfw.org
// GLFW 3.4 Linux - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@@ -52,7 +52,7 @@ typedef struct _GLFWlibraryLinux
int inotify;
int watch;
regex_t regex;
bool dropped;
bool dropped;
} _GLFWlibraryLinux;

2
glfw/mappings.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
//

2
glfw/monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

2
glfw/nsgl_context.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 macOS - www.glfw.org
// GLFW 3.4 macOS - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
//

2
glfw/null_init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
//

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
//

2
glfw/null_monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

2
glfw/null_window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
// GLFW 3.4 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
// GLFW 3.4 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>

2
glfw/posix_thread.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

6
glfw/posix_thread.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -35,7 +35,7 @@
//
typedef struct _GLFWtlsPOSIX
{
bool allocated;
bool allocated;
pthread_key_t key;
} _GLFWtlsPOSIX;
@@ -44,7 +44,7 @@ typedef struct _GLFWtlsPOSIX
//
typedef struct _GLFWmutexPOSIX
{
bool allocated;
bool allocated;
pthread_mutex_t handle;
} _GLFWmutexPOSIX;

2
glfw/posix_time.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>

4
glfw/posix_time.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 POSIX - www.glfw.org
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
@@ -34,7 +34,7 @@
//
typedef struct _GLFWtimerPOSIX
{
bool monotonic;
bool monotonic;
uint64_t frequency;
} _GLFWtimerPOSIX;

2
glfw/vulkan.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>

2
glfw/window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 - www.glfw.org
// GLFW 3.4 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

2
glfw/wl_init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//

2
glfw/wl_monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//

2
glfw/wl_platform.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//

6
glfw/wl_window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 Wayland - www.glfw.org
// GLFW 3.4 Wayland - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
//
@@ -173,7 +173,7 @@ static void dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, in
* SCM_RIGHTS methods.
*
* posix_fallocate() is used to guarantee that disk space is available
* for the file at the given size. If disk space is insufficent, errno
* for the file at the given size. If disk space is insufficient, errno
* is set to ENOSPC. If posix_fallocate() is not supported, program may
* receive SIGBUS on accessing mmap()'ed file contents instead.
*/
@@ -1836,7 +1836,7 @@ static inline bool _glfwEnsureDataDevice(void) {
if (!_glfw.wl.dataDevice)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Cannot use clipboard, failed to create data device");
"Wayland: Cannot use clipboard, failed to create data device");
return false;
}
}

2
glfw/x11_init.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

2
glfw/x11_monitor.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

2
glfw/x11_platform.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>

6
glfw/x11_window.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 X11 - www.glfw.org
// GLFW 3.4 X11 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
@@ -78,7 +78,7 @@ handleEvents(double timeout) {
static bool
waitForX11Event(double timeout) {
// returns true iff there is X11 data waiting to be read, does not run watches and timers
// returns true if there is X11 data waiting to be read, does not run watches and timers
double end_time = glfwGetTime() + timeout;
while(true) {
if (timeout >= 0) {
@@ -2512,7 +2512,7 @@ _glfwDispatchX11Events(void) {
}
XFlush(_glfw.x11.display);
// XFlush can cause events to be queued, we dont use QueuedAfterFlush here
// XFlush can cause events to be queued, we don't use QueuedAfterFlush here
// as something might have inserted events into the queue, but we want to guarantee
// a flush.
dispatched += dispatch_x11_queued_events(XEventsQueued(_glfw.x11.display, QueuedAlready));

4
glfw/xkb_glfw.c vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//
@@ -434,7 +434,7 @@ glfw_xkb_key_from_ime(KeyEvent *ev, bool handled_by_ime, bool failed) {
}
static xkb_keycode_t last_handled_press_keycode = 0;
// We filter out release events that correspond to the last press event
// handled by the IME system. This wont fix the case of multiple key
// handled by the IME system. This won't fix the case of multiple key
// presses before a release, but is better than nothing. For that case
// you'd need to implement a ring buffer to store pending key presses.
xkb_keycode_t prev_handled_press = last_handled_press_keycode;

6
glfw/xkb_glfw.h vendored
View File

@@ -1,5 +1,5 @@
//========================================================================
// GLFW 3.3 XKB - www.glfw.org
// GLFW 3.4 XKB - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2018 Kovid Goyal <kovid@kovidgoyal.net>
//
@@ -67,8 +67,8 @@ typedef struct {
#ifdef _GLFW_X11
int32_t keyboard_device_id;
bool available;
bool detectable;
bool available;
bool detectable;
int majorOpcode;
int eventBase;
int errorBase;

View File

@@ -20,7 +20,7 @@ from ..tui.loop import Loop
from ..tui.operations import faint, styled
URL_PREFIXES = 'http https file ftp'.split()
HINT_ALPHABET = string.digits + string.ascii_lowercase
DEFAULT_HINT_ALPHABET = string.digits + string.ascii_lowercase
screen_size = screen_size_function()
@@ -34,21 +34,26 @@ class Mark:
@lru_cache(maxsize=2048)
def encode_hint(num):
def encode_hint(num, alphabet):
res = ''
d = len(HINT_ALPHABET)
d = len(alphabet)
while not res or num > 0:
num, i = divmod(num, d)
res = HINT_ALPHABET[i] + res
res = alphabet[i] + res
return res
def decode_hint(x):
return int(x, 36)
def decode_hint(x, alphabet=DEFAULT_HINT_ALPHABET):
base = len(alphabet)
index_map = {c: i for i, c in enumerate(alphabet)}
i = 0
for char in x:
i = i * base + index_map[char]
return i
def highlight_mark(m, text, current_input):
hint = encode_hint(m.index)
def highlight_mark(m, text, current_input, alphabet):
hint = encode_hint(m.index, alphabet)
if current_input and not hint.startswith(current_input):
return faint(text)
hint = hint[len(current_input):] or ' '
@@ -63,11 +68,11 @@ def highlight_mark(m, text, current_input):
)
def render(text, current_input, all_marks, ignore_mark_indices):
def render(text, current_input, all_marks, ignore_mark_indices, alphabet):
for mark in reversed(all_marks):
if mark.index in ignore_mark_indices:
continue
mtext = highlight_mark(mark, text[mark.start:mark.end], current_input)
mtext = highlight_mark(mark, text[mark.start:mark.end], current_input, alphabet)
text = text[:mark.start] + mtext + text[mark.end:]
text = text.replace('\0', '')
@@ -79,6 +84,7 @@ class Hints(Handler):
def __init__(self, text, all_marks, index_map, args):
self.text, self.index_map = text, index_map
self.alphabet = args.alphabet or DEFAULT_HINT_ALPHABET
self.all_marks = all_marks
self.ignore_mark_indices = set()
self.args = args
@@ -111,13 +117,13 @@ class Hints(Handler):
def on_text(self, text, in_bracketed_paste):
changed = False
for c in text:
if c in HINT_ALPHABET:
if c in self.alphabet:
self.current_input += c
changed = True
if changed:
matches = [
m for idx, m in self.index_map.items()
if encode_hint(idx).startswith(self.current_input)
if encode_hint(idx, self.alphabet).startswith(self.current_input)
]
if len(matches) == 1:
self.chosen.append(matches[0].text + self.match_suffix)
@@ -137,7 +143,7 @@ class Hints(Handler):
self.draw_screen()
elif key_event is enter_key and self.current_input:
try:
idx = decode_hint(self.current_input)
idx = decode_hint(self.current_input, self.alphabet)
self.chosen.append(self.index_map[idx].text + self.match_suffix)
self.ignore_mark_indices.add(idx)
except Exception:
@@ -164,7 +170,7 @@ class Hints(Handler):
def draw_screen(self):
if self.current_text is None:
self.current_text = render(self.text, self.current_input, self.all_marks, self.ignore_mark_indices)
self.current_text = render(self.text, self.current_input, self.all_marks, self.ignore_mark_indices, self.alphabet)
self.cmd.clear_screen()
self.write(self.current_text)
@@ -246,7 +252,7 @@ def run_loop(args, text, all_marks, index_map):
handler = Hints(text, all_marks, index_map, args)
loop.loop(handler)
if handler.chosen and loop.return_code == 0:
return {'match': handler.chosen, 'program': args.program,
return {'match': handler.chosen, 'programs': args.program,
'multiple_joiner': args.multiple_joiner,
'type': args.type}
raise SystemExit(loop.return_code)
@@ -333,10 +339,12 @@ def run(args, text):
# CLI {{{
OPTIONS = r'''
--program
default=default
type=list
What program to use to open matched text. Defaults to the default open program
for the operating system. Use a value of :file:`-` to paste the match into the
for the operating system. Use a value of :file:`-` to paste the match into the
terminal window instead. A value of :file:`@` will copy the match to the clipboard.
A value of :file:`default` will run the default open program. Can be specified
multiple times to run multiple programs.
--type
@@ -348,11 +356,11 @@ The type of text to search for.
--regex
default=(?m)^\s*(.+)\s*$
The regular expression to use when :option:`kitty +kitten hints --type`=regex.
If you specify a group in the regular expression only the group
will be matched. This allow you to match text ignoring a prefix/suffix, as
needed. The default expression matches lines. To match text over
multiple lines you should prefix the regular expression with :code:`(?ms)`,
which turns on MULTILINE and DOTALL modes for the regex engine.
The regular expression is in python syntax. If you specify a group in
the regular expression only the group will be matched. This allow you to match
text ignoring a prefix/suffix, as needed. The default expression matches lines.
To match text over multiple lines you should prefix the regular expression with
:code:`(?ms)`, which turns on MULTILINE and DOTALL modes for the regex engine.
--url-prefixes
@@ -362,7 +370,7 @@ Comma separated list of recognized URL prefixes.
--word-characters
Characters to consider as part of a word. In addition, all characters marked as
alpha-numeric in the unicode database will be considered as word characters.
alphanumeric in the unicode database will be considered as word characters.
Defaults to the select_by_word_characters setting from kitty.conf.
@@ -401,6 +409,15 @@ default=1
type=int
The offset (from zero) at which to start hint numbering. Note that only numbers
greater than or equal to zero are respected.
--alphabet
The list of characters to use for hints. The default is to use numbers and lowercase
English alphabets. Specify your preference as a string of characters. Note that
unless you specify the hints offset as zero the first match will be highlighted with
the second character you specify.
'''.format(','.join(sorted(URL_PREFIXES))).format
help_text = 'Select text from the screen using the keyboard. Defaults to searching for URLs.'
usage = ''
@@ -430,12 +447,11 @@ def main(args):
if items:
print('Extra command line arguments present: {}'.format(' '.join(items)), file=sys.stderr)
input(_('Press Enter to quit'))
return
return run(args, text)
def handle_result(args, data, target_window_id, boss):
program = data['program']
programs = data['programs'] or ('default',)
matches = tuple(filter(None, data['match']))
joiner = data['multiple_joiner']
try:
@@ -444,6 +460,7 @@ def handle_result(args, data, target_window_id, boss):
is_int = None
text_type = data['type']
@lru_cache()
def joined_text():
if is_int is not None:
try:
@@ -459,20 +476,21 @@ def handle_result(args, data, target_window_id, boss):
q = {'newline': '\n\r', 'space': ' '}.get(joiner, '')
return q.join(matches)
if program == '-':
w = boss.window_id_map.get(target_window_id)
if w is not None:
w.paste(joined_text())
elif program == '@':
set_clipboard_string(joined_text())
else:
cwd = None
w = boss.window_id_map.get(target_window_id)
if w is not None:
cwd = w.cwd_of_child
program = None if program == 'default' else program
for m in matches:
boss.open_url(m, program, cwd=cwd)
for program in programs:
if program == '-':
w = boss.window_id_map.get(target_window_id)
if w is not None:
w.paste(joined_text())
elif program == '@':
set_clipboard_string(joined_text())
else:
cwd = None
w = boss.window_id_map.get(target_window_id)
if w is not None:
cwd = w.cwd_of_child
program = None if program == 'default' else program
for m in matches:
boss.open_url(m, program, cwd=cwd)
handle_result.type_of_input = 'screen'

View File

@@ -194,11 +194,13 @@ def process(path, args, is_tempfile):
available_height = args.place.height * (ss.height / ss.rows) if args.place else 10 * m.height
needs_scaling = m.width > available_width or m.height > available_height
needs_scaling = needs_scaling or args.scale_up
file_removed = False
if m.fmt == 'png' and not needs_scaling:
outfile = path
transmit_mode = 't' if is_tempfile else 'f'
fmt = 100
width, height = m.width, m.height
file_removed = transmit_mode == 't'
else:
fmt = 24 if m.mode == 'rgb' else 32
transmit_mode = 't'
@@ -206,6 +208,7 @@ def process(path, args, is_tempfile):
show(outfile, width, height, fmt, transmit_mode, align=args.align, place=args.place)
if not args.place:
print() # ensure cursor is on a new line
return file_removed
def scan(d):
@@ -272,6 +275,7 @@ usage = 'image-file-or-url-or-directory ...'
def process_single_item(item, args, url_pat=None, maybe_dir=True):
is_tempfile = False
file_removed = False
try:
if isinstance(item, bytes):
tf = NamedTemporaryFile(prefix='stdin-image-data-', delete=False)
@@ -287,7 +291,7 @@ def process_single_item(item, args, url_pat=None, maybe_dir=True):
raise SystemExit('Failed to download image at URL: {} with error: {}'.format(item, e))
item = tf.name
is_tempfile = True
process(item, args, is_tempfile)
file_removed = process(item, args, is_tempfile)
elif item.lower().startswith('file://'):
from urllib.parse import urlparse
from urllib.request import url2pathname
@@ -297,15 +301,15 @@ def process_single_item(item, args, url_pat=None, maybe_dir=True):
else:
item = item.path
item = url2pathname(item)
process(item, args, is_tempfile)
file_removed = process(item, args, is_tempfile)
else:
if maybe_dir and os.path.isdir(item):
for (x, mt) in scan(item):
process_single_item(x, args, url_pat=None, maybe_dir=False)
else:
process(item, args, is_tempfile)
file_removed = process(item, args, is_tempfile)
finally:
if is_tempfile:
if is_tempfile and not file_removed:
os.remove(item)

View File

@@ -95,7 +95,7 @@ def parse_ssh_args(args):
def quote(x):
# we have to escape unbalanced quotes and other unparseable
# we have to escape unbalanced quotes and other unparsable
# args as they will break the shell script
# But we do not want to quote things like * or 'echo hello'
# See https://github.com/kovidgoyal/kitty/issues/1787

View File

@@ -249,7 +249,8 @@ class ImageManager:
cmd, standard_b64encode(rgba_path.encode(fsenc)))
else:
import zlib
data = open(rgba_path, 'rb').read()
with open(rgba_path, 'rb') as f:
data = f.read()
cmd['S'] = len(data)
data = zlib.compress(data)
cmd['o'] = 'z'

File diff suppressed because one or more lines are too long

View File

@@ -619,12 +619,12 @@ class Boss:
if tm is not None:
tm.update_tab_bar_data()
def on_drop(self, os_window_id, paths):
def on_drop(self, os_window_id, strings):
tm = self.os_window_map.get(os_window_id)
if tm is not None:
w = tm.active_window
if w is not None:
w.paste('\n'.join(paths))
w.paste('\n'.join(strings))
def on_os_window_closed(self, os_window_id, viewport_width, viewport_height):
self.cached_values['window-size'] = viewport_width, viewport_height
@@ -716,7 +716,9 @@ class Boss:
},
cwd=w.cwd_of_child,
overlay_for=w.id
))
),
copy_colors_from=w
)
overlay_window.action_on_close = partial(self.on_kitten_finish, w.id, end_kitten)
return overlay_window

View File

@@ -114,7 +114,7 @@ vec3 choose_color(float q, vec3 a, vec3 b) {
return mix(b, a, q);
}
float are_integers_equal(float a, float b) { // return 1 iff equal otherwise 0
float are_integers_equal(float a, float b) { // return 1 if equal otherwise 0
float delta = abs(a - b); // delta can be 0, 1 or larger
return step(delta, 0.5); // 0 if 0.5 < delta else 1
}

View File

@@ -518,7 +518,7 @@ update_window_title(Window *w, OSWindow *os_window) {
Py_INCREF(os_window->window_title);
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
#ifdef __APPLE__
if (os_window->is_focused && OPT(macos_show_window_title_in_menubar)) cocoa_update_menu_bar_title(w->title);
if (os_window->is_focused && (OPT(macos_show_window_title_in) & MENUBAR)) cocoa_update_menu_bar_title(w->title);
#endif
return true;
}

View File

@@ -30,14 +30,16 @@ if is_macos:
else:
def cmdline_of_process(pid):
return list(filter(None, open('/proc/{}/cmdline'.format(pid), 'rb').read().decode('utf-8').split('\0')))
with open('/proc/{}/cmdline'.format(pid), 'rb') as f:
return list(filter(None, f.read().decode('utf-8').split('\0')))
def cwd_of_process(pid):
ans = '/proc/{}/cwd'.format(pid)
return os.path.realpath(ans)
def _environ_of_process(pid):
return open('/proc/{}/environ'.format(pid), 'rb').read().decode('utf-8')
with open('/proc/{}/environ'.format(pid), 'rb') as f:
return f.read().decode('utf-8')
def process_group_map():
ans = defaultdict(list)
@@ -47,7 +49,8 @@ else:
except Exception:
continue
try:
raw = open('/proc/' + x + '/stat', 'rb').read().decode('utf-8')
with open('/proc/' + x + '/stat', 'rb') as f:
raw = f.read().decode('utf-8')
except EnvironmentError:
continue
try:
@@ -118,6 +121,10 @@ def remove_cloexec(fd):
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
def remove_blocking(fd):
os.set_blocking(fd, False)
def default_env():
try:
return default_env.env
@@ -132,6 +139,13 @@ def set_default_env(val=None):
default_env.env = env
def openpty():
master, slave = os.openpty() # Note that master and slave are in blocking mode
remove_cloexec(slave)
fast_data_types.set_iutf8_fd(master, True)
return master, slave
class Child:
child_fd = pid = None
@@ -166,7 +180,7 @@ class Child:
env['TERM'] = self.opts.term
env['COLORTERM'] = 'truecolor'
if self.cwd:
# needed incase cwd is a symlink, in which case shells
# needed in case cwd is a symlink, in which case shells
# can use it to display the current directory name rather
# than the resolved path
env['PWD'] = self.cwd
@@ -178,9 +192,7 @@ class Child:
if self.forked:
return
self.forked = True
master, slave = os.openpty() # Note that master and slave are in blocking mode
remove_cloexec(slave)
fast_data_types.set_iutf8_fd(master, True)
master, slave = openpty()
stdin, self.stdin = self.stdin, None
ready_read_fd, ready_write_fd = os.pipe()
remove_cloexec(ready_read_fd)
@@ -194,8 +206,20 @@ class Child:
argv = list(self.argv)
exe = argv[0]
if is_macos and exe == shell_path:
# Some macOS machines need the shell to have argv[0] prefixed by
# hyphen, see https://github.com/kovidgoyal/kitty/issues/247
# bash will only source ~/.bash_profile if it detects it is a login
# shell (see the invocation section of the bash man page), which it
# does if argv[0] is prefixed by a hyphen see
# https://github.com/kovidgoyal/kitty/issues/247
# it is apparently common to use ~/.bash_profile instead of the
# more correct ~/.bashrc on macOS to setup env vars, so if
# the default shell is used prefix argv[0] by '-'
#
# it is arguable whether graphical terminals should start shells
# in login mode in general, there are at least a few Linux users
# that also make this incorrect assumption, see for example
# https://github.com/kovidgoyal/kitty/issues/1870
# xterm, urxvt, konsole and gnome-terminal do not do it in my
# testing.
argv[0] = ('-' + exe.split('/')[-1])
pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd)
os.close(slave)
@@ -206,7 +230,7 @@ class Child:
fast_data_types.thread_write(stdin_write_fd, stdin)
os.close(ready_read_fd)
self.terminal_ready_fd = ready_write_fd
fcntl.fcntl(self.child_fd, fcntl.F_SETFL, fcntl.fcntl(self.child_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
remove_blocking(self.child_fd)
return pid
def mark_terminal_ready(self):

View File

@@ -728,9 +728,11 @@ def create_opts(args, debug_config=False, accumulate_bad_lines=None):
import subprocess
print(' '.join(subprocess.check_output(['sw_vers']).decode('utf-8').splitlines()).strip())
if os.path.exists('/etc/issue'):
print(open('/etc/issue', encoding='utf-8', errors='replace').read().strip())
with open('/etc/issue', encoding='utf-8', errors='replace') as f:
print(f.read().strip())
if os.path.exists('/etc/lsb-release'):
print(open('/etc/lsb-release', encoding='utf-8', errors='replace').read().strip())
with open('/etc/lsb-release', encoding='utf-8', errors='replace') as f:
print(f.read().strip())
config = tuple(x for x in config if os.path.exists(x))
if config:
print(green('Loaded config files:'), ', '.join(config))

View File

@@ -157,7 +157,8 @@ def replay(raw):
def main(path):
raw = open(path).read()
with open(path) as f:
raw = f.read()
replay(raw)
with suppress(EOFError, KeyboardInterrupt):
input()

View File

@@ -999,7 +999,7 @@ def cmd_set_background_opacity(global_opts, opts, args):
def set_background_opacity(boss, window, payload):
if not boss.opts.dynamic_background_opacity:
raise OpacityError('You must turn on the dynamic_background_opacity option in kitty.conf to be able to set background opacity')
windows = windows_for_payload(payload)
windows = windows_for_payload(boss, window, payload)
for os_window_id in {w.os_window_id for w in windows}:
boss._set_os_window_background_opacity(os_window_id, payload['opacity'])
# }}}

View File

@@ -477,6 +477,17 @@ cleanup() {
} // autoreleasepool
}
void
cocoa_hide_window_title(void *w)
{
@autoreleasepool {
NSWindow *window = (NSWindow*)w;
[window setTitleVisibility:NSWindowTitleHidden];
} // autoreleasepool
}
static PyMethodDef module_methods[] = {
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
{"cocoa_set_new_window_trigger", (PyCFunction)cocoa_set_new_window_trigger, METH_VARARGS, ""},

View File

@@ -98,6 +98,15 @@ update_ansi_color_table(ColorProfile *self, PyObject *val) {
Py_RETURN_NONE;
}
void
copy_color_profile(ColorProfile *dest, ColorProfile *src) {
memcpy(dest->color_table, src->color_table, sizeof(dest->color_table));
memcpy(dest->orig_color_table, src->orig_color_table, sizeof(dest->color_table));
memcpy(&dest->configured, &src->configured, sizeof(dest->configured));
memcpy(&dest->overridden, &src->overridden, sizeof(dest->overridden));
dest->dirty = true;
}
static PyObject*
patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; PyObject *cursor_text_color;

View File

@@ -177,12 +177,11 @@ def load_config(Options, defaults, parse_config, merge_configs, *paths, override
if not path:
continue
try:
f = open(path, encoding='utf-8', errors='replace')
with open(path, encoding='utf-8', errors='replace') as f:
vals = parse_config(f)
except FileNotFoundError:
continue
with f:
vals = parse_config(f)
ans = merge_configs(ans, vals)
ans = merge_configs(ans, vals)
if overrides is not None:
vals = parse_config(overrides)
ans = merge_configs(ans, vals)

View File

@@ -263,6 +263,21 @@ class KeyDefinition:
self.trigger = defines.resolve_key_mods(kitty_mod, self.trigger[0]), self.trigger[1], self.trigger[2]
self.rest = tuple((defines.resolve_key_mods(kitty_mod, mods), is_native, key) for mods, is_native, key in self.rest)
def resolve_kitten_aliases(self, aliases):
if not self.action.args:
return
kitten = self.action.args[0]
rest = self.action.args[1] if len(self.action.args) > 1 else ''
changed = False
for key, expanded in aliases.items():
if key == kitten:
changed = True
kitten = expanded[0]
if len(expanded) > 1:
rest = expanded[1] + ' ' + rest
if changed:
self.action = self.action._replace(args=[kitten + (' ' + rest).rstrip()])
def parse_key(val, key_definitions):
parts = val.split(maxsplit=1)
@@ -385,6 +400,13 @@ def handle_symbol_map(key, val, ans):
ans['symbol_map'].update(parse_symbol_map(val))
@special_handler
def handle_kitten_alias(key, val, ans):
parts = val.split(maxsplit=2)
if len(parts) >= 2:
ans['kitten_aliases'][parts[0]] = parts[1:]
@special_handler
def handle_send_text(key, val, ans):
# For legacy compatibility
@@ -407,6 +429,25 @@ def handle_deprecated_hide_window_decorations_aliases(key, val, ans):
ans['hide_window_decorations'] = True
@deprecated_handler('macos_show_window_title_in_menubar')
def handle_deprecated_macos_show_window_title_in_menubar_alias(key, val, ans):
if not hasattr(handle_deprecated_macos_show_window_title_in_menubar_alias, key):
handle_deprecated_macos_show_window_title_in_menubar_alias.key = True
log_error('The option {} is deprecated. Use macos_show_window_title_in menubar instead.'.format(key))
macos_show_window_title_in = ans.get('macos_show_window_title_in', 'all')
if to_bool(val):
if macos_show_window_title_in == 'none':
macos_show_window_title_in = 'menubar'
elif macos_show_window_title_in == 'window':
macos_show_window_title_in = 'all'
else:
if macos_show_window_title_in == 'all':
macos_show_window_title_in = 'window'
elif macos_show_window_title_in == 'menubar':
macos_show_window_title_in = 'none'
ans['macos_show_window_title_in'] = macos_show_window_title_in
def expandvars(val, env):
def sub(m):
@@ -444,7 +485,7 @@ def option_names_for_completion():
def parse_config(lines, check_keys=True, accumulate_bad_lines=None):
ans = {'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], 'env': {}}
ans = {'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], 'env': {}, 'kitten_aliases': {}}
parse_config_base(
lines,
defaults,
@@ -594,8 +635,11 @@ def finalize_keys(opts):
defns = []
else:
defns.append(d)
kitten_aliases = opts.kitten_aliases
for d in defns:
d.resolve(opts.kitty_mod)
if kitten_aliases and d.action.func == 'kitten':
d.resolve_kitten_aliases(kitten_aliases)
keymap = {}
sequence_map = {}

View File

@@ -112,7 +112,9 @@ Here, the key name for the :kbd:`A` key is :kbd:`0x61` and you can use it with::
to map :kbd:`ctrl+a` to something.
You can use the special action :code:`no_op` to unmap a keyboard shortcut that is
assigned in the default configuration.
assigned in the default configuration::
map kitty_mod+space no_op
You can combine multiple actions to be triggered by a single shortcut, using the
syntax below::
@@ -461,7 +463,7 @@ The modifiers to override mouse selection even when a terminal application has g
o('select_by_word_characters', ':@-./_~?&=%+#', long_text=_('''
Characters considered part of a word when double clicking. In addition to these characters
any character that is marked as an alpha-numeric character in the unicode
any character that is marked as an alphanumeric character in the unicode
database will be matched.'''))
o('click_interval', -1.0, option_type=float, long_text=_('''
@@ -964,9 +966,15 @@ o('macos_traditional_fullscreen', False, long_text=_('''
Use the traditional full-screen transition, that is faster, but less pretty.
'''))
o('macos_show_window_title_in_menubar', True, long_text=_('''
Show the title of the currently active window in the macOS
menu-bar, making use of otherwise wasted space.'''))
o('macos_show_window_title_in', 'all', option_type=choices('all', 'window', 'menubar', 'none'), long_text=_('''
Show or hide the window title in the macOS window or menu-bar.
A value of :code:`window` will show the title of the currently
active window at the top of the macOS window. A value of
:code:`menubar` will show the title of the currently active window
in the macOS menu-bar, making use of otherwise wasted space.
:code:`all` will show the title everywhere and :code:`none`
hides the title in the window and the menu-bar.
'''))
# Disabled by default because of https://github.com/kovidgoyal/kitty/issues/794
o('macos_custom_beam_cursor', False, long_text=_('''
@@ -992,6 +1000,14 @@ o('clear_all_shortcuts', False, long_text=_('''
You can have kitty remove all shortcut definition seen up to this point. Useful, for
instance, to remove the default shortcuts.'''))
o('kitten_alias', 'hints hints --hints-offset=0', add_to_default=False, long_text=_('''
You can create aliases for kitten names, this allows overriding the defaults
for kitten options and can also be used to shorten repeated mappings of the same
kitten with a specific group of options. For example, the above alias
changes the default value of :option:`kitty +kitten hints --hints-offset`
to zero for all mappings, including the builtin ones.
'''))
g('shortcuts.clipboard') # {{{
k('copy_to_clipboard', 'kitty_mod+c', 'copy_to_clipboard', _('Copy to clipboard'), long_text=_('''
There is also a :code:`copy_or_interrupt` action that can be optionally mapped to :kbd:`Ctrl+c`.

View File

@@ -9,7 +9,7 @@ from collections import namedtuple
from contextlib import suppress
appname = 'kitty'
version = (0, 14, 3)
version = (0, 14, 4)
str_version = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos = 'darwin' in _plat

View File

@@ -530,6 +530,14 @@ static PyMethodDef methods[] = {
{NULL} /* Sentinel */
};
const char*
postscript_name_for_face(const PyObject *face_) {
const CTFace *self = (const CTFace*)face_;
if (self->postscript_name) return PyUnicode_AsUTF8(self->postscript_name);
return "";
}
static PyObject *
repr(CTFace *self) {
char buf[1024] = {0};

View File

@@ -53,6 +53,7 @@ typedef enum { DISABLE_LIGATURES_NEVER, DISABLE_LIGATURES_CURSOR, DISABLE_LIGATU
typedef enum MouseTrackingModes { NO_TRACKING, BUTTON_MODE, MOTION_MODE, ANY_MODE } MouseTrackingMode;
typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL} MouseTrackingProtocol;
typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
#define MAX_CHILDREN 512
#define BLANK_CHAR 0
@@ -277,6 +278,7 @@ Cursor* alloc_cursor(void);
LineBuf* alloc_linebuf(unsigned int, unsigned int);
HistoryBuf* alloc_historybuf(unsigned int, unsigned int, unsigned int);
ColorProfile* alloc_color_profile(void);
void copy_color_profile(ColorProfile*, ColorProfile*);
PyObject* create_256_color_table(void);
PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *);
PyObject* parse_bytes(PyObject UNUSED *, PyObject *);
@@ -286,7 +288,7 @@ void cursor_copy_to(Cursor *src, Cursor *dest);
void cursor_reset_display_attrs(Cursor*);
void cursor_from_sgr(Cursor *self, unsigned int *params, unsigned int count);
void apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, unsigned int *params, unsigned int count);
const char* cell_as_sgr(GPUCell *, GPUCell *);
const char* cell_as_sgr(const GPUCell *, const GPUCell *);
const char* cursor_as_sgr(const Cursor *);
double monotonic(void);

2
kitty/emoji.h generated
View File

@@ -1,4 +1,4 @@
// unicode data, built from the unicode standard on: 2019-03-06
// unicode data, built from the unicode standard on: 2019-08-02
// see gen-wcwidth.py
#pragma once
#include "data-types.h"

View File

@@ -58,9 +58,10 @@ typedef struct {
static hb_buffer_t *harfbuzz_buffer = NULL;
static hb_feature_t no_calt_feature = {0};
static hb_feature_t hb_features[3] = {{0}};
static char_type shape_buffer[4096] = {0};
static size_t max_texture_size = 1024, max_array_len = 1024;
typedef enum { LIGA_FEATURE, DLIG_FEATURE, CALT_FEATURE } HBFeature;
typedef struct {
char_type left, right;
@@ -76,6 +77,8 @@ typedef struct {
PyObject *face;
// Map glyphs to sprite map co-ords
SpritePosition sprite_map[1024];
hb_feature_t hb_features[8];
size_t num_hb_features;
SpecialGlyphCache special_glyph_cache[SPECIAL_GLYPH_CACHE_SIZE];
bool bold, italic, emoji_presentation;
} Font;
@@ -345,11 +348,21 @@ desc_to_face(PyObject *desc, FONTS_DATA_HANDLE fg) {
return ans;
}
static inline void
copy_hb_feature(Font *f, HBFeature which) {
memcpy(f->hb_features + f->num_hb_features++, hb_features + which, sizeof(hb_features[0]));
}
static inline bool
init_font(Font *f, PyObject *face, bool bold, bool italic, bool emoji_presentation) {
f->face = face; Py_INCREF(f->face);
f->bold = bold; f->italic = italic; f->emoji_presentation = emoji_presentation;
f->num_hb_features = 0;
const char *psname = postscript_name_for_face(face);
if (strstr(psname, "NimbusMonoPS-") == psname) {
copy_hb_feature(f, LIGA_FEATURE); copy_hb_feature(f, DLIG_FEATURE);
}
copy_hb_feature(f, CALT_FEATURE);
return true;
}
@@ -484,6 +497,20 @@ load_fallback_font(FontGroup *fg, CPUCell *cell, bool bold, bool italic, bool em
Font *af = &fg->fonts[ans];
if (!init_font(af, face, bold, italic, emoji_presentation)) fatal("Out of memory");
Py_DECREF(face);
if (!has_cell_text(af, cell)) {
if (global_state.debug_font_fallback) {
printf("The font chosen by the OS for the text: ");
printf("U+%x ", cell->ch);
for (unsigned i = 0; i < arraysz(cell->cc_idx) && cell->cc_idx[i]; i++) {
printf("U+%x ", codepoint_for_mark(cell->cc_idx[i]));
}
printf("is ");
PyObject_Print(af->face, stdout, 0);
printf(" but it does not actually contain glyphs for that text\n");
}
del_font(af);
return MISSING_FONT;
}
fg->fallback_fonts_count++;
fg->fonts_count++;
return ans;
@@ -714,7 +741,7 @@ num_codepoints_in_cell(CPUCell *cell) {
}
static inline void
shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb_font_t *font, bool disable_ligature) {
shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb_font_t *font, Font *fobj, bool disable_ligature) {
if (group_state.groups_capacity <= 2 * num_cells) {
group_state.groups_capacity = MAX(128u, 2 * num_cells); // avoid unnecessary reallocs
group_state.groups = realloc(group_state.groups, sizeof(Group) * group_state.groups_capacity);
@@ -739,11 +766,7 @@ shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb
group_state.last_gpu_cell = first_gpu_cell + (num_cells ? num_cells - 1 : 0);
load_hb_buffer(first_cpu_cell, first_gpu_cell, num_cells);
if (disable_ligature) {
hb_shape(font, harfbuzz_buffer, &no_calt_feature, 1);
} else {
hb_shape(font, harfbuzz_buffer, NULL, 0);
}
hb_shape(font, harfbuzz_buffer, fobj->hb_features, fobj->num_hb_features - (disable_ligature ? 0 : 1));
unsigned int info_length, positions_length;
group_state.info = hb_buffer_get_glyph_infos(harfbuzz_buffer, &info_length);
@@ -814,7 +837,7 @@ check_cell_consumed(CellData *cell_data, CPUCell *last_cpu_cell) {
static inline void
shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, Font *font, bool disable_ligature) {
shape(first_cpu_cell, first_gpu_cell, num_cells, harfbuzz_font_for_face(font->face), disable_ligature);
shape(first_cpu_cell, first_gpu_cell, num_cells, harfbuzz_font_for_face(font->face), font, disable_ligature);
#if 0
static char dbuf[1024];
// You can also generate this easily using hb-shape --show-extents --cluster-level=1 --shapers=ot /path/to/font/file text
@@ -989,6 +1012,8 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
if (face == NULL) return NULL;
font = calloc(1, sizeof(Font));
font->face = face;
font->hb_features[0] = hb_features[CALT_FEATURE];
font->num_hb_features = 1;
} else {
FontGroup *fg = font_groups;
font = fg->fonts + fg->medium_font_idx;
@@ -1414,12 +1439,15 @@ init_fonts(PyObject *module) {
harfbuzz_buffer = hb_buffer_create();
if (harfbuzz_buffer == NULL || !hb_buffer_allocation_successful(harfbuzz_buffer) || !hb_buffer_pre_allocate(harfbuzz_buffer, 2048)) { PyErr_NoMemory(); return false; }
hb_buffer_set_cluster_level(harfbuzz_buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
#define feature_str "-calt"
if (!hb_feature_from_string(feature_str, sizeof(feature_str) - 1, &no_calt_feature)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to create -calt harfbuzz feature");
return false;
}
#undef feature_str
#define create_feature(feature, where) {\
if (!hb_feature_from_string(feature, sizeof(feature) - 1, &hb_features[where])) { \
PyErr_SetString(PyExc_RuntimeError, "Failed to create " feature " harfbuzz feature"); \
return false; \
}}
create_feature("-liga", LIGA_FEATURE);
create_feature("-dlig", DLIG_FEATURE);
create_feature("-calt", CALT_FEATURE);
#undef create_feature
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
current_send_sprite_to_gpu = send_sprite_to_gpu;
return true;

View File

@@ -31,6 +31,7 @@ PyObject* create_fallback_face(PyObject *base_face, CPUCell* cell, bool bold, bo
PyObject* specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE);
PyObject* face_from_path(const char *path, int index, FONTS_DATA_HANDLE);
PyObject* face_from_descriptor(PyObject*, FONTS_DATA_HANDLE);
const char* postscript_name_for_face(const PyObject*);
void sprite_tracker_current_layout(FONTS_DATA_HANDLE data, unsigned int *x, unsigned int *y, unsigned int *z);
void render_alpha_mask(uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *dest_rect, size_t src_stride, size_t dest_stride);

View File

@@ -272,6 +272,13 @@ repr(Face *self) {
}
const char*
postscript_name_for_face(const PyObject *face_) {
const Face *self = (const Face*)face_;
const char *ps_name = FT_Get_Postscript_Name(self->face);
return ps_name ? ps_name : "";
}
static inline unsigned int
calc_cell_width(Face *self) {
unsigned int ans = 0;

2
kitty/glfw-wrapper.h generated
View File

@@ -81,7 +81,7 @@
*
* The naming of the key codes follow these rules:
* - The US keyboard layout is used
* - Names of printable alpha-numeric characters are used (e.g. "A", "R",
* - Names of printable alphanumeric characters are used (e.g. "A", "R",
* "3", etc.)
* - For non-alphanumeric characters, Unicode:ish names are used (e.g.
* "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not

View File

@@ -12,6 +12,7 @@
extern bool cocoa_make_window_resizable(void *w, bool);
extern void cocoa_focus_window(void *w);
extern void cocoa_create_global_menu(void);
extern void cocoa_hide_window_title(void *w);
extern void cocoa_set_activation_policy(bool);
extern void cocoa_set_titlebar_color(void *w, color_type color);
extern bool cocoa_alt_option_key_pressed(unsigned long);
@@ -43,10 +44,20 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) {
if (fw == window->viewport_width && fh == window->viewport_height && w == window->window_width && h == window->window_height) {
return; // no change, ignore
}
if (fw / w > 5 || fh / h > 5 || fw < min_width || fh < min_height || fw < w || fh < h) {
if (w <= 0 || h <= 0 || fw / w > 5 || fh / h > 5 || fw < min_width || fh < min_height || fw < w || fh < h) {
log_error("Invalid geometry ignored: framebuffer: %dx%d window: %dx%d\n", fw, fh, w, h);
if (!window->viewport_updated_at_least_once) {
window->viewport_width = min_width; window->viewport_height = min_height;
window->window_width = min_width; window->window_height = min_height;
window->viewport_x_ratio = 1; window->viewport_y_ratio = 1;
window->viewport_size_dirty = true;
if (notify_boss) {
call_boss(on_window_resize, "KiiO", window->id, window->viewport_width, window->viewport_height, Py_False);
}
}
return;
}
window->viewport_updated_at_least_once = true;
window->viewport_width = fw; window->viewport_height = fh;
double xr = window->viewport_x_ratio, yr = window->viewport_y_ratio;
window->viewport_x_ratio = w > 0 ? (double)window->viewport_width / (double)w : xr;
@@ -58,8 +69,8 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) {
window->viewport_size_dirty = true;
window->viewport_width = MAX(window->viewport_width, min_width);
window->viewport_height = MAX(window->viewport_height, min_height);
window->window_width = MAX(w, 100);
window->window_height = MAX(h, 100);
window->window_width = MAX(w, min_width);
window->window_height = MAX(h, min_height);
if (notify_boss) {
call_boss(on_window_resize, "KiiO", window->id, window->viewport_width, window->viewport_height, dpi_changed ? Py_True : Py_False);
}
@@ -308,13 +319,13 @@ window_focus_callback(GLFWwindow *w, int focused) {
}
static void
drop_callback(GLFWwindow *w, int count, const char **paths) {
drop_callback(GLFWwindow *w, int count, const char **strings) {
if (!set_callback_window(w)) return;
PyObject *p = PyTuple_New(count);
if (p) {
for (int i = 0; i < count; i++) PyTuple_SET_ITEM(p, i, PyUnicode_FromString(paths[i]));
WINDOW_CALLBACK(on_drop, "O", p);
Py_CLEAR(p);
PyObject *s = PyTuple_New(count);
if (s) {
for (int i = 0; i < count; i++) PyTuple_SET_ITEM(s, i, PyUnicode_FromString(strings[i]));
WINDOW_CALLBACK(on_drop, "O", s);
Py_CLEAR(s);
request_tick_callback();
}
global_state.callback_os_window = NULL;
@@ -636,8 +647,12 @@ create_os_window(PyObject UNUSED *self, PyObject *args) {
glfwSetKeyboardCallback(glfw_window, key_callback);
glfwSetDropCallback(glfw_window, drop_callback);
#ifdef __APPLE__
if (glfwGetCocoaWindow) cocoa_make_window_resizable(glfwGetCocoaWindow(glfw_window), OPT(macos_window_resizable));
else log_error("Failed to load glfwGetCocoaWindow");
if (glfwGetCocoaWindow) {
if (!(OPT(macos_show_window_title_in) & WINDOW)) {
cocoa_hide_window_title(glfwGetCocoaWindow(glfw_window));
}
cocoa_make_window_resizable(glfwGetCocoaWindow(glfw_window), OPT(macos_window_resizable));
} else log_error("Failed to load glfwGetCocoaWindow");
#endif
double now = monotonic();
w->is_focused = true;

View File

@@ -179,6 +179,7 @@ pagerhist_push(HistoryBuf *self) {
PagerHistoryBuf *ph = self->pagerhist;
if (!ph) return;
bool truncated;
const GPUCell *prev_cell = NULL;
Line l = {.xnum=self->xnum};
init_line(self, self->start_of_data, &l);
#define EXPAND_IF_FULL(sz) { \
@@ -193,7 +194,7 @@ pagerhist_push(HistoryBuf *self) {
ph->buffer[ph->end++] = '\n';
}
while(sz < ph->maxsz - 2) {
size_t num = line_as_ansi(&l, ph->buffer + ph->end, ph->bufsize - ph->end - 2, &truncated);
size_t num = line_as_ansi(&l, ph->buffer + ph->end, ph->bufsize - ph->end - 2, &truncated, &prev_cell);
if (!truncated) {
ph->end += num;
ph->buffer[ph->end++] = '\r';
@@ -270,12 +271,13 @@ as_ansi(HistoryBuf *self, PyObject *callback) {
static Py_UCS4 t[5120];
Line l = {.xnum=self->xnum};
bool truncated;
const GPUCell *prev_cell = NULL;
for(unsigned int i = 0; i < self->count; i++) {
init_line(self, i, &l);
if (i < self->count - 1) {
l.continued = *attrptr(self, index_of(self, i + 1)) & CONTINUED_MASK;
} else l.continued = false;
index_type num = line_as_ansi(&l, t, 5120, &truncated);
index_type num = line_as_ansi(&l, t, 5120, &truncated, &prev_cell);
if (!(l.continued) && num < 5119) t[num++] = 10; // 10 = \n
PyObject *ans = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, t, num);
if (ans == NULL) return PyErr_NoMemory();

8
kitty/key_encoding.py generated
View File

@@ -129,7 +129,8 @@ ENCODING = {
'Y': 'q',
'Z': 'r',
'PLUS': 'Bi',
'UNDERSCORE': 'Bj'
'UNDERSCORE': 'Bj',
'MENU': 'Bk'
}
KEY_MAP = {
32: 'A',
@@ -252,7 +253,8 @@ KEY_MAP = {
344: 'Be',
345: 'Bf',
346: 'Bg',
347: 'Bh'
347: 'Bh',
348: 'Bk'
}
# END_ENCODING }}}
@@ -296,7 +298,7 @@ def update_encoding():
for k in sorted(keys, key=lambda k: getattr(defines, k)):
val = getattr(defines, k)
name = symbolic_name(k)
if val < defines.GLFW_KEY_LAST and val != defines.GLFW_KEY_UNKNOWN:
if val <= defines.GLFW_KEY_LAST and name != 'LAST' and val != defines.GLFW_KEY_UNKNOWN:
if name not in ans:
ans[name] = encode(i)
i += 1

View File

@@ -289,12 +289,7 @@ def shortcut_matches(s, mods, key, scancode):
return s[0] & 0b1111 == mods & 0b1111 and s[2] == q
def generate_key_table():
# To run this, use: python3 . +runpy "from kitty.keys import *; generate_key_table()"
import os
from functools import partial
f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys.h'), 'w')
w = partial(print, file=f)
def generate_key_table_impl(w):
w('// auto-generated from keys.py, do not edit!')
w('#pragma once')
w('#include <stddef.h>')
@@ -389,3 +384,12 @@ def generate_key_table():
ind('return NULL;')
i -= 1
w('}')
def generate_key_table():
# To run this, use: python3 . +runpy "from kitty.keys import *; generate_key_table()"
import os
from functools import partial
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys.h'), 'w') as f:
w = partial(print, file=f)
generate_key_table_impl(w)

View File

@@ -398,16 +398,17 @@ as_ansi(LineBuf *self, PyObject *callback) {
// remove trailing empty lines
index_type ylimit = self->ynum - 1;
bool truncated;
const GPUCell *prev_cell = NULL;
do {
init_line(self, (&l), self->line_map[ylimit]);
if (line_as_ansi(&l, t, 5120, &truncated) != 0) break;
if (line_as_ansi(&l, t, 5120, &truncated, &prev_cell) != 0) break;
ylimit--;
} while(ylimit > 0);
for(index_type i = 0; i <= ylimit; i++) {
l.continued = ((i < self->ynum - 1) ? self->line_attrs[i+1] : self->line_attrs[i]) & CONTINUED_MASK;
init_line(self, (&l), self->line_map[i]);
index_type num = line_as_ansi(&l, t, 5120, &truncated);
index_type num = line_as_ansi(&l, t, 5120, &truncated, &prev_cell);
if (!(l.continued) && num < 5119) t[num++] = 10; // 10 = \n
PyObject *ans = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, t, num);
if (ans == NULL) return PyErr_NoMemory();

View File

@@ -258,7 +258,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, bool *truncated) {
line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen, bool *truncated, const GPUCell** prev_cell) {
#define WRITE_SGR(val) { if (!write_sgr(val, buf, buflen, &i)) { *truncated = true; return i; } }
#define WRITE_CH(val) if (i > buflen - 1) { *truncated = true; return i; } buf[i++] = val;
@@ -267,8 +267,9 @@ line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen, bool *truncated) {
if (limit == 0) return 0;
char_type previous_width = 0;
GPUCell blank_cell = { 0 };
GPUCell *cell, *prev_cell = &blank_cell;
static const GPUCell blank_cell = { 0 };
GPUCell *cell;
if (*prev_cell == NULL) *prev_cell = &blank_cell;
for (index_type pos=0; pos < limit; pos++) {
char_type ch = self->cpu_cells[pos].ch;
@@ -279,13 +280,13 @@ line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen, bool *truncated) {
cell = &self->gpu_cells[pos];
#define CMP_ATTRS (cell->attrs & ATTRS_MASK_WITHOUT_WIDTH) != (prev_cell->attrs & ATTRS_MASK_WITHOUT_WIDTH)
#define CMP(x) cell->x != prev_cell->x
#define CMP_ATTRS (cell->attrs & ATTRS_MASK_WITHOUT_WIDTH) != ((*prev_cell)->attrs & ATTRS_MASK_WITHOUT_WIDTH)
#define CMP(x) cell->x != (*prev_cell)->x
if (CMP_ATTRS || CMP(fg) || CMP(bg) || CMP(decoration_fg)) {
const char *sgr = cell_as_sgr(cell, prev_cell);
const char *sgr = cell_as_sgr(cell, *prev_cell);
if (*sgr) WRITE_SGR(sgr);
}
prev_cell = cell;
*prev_cell = cell;
WRITE_CH(ch);
for(unsigned c = 0; c < arraysz(self->cpu_cells[pos].cc_idx) && self->cpu_cells[pos].cc_idx[c]; c++) {
WRITE_CH(codepoint_for_mark(self->cpu_cells[pos].cc_idx[c]));
@@ -304,7 +305,8 @@ as_ansi(Line* self, PyObject *a UNUSED) {
#define as_ansi_doc "Return the line's contents with ANSI (SGR) escape codes for formatting"
static Py_UCS4 t[5120] = {0};
bool truncated;
index_type num = line_as_ansi(self, t, 5120, &truncated);
const GPUCell *prev_cell = NULL;
index_type num = line_as_ansi(self, t, 5120, &truncated, &prev_cell);
PyObject *ans = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, t, num);
return ans;
}
@@ -589,7 +591,7 @@ decoration_as_sgr(uint8_t decoration) {
const char*
cell_as_sgr(GPUCell *cell, GPUCell *prev) {
cell_as_sgr(const GPUCell *cell, const GPUCell *prev) {
static char buf[128];
#define SZ sizeof(buf) - (p - buf) - 2
#define P(s) { size_t len = strlen(s); if (SZ > len) { memcpy(p, s, len); p += len; } }

View File

@@ -61,7 +61,7 @@ void line_right_shift(Line *, unsigned int , unsigned int );
void line_add_combining_char(Line *, uint32_t , unsigned int );
index_type line_url_start_at(Line *self, index_type x);
index_type line_url_end_at(Line *self, index_type x, bool, char_type);
index_type line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen, bool*);
index_type line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen, bool*, const GPUCell**) __attribute__((nonnull));
unsigned int line_length(Line *self);
size_t cell_as_unicode(CPUCell *cell, bool include_cc, Py_UCS4 *buf, char_type);
size_t cell_as_unicode_for_fallback(CPUCell *cell, Py_UCS4 *buf);
@@ -100,6 +100,7 @@ void historybuf_clear(HistoryBuf *self);
Py_UCS4 *buf = NULL; \
PyObject *nl = PyUnicode_FromString("\n"); \
PyObject *cr = PyUnicode_FromString("\r"); \
const GPUCell *prev_cell = NULL; \
if (nl == NULL || cr == NULL) goto end; \
if (as_ansi) { \
buf = malloc(sizeof(Py_UCS4) * columns * 100); \
@@ -114,7 +115,7 @@ void historybuf_clear(HistoryBuf *self);
} \
if (as_ansi) { \
bool truncated; \
index_type num = line_as_ansi(line, buf, columns * 100 - 2, &truncated); \
index_type num = line_as_ansi(line, buf, columns * 100 - 2, &truncated, &prev_cell); \
t = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, num); \
} else { \
t = line_as_unicode(line); \

View File

@@ -75,7 +75,7 @@ cmdline_of_process(PyObject *self UNUSED, PyObject *pid_) {
mib[1] = KERN_PROCARGS2;
mib[2] = (pid_t)pid;
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
// In case of zombie process or non-existant process we'll get EINVAL.
// In case of zombie process or non-existent process we'll get EINVAL.
if (errno == EINVAL)
PyErr_Format(PyExc_ValueError, "process with pid %ld either does not exist or is a zombie", pid);
else
@@ -171,7 +171,7 @@ environ_of_process(PyObject *self UNUSED, PyObject *pid_) {
mib[1] = KERN_PROCARGS2;
mib[2] = (pid_t)pid;
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
// In case of zombie process or a non-existant process we'll get EINVAL
// In case of zombie process or a non-existent process we'll get EINVAL
// to NSP and _psosx.py will translate it to ZP.
if (errno == EINVAL)
PyErr_Format(PyExc_ValueError, "process with pid %ld either does not exist or is a zombie", pid);

View File

@@ -10,7 +10,7 @@ from contextlib import contextmanager, suppress
from .borders import load_borders_program
from .boss import Boss
from .child import set_default_env
from .child import set_default_env, openpty, remove_blocking
from .cli import create_opts, parse_args
from .config import cached_values_for, initial_window_size_func
from .constants import (
@@ -203,20 +203,44 @@ def macos_cmdline(argv_args):
return ans
def read_shell_environment(opts):
def read_shell_environment(opts=None):
if not hasattr(read_shell_environment, 'ans'):
import subprocess
from .session import resolved_shell
shell = resolved_shell(opts)
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=subprocess.PIPE)
raw = p.stdout.read()
if p.wait() == 0:
raw = raw.decode('utf-8', 'replace')
ans = read_shell_environment.ans = {}
for line in raw.splitlines():
k, v = line.partition('=')[::2]
if k and v:
ans[k] = v
master, slave = openpty()
remove_blocking(master)
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=slave, stdin=slave, stderr=slave, start_new_session=True, close_fds=True)
with os.fdopen(master, 'rb') as stdout, os.fdopen(slave, 'wb'):
raw = b''
from subprocess import TimeoutExpired
while True:
try:
ret = p.wait(0.01)
except TimeoutExpired:
ret = None
with suppress(Exception):
raw += stdout.read()
if ret is not None:
break
if p.returncode == 0:
while True:
try:
x = stdout.read()
except Exception:
break
if not x:
break
raw += x
raw = raw.decode('utf-8', 'replace')
ans = read_shell_environment.ans = {}
for line in raw.splitlines():
k, v = line.partition('=')[::2]
if k and v:
ans[k] = v
else:
log_error('Failed to run shell to read its environment')
read_shell_environment.ans = {}
return read_shell_environment.ans

17
kitty/rgb.py generated
View File

@@ -835,14 +835,15 @@ if __name__ == '__main__':
import sys
import pprint
data = {}
for line in open(sys.argv[-1]):
line = line.strip()
if not line or line.startswith('!'):
continue
parts = line.split()
r, g, b = map(int, parts[:3])
name = ' '.join(parts[3:]).lower()
data[name] = data[name.replace(' ', '')] = r, g, b
with open(sys.argv[-1]) as f:
for line in f:
line = line.strip()
if not line or line.startswith('!'):
continue
parts = line.split()
r, g, b = map(int, parts[:3])
name = ' '.join(parts[3:]).lower()
data[name] = data[name.replace(' ', '')] = r, g, b
data = pprint.pformat(data).replace('{', '{\n ').replace('(', 'Color(')
with open(__file__, 'r+') as src:
raw = src.read()

View File

@@ -1989,6 +1989,12 @@ is_rectangle_select(Screen *self, PyObject *a UNUSED) {
return ans;
}
static PyObject*
copy_colors_from(Screen *self, Screen *other) {
copy_color_profile(self->color_profile, other->color_profile);
Py_RETURN_NONE;
}
static PyObject*
text_for_selection(Screen *self, PyObject *a UNUSED) {
FullSelectionBoundary start, end;
@@ -2294,6 +2300,7 @@ static PyMethodDef methods[] = {
MND(toggle_alt_screen, METH_NOARGS)
MND(reset_callbacks, METH_NOARGS)
MND(paste, METH_O)
MND(copy_colors_from, METH_O)
{"select_graphic_rendition", (PyCFunction)_select_graphic_rendition, METH_VARARGS, ""},
{NULL} /* Sentinel */

View File

@@ -74,8 +74,8 @@ class Session:
self.tabs[-1].cwd = val
def resolved_shell(opts):
ans = opts.shell
def resolved_shell(opts=None):
ans = getattr(opts, 'shell', '.')
if ans == '.':
ans = [shell_path]
else:

View File

@@ -320,6 +320,19 @@ convert_mods(PyObject *obj) {
return resolve_mods(PyLong_AsLong(obj));
}
static WindowTitleIn
window_title_in(PyObject *title_in) {
const char *in = PyUnicode_AsUTF8(title_in);
switch(in[0]) {
case 'a': return ALL;
case 'w': return WINDOW;
case 'm': return MENUBAR;
case 'n': return NONE;
default: break;
}
return ALL;
}
static MouseShape
pointer_shape(PyObject *shape_name) {
const char *name = PyUnicode_AsUTF8(shape_name);
@@ -415,7 +428,7 @@ PYWRAP1(set_options) {
S(macos_option_as_alt, PyLong_AsUnsignedLong);
S(macos_traditional_fullscreen, PyObject_IsTrue);
S(macos_quit_when_last_window_closed, PyObject_IsTrue);
S(macos_show_window_title_in_menubar, PyObject_IsTrue);
S(macos_show_window_title_in, window_title_in);
S(macos_window_resizable, PyObject_IsTrue);
S(macos_hide_from_tasks, PyObject_IsTrue);
S(macos_thicken_font, PyFloat_AsDouble);

View File

@@ -26,9 +26,10 @@ typedef struct {
color_type url_color, background, foreground, active_border_color, inactive_border_color, bell_border_color;
double repaint_delay, input_delay;
bool focus_follows_mouse, hide_window_decorations;
bool macos_hide_from_tasks, macos_quit_when_last_window_closed, macos_window_resizable, macos_traditional_fullscreen, macos_show_window_title_in_menubar;
bool macos_hide_from_tasks, macos_quit_when_last_window_closed, macos_window_resizable, macos_traditional_fullscreen;
unsigned int macos_option_as_alt;
float macos_thicken_font;
WindowTitleIn macos_show_window_title_in;
int adjust_line_height_px, adjust_column_width_px;
float adjust_line_height_frac, adjust_column_width_frac;
float background_opacity, dim_opacity;
@@ -139,7 +140,7 @@ typedef struct {
bool mouse_button_pressed[20];
PyObject *window_title;
bool is_key_pressed[MAX_KEY_COUNT];
bool viewport_size_dirty;
bool viewport_size_dirty, viewport_updated_at_least_once;
LiveResizeInfo live_resize;
bool has_pending_resizes, is_semi_transparent, shown_once, is_damaged;
uint32_t offscreen_texture_id;

View File

@@ -232,9 +232,13 @@ class Tab: # {{{
ans.fork()
return ans
def new_window(self, use_shell=True, cmd=None, stdin=None, override_title=None, cwd_from=None, cwd=None, overlay_for=None, env=None, location=None):
def new_window(
self, use_shell=True, cmd=None, stdin=None, override_title=None,
cwd_from=None, cwd=None, overlay_for=None, env=None, location=None,
copy_colors_from=None
):
child = self.launch_child(use_shell=use_shell, cmd=cmd, stdin=stdin, cwd_from=cwd_from, cwd=cwd, env=env)
window = Window(self, child, self.opts, self.args, override_title=override_title)
window = Window(self, child, self.opts, self.args, override_title=override_title, copy_colors_from=copy_colors_from)
if overlay_for is not None:
overlaid = next(w for w in self.windows if w.id == overlay_for)
window.overlay_for = overlay_for
@@ -245,8 +249,8 @@ class Tab: # {{{
self.relayout_borders()
return window
def new_special_window(self, special_window, location=None):
return self.new_window(False, *special_window, location=location)
def new_special_window(self, special_window, location=None, copy_colors_from=None):
return self.new_window(False, *special_window, location=location, copy_colors_from=copy_colors_from)
def close_window(self):
if self.windows:

Some files were not shown because too many files have changed in this diff Show More