Compare commits

...

106 Commits

Author SHA1 Message Date
Kovid Goyal
fbccfb9d0d version 0.13.3 2019-01-19 14:06:53 +05:30
Kovid Goyal
9fdd8e4ae4 macOS: Fix some kittens causing 100% CPU usage 2019-01-19 14:01:36 +05:30
Kovid Goyal
6b6dea5190 ... 2019-01-19 13:51:18 +05:30
Kovid Goyal
5af551c96d macOS: Fix detection of differ
There can be a wrapper git on macOS that complains about command line
tools installation, so check that passing --help to it actually works.
2019-01-19 12:36:34 +05:30
Kovid Goyal
6761fdca1a ... 2019-01-19 12:16:44 +05:30
Kovid Goyal
725da39ecb macOS: Add aliases for lose window and new tab actions that conform to common Apple shortcuts for these actions
Fixes #1313
2019-01-19 09:18:25 +05:30
Kovid Goyal
9005fc359d Merge branch 'unjam' of https://github.com/jacwah/kitty
Fixes #1312
2019-01-18 22:23:12 +05:30
Jacob Wahlgren
33e4a44008 Unjam event loop when adding pending cocoa action
Fixes the problem reported in
https://github.com/kovidgoyal/kitty/issues/1312.
2019-01-18 17:32:22 +01:00
Kovid Goyal
3bddb9d95b Fix an exception when chaging diff context on very small diffs 2019-01-16 21:24:34 +05:30
Kovid Goyal
fa01e0b76f icat kitten: Add a --stdin option to control if image data is read from stdin
See #1308
2019-01-16 16:35:53 +05:30
Kovid Goyal
f8f188ecff Merge branch 'travis-osx' of https://github.com/stephengroat/kitty 2019-01-16 06:26:02 +05:30
Stephen G
07935d9bd3 Use brew for osx 2019-01-15 15:00:29 -08:00
Kovid Goyal
a827f4190c Merge branch 'fix_white_background_transparency' of https://github.com/Luflosi/kitty 2019-01-14 13:10:15 +05:30
Kovid Goyal
18c108ed03 macOS: Fix a regression that broke mapping of ctrl+tab
Fixes #1304
2019-01-14 10:53:31 +05:30
Kovid Goyal
2d70059f47 Document fix for #1299
Fix #1299
2019-01-14 10:12:05 +05:30
Kovid Goyal
63ff3cfb9f Merge branch 'negative_scroll_alternate_mode' of https://github.com/Luflosi/kitty 2019-01-14 10:10:22 +05:30
Kovid Goyal
ca70f22d46 Add a list of user-created kittens to the docs 2019-01-14 10:03:28 +05:30
Kovid Goyal
c247a6c0cc macOS: Ensure that when running from a bundle, the bundle kitty exe is preferred over any kitty in PATH
Fix #1280
2019-01-14 09:32:49 +05:30
Luflosi
7421a0b9e3 Apply negative scroll multiplier in alternate screen mode
Fixes kovidgoyal/kitty#1299
2019-01-14 00:11:19 +01:00
Kovid Goyal
30b5e8bf8f Merge branch 'patch-1' of https://github.com/robbyoconnor/kitty 2019-01-13 09:50:25 +05:30
Robby O'Connor
96475ce3ee Switch travis to Xenial 2019-01-11 20:53:43 -05:00
Kovid Goyal
24669fb6af Port a couple of fixes from upstream
72c3908e14
cde0aaaab1
2019-01-11 14:20:26 +05:30
Kovid Goyal
851885568f macOS: Fix dragging kitty window tabs in traditional full screen mode causing crashes
Fixes #1296
Apparently, macOS reports NaN DPI values in this scenario.

I dont know enough about cocoa internals to understand why, or
what is actually supposed to happen in this scenario, but at least we
should not crash.
2019-01-11 11:09:34 +05:30
Kovid Goyal
8efbc479e1 Remove unused code 2019-01-09 10:13:43 +05:30
Luflosi
2167bfd5b5 Fix #1221 in a different way 2019-01-08 16:14:41 +01:00
Luflosi
490d4455af Fix white background color not allowing transparency 2019-01-08 16:14:01 +01:00
Kovid Goyal
c94e06ccd2 hints kitten: Start hints numbering at one instead of zero by default. Added an option `--hints-offset` to control it.
Fixes #1289
Fixes #1290
2019-01-08 07:31:54 +05:30
Kovid Goyal
ea37799fb0 Fix linking happening even when not needed 2019-01-06 10:25:37 +05:30
Kovid Goyal
d00fbd73fc Fix a regression in the previous release that broke using `background for cursor_text_color`
Fixes #1288
2019-01-06 10:23:33 +05:30
Kovid Goyal
361b23e3f1 Fix long text docs for copy_to_clipboard 2019-01-04 09:37:59 +05:30
Kovid Goyal
8feccdf63f version 0.13.2 2019-01-04 09:26:51 +05:30
Kovid Goyal
ed905fcf6d Add a new `copy_or_interrupt action that can be mapped to kbd:ctrl+c`. It will copy if there is a selection and interrupt otherwise
Fixes #1286
2019-01-04 09:21:29 +05:30
Kovid Goyal
50a6abaac1 Also fix move_tab to preserve existing tab order 2019-01-04 06:59:38 +05:30
Kovid Goyal
718f7e77a1 Use the current working directory of the foreground process for the *_with_cwd actions that open a new window with the current working directory. 2019-01-03 13:29:52 +05:30
Kovid Goyal
c4aeb1adba Report the current foreground processes as well as the original child process, when using kitty @ ls 2019-01-03 13:14:39 +05:30
Kovid Goyal
d9c69f0a54 Merge branch 'sentexttab' of https://github.com/grimpy/kitty 2019-01-01 18:29:10 +05:30
Jo De Boeck
5afdbbe6f1 Add match-tab for send-text
Signed-off-by: Jo De Boeck <deboeck.jo@gmail.com>
2019-01-01 14:39:28 +02:00
Kovid Goyal
4273cb35bf Linux: Dont fail on systems with fonts that have non-UTF-8 names. Fixes #1281 2018-12-31 07:31:17 +05:30
Kovid Goyal
89be7a031d Fix #1278 2018-12-30 15:22:05 +05:30
Kovid Goyal
06c5127856 Fix #1275 2018-12-29 08:08:24 +05:30
Kovid Goyal
fd298256d7 Merge branch 'more_switch_cases' of https://github.com/Luflosi/kitty 2018-12-28 14:57:18 +05:30
Luflosi
e0246044b7 Add remaining momentum scroll phases to switch statement
According to https://developer.apple.com/documentation/appkit/nsevent/1533550-phase the momentum phase may end with "cancelled" instead of "ended"
2018-12-28 09:03:16 +01:00
Kovid Goyal
2f677990b2 Fix glfwSetGamma generating ramps of invalid sizes
3531c320af
2018-12-28 08:19:17 +05:30
Kovid Goyal
da2e4c8503 ... 2018-12-28 08:14:08 +05:30
Kovid Goyal
a1eb236616 Fix glfwGetGammaRamp error handling
751c6f9a27
2018-12-28 08:13:28 +05:30
Kovid Goyal
11186735c2 Couple of trivial commits from glfw upstream
064dfaa549
751c6f9a27
2018-12-28 08:06:26 +05:30
Kovid Goyal
a038f62a5b Fix #1272 2018-12-28 07:52:29 +05:30
Kovid Goyal
f45acc055e Merge branch 'more_event_phases' of https://github.com/Luflosi/kitty 2018-12-28 07:45:43 +05:30
Luflosi
43a25c49c4 Micro optimization 2018-12-27 15:19:22 +01:00
Luflosi
e47e2b2560 Move check for zero scroll distance to scroll_event() 2018-12-27 15:17:18 +01:00
Luflosi
7652065134 Add more momentum scroll phases 2018-12-27 15:12:57 +01:00
Kovid Goyal
d0da418e49 ... 2018-12-27 08:19:06 +05:30
Kovid Goyal
77e72cfd9a Fix #1270 2018-12-27 08:05:31 +05:30
Kovid Goyal
7b2ecb0498 Forgot a break 2018-12-27 08:02:24 +05:30
Kovid Goyal
318c5bca67 Merge branch 'fix_bitshift' of https://github.com/Luflosi/kitty 2018-12-27 07:57:46 +05:30
Luflosi
d52da934ca Fix typo in bitshift 2018-12-26 22:47:23 +01:00
Kovid Goyal
21951e3668 Add explicit default case 2018-12-26 20:39:39 +05:30
Kovid Goyal
64bef38813 macOS: Fix momentum scrolling continuing when changing the active window/tab
Fixes #1267
2018-12-26 20:39:04 +05:30
Kovid Goyal
fe67e3dde7 Cocoa: Remove subclassing of NSApplication
From upstream: 88c5edb409
2018-12-26 12:29:38 +05:30
Kovid Goyal
fc5e74e457 Report momentum scrolling status of scroll events on cocoa 2018-12-26 11:03:36 +05:30
Kovid Goyal
fdbd8df7b2 Add patch from upstream to report caps lock key presses on cocoa
c4903d9267
2018-12-26 10:01:02 +05:30
Kovid Goyal
246972b59f Add a patch from upstream, altered to not change behavior 2018-12-26 09:58:12 +05:30
Kovid Goyal
6057296499 Cocoa: Move to modern Objective-C literals 2018-12-26 09:45:24 +05:30
Kovid Goyal
b4b2207b93 Merge branch 'issue_1176' of https://github.com/daniel-pfeiffer/kitty
Add a FAQ entry about terminfo and sudo/su
2018-12-25 08:48:57 +05:30
Kovid Goyal
b881364c50 Merge branch 'mouse_scroll_acceleration_alternate_screen_mode' of https://github.com/Luflosi/kitty 2018-12-23 20:41:48 +05:30
Luflosi
76059882c4 Allow for scrolling acceleration in alternate screen mode when using low-resolution input devices like mice 2018-12-23 14:37:50 +01:00
Kovid Goyal
be71f5f1f4 Merge branch 'fix_downward_scrolling' of https://github.com/Luflosi/kitty 2018-12-23 17:25:46 +05:30
Luflosi
021dfcad39 Fix broken downward scrolling 2018-12-23 12:49:00 +01:00
Kovid Goyal
4e7498b854 Fix using the `new_tab !neighbor` action changing the order of the non-neighboring tabs
Fixes #1256
2018-12-23 08:45:34 +05:30
Kovid Goyal
494035c94b remove redundant code 2018-12-23 08:15:57 +05:30
Kovid Goyal
9c4230ad9c Add a comment for why we reset SIGPIPE 2018-12-20 09:29:09 +05:30
Kovid Goyal
056c2c12bb Explicitly reset the SIGPIPE handler in child processes
Fixes #1253
2018-12-20 09:06:21 +05:30
Kovid Goyal
a97c440872 Merge branch 'fix-resize-window-doc' of https://github.com/eepp/kitty 2018-12-20 05:50:37 +05:30
Kovid Goyal
653d823175 Merge branch 'doc-change-font-size-current' of https://github.com/eepp/kitty 2018-12-20 05:49:16 +05:30
Daniel Pfeiffer
c2a2dbc88c Help others avoid issue 1176. 2018-12-20 00:31:57 +01:00
Philippe Proulx
77492d31cf change_font_size current ... changes the current OS window's font size
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
2018-12-19 11:51:05 -05:00
Philippe Proulx
aaa609109e Fix resize_window documentation example
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
2018-12-19 11:34:15 -05:00
Kovid Goyal
2367fad90b Merge branch 'resize-window-cfg' of https://github.com/eepp/kitty 2018-12-19 11:05:31 +05:30
Kovid Goyal
aaa521bd24 Merge branch 'sigint' of https://github.com/jacwah/kitty 2018-12-19 10:07:11 +05:30
Philippe Proulx
d22686da10 Add resize_window configuration action
This patch adds the `resize_window` configuration action, which has the
following arguments:

1. Quality of resize amongst `wider`, `narrower`, `taller`, and
   `shorter` (mandatory).
2. Increment in number of cells (optional, default: 1).

This makes it possible to configure keys as such:

    map ctrl+shift+left resize_window narrower
    map ctrl+shift+right resize_window wider
    map ctrl+shift+up resize_window taller
    map ctrl+shift+down resize_window shorter

and have a behaviour which is somewhat close to Terminator's.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
2018-12-18 20:33:21 -05:00
Jacob Wahlgren
48b93ab28f macOS: Exit on SIGINT
With the default macos_quit_when_last_window_closed no setting, Kitty
would not exit when receiving a SIGINT signal (e.g. from Ctrl-C).
2018-12-19 01:52:47 +01:00
Kovid Goyal
703a1b83a8 macOS: Fix scrolling very slowly with wheel mice not working
Fixes #1238
2018-12-18 11:15:22 +05:30
Kovid Goyal
c9441bd3e2 Add a changelog entry for the dock menu item 2018-12-18 11:00:07 +05:30
Kovid Goyal
9de6d619ee Merge branch 'dockmenu' of https://github.com/jacwah/kitty
Fixes #1242
2018-12-18 10:59:13 +05:30
Jacob Wahlgren
9aae31ef2f macOS: Add "New OS Window" to dock menu
Discussed in #1242.
2018-12-17 23:53:43 +01:00
Kovid Goyal
dca04c549b Forgot to regenerate keys table with plus key. Fixes #1246 2018-12-18 03:03:35 +05:30
Kovid Goyal
69e76d6eeb Frogot to ad dplus key to _glfwGetKeyName 2018-12-17 21:16:57 +05:30
Kovid Goyal
b4a93c67c9 + key change also works on macOS apparently 2018-12-17 13:57:20 +05:30
Kovid Goyal
f098e6c973 Use -std=c11 when building
This is needed for harfbuzz 2.0 on macOS. -std=c11 was supported as of
gcc 4.7 released in 2014. So hopefully this wont break compilation on any
systems otherwise capable of running kitty. Fixes #1196
2018-12-17 08:41:06 +05:30
Kovid Goyal
f8ebba3954 Fix changing cursor_text_color via remote control not working
Fixes #1229
2018-12-16 17:12:49 +05:30
Kovid Goyal
37ee693de2 Fix Private use Unicode area characters followed by spaces at the end of text not being rendered correctly
Fixes #1210
2018-12-16 13:10:47 +05:30
Kovid Goyal
f77ad2b41d Add a couple of extra lib names for libstartup-notification.so
Fixes #1235
2018-12-14 23:01:49 +05:30
Kovid Goyal
e99eb2e72b Handle malformed tab title templates gracefully 2018-12-13 13:43:22 +05:30
Kovid Goyal
86b89072f3 ... 2018-12-13 13:35:17 +05:30
Kovid Goyal
022bee0560 Add a new option tab_title_template to control how tab titles are formatted.
In particular the template can be used to display the tab number next to the title
Merge branch 'tab-title-index' of https://github.com/nerdrew/kitty
2018-12-13 13:33:06 +05:30
Andrew Lazarus
204ea44946 add option to show tab index in tab_bar title 2018-12-12 23:21:08 -08:00
Kovid Goyal
3f2489b306 Linux: Handle keyboards with a "+" key
Adds a plus key to glfw so that it can be mapped as a shortcut. Fixes #1224
2018-12-13 09:56:30 +05:30
Kovid Goyal
291a2d6295 Merge branch 'kitten-stdin-docs' of https://github.com/nerdrew/kitty 2018-12-12 23:07:48 +05:30
Andrew Lazarus
b244d13e8a update docs for kitten STDIN 2018-12-12 09:20:41 -08:00
Kovid Goyal
b33324d07c Merge branch 'patch-1' of https://github.com/voxadam/kitty 2018-12-12 17:41:18 +05:30
Adam Hunt
ae2a641db5 Typo 2018-12-12 03:43:08 -08:00
Kovid Goyal
1cac757365 Merge branch 'yk-terminfo' of https://github.com/yurikhan/kitty 2018-12-12 06:26:45 +05:30
Yuri Khan
992de77040 Declare more function and editing keys with modifiers
Resolves #1220.
2018-12-11 23:42:59 +07:00
Kovid Goyal
f6b5e54890 Fix failing test 2018-12-11 10:08:52 +05:30
Kovid Goyal
d20c65ef80 Graphics protocol: Only delete temporary image-data files if they are in a known temporary file location 2018-12-11 10:00:43 +05:30
Kovid Goyal
4a8562a85f Fix setting background_opacity causing window margins/padding to be slightly different shade from background
Fixes #1221
2018-12-11 08:36:03 +05:30
66 changed files with 6968 additions and 6219 deletions

View File

@@ -4,7 +4,7 @@ matrix:
fast_finish: true
include:
- os: linux
dist: trusty
dist: xenial
group: beta
language: python
sudo: false
@@ -12,6 +12,7 @@ matrix:
addons:
apt:
packages:
- libgl1-mesa-dev
- libxi-dev
- libxrandr-dev
- libxinerama-dev
@@ -20,7 +21,7 @@ matrix:
- libdbus-1-dev
- os: linux
dist: trusty
dist: xenial
group: beta
sudo: false
env:
@@ -30,6 +31,7 @@ matrix:
addons:
apt:
packages:
- libgl1-mesa-dev
- libfontconfig1-dev
- libharfbuzz-dev
- libxi-dev
@@ -42,7 +44,7 @@ matrix:
- python3-pil
- os: linux
dist: trusty
dist: xenial
group: beta
sudo: false
env:
@@ -52,6 +54,7 @@ matrix:
addons:
apt:
packages:
- libgl1-mesa-dev
- libfontconfig1-dev
- libharfbuzz-dev
- libxi-dev
@@ -64,7 +67,7 @@ matrix:
- python3-pil
- os: linux
dist: trusty
dist: xenial
group: beta
sudo: false
env:
@@ -74,6 +77,7 @@ matrix:
addons:
apt:
packages:
- libgl1-mesa-dev
- libfontconfig1-dev
- libharfbuzz-dev
- libxi-dev
@@ -89,10 +93,13 @@ matrix:
language: generic
env: SWBASE=/Users/Shared/buildbot/sw SW=$SWBASE/sw PATH=$SW/bin:$PATH
# Disabled because harfbuzz is currently broken in brew
# - os: osx
# language: generic
# env: USE_BREW=1 BUILD_PKG=osx-bundle
- os: osx
language: generic
addons:
homebrew:
update: true
brewfile: true
env: USE_BREW=1 BUILD_PKG=osx-bundle
env:
global:
@@ -106,12 +113,6 @@ install: |
if [[ "$RUN_FLAKE" == "1" ]]; then pip install flake8; fi
if [[ "$TRAVIS_OS_NAME" == 'osx' ]]; then
if [[ "$USE_BREW" == "1" ]]; then
brew update;
# brew upgrade python;
brew install harfbuzz --without-graphite2 --without-icu4c --without-freetype;
brew install imagemagick
brew install optipng
brew install librsvg
logo/make.py
else
mkdir -p $SW;

5
Brewfile Normal file
View File

@@ -0,0 +1,5 @@
brew 'imagemagick'
brew 'optipng'
brew 'librsvg'
brew 'harfbuzz'
brew 'python'

View File

@@ -3,6 +3,86 @@ Changelog
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
0.13.3 [2019-01-19]
------------------------------
- icat kitten: Add a ``--stdin`` option to control if image data is read from
STDIN (:iss:`1308`)
- hints kitten: Start hints numbering at one instead of zero by default. Added
an option ``--hints-offset`` to control it. (:iss:`1289`)
- Fix a regression in the previous release that broke using ``background`` for
:opt:`cursor_text_color` (:iss:`1288`)
- macOS: Fix dragging kitty window tabs in traditional full screen mode causing
crashes (:iss:`1296`)
- macOS: Ensure that when running from a bundle, the bundle kitty exe is
preferred over any kitty in PATH (:iss:`1280`)
- macOS: Fix a regression that broke mapping of :kbd:`ctrl+tab` (:iss:`1304`)
- Add a list of user-created kittens to the docs
- Fix a regression that broke changing mouse wheel scroll direction with
negative :opt:`wheel_scroll_multiplier` values in full-screen applications
like vim (:iss:`1299`)
- Fix :opt:`background_opacity` not working with pure white backgrounds
(:iss:`1285`)
- macOS: Fix "New OS Window" dock action not working when kitty is not focused
(:iss:`1312`)
- macOS: Add aliases for close window and new tab actions that conform to common
Apple shortcuts for these actions (:iss:`1313`)
- macOS: Fix some kittens causing 100% CPU usage
0.13.2 [2019-01-04]
------------------------------
- Add a new option :opt:`tab_title_template` to control how tab titles
are formatted. In particular the template can be used to display
the tab number next to the title (:iss:`1223`)
- Report the current foreground processes as well as the original child process,
when using `kitty @ ls`
- Use the current working directory of the foreground process for the
`*_with_cwd` actions that open a new window with the current working
directory.
- Add a new ``copy_or_interrupt`` action that can be mapped to kbd:`ctrl+c`. It
will copy if there is a selection and interrupt otherwise (:iss:`1286`)
- Fix setting :opt:`background_opacity` causing window margins/padding to be slightly
different shade from background (:iss:`1221`)
- Handle keyboards with a "+" key (:iss:`1224`)
- Fix Private use Unicode area characters followed by spaces at the end of text
not being rendered correctly (:iss:`1210`)
- macOS: Add an entry to the dock menu to open a new OS window (:iss:`1242`)
- macOS: Fix scrolling very slowly with wheel mice not working (:iss:`1238`)
- Fix changing :opt:`cursor_text_color` via remote control not working
(:iss:`1229`)
- Add an action to resize windows that can be mapped to shortcuts in :file:`kitty.conf`
(:pull:`1245`)
- Fix using the ``new_tab !neighbor`` action changing the order of the
non-neighboring tabs (:iss:`1256`)
- macOS: Fix momentum scrolling continuing when changing the active window/tab
(:iss:`1267`)
0.13.1 [2018-12-06]
------------------------------

View File

@@ -6,7 +6,7 @@ Frequently Asked Questions
.. contents::
Some special symbols are rendered small/truncated in kitty?
-----------------------------------------------------------------
-----------------------------------------------------------
The number of cells a unicode character takes up are controlled by the unicode
standard. All characters are rendered in a single cell unless the unicode
@@ -48,15 +48,43 @@ terminfo files to the server::
kitty +kitten ssh myserver
If for some reason that does not work (typically because the server is using a
a non POSIX compliant shell), you can use the following one-liner instead (it
non POSIX compliant shell), you can use the following one-liner instead (it
is slower as it needs to ssh into the server twice, but will work with most
servers)::
infocmp xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
If you are behind a proxy (like Balabit) that prevents this, you must redirect the
1st command to a file, copy that to the server and run ``tic`` manually. If you
connect to a server, embedded or Android system that doesn't have ``tic``, copy over
your local file terminfo to the other system as :file:`~/.terminfo/x/xterm-kitty`.
Really, the correct solution for this is to convince the OpenSSH maintainers to
have ssh do this automatically when connecting to a server, so that all
terminals work transparently.
have ssh do this automatically, if possible, when connecting to a server, so that
all terminals work transparently.
Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo?
-------------------------------------------------------------------------------------------------
Make sure the TERM environment variable, is ``xterm-kitty``. And either the
TERMINFO environment variable points to a directory containing :file:`x/xterm-kitty`
or that file is under :file:`~/.terminfo/x/`.
Note that ``sudo`` might remove TERMINFO. Then setting it at the shell prompt can
be too late, because command line editing may not be reinitialized. In that case
you can either ask ``sudo`` to set it or if that is not supported, insert an ``env``
command before starting the shell, or, if not possible, after sudo start another
Shell providing the right terminfo path::
sudo … TERMINFO=$HOME/.terminfo bash -i
sudo … env TERMINFO=$HOME/.terminfo bash -i
TERMINFO=/home/ORIGINALUSER/.terminfo exec bash -i
If you have double width characters in your prompt, you may also need to
explicitly set a UTF-8 locale, like::
export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
How do I change the colors in a running kitty instance?

View File

@@ -201,7 +201,11 @@ Value of `t` Meaning
================== ============
``d`` Direct (the data is transmitted within the escape code itself)
``f`` A simple file
``t`` A temporary file, the terminal emulator will delete the file after reading the pixel data
``t`` A temporary file, the terminal emulator will delete the file after reading the pixel data. For security reasons
the terminal emulator should only delete the file if it
is in a known temporary directory, such as :file:`/tmp`,
:file:`/dev/shm`, :file:`TMPDIR env var if present` and any platform
specific temporary directories.
``s`` A `POSIX shared memory object <http://man7.org/linux/man-pages/man7/shm_overview.7.html>`_.
The terminal emulator will delete it after reading the pixel data
================== ============

View File

@@ -122,7 +122,7 @@ Tabs
======================== =======================
Action Shortcut
======================== =======================
New tab :sc:`new_tab`
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
Close tab :sc:`close_tab`
Next tab :sc:`next_tab` (also :kbd:`control+tab` on macOS)
Previous tab :sc:`previous_tab` (also :kbd:`control+shift+tab` on macOS)
@@ -141,7 +141,7 @@ Action Shortcut
======================== =======================
New window :sc:`new_window`
New OS window :sc:`new_os_window` (also :kbd:`⌘+n` on macOS)
Close window :sc:`close_window`
Close window :sc:`close_window` (also :kbd:`⌘+w` on macOS)
Next window :sc:`next_window`
Previous window :sc:`previous_window`
Move window forward :sc:`move_window_forward`
@@ -223,6 +223,19 @@ example, in the Tall layout you can make the first window wider/narrower, but
not taller/shorter. Note that what you are resizing is actually not a window,
but a row/column in the layout, all windows in that row/column will be resized.
You can also define shortcuts in :file:`kitty.conf` to make the active window
wider, narrower, taller, or shorter by mapping to the ``resize_window``
action, for example::
map ctrl+left resize_window narrower
map ctrl+right resize_window wider
map ctrl+up resize_window taller
map ctrl+down resize_window shorter 3
The ``resize_window`` action has a second, optional argument to control
the resizing increment (a positive integer that defaults to 1).
Some layouts take options to control their behavior. For example, the ``fat``
and ``tall`` layouts accept the ``bias`` option to control how the available
space is split up. To specify the option, in :opt:`kitty.conf <enabled_layouts>` use::

View File

@@ -43,6 +43,8 @@ Now in :file:`kitty.conf` add the lines::
Start kitty and press :kbd:`ctrl+k` and you should see the kitten running.
The best way to develop your own kittens is to modify one of the built in
kittens. Look in the kittens sub-directory of the kitty source code for those.
Or see below for a list of :ref:`third-party kittens <external_kittens>`,
that other kitty users have created.
Passing arguments to kittens
@@ -68,7 +70,14 @@ function, telling kitty what kind of input your kitten would like. For example:
.. code-block:: py
def handle_result(...):
# in main, STDIN is for the kitten process and will contain
# the contents of the screen
def main(args):
return sys.stdin.read()
# in handle_result, STDIN is for the kitty process itself, rather
# than the kitten process and should not be read from.
def handle_result(args, stdin_data, target_window_id, boss):
pass
handle_result.type_of_input = 'text'
@@ -120,3 +129,18 @@ layout, by simply adding the line::
to the ``handle_result()`` function, above.
.. _external_kittens:
Kittens created by kitty users
---------------------------------------------
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys.
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
Makes the kitty scroll bindings work in full screen applications
`insert password <https://github.com/kovidgoyal/kitty/issues/1222>`_
Insert a password from a CLI password manager, taking care to only do it at
a password prompt.

View File

@@ -26,7 +26,11 @@
#include "internal.h"
#include <sys/param.h> // For MAXPATHLEN
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSEventMaskKeyUp NSKeyUpMask
#define NSEventMaskKeyDown NSKeyDownMask
#define NSEventModifierFlagCommand NSCommandKeyMask
#endif
// Change to our application bundle's resources directory, if present
//
@@ -274,33 +278,83 @@ static GLFWbool initializeTIS(void)
return updateUnicodeDataNS();
}
@interface GLFWLayoutListener : NSObject
@interface GLFWHelper : NSObject
@end
@implementation GLFWLayoutListener
@implementation GLFWHelper
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
{
updateUnicodeDataNS();
}
@end
- (void)doNothing:(id)object
{
}
@end // GLFWHelper
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
static inline bool
is_ctrl_tab(NSEvent *event) {
NSEventModifierFlags modifierFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
return event.keyCode == kVK_Tab && (modifierFlags == NSEventModifierFlagControl || modifierFlags == (
NSEventModifierFlagControl | NSEventModifierFlagShift));
}
int _glfwPlatformInit(void)
{
_glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
_glfw.ns.helper = [[GLFWHelper alloc] init];
[NSThread detachNewThreadSelector:@selector(doNothing:)
toTarget:_glfw.ns.helper
withObject:nil];
[NSApplication sharedApplication];
NSEvent* (^keydown_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
{
if (is_ctrl_tab(event)) {
// Cocoa swallows Ctrl+Tab to cycle between views
[[NSApp keyWindow].contentView keyDown:event];
}
return event;
};
NSEvent* (^keyup_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
{
if ([event modifierFlags] & NSEventModifierFlagCommand) {
// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
// This works around an AppKit bug, where key up events while holding
// down the command key don't get sent to the key window.
[[NSApp keyWindow] sendEvent:event];
}
if (is_ctrl_tab(event)) {
// Cocoa swallows Ctrl+Tab to cycle between views
[[NSApp keyWindow].contentView keyUp:event];
}
return event;
};
_glfw.ns.keyUpMonitor =
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
handler:keyup_block];
_glfw.ns.keyDownMonitor =
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
handler:keydown_block];
if (_glfw.hints.init.ns.chdir)
changeToResourcesDirectory();
_glfw.ns.listener = [[GLFWLayoutListener alloc] init];
[[NSNotificationCenter defaultCenter]
addObserver:_glfw.ns.listener
addObserver:_glfw.ns.helper
selector:@selector(selectedKeyboardInputSourceChanged:)
name:NSTextInputContextKeyboardSelectionDidChangeNotification
object:nil];
@@ -345,17 +399,21 @@ void _glfwPlatformTerminate(void)
_glfw.ns.delegate = nil;
}
if (_glfw.ns.listener)
if (_glfw.ns.helper)
{
[[NSNotificationCenter defaultCenter]
removeObserver:_glfw.ns.listener
removeObserver:_glfw.ns.helper
name:NSTextInputContextKeyboardSelectionDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter]
removeObserver:_glfw.ns.listener];
[_glfw.ns.listener release];
_glfw.ns.listener = nil;
removeObserver:_glfw.ns.helper];
[_glfw.ns.helper release];
_glfw.ns.helper = nil;
}
if (_glfw.ns.keyUpMonitor)
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
if (_glfw.ns.keyDownMonitor)
[NSEvent removeMonitor:_glfw.ns.keyDownMonitor];
free(_glfw.ns.clipboardString);

View File

@@ -467,7 +467,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
CVDisplayLinkRelease(link);
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
@@ -489,6 +489,7 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
}
free(values);
return GLFW_TRUE;
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
@@ -523,4 +524,3 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
_GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay);
return monitor->ns.displayID;
}

View File

@@ -118,7 +118,9 @@ typedef struct _GLFWlibraryNS
TISInputSourceRef inputSource;
IOHIDManagerRef hidManager;
id unicodeData;
id listener;
id helper;
id keyUpMonitor;
id keyDownMonitor;
char keyName[64];
char text[256];

View File

@@ -47,7 +47,6 @@
#define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
#define NSEventMaskAny NSAnyEventMask
#define NSEventTypeApplicationDefined NSApplicationDefined
#define NSEventTypeKeyUp NSKeyUp
#endif
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101400)
@@ -312,6 +311,7 @@ static int translateKey(unsigned int key, GLFWbool apply_keymap)
K(';', SEMICOLON);
K('[', LEFT_BRACKET);
K(']', RIGHT_BRACKET);
K('+', PLUS);
K('`', GRAVE_ACCENT);
K('\\', BACKSLASH);
#undef K
@@ -344,6 +344,8 @@ static NSUInteger translateKeyToModifierFlag(int key)
case GLFW_KEY_LEFT_SUPER:
case GLFW_KEY_RIGHT_SUPER:
return NSEventModifierFlagCommand;
case GLFW_KEY_CAPS_LOCK:
return NSEventModifierFlagCapsLock;
}
return 0;
@@ -625,6 +627,11 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
updateCursorImage(window);
}
- (BOOL)acceptsFirstMouse:(NSEvent *)event
{
return NO; // changed by Kovid, to follow cocoa platform conventions
}
- (void)mouseDown:(NSEvent *)event
{
_glfwInputMouseClick(window,
@@ -915,8 +922,25 @@ is_ascii_control_char(char x) {
if (yscale > 0) deltaY *= yscale;
}
if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0)
_glfwInputScroll(window, deltaX, deltaY, flags);
switch([event momentumPhase]) {
case NSEventPhaseBegan:
flags |= (1 << 1); break;
case NSEventPhaseStationary:
flags |= (2 << 1); break;
case NSEventPhaseChanged:
flags |= (3 << 1); break;
case NSEventPhaseEnded:
flags |= (4 << 1); break;
case NSEventPhaseCancelled:
flags |= (5 << 1); break;
case NSEventPhaseMayBegin:
flags |= (6 << 1); break;
case NSEventPhaseNone:
default:
break;
}
_glfwInputScroll(window, deltaX, deltaY, flags);
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
@@ -1068,67 +1092,6 @@ is_ascii_control_char(char x) {
@end
//------------------------------------------------------------------------
// GLFW application class
//------------------------------------------------------------------------
@interface GLFWApplication : NSApplication
{
NSArray* nibObjects;
}
@end
@implementation GLFWApplication
- (void)sendEvent:(NSEvent *)event
{
NSEventType etype = [event type];
NSEventModifierFlags flags;
switch(etype) {
case NSEventTypeKeyUp:
flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
if (flags & NSEventModifierFlagCommand) {
// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
// This works around an AppKit bug, where key up events while holding
// down the command key don't get sent to the key window.
[[self keyWindow] sendEvent:event];
return;
}
if (event.keyCode == kVK_Tab && (flags == NSEventModifierFlagControl || flags == (NSEventModifierFlagControl | NSEventModifierFlagShift))) {
// Cocoa swallows Ctrl+Tab to cycle between views
[[self keyWindow].contentView keyUp:event];
return;
}
break;
case NSEventTypeKeyDown:
flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
if (event.keyCode == kVK_Tab && (flags == NSEventModifierFlagControl || flags == (NSEventModifierFlagControl | NSEventModifierFlagShift))) {
// Cocoa swallows Ctrl+Tab to cycle between views
[[self keyWindow].contentView keyDown:event];
return;
}
break;
default:
break;
}
[super sendEvent:event];
}
// No-op thread entry point
//
- (void)doNothing:(id)object
{
}
- (void)loadMainMenu
{ // removed by Kovid as it generated compiler warnings
}
@end
// Set up the menu bar (manually)
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
// could go away at any moment, lots of stuff that really should be
@@ -1238,32 +1201,9 @@ static void createMenuBar(void)
//
static GLFWbool initializeAppKit(void)
{
if (NSApp)
if (_glfw.ns.delegate)
return GLFW_TRUE;
// Implicitly create shared NSApplication instance
[GLFWApplication sharedApplication];
// Make Cocoa enter multi-threaded mode
[NSThread detachNewThreadSelector:@selector(doNothing:)
toTarget:NSApp
withObject:nil];
if (_glfw.hints.init.ns.menubar)
{
// In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
// of NSApplicationMain
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
[NSApp loadMainMenu];
else
createMenuBar();
}
// There can only be one application delegate, but we allocate it the
// first time a window is created to keep all window code in this file
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
@@ -1273,15 +1213,29 @@ static GLFWbool initializeAppKit(void)
"Cocoa: Failed to create application delegate");
return GLFW_FALSE;
}
[NSApp setDelegate:_glfw.ns.delegate];
if (_glfw.hints.init.ns.menubar)
{
// In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
// Menu bar setup must go between sharedApplication above and
// finishLaunching below, in order to properly emulate the behavior
// of NSApplicationMain
// disabled by Kovid
/* if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) */
/* [NSApp loadMainMenu]; */
/* else */
createMenuBar();
}
[NSApp run];
// Press and Hold prevents some keys from emitting repeated characters
NSDictionary* defaults =
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],
@"ApplePressAndHoldEnabled",
nil];
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
return GLFW_TRUE;
@@ -1793,9 +1747,6 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
void _glfwPlatformPollEvents(void)
{
if (!initializeAppKit())
return;
for (;;)
{
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
@@ -1936,8 +1887,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
NSImage* native;
NSBitmapImageRep* rep;
if (!initializeAppKit())
return GLFW_FALSE;
native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)];
if (native == nil)
return GLFW_FALSE;
@@ -1974,8 +1923,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
{
if (!initializeAppKit())
return GLFW_FALSE;
if (shape == GLFW_ARROW_CURSOR)
cursor->ns.object = [NSCursor arrowCursor];
@@ -2015,10 +1962,8 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
void _glfwPlatformSetClipboardString(const char* string)
{
NSArray* types = [NSArray arrayWithObjects:NSPasteboardTypeString, nil];
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
[pasteboard declareTypes:types owner:nil];
[pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
[pasteboard setString:[NSString stringWithUTF8String:string]
forType:NSPasteboardTypeString];
}
@@ -2218,6 +2163,7 @@ GLFWAPI void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, unsigned sho
K(';', SEMICOLON);
K('[', LEFT_BRACKET);
K(']', RIGHT_BRACKET);
K('+', PLUS);
K('`', GRAVE_ACCENT);
K('\\', BACKSLASH);

19
glfw/glfw3.h vendored
View File

@@ -407,6 +407,7 @@ extern "C" {
#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */
#define GLFW_KEY_WORLD_1 161 /* non-US #1 */
#define GLFW_KEY_WORLD_2 162 /* non-US #2 */
#define GLFW_KEY_PLUS 163
/* Function keys */
#define GLFW_KEY_ESCAPE 256
@@ -1379,7 +1380,13 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
* @param[in] window The window that received the event.
* @param[in] xoffset The scroll offset along the x-axis.
* @param[in] yoffset The scroll offset along the y-axis.
* @param[in] flags A bit-mask providing extra data about the event. flags & 1 will be true if and only if the offset values are "high-precision". Typically pixel values. Otherwise the offset values are number of lines.
* @param[in] flags A bit-mask providing extra data about the event.
* flags & 1 will be true if and only if the offset values are "high-precision".
* Typically pixel values. Otherwise the offset values are number of lines.
* (flags >> 1) & 7 will have value 1 for the start of momentum scrolling,
* value 2 for stationary momentum scrolling, value 3 for momentum scrolling
* in progress, value 4 for momentum scrolling ended, value 5 for momentum
* scrolling cancelled and value 6 if scrolling may begin soon.
*
* @sa @ref scrolling
* @sa @ref glfwSetScrollCallback
@@ -2121,9 +2128,9 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
/*! @brief Generates a gamma ramp and sets it for the specified monitor.
*
* This function generates a 256-element gamma ramp from the specified exponent
* and then calls @ref glfwSetGammaRamp with it. The value must be a finite
* number greater than zero.
* This function generates an appropriately sized gamma ramp from the
* specified exponent and then calls @ref glfwSetGammaRamp with it. The value
* must be a finite number greater than zero.
*
* The software controlled gamma ramp is applied _in addition_ to the hardware
* gamma correction, which today is usually an approximation of sRGB gamma.
@@ -2202,8 +2209,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark Gamma ramp sizes other than 256 are not supported by all platforms
* or graphics hardware.
* @remark The size of the specified gamma ramp should match the size of the
* current ramp for that monitor.
*
* @remark @win32 The gamma ramp size must be 256.
*

1
glfw/input.c vendored
View File

@@ -487,6 +487,7 @@ const char* _glfwGetKeyName(int key)
case GLFW_KEY_SLASH: return "SLASH";
case GLFW_KEY_WORLD_1: return "WORLD 1";
case GLFW_KEY_WORLD_2: return "WORLD 2";
case GLFW_KEY_PLUS: return "PLUS";
// Function keys
case GLFW_KEY_ESCAPE: return "ESCAPE";

2
glfw/internal.h vendored
View File

@@ -619,7 +619,7 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
float* xscale, float* yscale);
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwPlatformSetClipboardString(const char* string);

27
glfw/monitor.c vendored
View File

@@ -427,11 +427,11 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
{
int i;
unsigned short values[256];
unsigned int i;
unsigned short* values;
GLFWgammaramp ramp;
const GLFWgammaramp* original;
assert(handle != NULL);
assert(gamma == gamma);
assert(gamma >= 0.f);
assert(gamma <= FLT_MAX);
@@ -442,13 +442,18 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
return;
}
original = glfwGetGammaRamp(handle);
if (!original)
return;
for (i = 0; i < 256; i++)
values = calloc(original->size, sizeof(unsigned short));
for (i = 0; i < original->size; i++)
{
float value;
// Calculate intensity
value = i / 255.f;
value = i / (float) (original->size - 1);
// Apply gamma curve
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
@@ -462,9 +467,10 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
ramp.red = values;
ramp.green = values;
ramp.blue = values;
ramp.size = 256;
ramp.size = original->size;
glfwSetGammaRamp(handle, &ramp);
free(values);
}
GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
@@ -475,7 +481,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_glfwFreeGammaArrays(&monitor->currentRamp);
_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp);
if (!_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp))
return NULL;
return &monitor->currentRamp;
}
@@ -501,8 +508,10 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
_GLFW_REQUIRE_INIT();
if (!monitor->originalRamp.size)
_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
{
if (!_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp))
return;
}
_glfwPlatformSetGammaRamp(monitor, ramp);
}

4
glfw/null_monitor.c vendored
View File

@@ -58,11 +58,11 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
return GLFW_FALSE;
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
}

View File

@@ -240,7 +240,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
if (ctxconfig->forward)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"OSMesa: Foward-compatible contexts not supported");
"OSMesa: Forward-compatible contexts not supported");
return GLFW_FALSE;
}
@@ -367,4 +367,3 @@ GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
return window->context.osmesa.handle;
}

View File

@@ -455,7 +455,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
&mode->blueBits);
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
HDC dc;
WORD values[768];
@@ -469,6 +469,8 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short));
memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short));
return GLFW_TRUE;
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
@@ -510,4 +512,3 @@ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return monitor->win32.publicDisplayName;
}

9
glfw/wl_monitor.c vendored
View File

@@ -180,18 +180,17 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
*mode = monitor->modes[monitor->wl.currentMode];
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Gamma ramp getting not supported yet");
"Wayland: Gamma ramp access is not available");
return GLFW_FALSE;
}
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
// TODO
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Gamma ramp setting not supported yet");
"Wayland: Gamma ramp access is not available");
}

14
glfw/x11_monitor.c vendored
View File

@@ -433,7 +433,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
}
}
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
{
@@ -449,6 +449,7 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short));
XRRFreeGamma(gamma);
return GLFW_TRUE;
}
else if (_glfw.x11.vidmode.available)
{
@@ -460,6 +461,13 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
XF86VidModeGetGammaRamp(_glfw.x11.display,
_glfw.x11.screen,
ramp->size, ramp->red, ramp->green, ramp->blue);
return GLFW_TRUE;
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Gamma ramp access not supported by server");
return GLFW_FALSE;
}
}
@@ -492,6 +500,10 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
(unsigned short*) ramp->green,
(unsigned short*) ramp->blue);
}
else {
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Gamma ramp access not supported by server");
}
}

3
glfw/x11_platform.h vendored
View File

@@ -198,9 +198,6 @@ typedef struct _GLFWwindowX11
// The last position the cursor was warped to by GLFW
int warpCursorPosX, warpCursorPosY;
// The time of the last KeyPress event
Time lastKeyTime;
} _GLFWwindowX11;
// X11-specific global data

4
glfw/x11_window.c vendored
View File

@@ -2244,10 +2244,14 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
}
else
{
if (!window->resizable)
updateNormalHints(window, width, height);
XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
xpos, ypos, width, height);
}
XFlush(_glfw.x11.display);
return;
}

1
glfw/xkb_glfw.c vendored
View File

@@ -46,6 +46,7 @@
S(bracketleft, LEFT_BRACKET); \
S(backslash, BACKSLASH); \
S(bracketright, RIGHT_BRACKET); \
S(plus, PLUS); \
S(grave, GRAVE_ACCENT); \
S(Escape, ESCAPE); \
S(Return, ENTER); \

View File

@@ -208,7 +208,7 @@ class DiffHandler(Handler):
break
if num is not None:
self.scroll_pos = min(num, self.max_scroll_pos)
self.scroll_pos = max(0, min(num, self.max_scroll_pos))
@property
def num_lines(self):

View File

@@ -18,7 +18,7 @@ worker_processes = []
def find_differ():
if shutil.which('git'):
if shutil.which('git') and subprocess.Popen(['git', '--help'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL).wait() == 0:
return GIT_DIFF
if shutil.which('diff'):
return DIFF_DIFF

View File

@@ -315,8 +315,9 @@ def run(args, text):
return
largest_index = all_marks[-1].index
offset = max(0, args.hints_offset)
for m in all_marks:
m.index = largest_index - m.index
m.index = largest_index - m.index + offset
index_map = {m.index: m for m in all_marks}
except Exception:
import traceback
@@ -378,6 +379,13 @@ default=auto
choices=auto,always,never
Add trailing space after matched text. Defaults to auto, which adds the space
when used together with --multiple.
--hints-offset
default=1
type=int
The offset (from zero) at which to start hint numbering. Note that only numbers
greater than zero are respected.
'''.format(','.join(sorted(URL_PREFIXES))).format
help_text = 'Select text from the screen using the keyboard. Defaults to searching for URLs.'
usage = ''

View File

@@ -81,6 +81,14 @@ type=bool-set
Print out the window size as :italic:`widthxheight` (in pixels) and quit. This is a
convenience method to query the window size if using kitty icat from a
scripting language that cannot make termios calls.
--stdin
type=choices
choices=detect,yes,no
default=detect
Read image data from stdin. The default is to do it automatically, when STDIN is not a terminal,
but you can turn it off or on explicitly, if needed.
'''
@@ -269,9 +277,10 @@ def main(args=sys.argv):
if not sys.stdout.isatty():
sys.stdout = open(os.ctermid(), 'w')
stdin_data = None
if not sys.stdin.isatty():
if args.stdin == 'yes' or (not sys.stdin.isatty() and args.stdin == 'detect'):
stdin_data = sys.stdin.buffer.read()
items.insert(0, stdin_data)
if stdin_data:
items.insert(0, stdin_data)
sys.stdin.close()
sys.stdin = open(os.ctermid(), 'r')
@@ -307,7 +316,7 @@ def main(args=sys.argv):
raise SystemExit('You must specify at least one file to cat')
if args.place:
if len(items) > 1 or (isinstance(items[0], str) and os.path.isdir(items[0])):
raise SystemExit('The --place option can only be used with a single image')
raise SystemExit(f'The --place option can only be used with a single image, not {items}')
sys.stdout.buffer.write(b'\0337') # save cursor
for item in items:
is_tempfile = False

View File

@@ -153,8 +153,9 @@ class Loop:
def __init__(self,
sanitize_bracketed_paste='[\x03\x04\x0e\x0f\r\x07\x7f\x8d\x8e\x8f\x90\x9b\x9d\x9e\x9f]'):
if is_macos:
# On macOS PTY devices are not supported by the KqueueSelector
self.asycio_loop = asyncio.SelectorEventLoop(selectors.PollSelector())
# On macOS PTY devices are not supported by the KqueueSelector and
# the PollSelector is broken, causes 100% CPU usage
self.asycio_loop = asyncio.SelectorEventLoop(selectors.SelectSelector())
asyncio.set_event_loop(self.asycio_loop)
else:
self.asycio_loop = asyncio.get_event_loop()

View File

@@ -4,5 +4,5 @@ in vec3 color;
out vec4 final_color;
void main() {
final_color = vec4(color, background_opacity);
final_color = vec4(color * background_opacity, background_opacity);
}

View File

@@ -10,6 +10,7 @@ from functools import partial
from gettext import gettext as _
from weakref import WeakValueDictionary
from .child import cached_process_data
from .cli import create_opts, parse_args
from .conf.utils import to_cmdline
from .config import initial_window_size_func, prepare_config_file_for_editing
@@ -32,9 +33,9 @@ from .rgb import Color, color_from_int
from .session import create_session
from .tabs import SpecialWindow, SpecialWindowInstance, TabManager
from .utils import (
get_editor, get_primary_selection, log_error, open_url, parse_address_spec,
remove_socket_file, safe_print, set_primary_selection, single_instance,
startup_notification_handler
get_editor, get_primary_selection, is_path_in_temp_dir, log_error,
open_url, parse_address_spec, remove_socket_file, safe_print,
set_primary_selection, single_instance, startup_notification_handler
)
@@ -106,6 +107,7 @@ class Boss:
set_draw_minimal_borders(opts)
self.window_id_map = WeakValueDictionary()
self.startup_colors = {k: opts[k] for k in opts if isinstance(opts[k], Color)}
self.startup_cursor_text_color = opts.cursor_text_color
self.pending_sequences = None
self.cached_values = cached_values
self.os_window_map = {}
@@ -149,14 +151,15 @@ class Boss:
return os_window_id
def list_os_windows(self):
active_tab, active_window = self.active_tab, self.active_window
active_tab_manager = self.active_tab_manager
for os_window_id, tm in self.os_window_map.items():
yield {
'id': os_window_id,
'is_focused': tm is active_tab_manager,
'tabs': list(tm.list_tabs(active_tab, active_window)),
}
with cached_process_data():
active_tab, active_window = self.active_tab, self.active_window
active_tab_manager = self.active_tab_manager
for os_window_id, tm in self.os_window_map.items():
yield {
'id': os_window_id,
'is_focused': tm is active_tab_manager,
'tabs': list(tm.list_tabs(active_tab, active_window)),
}
@property
def all_tab_managers(self):
@@ -253,7 +256,7 @@ class Boss:
def new_os_window_with_cwd(self, *args):
w = self.active_window_for_cwd
cwd_from = w.child.pid if w is not None else None
cwd_from = w.child.pid_for_cwd if w is not None else None
self._new_os_window(args, cwd_from)
def add_child(self, window):
@@ -852,7 +855,7 @@ class Boss:
def pipe(self, source, dest, exe, *args):
cmd = [exe] + list(args)
window = self.active_window
cwd_from = window.child.pid if window else None
cwd_from = window.child.pid_for_cwd if window else None
def create_window():
return self.special_window_for_cmd(
@@ -920,7 +923,7 @@ class Boss:
def new_tab_with_cwd(self, *args):
w = self.active_window_for_cwd
cwd_from = w.child.pid if w is not None else None
cwd_from = w.child.pid_for_cwd if w is not None else None
self._create_tab(args, cwd_from=cwd_from)
def _new_window(self, args, cwd_from=None):
@@ -938,7 +941,7 @@ class Boss:
w = self.active_window_for_cwd
if w is None:
return self.new_window(*args)
cwd_from = w.child.pid if w is not None else None
cwd_from = w.child.pid_for_cwd if w is not None else None
self._new_window(args, cwd_from=cwd_from)
def move_tab_forward(self):
@@ -951,11 +954,20 @@ class Boss:
if tm is not None:
tm.move_tab(-1)
def patch_colors(self, spec, configured=False):
def patch_colors(self, spec, cursor_text_color, configured=False):
if configured:
for k, v in spec.items():
if hasattr(self.opts, k):
setattr(self.opts, k, color_from_int(v))
if cursor_text_color is not False:
self.opts.cursor_text_color = cursor_text_color
for tm in self.all_tab_managers:
tm.tab_bar.patch_colors(spec)
patch_global_colors(spec, configured)
def safe_delete_temp_file(self, path):
if is_path_in_temp_dir(path):
try:
os.remove(path)
except FileNotFoundError:
pass

View File

@@ -72,7 +72,11 @@ vec4 calculate_foreground() {
void main() {
#ifdef BACKGROUND
#ifdef TRANSPARENT
final_color = vec4(background.rgb * bg_alpha, bg_alpha);
// bg_alpha is doubled to match rendering in the SIMPLE case
// and also rendering of the margin/padding, see https://github.com/kovidgoyal/kitty/pull/1291
// to test use background_opacity, window_margin_width and icat to display
// an image.
final_color = vec4(background.rgb * bg_alpha * bg_alpha, bg_alpha);
#else
final_color = vec4(background.rgb, 1.0f);
#endif

View File

@@ -5,13 +5,12 @@
#define REVERSE_SHIFT {REVERSE_SHIFT}
#define STRIKE_SHIFT {STRIKE_SHIFT}
#define DIM_SHIFT {DIM_SHIFT}
#define CURSOR_TEXT_COLOR {CURSOR_TEXT_COLOR}
// Inputs {{{
layout(std140) uniform CellRenderData {
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
float xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg;
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, url_color, url_style, inverted;
uint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted;
uint xnum, ynum, cursor_fg_sprite_idx;
float cursor_x, cursor_y, cursor_w;
@@ -182,8 +181,9 @@ void main() {
// Cursor
cursor_color_vec = vec4(color_to_vec(cursor_color), 1.0);
foreground = choose_color(cell_has_block_cursor, CURSOR_TEXT_COLOR, foreground);
decoration_fg = choose_color(cell_has_block_cursor, CURSOR_TEXT_COLOR, decoration_fg);
vec3 final_cursor_text_color = mix(color_to_vec(cursor_text_color), bg, cursor_text_uses_bg);
foreground = choose_color(cell_has_block_cursor, final_cursor_text_color, foreground);
decoration_fg = choose_color(cell_has_block_cursor, final_cursor_text_color, decoration_fg);
cursor_pos = to_sprite_pos(pos, cursor_fg_sprite_idx * uint(cell_has_cursor), ZERO, ZERO);
#endif
// }}}

View File

@@ -372,7 +372,7 @@ parse_input(ChildMonitor *self) {
}
if (UNLIKELY(kill_signal_received)) {
global_state.close_all_windows = true;
global_state.terminate = true;
} else {
count = self->count;
for (size_t i = 0; i < count; i++) {
@@ -737,7 +737,6 @@ process_pending_resizes(double now) {
static inline void
close_all_windows() {
for (size_t w = 0; w < global_state.num_os_windows; w++) mark_os_window_for_close(&global_state.os_windows[w], true);
global_state.close_all_windows = false;
}
static inline bool
@@ -772,6 +771,9 @@ static unsigned int cocoa_pending_actions = 0;
void
set_cocoa_pending_action(CocoaPendingAction action) {
cocoa_pending_actions |= action;
// The main loop may be blocking on the event queue, if e.g. unfocused.
// Unjam it so the pending action is processed right now.
unjam_event_loop();
}
#endif
@@ -793,7 +795,13 @@ main_loop(ChildMonitor *self, PyObject *a UNUSED) {
}
#endif
parse_input(self);
if (global_state.close_all_windows) close_all_windows();
if (global_state.terminate) {
global_state.terminate = false;
close_all_windows();
#ifdef __APPLE__
request_application_quit();
#endif
}
has_open_windows = process_pending_closes(self);
}
if (PyErr_Occurred()) return NULL;

View File

@@ -115,6 +115,9 @@ spawn(PyObject *self UNUSED, PyObject *args) {
for (int c = 3; c < 201; c++) close(c);
environ = env;
// for some reason SIGPIPE is set to SIG_IGN, so reset it, needed by bash,
// which does not reset signal handlers on its own
signal(SIGPIPE, SIG_DFL);
execvp(exe, argv);
// Report the failure and exec a shell instead, so that we are not left
// with a forked but not exec'ed process

View File

@@ -4,17 +4,28 @@
import fcntl
import os
from collections import defaultdict
from contextlib import contextmanager
import kitty.fast_data_types as fast_data_types
from .constants import is_macos, shell_path, terminfo_dir
if is_macos:
from kitty.fast_data_types import cmdline_of_process, cwd_of_process as _cwd, environ_of_process as _environ_of_process
from kitty.fast_data_types import (
cmdline_of_process, cwd_of_process as _cwd, environ_of_process as _environ_of_process,
process_group_map as _process_group_map
)
def cwd_of_process(pid):
return os.path.realpath(_cwd(pid))
def process_group_map():
ans = defaultdict(list)
for pid, pgid in _process_group_map():
ans[pgid].append(pid)
return ans
else:
def cmdline_of_process(pid):
@@ -27,6 +38,46 @@ else:
def _environ_of_process(pid):
return open('/proc/{}/environ'.format(pid), 'rb').read().decode('utf-8')
def process_group_map():
ans = defaultdict(list)
for x in os.listdir('/proc'):
try:
pid = int(x)
except Exception:
continue
try:
raw = open('/proc/' + x + '/stat', 'rb').read().decode('utf-8')
except EnvironmentError:
continue
try:
q = int(raw.split(' ', 5)[4])
except Exception:
continue
ans[q].append(pid)
return ans
def processes_in_group(grp):
gmap = getattr(process_group_map, 'cached_map', None)
if gmap is None:
try:
gmap = process_group_map()
except Exception:
gmap = {}
return gmap.get(grp, [])
@contextmanager
def cached_process_data():
try:
process_group_map.cached_map = process_group_map()
except Exception:
process_group_map.cached_map = {}
try:
yield
finally:
process_group_map.cached_map = None
def parse_environ_block(data):
"""Parse a C environ block of environment variables into a dictionary."""
@@ -142,6 +193,28 @@ class Child:
os.close(self.terminal_ready_fd)
self.terminal_ready_fd = -1
@property
def foreground_processes(self):
try:
pgrp = os.tcgetpgrp(self.child_fd)
foreground_processes = processes_in_group(pgrp) if pgrp >= 0 else []
def process_desc(pid):
ans = {'pid': pid}
try:
ans['cmdline'] = cmdline_of_process(pid)
except Exception:
pass
try:
ans['cwd'] = cwd_of_process(pid) or None
except Exception:
pass
return ans
return list(map(process_desc, foreground_processes))
except Exception:
return []
@property
def cmdline(self):
try:
@@ -162,3 +235,21 @@ class Child:
return cwd_of_process(self.pid)
except Exception:
pass
@property
def pid_for_cwd(self):
try:
pgrp = os.tcgetpgrp(self.child_fd)
foreground_processes = processes_in_group(pgrp) if pgrp >= 0 else []
if len(foreground_processes) == 1:
return foreground_processes[0]
except Exception:
pass
return self.pid
@property
def foreground_cwd(self):
try:
return cwd_of_process(self.pid_for_cwd) or None
except Exception:
pass

View File

@@ -126,7 +126,7 @@ def set_font_size(boss, window, payload):
' and :italic:`\\u21fa` to send unicode characters. If you use the :option:`kitty @ send-text --match` option'
' the text will be sent to all matched windows. By default, text is sent to'
' only the currently active window.',
options_spec=MATCH_WINDOW_OPTION + '''\n
options_spec=MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t') + '''\n
--stdin
type=bool-set
Read the text to be sent from :italic:`stdin`. Note that in this case the text is sent as is,
@@ -142,7 +142,7 @@ are sent as is, not interpreted for escapes.
)
def cmd_send_text(global_opts, opts, args):
limit = 1024
ret = {'match': opts.match, 'is_binary': False}
ret = {'match': opts.match, 'is_binary': False, 'match_tab': opts.match_tab}
def pipe():
ret['is_binary'] = True
@@ -209,6 +209,13 @@ def send_text(boss, window, payload):
match = payload['match']
if match:
windows = tuple(boss.match_windows(match))
if payload['match_tab']:
windows = []
tabs = tuple(boss.match_tabs(payload['match_tab']))
if not tabs:
raise MatchError(payload['match_tab'], 'tabs')
for tab in tabs:
windows += tuple(tab)
data = payload['text'].encode('utf-8') if payload['is_binary'] else parse_send_text_bytes(payload['text'])
for window in windows:
if window is not None:
@@ -684,7 +691,7 @@ this option, any color arguments are ignored and --configured and --all are impl
)
def cmd_set_colors(global_opts, opts, args):
from .rgb import color_as_int, Color
colors = {}
colors, cursor_text_color = {}, False
if not opts.reset:
for spec in args:
if '=' in spec:
@@ -692,15 +699,17 @@ def cmd_set_colors(global_opts, opts, args):
else:
with open(os.path.expanduser(spec), encoding='utf-8', errors='replace') as f:
colors.update(parse_config(f))
cursor_text_color = colors.pop('cursor_text_color', False)
colors = {k: color_as_int(v) for k, v in colors.items() if isinstance(v, Color)}
return {
'title': ' '.join(args), 'match_window': opts.match, 'match_tab': opts.match_tab,
'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset, 'colors': colors, 'reset': opts.reset
'title': ' '.join(args), 'match_window': opts.match, 'match_tab': opts.match_tab,
'all': opts.all or opts.reset, 'configured': opts.configured or opts.reset,
'colors': colors, 'reset': opts.reset, 'cursor_text_color': cursor_text_color
}
def set_colors(boss, window, payload):
from .rgb import color_as_int
from .rgb import color_as_int, Color
if payload['all']:
windows = tuple(boss.all_windows)
else:
@@ -717,10 +726,14 @@ def set_colors(boss, window, payload):
windows += tuple(tab)
if payload['reset']:
payload['colors'] = {k: color_as_int(v) for k, v in boss.startup_colors.items()}
payload['cursor_text_color'] = boss.startup_cursor_text_color
profiles = tuple(w.screen.color_profile for w in windows)
from .fast_data_types import patch_color_profiles
patch_color_profiles(payload['colors'], profiles, payload['configured'])
boss.patch_colors(payload['colors'], payload['configured'])
cursor_text_color = payload.get('cursor_text_color', False)
if isinstance(cursor_text_color, (tuple, list, Color)):
cursor_text_color = color_as_int(Color(*cursor_text_color))
patch_color_profiles(payload['colors'], cursor_text_color, profiles, payload['configured'])
boss.patch_colors(payload['colors'], cursor_text_color, payload['configured'])
default_bg_changed = 'background' in payload['colors']
for w in windows:
if default_bg_changed:

View File

@@ -12,6 +12,7 @@
#include <AvailabilityMacros.h>
// Needed for _NSGetProgname
#include <crt_externs.h>
#include <objc/runtime.h>
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101200)
#define NSWindowStyleMaskResizable NSResizableWindowMask
@@ -99,6 +100,21 @@ cocoa_set_new_window_trigger(PyObject *self UNUSED, PyObject *args) {
Py_RETURN_FALSE;
}
// Implementation of applicationDockMenu: for the app delegate
static NSMenu *dockMenu = nil;
static NSMenu *
get_dock_menu(id self UNUSED, SEL _cmd UNUSED, NSApplication *sender UNUSED) {
if (!dockMenu) {
GlobalMenuTarget *global_menu_target = [GlobalMenuTarget shared_instance];
dockMenu = [[NSMenu alloc] init];
NSMenuItem *newWindowItem = [dockMenu addItemWithTitle:@"New OS window"
action:@selector(new_os_window:)
keyEquivalent:@""];
[newWindowItem setTarget:global_menu_target];
}
return dockMenu;
}
void
cocoa_create_global_menu(void) {
NSString* app_name = find_app_name();
@@ -183,6 +199,12 @@ cocoa_create_global_menu(void) {
}
[bar release];
class_addMethod(
object_getClass([NSApp delegate]),
@selector(applicationDockMenu:),
(IMP)get_dock_menu,
"@@:@");
}
void
@@ -292,6 +314,12 @@ cocoa_set_titlebar_color(void *w, color_type titlebar_color)
}
}
static void
cleanup() {
if (dockMenu) [dockMenu release];
dockMenu = nil;
}
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, ""},
@@ -301,5 +329,9 @@ static PyMethodDef module_methods[] = {
bool
init_cocoa(PyObject *module) {
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
if (Py_AtExit(cleanup) != 0) {
PyErr_SetString(PyExc_RuntimeError, "Failed to register the cocoa_window at exit handler");
return false;
}
return true;
}

View File

@@ -100,8 +100,8 @@ update_ansi_color_table(ColorProfile *self, PyObject *val) {
static PyObject*
patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured;
if (!PyArg_ParseTuple(args, "O!O!p", &PyDict_Type, &spec, &PyTuple_Type, &profiles, &change_configured)) return NULL;
PyObject *spec, *profiles, *v; ColorProfile *self; int change_configured; PyObject *cursor_text_color;
if (!PyArg_ParseTuple(args, "O!OO!p", &PyDict_Type, &spec, &cursor_text_color, &PyTuple_Type, &profiles, &change_configured)) return NULL;
char key[32] = {0};
for (size_t i = 0; i < arraysz(FG_BG_256); i++) {
snprintf(key, sizeof(key) - 1, "color%zu", i);
@@ -131,6 +131,22 @@ patch_color_profiles(PyObject *module UNUSED, PyObject *args) {
S(foreground, default_fg); S(background, default_bg); S(cursor, cursor_color);
S(selection_foreground, highlight_fg); S(selection_background, highlight_bg);
#undef S
if (cursor_text_color != Py_False) {
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(profiles); i++) {
self = (ColorProfile*)PyTuple_GET_ITEM(profiles, i);
self->overridden.cursor_text_color = 0x111111;
self->overridden.cursor_text_uses_bg = 3;
if (cursor_text_color != Py_None) {
self->overridden.cursor_text_color = (PyLong_AsUnsignedLong(cursor_text_color) << 8) | 2;
self->overridden.cursor_text_uses_bg = 1;
}
if (change_configured) {
self->configured.cursor_text_color = self->overridden.cursor_text_color;
self->configured.cursor_text_uses_bg = self->overridden.cursor_text_uses_bg;
}
self->dirty = true;
}
}
Py_RETURN_NONE;
}
@@ -149,6 +165,14 @@ colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval) {
}
}
float
cursor_text_as_bg(ColorProfile *self) {
if (self->overridden.cursor_text_uses_bg & 1) {
return self->overridden.cursor_text_uses_bg & 2 ? 1.f : 0.f;
}
return self->configured.cursor_text_uses_bg & 2 ? 1.f : 0.f;
}
static PyObject*
as_dict(ColorProfile *self, PyObject *args UNUSED) {
@@ -174,7 +198,7 @@ as_dict(ColorProfile *self, PyObject *args UNUSED) {
if (ret != 0) { Py_CLEAR(ans); return NULL; } \
}}
D(default_fg, foreground); D(default_bg, background);
D(cursor_color, cursor); D(highlight_fg, selection_foreground);
D(cursor_color, cursor); D(cursor_text_color, cursor_text); D(highlight_fg, selection_foreground);
D(highlight_bg, selection_background);
#undef D
@@ -236,7 +260,11 @@ set_color(ColorProfile *self, PyObject *args) {
static PyObject*
set_configured_colors(ColorProfile *self, PyObject *args) {
#define set_configured_colors_doc "Set the configured colors"
if (!PyArg_ParseTuple(args, "II|III", &(self->configured.default_fg), &(self->configured.default_bg), &(self->configured.cursor_color), &(self->configured.highlight_fg), &(self->configured.highlight_bg))) return NULL;
if (!PyArg_ParseTuple(
args, "II|IIIII",
&(self->configured.default_fg), &(self->configured.default_bg),
&(self->configured.cursor_color), &(self->configured.cursor_text_color), &(self->configured.cursor_text_uses_bg),
&(self->configured.highlight_fg), &(self->configured.highlight_bg))) return NULL;
self->dirty = true;
Py_RETURN_NONE;
}
@@ -286,6 +314,7 @@ default_color_table(PyObject *self UNUSED, PyObject *args UNUSED) {
CGETSET(default_fg)
CGETSET(default_bg)
CGETSET(cursor_color)
CGETSET(cursor_text_color)
CGETSET(highlight_fg)
CGETSET(highlight_bg)
@@ -293,6 +322,7 @@ static PyGetSetDef getsetters[] = {
GETSET(default_fg)
GETSET(default_bg)
GETSET(cursor_color)
GETSET(cursor_text_color)
GETSET(highlight_fg)
GETSET(highlight_bg)
{NULL} /* Sentinel */

View File

@@ -115,7 +115,7 @@ def float_parse(func, rest):
@func_with_args('change_font_size')
def parse_change_font_size(func, rest):
vals = rest.split(' ', 1)
vals = rest.strip().split(' ', 1)
if len(vals) != 2:
log_error('Invalid change_font_size specification: {}, treating it as default'.format(rest))
args = [True, None, 0]
@@ -125,13 +125,13 @@ def parse_change_font_size(func, rest):
if amt[0] in '+-':
args[1] = amt[0]
amt = amt[1:]
args[2] = float(amt)
args[2] = float(amt.strip())
return func, args
@func_with_args('clear_terminal')
def clear_terminal(func, rest):
vals = rest.split(' ', 1)
vals = rest.strip().split(' ', 1)
if len(vals) != 2:
log_error('clear_terminal needs two arguments, using defaults')
args = ['reset', 'active']
@@ -150,6 +150,27 @@ def neighboring_window(func, rest):
return func, [rest]
@func_with_args('resize_window')
def resize_window(func, rest):
vals = rest.strip().split(' ', 1)
if len(vals) > 2:
log_error('resize_window needs one or two arguments, using defaults')
args = ['wider', 1]
else:
quality = vals[0].lower()
if quality not in ('taller', 'shorter', 'wider', 'narrower'):
log_error('Invalid quality specification: {}'.format(quality))
quality = 'wider'
increment = 1
if len(vals) == 2:
try:
increment = int(vals[1])
except Exception:
log_error('Invalid increment specification: {}'.format(vals[1]))
args = [quality, increment]
return func, args
@func_with_args('move_window')
def move_window(func, rest):
rest = rest.lower()
@@ -184,7 +205,7 @@ def nth_window(func, rest):
def parse_key_action(action):
parts = action.split(' ', 1)
parts = action.strip().split(' ', 1)
func = parts[0]
if len(parts) == 1:
return KeyAction(func, ())
@@ -195,7 +216,8 @@ def parse_key_action(action):
func, args = parser(func, rest)
except Exception:
log_error('Ignoring invalid key action: {}'.format(action))
return KeyAction(func, args)
else:
return KeyAction(func, args)
all_key_actions = set()

View File

@@ -169,14 +169,14 @@ Similarly, to switch back to the previous layout::
''')],
'shortcuts.fonts': [
_('Font sizes'), _('''\
You can change the font size for all top-level kitty windows at a time
You can change the font size for all top-level kitty OS windows at a time
or only the current one.
'''), _('''\
To setup shortcuts for specific font sizes::
map kitty_mod+f6 change_font_size all 10.0
To setup shortcuts to change only the current window's font size::
To setup shortcuts to change only the current OS window's font size::
map kitty_mod+f6 change_font_size current 10.0
''')],
@@ -608,6 +608,13 @@ entries to this list.
o('tab_separator', '"{}"'.format(default_tab_separator), option_type=tab_separator, long_text=_('''
The separator between tabs in the tab bar when using :code:`separator` as the :opt:`tab_bar_style`.'''))
o('tab_title_template', '{title}', long_text=_('''
A template to render the tab title. The default just renders
the title. If you wish to include the tab-index as well,
use something like: :code:`{index}: {title}`. Useful
if you have shortcuts mapped for :code:`goto_tab N`.
'''))
o('active_tab_foreground', '#000', option_type=to_color, long_text=_('''
Tab bar colors and styles'''))
o('active_tab_background', '#eee', option_type=to_color)
@@ -841,7 +848,9 @@ g('shortcuts.clipboard') # {{{
if is_macos:
k('copy_to_clipboard', 'cmd+c', 'copy_to_clipboard', _('Copy to clipboard'), add_to_docs=False)
k('paste_from_clipboard', 'cmd+v', 'paste_from_clipboard', _('Paste from clipboard'), add_to_docs=False)
k('copy_to_clipboard', 'kitty_mod+c', 'copy_to_clipboard', _('Copy to 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`.
It will copy only if there is a selection and send an interrupt otherwise.'''))
k('paste_from_clipboard', 'kitty_mod+v', 'paste_from_clipboard', _('Paste from clipboard'))
k('paste_from_selection', 'kitty_mod+s', 'paste_from_selection', _('Paste from selection'))
k('paste_from_selection', 'shift+insert', 'paste_from_selection', _('Paste from selection'))
@@ -906,6 +915,8 @@ if is_macos:
k('new_os_window', 'cmd+n', 'new_os_window', _('New OS window'))
k('new_os_window', 'kitty_mod+n', 'new_os_window', _('New OS window'))
k('close_window', 'kitty_mod+w', 'close_window', _('Close window'))
if is_macos:
k('close_window', 'cmd+w', 'close_window', _('Close window'), add_to_docs=False)
k('next_window', 'kitty_mod+]', 'next_window', _('Next window'))
k('previous_window', 'kitty_mod+[', 'previous_window', _('Previous window'))
k('move_window_forward', 'kitty_mod+f', 'move_window_forward', _('Move window forward'))
@@ -926,12 +937,14 @@ k('tenth_window', 'kitty_mod+0', 'tenth_window', _('Tenth window'))
g('shortcuts.tab') # {{{
if is_macos:
k('next_tab', 'ctrl+tab', 'next_tab', _('Next tab'))
k('next_tab', 'ctrl+tab', 'next_tab', _('Next tab'), add_to_docs=False)
k('next_tab', 'kitty_mod+right', 'next_tab', _('Next tab'))
if is_macos:
k('previous_tab', 'ctrl+shift+tab', 'previous_tab', _('Previous tab'))
k('previous_tab', 'ctrl+shift+tab', 'previous_tab', _('Previous tab'), add_to_docs=False)
k('previous_tab', 'kitty_mod+left', 'previous_tab', _('Previous tab'))
k('new_tab', 'kitty_mod+t', 'new_tab', _('New tab'))
if is_macos:
k('new_tab', 'cmd+t', 'new_tab', _('New tab'), add_to_docs=False)
k('close_tab', 'kitty_mod+q', 'close_tab', _('Close tab'))
k('move_tab_forward', 'kitty_mod+.', 'move_tab_forward', _('Move tab forward'))
k('move_tab_backward', 'kitty_mod+,', 'move_tab_backward', _('Move tab backward'))

View File

@@ -8,7 +8,7 @@ import sys
from collections import namedtuple
appname = 'kitty'
version = (0, 13, 1)
version = (0, 13, 3)
str_version = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos = 'darwin' in _plat

View File

@@ -40,6 +40,7 @@
#define NS_TO_US (1000)
#ifdef __APPLE__
#include <libproc.h>
#include <mach/mach_time.h>
static mach_timebase_info_data_t timebase = {0};
@@ -54,6 +55,25 @@ user_cache_dir() {
return PyUnicode_FromString(buf);
}
static PyObject*
process_group_map() {
int num_of_processes = proc_listallpids(NULL, 0);
size_t bufsize = sizeof(pid_t) * (num_of_processes + 1024);
pid_t *buf = malloc(bufsize);
if (!buf) return PyErr_NoMemory();
num_of_processes = proc_listallpids(buf, (int)bufsize);
PyObject *ans = PyTuple_New(num_of_processes);
if (ans == NULL) { free(buf); return PyErr_NoMemory(); }
for (int i = 0; i < num_of_processes; i++) {
long pid = buf[i], pgid = getpgid(buf[i]);
PyObject *t = Py_BuildValue("ll", pid, pgid);
if (t == NULL) { free(buf); Py_DECREF(ans); return NULL; }
PyTuple_SET_ITEM(ans, i, t);
}
free(buf);
return ans;
}
#else
#include <time.h>
static inline double monotonic_() {
@@ -177,6 +197,7 @@ static PyMethodDef module_methods[] = {
{"redirect_std_streams", (PyCFunction)redirect_std_streams, METH_VARARGS, ""},
#ifdef __APPLE__
METHODB(user_cache_dir, METH_NOARGS),
METHODB(process_group_map, METH_NOARGS),
#endif
#ifdef WITH_PROFILER
{"start_profiler", (PyCFunction)start_profiler, METH_VARARGS, ""},

View File

@@ -210,7 +210,7 @@ typedef struct {
} CursorRenderInfo;
typedef struct {
color_type default_fg, default_bg, cursor_color, highlight_fg, highlight_bg;
color_type default_fg, default_bg, cursor_color, cursor_text_color, cursor_text_uses_bg, highlight_fg, highlight_bg;
} DynamicColor;
typedef struct {
@@ -285,6 +285,7 @@ bool schedule_write_to_child(unsigned long id, unsigned int num, ...);
bool set_iutf8(int, bool);
color_type colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval);
float cursor_text_as_bg(ColorProfile *self);
void copy_color_table_to_buffer(ColorProfile *self, color_type *address, int offset, size_t stride);
void colorprofile_push_dynamic_colors(ColorProfile*);
void colorprofile_pop_dynamic_colors(ColorProfile*);

View File

@@ -31,10 +31,15 @@ static PyObject*
init_x11_startup_notification(PyObject UNUSED *self, PyObject *args) {
static bool done = false;
static const char* libname = "libstartup-notification-1.so";
// some installs are missing the .so symlink, so try the full name
static const char* libname2 = "libstartup-notification-1.so.0";
static const char* libname3 = "libstartup-notification-1.so.0.0.0";
if (!done) {
done = true;
libsn_handle = dlopen(libname, RTLD_LAZY);
if (libsn_handle == NULL) libsn_handle = dlopen(libname2, RTLD_LAZY);
if (libsn_handle == NULL) libsn_handle = dlopen(libname3, RTLD_LAZY);
if (libsn_handle == NULL) {
PyErr_Format(PyExc_OSError, "Failed to load %s with error: %s", libname, dlerror());
return NULL;

View File

@@ -24,11 +24,12 @@ pyspacing(int val) {
#undef S
}
static inline PyObject*
pattern_as_dict(FcPattern *pat) {
PyObject *ans = PyDict_New();
if (ans == NULL) return NULL;
#define PS(x) PyUnicode_FromString((char*)x)
#define PS(x) PyUnicode_Decode((const char*)x, strlen((const char*)x), "UTF-8", "replace")
#define G(type, get, which, conv, name) { \
type out; PyObject *p; \
if (get(pat, which, 0, &out) == FcResultMatch) { \

View File

@@ -1012,19 +1012,17 @@ render_line(FONTS_DATA_HANDLE fg_, Line *line) {
if (is_private_use(cpu_cell->ch)
&& cell_font_idx != BOX_FONT
&& cell_font_idx != MISSING_FONT) {
int desired_cells;
int desired_cells = 1;
if (cell_font_idx > 0) {
Font *font = (fg->fonts + cell_font_idx);
glyph_index glyph_id = glyph_id_for_codepoint(font->face, cpu_cell->ch);
int width = get_glyph_width(font->face, glyph_id);
desired_cells = ceilf((float)width / fg->cell_width);
} else {
desired_cells = 1;
}
int num_spaces = 0;
while ((line->cpu_cells[i+num_spaces+1].ch == ' ' || line->cpu_cells[i+num_spaces+1].ch == 0)
while ((line->cpu_cells[i+num_spaces+1].ch == ' ')
&& num_spaces < MAX_NUM_EXTRA_GLYPHS_PUA
&& num_spaces < desired_cells
&& i + num_spaces + 1 < line->xnum) {

1
kitty/glfw-wrapper.h generated
View File

@@ -166,6 +166,7 @@
#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */
#define GLFW_KEY_WORLD_1 161 /* non-US #1 */
#define GLFW_KEY_WORLD_2 162 /* non-US #2 */
#define GLFW_KEY_PLUS 163 /* non-US #2 */
/* Function keys */
#define GLFW_KEY_ESCAPE 256

View File

@@ -35,8 +35,8 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) {
}
window->viewport_width = fw; window->viewport_height = fh;
double xr = window->viewport_x_ratio, yr = window->viewport_y_ratio;
window->viewport_x_ratio = (double)window->viewport_width / (double)w;
window->viewport_y_ratio = (double)window->viewport_height / (double)h;
window->viewport_x_ratio = w > 0 ? (double)window->viewport_width / (double)w : xr;
window->viewport_y_ratio = h > 0 ? (double)window->viewport_height / (double)h : yr;
double xdpi = window->logical_dpi_x, ydpi = window->logical_dpi_y;
set_os_window_dpi(window);
bool dpi_changed = (xr != 0.0 && xr != window->viewport_x_ratio) || (yr != 0.0 && yr != window->viewport_y_ratio) || (xdpi != window->logical_dpi_x) || (ydpi != window->logical_dpi_y);
@@ -57,6 +57,19 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) {
}
}
// On Cocoa, glfwWaitEvents() can block indefinitely because of the way Cocoa
// works. See https://github.com/glfw/glfw/issues/1251. I have noticed this
// happening in particular with window resize events, when waiting with no
// timeout. See https://github.com/kovidgoyal/kitty/issues/458
// So we use an unlovely hack to workaround that case
void
unjam_event_loop() {
#ifdef __APPLE__
if (event_loop_blocking_with_no_timeout)
wakeup_main_loop();
#endif
}
// callbacks {{{
@@ -98,16 +111,6 @@ show_mouse_cursor(GLFWwindow *w) {
}
static int min_width = 100, min_height = 100;
// On Cocoa, glfwWaitEvents() can block indefinitely because of the way Cocoa
// works. See https://github.com/glfw/glfw/issues/1251. I have noticed this
// happening in particular with window resize events, when waiting with no
// timeout. See https://github.com/kovidgoyal/kitty/issues/458
// So we use an unlovely hack to workaround that case
#ifdef __APPLE__
#define unjam_event_loop() { if (event_loop_blocking_with_no_timeout) wakeup_main_loop(); }
#else
#define unjam_event_loop()
#endif
static void
framebuffer_size_callback(GLFWwindow *w, int width, int height) {
@@ -352,8 +355,9 @@ get_window_dpi(GLFWwindow *w, double *x, double *y) {
float xscale = 1, yscale = 1;
if (w) glfwGetWindowContentScale(w, &xscale, &yscale);
else glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale);
if (!xscale) xscale = 1.0;
if (!yscale) yscale = 1.0;
// check for zero or NaN values of xscale/yscale
if (!xscale || xscale != xscale) xscale = 1.0;
if (!yscale || yscale != yscale) yscale = 1.0;
#ifdef __APPLE__
double factor = 72.0;
#else
@@ -650,6 +654,12 @@ bool
application_quit_requested() {
return !application_quit_canary || glfwWindowShouldClose(application_quit_canary);
}
void
request_application_quit() {
if (application_quit_canary)
glfwSetWindowShouldClose(application_quit_canary, true);
}
#endif
// Global functions {{{
@@ -749,6 +759,24 @@ get_clipboard_string(PYNOARG) {
return Py_BuildValue("s", "");
}
void
ring_audio_bell(OSWindow *w) {
static double last_bell_at = -1;
double now = monotonic();
if (now - last_bell_at <= 0.1) return;
last_bell_at = now;
if (w->handle) {
glfwWindowBell(w->handle);
}
}
static PyObject*
ring_bell(PYNOARG) {
OSWindow *w = current_os_window();
ring_audio_bell(w);
Py_RETURN_NONE;
}
static PyObject*
get_content_scale_for_window(PYNOARG) {
OSWindow *w = global_state.callback_os_window ? global_state.callback_os_window : global_state.os_windows;
@@ -786,17 +814,6 @@ change_os_window_state(PyObject *self UNUSED, PyObject *args) {
Py_RETURN_NONE;
}
void
ring_audio_bell(OSWindow *w) {
static double last_bell_at = -1;
double now = monotonic();
if (now - last_bell_at <= 0.1) return;
last_bell_at = now;
if (w->handle) {
glfwWindowBell(w->handle);
}
}
void
request_window_attention(id_type kitty_window_id, bool audio_bell) {
OSWindow *w = os_window_for_kitty_window(kitty_window_id);
@@ -1019,6 +1036,7 @@ static PyMethodDef module_methods[] = {
METHODB(set_default_window_icon, METH_VARARGS),
METHODB(get_clipboard_string, METH_NOARGS),
METHODB(get_content_scale_for_window, METH_NOARGS),
METHODB(ring_bell, METH_NOARGS),
METHODB(set_clipboard_string, METH_VARARGS),
METHODB(toggle_fullscreen, METH_NOARGS),
METHODB(change_os_window_state, METH_VARARGS),
@@ -1116,6 +1134,7 @@ init_glfw(PyObject *m) {
ADDC(GLFW_KEY_GRAVE_ACCENT);
ADDC(GLFW_KEY_WORLD_1);
ADDC(GLFW_KEY_WORLD_2);
ADDC(GLFW_KEY_PLUS);
// --- Function keys -----------------------------------------------------------
ADDC(GLFW_KEY_ESCAPE);

View File

@@ -368,7 +368,10 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
if (fd == -1) ABRT(EBADF, "Failed to open file %s for graphics transmission with error: [%d] %s", fname, errno, strerror(errno));
img->data_loaded = mmap_img_file(self, img, fd, g->data_sz, g->data_offset);
close(fd);
if (tt == 't') unlink(fname);
if (tt == 't') {
if (global_state.boss) { call_boss(safe_delete_temp_file, "s", fname); }
else unlink(fname);
}
else if (tt == 's') shm_unlink(fname);
break;
default:

47
kitty/key_encoding.py generated
View File

@@ -127,7 +127,8 @@ ENCODING = {
'WORLD 2': 'x',
'X': 'p',
'Y': 'q',
'Z': 'r'
'Z': 'r',
'PLUS': 'Bi'
}
KEY_MAP = {
32: 'A',
@@ -180,6 +181,7 @@ KEY_MAP = {
96: 'v',
161: 'w',
162: 'x',
163: 'Bi',
256: 'y',
257: 'z',
258: '0',
@@ -250,10 +252,8 @@ KEY_MAP = {
346: 'Bg',
347: 'Bh'
}
# END_ENCODING }}}
text_keys = string.ascii_uppercase + string.ascii_lowercase + string.digits + '`~!@#$%^&*()_-+=[{]}\\|<,>./?;:\'" '
@@ -324,28 +324,35 @@ mod_map = {c: i for i, c in enumerate('ABCDEFGHIJKLMNOP')}
key_rmap = {}
g = globals()
config_key_map = {}
config_mod_map = {'SHIFT': SHIFT, 'ALT': ALT, 'OPTION': ALT, '': ALT, '': SUPER, 'CMD': SUPER, 'SUPER': SUPER, 'CTRL': CTRL, 'CONTROL': CTRL}
config_mod_map = {
'SHIFT': SHIFT,
'ALT': ALT,
'OPTION': ALT,
'': ALT,
'': SUPER,
'CMD': SUPER,
'SUPER': SUPER,
'CTRL': CTRL,
'CONTROL': CTRL
}
for key_name, enc in ENCODING.items():
key_name = key_name.replace(' ', '_')
g[key_name] = config_key_map[key_name] = key_name
key_rmap[enc] = key_name
config_key_map.update({
'`': g['GRAVE_ACCENT'],
'-': g['MINUS'],
'=': g['EQUAL'],
'[': g['LEFT_BRACKET'],
']': g['RIGHT_BRACKET'],
'\\': g['BACKSLASH'],
';': g['SEMICOLON'],
"'": g['APOSTROPHE'],
',': g['COMMA'],
'.': g['PERIOD'],
'/': g['SLASH'],
'ESC': g['ESCAPE'],
'`': g['GRAVE_ACCENT'],
'-': g['MINUS'],
'=': g['EQUAL'],
'[': g['LEFT_BRACKET'],
']': g['RIGHT_BRACKET'],
'\\': g['BACKSLASH'],
';': g['SEMICOLON'],
"'": g['APOSTROPHE'],
',': g['COMMA'],
'.': g['PERIOD'],
'/': g['SLASH'],
'ESC': g['ESCAPE'],
'+': g['PLUS'],
})
enter_key = KeyEvent(PRESS, 0, g['ENTER'])

11691
kitty/keys.h generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,20 +6,10 @@ import string
from . import fast_data_types as defines
from .key_encoding import KEY_MAP
from .terminfo import key_as_bytes
from .terminfo import key_as_bytes, modify_key_bytes
from .utils import base64_encode
def modify_key_bytes(keybytes, amt):
ans = bytearray(keybytes)
amt = str(amt).encode('ascii')
if ans[-1] == ord('~'):
return bytes(ans[:-1] + bytearray(b';' + amt + b'~'))
if ans[1] == ord('O'):
return bytes(ans[:1] + bytearray(b'[1;' + amt) + ans[-1:])
raise ValueError('Unknown key type in key: {!r}'.format(keybytes))
def modify_complex_key(name, amt):
if not isinstance(name, bytes):
name = key_as_bytes(name)

View File

@@ -83,13 +83,10 @@ def talk_to_instance(args):
def load_all_shaders(semi_transparent=0):
load_shader_programs(semi_transparent, load_all_shaders.cursor_text_color)
load_shader_programs(semi_transparent)
load_borders_program()
load_all_shaders.cursor_text_color = None
def init_glfw(debug_keyboard=False):
glfw_module = 'cocoa' if is_macos else ('wayland' if is_wayland else 'x11')
if not glfw_init(glfw_path(glfw_module), debug_keyboard):
@@ -122,7 +119,6 @@ def _run_app(opts, args):
new_os_window_trigger = get_new_os_window_trigger(opts)
if is_macos and opts.macos_custom_beam_cursor:
set_custom_ibeam_cursor()
load_all_shaders.cursor_text_color = opts.cursor_text_color
if not is_wayland and not is_macos: # no window icons on wayland
with open(logo_data_file, 'rb') as f:
set_default_window_icon(f.read(), 256, 256)
@@ -235,7 +231,7 @@ def _main():
rpath = os.path.dirname(kitty_exe())
items = frozenset(os.environ['PATH'].split(os.pathsep))
if rpath and rpath not in items:
os.environ['PATH'] += os.pathsep + rpath
os.environ['PATH'] = rpath + os.pathsep + os.environ.get('PATH', '')
args = sys.argv[1:]
if is_macos and os.environ.pop('KITTY_LAUNCHED_BY_LAUNCH_SERVICES', None) == '1':

View File

@@ -557,6 +557,8 @@ mouse_event(int button, int modifiers, int action) {
void
scroll_event(double UNUSED xoffset, double yoffset, int flags) {
bool in_tab_bar;
static id_type window_for_momentum_scroll = 0;
static bool main_screen_for_momentum_scroll = false;
unsigned int window_idx = 0;
Window *w = window_for_event(&window_idx, &in_tab_bar);
if (!w && !in_tab_bar) {
@@ -567,9 +569,35 @@ scroll_event(double UNUSED xoffset, double yoffset, int flags) {
if (t) w = t->windows + t->active_window;
}
if (!w) return;
Screen *screen = w->render_data.screen;
enum MomentumData { NoMomentumData, MomentumPhaseBegan, MomentumPhaseStationary, MomentumPhaseActive, MomentumPhaseEnded, MomentumPhaseCancelled, MomentumPhaseMayBegin };
enum MomentumData momentum_data = (flags >> 1) & 7;
switch(momentum_data) {
case NoMomentumData:
break;
case MomentumPhaseBegan:
window_for_momentum_scroll = w->id;
main_screen_for_momentum_scroll = screen->linebuf == screen->main_linebuf;
break;
case MomentumPhaseStationary:
case MomentumPhaseActive:
if (window_for_momentum_scroll != w->id || main_screen_for_momentum_scroll != (screen->linebuf == screen->main_linebuf)) return;
break;
case MomentumPhaseEnded:
case MomentumPhaseCancelled:
window_for_momentum_scroll = 0;
break;
case MomentumPhaseMayBegin:
default:
break;
}
if (yoffset == 0.0) return;
int s;
bool is_high_resolution = flags & 1;
if (is_high_resolution) {
yoffset *= OPT(touch_scroll_multiplier);
if (yoffset * global_state.callback_os_window->pending_scroll_pixels < 0) {
@@ -580,16 +608,26 @@ scroll_event(double UNUSED xoffset, double yoffset, int flags) {
global_state.callback_os_window->pending_scroll_pixels = pixels;
return;
}
s = abs(((int)round(pixels))) / global_state.callback_os_window->fonts_data->cell_height;
if (pixels < 0) s *= -1;
s = (int)round(pixels) / (int)global_state.callback_os_window->fonts_data->cell_height;
global_state.callback_os_window->pending_scroll_pixels = pixels - s * (int) global_state.callback_os_window->fonts_data->cell_height;
} else {
s = (int) round(yoffset * OPT(wheel_scroll_multiplier));
if (screen->linebuf == screen->main_linebuf || !screen->modes.mouse_tracking_mode) {
// Only use wheel_scroll_multiplier if we are scrolling kitty scrollback or in mouse
// tracking mode, where the application is responsible for interpreting scroll events
yoffset *= OPT(wheel_scroll_multiplier);
} else if (OPT(wheel_scroll_multiplier) < 0) {
// ensure that changing scroll direction still works, even though
// we are not using wheel_scroll_multiplier
yoffset *= -1;
}
s = (int) round(yoffset);
// apparently on cocoa some mice generate really small yoffset values
// when scrolling slowly https://github.com/kovidgoyal/kitty/issues/1238
if (s == 0 && yoffset != 0) s = yoffset > 0 ? 1 : -1;
global_state.callback_os_window->pending_scroll_pixels = 0;
}
if (s == 0) return;
bool upwards = s > 0;
Screen *screen = w->render_data.screen;
if (screen->linebuf == screen->main_linebuf) {
screen_history_scroll(screen, abs(s), upwards);
} else {
@@ -597,13 +635,7 @@ scroll_event(double UNUSED xoffset, double yoffset, int flags) {
int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, 0);
if (sz > 0) {
mouse_event_buf[sz] = 0;
if (is_high_resolution) {
for (s = abs(s); s > 0; s--) {
write_escape_code_to_child(screen, CSI, mouse_event_buf);
}
} else {
// Since we are sending a mouse button 4/5 event, we ignore 's'
// and simply send one event per received scroll event
for (s = abs(s); s > 0; s--) {
write_escape_code_to_child(screen, CSI, mouse_event_buf);
}
}

View File

@@ -219,9 +219,9 @@ static struct CellUniformData cell_uniform_data = {0, .prev_inactive_text_alpha=
static inline void
cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, CursorRenderInfo *cursor, bool inverted, OSWindow *os_window) {
struct CellRenderData {
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity;
GLfloat xstart, ystart, dx, dy, sprite_dx, sprite_dy, background_opacity, cursor_text_uses_bg;
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, url_color, url_style, inverted;
GLuint default_fg, default_bg, highlight_fg, highlight_bg, cursor_color, cursor_text_color, url_color, url_style, inverted;
GLuint xnum, ynum, cursor_fg_sprite_idx;
GLfloat cursor_x, cursor_y, cursor_w;
@@ -260,8 +260,10 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G
#define COLOR(name) colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.name, screen->color_profile->configured.name)
rd->default_fg = COLOR(default_fg); rd->default_bg = COLOR(default_bg); rd->highlight_fg = COLOR(highlight_fg); rd->highlight_bg = COLOR(highlight_bg);
rd->cursor_text_color = COLOR(cursor_text_color);
#undef COLOR
rd->cursor_color = cursor->color; rd->url_color = OPT(url_color); rd->url_style = OPT(url_style);
rd->cursor_text_uses_bg = cursor_text_as_bg(screen->color_profile);
unmap_vao_buffer(vao_idx, uniform_buffer); rd = NULL;
}

View File

@@ -144,7 +144,7 @@ typedef struct {
OSWindow *os_windows;
size_t num_os_windows, capacity;
OSWindow *callback_os_window;
bool close_all_windows;
bool terminate;
bool is_wayland;
bool debug_gl, debug_font_fallback;
bool has_pending_resizes;
@@ -172,6 +172,7 @@ void make_os_window_context_current(OSWindow *w);
void update_os_window_references();
void mark_os_window_for_close(OSWindow* w, bool yes);
void update_os_window_viewport(OSWindow *window, bool);
void unjam_event_loop();
bool should_os_window_close(OSWindow* w);
bool should_os_window_be_rendered(OSWindow* w);
void wakeup_main_loop();
@@ -209,5 +210,6 @@ typedef enum {
} CocoaPendingAction;
void set_cocoa_pending_action(CocoaPendingAction action);
bool application_quit_requested();
void request_application_quit();
#endif
void wayland_request_frame_render(OSWindow *w);

View File

@@ -11,31 +11,40 @@ from .fast_data_types import (
viewport_for_window
)
from .layout import Rect
from .utils import color_as_int
from .utils import color_as_int, log_error
from .window import calculate_gl_geometry
from .rgb import alpha_blend, color_from_int
TabBarData = namedtuple('TabBarData', 'title is_active needs_attention')
DrawData = namedtuple('DrawData', 'leading_spaces sep trailing_spaces bell_on_tab bell_fg alpha active_bg inactive_bg default_bg')
DrawData = namedtuple(
'DrawData', 'leading_spaces sep trailing_spaces bell_on_tab'
' bell_fg alpha active_bg inactive_bg default_bg title_template')
def as_rgb(x):
return (x << 8) | 2
def draw_title(draw_data, screen, tab):
def draw_title(draw_data, screen, tab, index):
if tab.needs_attention and draw_data.bell_on_tab:
fg = screen.cursor.fg
screen.cursor.fg = draw_data.bell_fg
screen.draw('🔔 ')
screen.cursor.fg = fg
screen.draw(tab.title)
try:
title = draw_data.title_template.format(title=tab.title, index=index)
except Exception as e:
if not hasattr(draw_title, 'template_failure_reported'):
draw_title.template_failure_reported = True
log_error('Invalid tab title template: "{}" with error: {}'.format(draw_data.title_template, e))
title = tab.title
screen.draw(title)
def draw_tab_with_separator(draw_data, screen, tab, before, max_title_length):
def draw_tab_with_separator(draw_data, screen, tab, before, max_title_length, index):
if draw_data.leading_spaces:
screen.draw(' ' * draw_data.leading_spaces)
draw_title(draw_data, screen, tab)
draw_title(draw_data, screen, tab, index)
if draw_data.trailing_spaces:
screen.draw(' ' * draw_data.trailing_spaces)
extra = screen.cursor.x - before - max_title_length
@@ -49,17 +58,17 @@ def draw_tab_with_separator(draw_data, screen, tab, before, max_title_length):
return end
def draw_tab_with_fade(draw_data, screen, tab, before, max_title_length):
def draw_tab_with_fade(draw_data, screen, tab, before, max_title_length, index):
tab_bg = draw_data.active_bg if tab.is_active else draw_data.inactive_bg
fade_colors = [as_rgb(color_as_int(alpha_blend(tab_bg, draw_data.default_bg, alpha))) for alpha in draw_data.alpha]
for bg in fade_colors:
screen.cursor.bg = bg
screen.draw(' ')
draw_title(draw_data, screen, tab)
draw_title(draw_data, screen, tab, index)
extra = screen.cursor.x - before - max_title_length
if extra > 0:
screen.cursor.x = before
draw_title(draw_data, screen, tab)
draw_title(draw_data, screen, tab, index)
extra = screen.cursor.x - before - max_title_length
if extra > 0:
screen.cursor.x -= extra + 1
@@ -81,6 +90,7 @@ class TabBar:
def __init__(self, os_window_id, opts):
self.os_window_id = os_window_id
self.opts = opts
draw_title.template = opts.tab_title_template
self.num_tabs = 1
self.margin_width = pt_to_px(self.opts.tab_bar_margin_width, self.os_window_id)
self.cell_width, cell_height = cell_size_for_window(self.os_window_id)
@@ -112,7 +122,7 @@ class TabBar:
self.draw_data = DrawData(
self.leading_spaces, self.sep, self.trailing_spaces, self.opts.bell_on_tab, self.bell_fg,
self.opts.tab_fade, self.opts.active_tab_background, self.opts.inactive_tab_background,
self.opts.background
self.opts.background, self.opts.tab_title_template
)
self.draw_func = draw_tab_with_separator if self.opts.tab_bar_style == 'separator' else draw_tab_with_fade
@@ -162,12 +172,12 @@ class TabBar:
cr = []
last_tab = data[-1] if data else None
for t in data:
for i, t in enumerate(data):
s.cursor.bg = self.active_bg if t.is_active else 0
s.cursor.fg = self.active_fg if t.is_active else 0
s.cursor.bold, s.cursor.italic = self.active_font_style if t.is_active else self.inactive_font_style
before = s.cursor.x
end = self.draw_func(self.draw_data, s, t, before, max_title_length)
end = self.draw_func(self.draw_data, s, t, before, max_title_length, i + 1)
cr.append((before, end))
if s.cursor.x > s.columns - max_title_length and t is not last_tab:
s.draw('')

View File

@@ -11,7 +11,7 @@ from .child import Child
from .constants import appname, get_boss, is_macos, is_wayland
from .fast_data_types import (
add_tab, glfw_post_empty_event, mark_tab_bar_dirty, next_window_id,
pt_to_px, remove_tab, remove_window, set_active_tab, swap_tabs,
pt_to_px, remove_tab, remove_window, ring_bell, set_active_tab, swap_tabs,
x11_window_id
)
from .layout import create_layout_object_for, evict_cached_layouts
@@ -199,6 +199,16 @@ class Tab: # {{{
return
return 'Could not resize'
def resize_window(self, quality, increment):
if increment < 1:
raise ValueError(increment)
is_horizontal = quality in ('wider', 'narrower')
increment *= 1 if quality in ('wider', 'taller') else -1
if self.resize_window_by(
self.windows[self.active_window_idx].id,
increment, is_horizontal) is not None:
ring_bell()
def reset_window_sizes(self):
if self.current_layout.remove_all_biases():
self.relayout()
@@ -501,8 +511,10 @@ class TabManager: # {{{
if len(self.tabs) > 1:
idx = self.active_tab_idx
nidx = (idx + len(self.tabs) + delta) % len(self.tabs)
self.tabs[idx], self.tabs[nidx] = self.tabs[nidx], self.tabs[idx]
swap_tabs(self.os_window_id, idx, nidx)
step = 1 if idx < nidx else -1
for i in range(idx, nidx, step):
self.tabs[i], self.tabs[i + step] = self.tabs[i + step], self.tabs[i]
swap_tabs(self.os_window_id, i, i + step)
self._set_active_tab(nidx)
self.mark_tab_bar_dirty()
@@ -512,8 +524,9 @@ class TabManager: # {{{
self._add_tab(Tab(self, special_window=special_window, cwd_from=cwd_from))
self._set_active_tab(idx)
if len(self.tabs) > 2 and as_neighbor and idx != nidx:
self.tabs[idx], self.tabs[nidx] = self.tabs[nidx], self.tabs[idx]
swap_tabs(self.os_window_id, idx, nidx)
for i in range(idx, nidx, -1):
self.tabs[i], self.tabs[i-1] = self.tabs[i-1], self.tabs[i]
swap_tabs(self.os_window_id, i, i-1)
self._set_active_tab(nidx)
idx = nidx
self.mark_tab_bar_dirty()

View File

@@ -6,6 +6,22 @@ import re
from binascii import hexlify, unhexlify
def modify_key_bytes(keybytes, amt):
if amt == 0:
return keybytes
ans = bytearray(keybytes)
amt = str(amt).encode('ascii')
if ans[-1] == ord('~'):
return bytes(ans[:-1] + bytearray(b';' + amt + b'~'))
if ans[1] == ord('O'):
return bytes(ans[:1] + bytearray(b'[1;' + amt) + ans[-1:])
raise ValueError('Unknown key type in key: {!r}'.format(keybytes))
def encode_keystring(keybytes):
return keybytes.decode('ascii').replace('\033', r'\E')
names = 'xterm-kitty', 'KovIdTTY'
termcap_aliases = {
@@ -156,54 +172,8 @@ string_capabilities = {
# 'invis': r'\E[8m',
# Backspace
'kbs': r'\177',
# Left
'kcub1': r'\EOD',
# Down
'kcud1': r'\EOB',
# Right
'kcuf1': r'\EOC',
# Up
'kcuu1': r'\EOA',
# Function keys
'kf1': r'\EOP',
'kf2': r'\EOQ',
'kf3': r'\EOR',
'kf4': r'\EOS',
'kf5': r'\E[15~',
'kf6': r'\E[17~',
'kf7': r'\E[18~',
'kf8': r'\E[19~',
'kf9': r'\E[20~',
'kf10': r'\E[21~',
'kf11': r'\E[23~',
'kf12': r'\E[24~',
'kf13': r'\E[1;2P',
'kf14': r'\E[1;2Q',
'kf15': r'\E[1;2R',
'kf16': r'\E[1;2S',
'kf17': r'\E[15;2~',
'kf18': r'\E[17;2~',
'kf19': r'\E[18;2~',
'kf20': r'\E[19;2~',
'kf21': r'\E[20;2~',
'kf22': r'\E[21;2~',
'kf23': r'\E[23;2~',
'kf24': r'\E[24;2~',
'kf25': r'\E[1;5P',
# Home
'khome': r'\EOH',
# End
'kend': r'\EOF',
# Insert character key
'kich1': r'\E[2~',
# Delete character key
'kdch1': r'\E[3~',
# Mouse event has occurred
'kmous': r'\E[M',
# Page down
'knp': r'\E[6~',
# Page up
'kpp': r'\E[5~',
# Scroll backwards (reverse index)
'kri': r'\E[1;2A',
# scroll forwards (index)
@@ -270,11 +240,6 @@ string_capabilities = {
# Select alternate charset
'smacs': r'\E(0',
'rmacs': r'\E(B',
# Shifted keys
'kRIT': r'\E[1;2C',
'kLFT': r'\E[1;2D',
'kEND': r'\E[1;2F',
'kHOM': r'\E[1;2H',
# Special keys
'khlp': r'',
'kund': r'',
@@ -298,6 +263,27 @@ string_capabilities = {
# 'rs2': r'\E[!p\E[?3;4l\E[4l\E>',
}
string_capabilities.update({
'kf{}'.format(offset + n):
encode_keystring(modify_key_bytes(b'\033' + value, mod))
for offset, mod in {0: 0, 12: 2, 24: 5, 36: 6, 48: 3, 60: 4}.items()
for n, value in zip(range(1, 13),
b'OP OQ OR OS [15~ [17~ [18~ [19~ [20~ [21~ [23~ [24~'.split())
if offset + n < 64
})
string_capabilities.update({
name.format(unmod=unmod, key=key):
encode_keystring(modify_key_bytes(b'\033' + value, mod))
for unmod, key, value in zip(
'cuu1 cud1 cuf1 cub1 end home ich1 dch1 pp np'.split(),
'UP DN RIT LFT END HOM IC DC PRV NXT'.split(),
b'OA OB OC OD OF OH [2~ [3~ [5~ [6~'.split())
for name, mod in {
'k{unmod}': 0, 'k{key}': 2, 'k{key}3': 3, 'k{key}4': 4,
'k{key}5': 5, 'k{key}6': 6, 'k{key}7': 7}.items()
})
termcap_aliases.update({
'ac': 'acsc',
'bl': 'bel',
@@ -346,31 +332,6 @@ termcap_aliases.update({
'kd': 'kcud1',
'kr': 'kcuf1',
'ku': 'kcuu1',
'k1': 'kf1',
'k2': 'kf2',
'k3': 'kf3',
'k4': 'kf4',
'k5': 'kf5',
'k6': 'kf6',
'k7': 'kf7',
'k8': 'kf8',
'k9': 'kf9',
'k;': 'kf10',
'F1': 'kf11',
'F2': 'kf12',
'F3': 'kf13',
'F4': 'kf14',
'F5': 'kf15',
'F6': 'kf16',
'F7': 'kf17',
'F8': 'kf18',
'F9': 'kf19',
'FA': 'kf20',
'FB': 'kf21',
'FC': 'kf22',
'FD': 'kf23',
'FE': 'kf24',
'FF': 'kf25',
'kh': 'khome',
'@7': 'kend',
'kI': 'kich1',
@@ -410,8 +371,12 @@ termcap_aliases.update({
'ks': 'smkx',
'ke': 'rmkx',
'#2': 'kHOM',
'#3': 'kIC',
'#4': 'kLFT',
'*4': 'kDC',
'*7': 'kEND',
'%c': 'kNXT',
'%e': 'kPRV',
'%i': 'kRIT',
'%1': 'khlp',
'&8': 'kund',
@@ -433,10 +398,22 @@ termcap_aliases.update({
# 'r2': 'rs2',
})
termcap_aliases.update({
tc: 'kf{}'.format(n)
for n, tc in enumerate(
'k1 k2 k3 k4 k5 k6 k7 k8 k9 k; F1 F2 F3 F4 F5 F6 F7 F8 F9 FA '
'FB FC FD FE FF FG FH FI FJ FK FL FM FN FO FP FQ FR FS FT FU '
'FV FW FX FY FZ Fa Fb Fc Fd Fe Ff Fg Fh Fi Fj Fk Fl Fm Fn Fo '
'Fp Fq Fr'.split(), 1)})
queryable_capabilities = numeric_capabilities.copy()
queryable_capabilities.update(string_capabilities)
extra = (bool_capabilities | numeric_capabilities.keys() | string_capabilities.keys()) - set(termcap_aliases.values())
no_termcap_for = frozenset('Su Tc setrgbf setrgbb fullkbd'.split())
no_termcap_for = frozenset(
'Su Tc setrgbf setrgbb fullkbd kUP kDN'.split() + [
'k{}{}'.format(key, mod)
for key in 'UP DN RIT LFT END HOM IC DC PRV NXT'.split()
for mod in range(3, 8)])
if extra - no_termcap_for:
raise Exception('Termcap aliases not complete, missing: {}'.format(extra - no_termcap_for))
del extra

View File

@@ -432,3 +432,20 @@ def get_editor():
ans = shlex.split(ans)
get_editor.ans = ans
return ans
def is_path_in_temp_dir(path):
if not path:
return False
def abspath(x):
if x:
return os.path.abspath(os.path.realpath(x))
import tempfile
path = abspath(path)
candidates = frozenset(map(abspath, ('/tmp', '/dev/shm', os.environ.get('TMPDIR', None), tempfile.gettempdir())))
for q in candidates:
if q and path.startswith(q):
return True
return False

View File

@@ -10,7 +10,6 @@ from collections import deque
from enum import IntEnum
from itertools import chain
from .child import cwd_of_process
from .config import build_ansi_color_table
from .constants import (
ScreenGeometry, WindowGeometry, appname, get_boss, wakeup
@@ -24,7 +23,7 @@ from .fast_data_types import (
set_clipboard_string, set_titlebar_color, set_window_render_data,
update_window_title, update_window_visibility, viewport_for_window
)
from .keys import keyboard_mode_name
from .keys import keyboard_mode_name, extended_key_event, defines
from .rgb import to_color
from .terminfo import get_capabilities
from .utils import (
@@ -56,14 +55,13 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell
return ScreenGeometry(xstart, ystart, window_geometry.xnum, window_geometry.ynum, dx, dy)
def load_shader_programs(semi_transparent=0, cursor_text_color=None):
def load_shader_programs(semi_transparent=0):
compile_program(BLIT_PROGRAM, *load_shaders('blit'))
v, f = load_shaders('cell')
def color_as_vec3(x):
return 'vec3({}, {}, {})'.format(x.red / 255, x.green / 255, x.blue / 255)
cursor_text_color = color_as_vec3(cursor_text_color) if cursor_text_color else 'bg'
for which, p in {
'SIMPLE': CELL_PROGRAM,
'BACKGROUND': CELL_BG_PROGRAM,
@@ -76,7 +74,6 @@ def load_shader_programs(semi_transparent=0, cursor_text_color=None):
'STRIKE_SHIFT': STRIKETHROUGH,
'DIM_SHIFT': DIM,
'DECORATION_SHIFT': DECORATION,
'CURSOR_TEXT_COLOR': cursor_text_color,
}.items():
vv = vv.replace('{{{}}}'.format(gln), str(pyn), 1)
if semi_transparent:
@@ -95,8 +92,13 @@ def load_shader_programs(semi_transparent=0, cursor_text_color=None):
def setup_colors(screen, opts):
screen.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
cursor_text_color = opts.cursor_text_color or (12, 12, 12)
cursor_text_color_as_bg = 3 if opts.cursor_text_color is None else 1
screen.color_profile.set_configured_colors(*map(color_as_int, (
opts.foreground, opts.background, opts.cursor, opts.selection_foreground, opts.selection_background)))
opts.foreground, opts.background, opts.cursor,
cursor_text_color, (0, 0, cursor_text_color_as_bg),
opts.selection_foreground, opts.selection_background)
))
def text_sanitizer(as_ansi, add_wrap_markers):
@@ -165,6 +167,7 @@ class Window:
cwd=self.child.current_cwd or self.child.cwd,
cmdline=self.child.cmdline,
env=self.child.environ,
foreground_processes=self.child.foreground_processes
)
@property
@@ -477,11 +480,7 @@ class Window:
@property
def cwd_of_child(self):
# TODO: Maybe use the cwd of the leader of the foreground process
# group in the session of the child process?
pid = self.child.pid
if pid is not None:
return cwd_of_process(pid) or None
return self.child.foreground_cwd or self.child.current_cwd
def pipe_data(self, text, has_wrap_markers=False):
text = text or ''
@@ -525,6 +524,15 @@ class Window:
if text:
set_clipboard_string(text)
def copy_or_interrupt(self):
text = self.text_for_selection()
if text:
set_clipboard_string(text)
else:
mode = keyboard_mode_name(self.screen)
text = extended_key_event(defines.GLFW_KEY_C, defines.GLFW_MOD_CONTROL, defines.GLFW_PRESS) if mode == 'kitty' else b'\x03'
self.write_to_child(text)
def pass_selection_to_program(self, *args):
cwd = self.cwd_of_child
text = self.text_for_selection()

View File

@@ -2,13 +2,16 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import os
import tempfile
from kitty.config import build_ansi_color_table, defaults
from kitty.fast_data_types import (
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf,
parse_input_from_terminal, wcswidth, wcwidth, truncate_point_for_length
parse_input_from_terminal, truncate_point_for_length, wcswidth, wcwidth
)
from kitty.rgb import to_color
from kitty.utils import sanitize_title
from kitty.utils import is_path_in_temp_dir, sanitize_title
from . import BaseTest, filled_cursor, filled_history_buf, filled_line_buf
@@ -384,6 +387,12 @@ class TestDataTypes(BaseTest):
tp('a\033', '_', 'x\033', '\\b', text='a b', apc='x')
tp('a\033_', 'x', '\033', '\\', 'b', text='a b', apc='x')
for prefix in ('/tmp', tempfile.gettempdir()):
for path in ('a.png', 'x/b.jpg', 'y/../c.jpg'):
self.assertTrue(is_path_in_temp_dir(os.path.join(prefix, path)))
for path in ('/home/xy/d.png', '/tmp/../home/x.jpg'):
self.assertFalse(is_path_in_temp_dir(os.path.join(path)))
def test_color_profile(self):
c = ColorProfile()
c.update_ansi_color_table(build_ansi_color_table())

View File

@@ -190,7 +190,7 @@ def init_env(
cppflags = shlex.split(cppflags)
cflags = os.environ.get(
'OVERRIDE_CFLAGS', (
'-Wextra -Wno-missing-field-initializers -Wall -std=c99'
'-Wextra -Wno-missing-field-initializers -Wall -std=c11'
' -pedantic-errors -Werror {} {} -fwrapv {} {} -pipe {} -fvisibility=hidden'
).format(
optimize,
@@ -393,14 +393,23 @@ def compile_c_extension(kenv, module, incremental, compilation_database, all_key
todo[original_src] = cmd
if todo:
parallel_run(todo)
dest = os.path.join(base, module + '.so')
if not incremental or newer(dest, *objects):
dest = os.path.join(base, module + '.temp.so')
real_dest = dest[:-len('.temp.so')] + '.so'
if not incremental or newer(real_dest, *objects):
# Old versions of clang don't like -pthread being passed to the linker
# Don't treat linker warnings as errors (linker generates spurious
# warnings on some old systems)
unsafe = {'-pthread', '-Werror', '-pedantic-errors'}
linker_cflags = list(filter(lambda x: x not in unsafe, kenv.cflags))
run_tool([kenv.cc] + linker_cflags + kenv.ldflags + objects + kenv.ldpaths + ['-o', dest], desc='Linking {} ...'.format(emphasis(module)))
try:
run_tool([kenv.cc] + linker_cflags + kenv.ldflags + objects + kenv.ldpaths + ['-o', dest], desc='Linking {} ...'.format(emphasis(module)))
except Exception:
try:
os.remove(dest)
except EnvironmentError:
pass
else:
os.rename(dest, real_dest)
def find_c_files():

Binary file not shown.

View File

@@ -57,10 +57,66 @@ xterm-kitty|KovIdTTY,
ind=^J,
indn=\E[%p1%dS,
initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
kDC=\E[3;2~,
kDC3=\E[3;3~,
kDC4=\E[3;4~,
kDC5=\E[3;5~,
kDC6=\E[3;6~,
kDC7=\E[3;7~,
kDN=\E[1;2B,
kDN3=\E[1;3B,
kDN4=\E[1;4B,
kDN5=\E[1;5B,
kDN6=\E[1;6B,
kDN7=\E[1;7B,
kEND=\E[1;2F,
kEND3=\E[1;3F,
kEND4=\E[1;4F,
kEND5=\E[1;5F,
kEND6=\E[1;6F,
kEND7=\E[1;7F,
kHOM=\E[1;2H,
kHOM3=\E[1;3H,
kHOM4=\E[1;4H,
kHOM5=\E[1;5H,
kHOM6=\E[1;6H,
kHOM7=\E[1;7H,
kIC=\E[2;2~,
kIC3=\E[2;3~,
kIC4=\E[2;4~,
kIC5=\E[2;5~,
kIC6=\E[2;6~,
kIC7=\E[2;7~,
kLFT=\E[1;2D,
kLFT3=\E[1;3D,
kLFT4=\E[1;4D,
kLFT5=\E[1;5D,
kLFT6=\E[1;6D,
kLFT7=\E[1;7D,
kNXT=\E[6;2~,
kNXT3=\E[6;3~,
kNXT4=\E[6;4~,
kNXT5=\E[6;5~,
kNXT6=\E[6;6~,
kNXT7=\E[6;7~,
kPRV=\E[5;2~,
kPRV3=\E[5;3~,
kPRV4=\E[5;4~,
kPRV5=\E[5;5~,
kPRV6=\E[5;6~,
kPRV7=\E[5;7~,
kRIT=\E[1;2C,
kRIT3=\E[1;3C,
kRIT4=\E[1;4C,
kRIT5=\E[1;5C,
kRIT6=\E[1;6C,
kRIT7=\E[1;7C,
kUP=\E[1;2A,
kUP3=\E[1;3A,
kUP4=\E[1;4A,
kUP5=\E[1;5A,
kUP6=\E[1;6A,
kUP7=\E[1;7A,
ka1=,
ka3=,
kbs=\177,
@@ -91,10 +147,48 @@ xterm-kitty|KovIdTTY,
kf23=\E[23;2~,
kf24=\E[24;2~,
kf25=\E[1;5P,
kf26=\E[1;5Q,
kf27=\E[1;5R,
kf28=\E[1;5S,
kf29=\E[15;5~,
kf3=\EOR,
kf30=\E[17;5~,
kf31=\E[18;5~,
kf32=\E[19;5~,
kf33=\E[20;5~,
kf34=\E[21;5~,
kf35=\E[23;5~,
kf36=\E[24;5~,
kf37=\E[1;6P,
kf38=\E[1;6Q,
kf39=\E[1;6R,
kf4=\EOS,
kf40=\E[1;6S,
kf41=\E[15;6~,
kf42=\E[17;6~,
kf43=\E[18;6~,
kf44=\E[19;6~,
kf45=\E[20;6~,
kf46=\E[21;6~,
kf47=\E[23;6~,
kf48=\E[24;6~,
kf49=\E[1;3P,
kf5=\E[15~,
kf50=\E[1;3Q,
kf51=\E[1;3R,
kf52=\E[1;3S,
kf53=\E[15;3~,
kf54=\E[17;3~,
kf55=\E[18;3~,
kf56=\E[19;3~,
kf57=\E[20;3~,
kf58=\E[21;3~,
kf59=\E[23;3~,
kf6=\E[17~,
kf60=\E[24;3~,
kf61=\E[1;4P,
kf62=\E[1;4Q,
kf63=\E[1;4R,
kf7=\E[18~,
kf8=\E[19~,
kf9=\E[20~,

Binary file not shown.