Compare commits

...

45 Commits

Author SHA1 Message Date
Kovid Goyal
57b5e493a4 version 0.20.2 2021-04-28 10:50:34 +05:30
Kovid Goyal
fc184984a0 ... 2021-04-27 15:11:34 +05:30
Kovid Goyal
2178ff1c48 DRYer 2021-04-27 15:07:27 +05:30
Kovid Goyal
ae1df38c88 Fallback to mkostemp if O_TMPFILE fails 2021-04-27 12:03:24 +05:30
Kovid Goyal
162e498347 Fix @ set-colors for active_tab_foreground 2021-04-26 20:18:50 +05:30
Kovid Goyal
172023afca Forgot the double backslash in the docs 2021-04-26 17:31:43 +05:30
Kovid Goyal
18c7ea50b4 Cleanup text 2021-04-26 13:46:03 +05:30
Kovid Goyal
bdddb238f8 Also generate a man page for kitty.conf 2021-04-26 13:35:22 +05:30
Kovid Goyal
8d46237935 Add the most common keyboard shortcuts to the kitty man page 2021-04-26 12:39:25 +05:30
Kovid Goyal
3fcf83e685 Use a framed icon on macOS
Fits better with Apple's icon style
2021-04-26 12:07:35 +05:30
Kovid Goyal
d374af4341 Type check supersampled functions 2021-04-26 09:12:38 +05:30
Kovid Goyal
f32ad617a2 Special case rendering of the few remaining Powerline box drawing chars
Fixes #3535
2021-04-26 09:07:55 +05:30
Kovid Goyal
62656b24eb GNOME: Add a new option to control the color of the kitty window titlebar 2021-04-25 11:22:23 +05:30
Kovid Goyal
12763e19d8 Add a build argument to turn off -Werror
Fixes #3530
2021-04-24 18:32:57 +05:30
Kovid Goyal
89fd726e07 A new remote control command @env to change the default environment passed to newly created windows
Fixes #3529
2021-04-24 18:06:57 +05:30
Kovid Goyal
0b428987b1 ... 2021-04-24 18:02:16 +05:30
Kovid Goyal
1e29fad5f0 Typecheck @ls cli opts 2021-04-24 17:51:02 +05:30
Kovid Goyal
19524a4459 Update uthash 2021-04-24 09:47:40 +05:30
Kovid Goyal
7043d565c9 ... 2021-04-24 09:44:40 +05:30
Kovid Goyal
d6f856f2f2 Fix https://trac.macports.org/ticket/62732 2021-04-24 07:43:02 +05:30
Kovid Goyal
24f0451c10 Merge branch 'bug3514-fix' of https://github.com/orki/kitty 2021-04-23 21:27:31 +05:30
Ravi R Kiran
3c4460ca98 Give shift, control and caps lock precedence over other modifiers 2021-04-23 10:47:26 -05:00
Kovid Goyal
cbf33fa14b Fix #3523 2021-04-23 16:23:13 +05:30
Kovid Goyal
d782654819 Forgot to handle case of empty scrollback 2021-04-23 16:07:10 +05:30
Kovid Goyal
3c39cbf333 Add a note about over large scrollback fill 2021-04-23 15:54:21 +05:30
Kovid Goyal
bd746e5151 Add a note about what happens when no scrollback lines are present 2021-04-23 15:48:47 +05:30
Kovid Goyal
b32c346eed A new protocol extension to unscroll the screen
See https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/30
2021-04-23 15:44:38 +05:30
Kovid Goyal
77b8e204ad Fix graphics being cleared when switching to alt screen if the switch mode is to not clear the alt screen 2021-04-23 14:51:32 +05:30
Kovid Goyal
93dfe19c35 GNOME: Fix maximize state not being remembered when focus changes and window decorations are hidden
Apparently mutter needs window geometry set after the surface commit not
before, otherwise it doesnt "stick". When decorations are not hidden
there were other commits caused by the decorations, masking the issue.

Fixes #3507
2021-04-23 14:04:12 +05:30
Kovid Goyal
6dc8df5178 icat kitten: Respect EXIF orientation when displaying JPEG images
Fixes #3518
2021-04-23 07:31:37 +05:30
Kovid Goyal
237fd73702 Fix removal of inactive tab that is before the currently active tab causing the highlighted tab to be incorrect
Fixes #3516
2021-04-22 22:28:05 +05:30
Kovid Goyal
5f2d0142d1 Re-organize README a bit 2021-04-22 20:32:34 +05:30
Kovid Goyal
572d576d5b Merge branch 'fix-compilation-on-old-macos' of https://github.com/Luflosi/kitty 2021-04-22 14:30:38 +05:30
Luflosi
6606f51636 Fix compilation on macOS 10.12
The constants `NSControlStateValueOn`, `NSControlStateValueOff` and `NSControlStateValueMixed` are only available for macOS 10.13 or above according to https://developer.apple.com/documentation/appkit/nscontrolstatevalueon?language=objc.
Without this commit, compilation fails with this message:
```
glfw/cocoa_window.m:1537:28: error: use of undeclared identifier 'NSControlStateValueOn'
              item.state = NSControlStateValueOn;
                           ^
glfw/cocoa_window.m:1539:28: error: use of undeclared identifier 'NSControlStateValueMixed'
              item.state = NSControlStateValueMixed;
                           ^
glfw/cocoa_window.m:1542:47: error: use of undeclared identifier 'NSControlStateValueOn'
          item.state = controller.isDesired ? NSControlStateValueOn : NSControlStateValueOff;
                                              ^
glfw/cocoa_window.m:1542:71: error: use of undeclared identifier 'NSControlStateValueOff'
          item.state = controller.isDesired ? NSControlStateValueOn : NSControlStateValueOff;
                                                                      ^
```
To fix this, simply redefine the constants to use the old and now deprecated constants on older macOS versions.

The code that causes this was introduced in 98519bf326.
2021-04-22 10:53:34 +02:00
Kovid Goyal
36da65120a It's only alt and alt+shift that dont work in global menubar
alt in combination with ctrl/cmd works fine.
2021-04-22 10:50:43 +05:30
Kovid Goyal
b6c1e1a609 ... 2021-04-22 10:24:57 +05:30
Kovid Goyal
5d003ec772 Fix @close-tab not working with pipe based remote control
Fixes #3510
2021-04-22 10:23:04 +05:30
Kovid Goyal
b9210a2ba4 macOS: Prevent option based shortcuts for being used for global menu actions
Fixes #3515
2021-04-22 10:15:10 +05:30
Kovid Goyal
f3c559ea13 Cleanup secure keyboard entry logging 2021-04-22 09:41:01 +05:30
Kovid Goyal
6cee6b6429 More accurate ignoring message 2021-04-22 09:31:41 +05:30
Kovid Goyal
84f6aabf5b Clean up debug keyboard on macOS 2021-04-22 09:28:11 +05:30
Kovid Goyal
9ce947d6ea Ignore failure to read the readline init file on Linux as well
There are apparently people that like to break things randomly on their
systems by removing needed files. Fixes #3513
2021-04-22 08:13:57 +05:30
Kovid Goyal
0f23ad0d7e Merge branch 'u_int8_t' of https://github.com/sgn/kitty 2021-04-21 18:45:18 +05:30
Đoàn Trần Công Danh
1b760b6c53 freetype_render_ui_text: use uint8_t instead of u_int8_t
uint8_t is a standard type, while u_int8_t isn't. And we're assigning to
an uint8_t anyway.
2021-04-21 19:23:43 +07:00
Kovid Goyal
cdf64bf016 Linux: Fix binary kitty builds not able to load fonts in WOFF2 format
Fixes #3506
2021-04-20 17:07:47 +05:30
64 changed files with 839 additions and 408 deletions

View File

@@ -1,10 +1,12 @@
= kitty - the fast, feature-rich, cross-platform, GPU based terminal
See https://sw.kovidgoyal.net/kitty/
See https://sw.kovidgoyal.net/kitty/[the kitty website].
image:https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg["Build status", link="https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI"]
To ask questions about kitty usage, use either the https://github.com/kovidgoyal/kitty/discussions/[discussions on GitHub] or the
https://sw.kovidgoyal.net/kitty/faq.html[Frequently Asked Questions]
To ask other questions about kitty usage, use either the https://github.com/kovidgoyal/kitty/discussions/[discussions on GitHub] or the
https://www.reddit.com/r/KittyTerminal[Reddit community]
Packaging status in various repositories:

View File

@@ -31,7 +31,7 @@ def binary_includes():
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2', 'crypt',
'iconv', 'pcre', 'graphite2', 'glib-2.0', 'freetype',
'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
'ncursesw', 'readline',
'ncursesw', 'readline', 'brotlicommon', 'brotlienc', 'brotlidec'
))) + (
get_dll_path('bz2', 2), get_dll_path('ssl', 2), get_dll_path('crypto', 2),
get_dll_path('python' + py_ver, 2),

View File

@@ -222,6 +222,16 @@
}
},
{
"name": "brotli",
"os": "linux",
"unix": {
"filename": "brotli-1.0.9.tar.gz",
"hash": "sha256:f9e8d81d0405ba66d181529af42a3354f838c939095ff99930da6aa9cdf6fe46",
"urls": ["https://github.com/google/brotli/archive/v1.0.9/{filename}"]
}
},
{
"name": "freetype",
"os": "linux",

126
docs/basic.rst Normal file
View File

@@ -0,0 +1,126 @@
Tabs and Windows
-------------------
|kitty| is capable of running multiple programs organized into tabs and
windows. The top level of organization is the *Tab*. Each tab consists
of one or more *windows*. The windows can be arranged in multiple
different layouts, like windows are organized in a tiling window
manager. The keyboard controls (which are all customizable) for tabs and
windows are:
Scrolling
~~~~~~~~~~~~~~
======================== =======================
Action Shortcut
======================== =======================
Scroll line up :sc:`scroll_line_up` (also :kbd:`⌥+⌘+⇞` and :kbd:`⌘+↑` on macOS)
Scroll line down :sc:`scroll_line_down` (also :kbd:`⌥+⌘+⇟` and :kbd:`⌘+↓` on macOS)
Scroll page up :sc:`scroll_page_up` (also :kbd:`⌘+⇞` on macOS)
Scroll page down :sc:`scroll_page_down` (also :kbd:`⌘+⇟` on macOS)
Scroll to top :sc:`scroll_home` (also :kbd:`⌘+↖` on macOS)
Scroll to bottom :sc:`scroll_end` (also :kbd:`⌘+↘` on macOS)
======================== =======================
Tabs
~~~~~~~~~~~
======================== =======================
Action Shortcut
======================== =======================
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
Close tab :sc:`close_tab` (also :kbd:`⌘+w` on macOS)
Next tab :sc:`next_tab` (also :kbd:`^+⇥` and :kbd:`⇧+⌘+]` on macOS)
Previous tab :sc:`previous_tab` (also :kbd:`⇧+^+⇥` and :kbd:`⇧+⌘+[` on macOS)
Next layout :sc:`next_layout`
Move tab forward :sc:`move_tab_forward`
Move tab backward :sc:`move_tab_backward`
Set tab title :sc:`set_tab_title` (also :kbd:`⇧+⌘+i` on macOS)
======================== =======================
Windows
~~~~~~~~~~~~~~~~~~
======================== =======================
Action Shortcut
======================== =======================
New window :sc:`new_window` (also :kbd:`⌘+↩` on macOS)
New OS window :sc:`new_os_window` (also :kbd:`⌘+n` on macOS)
Close window :sc:`close_window` (also :kbd:`⇧+⌘+d` on macOS)
Next window :sc:`next_window`
Previous window :sc:`previous_window`
Move window forward :sc:`move_window_forward`
Move window backward :sc:`move_window_backward`
Move window to top :sc:`move_window_to_top`
Focus specific window :sc:`first_window`, :sc:`second_window` ... :sc:`tenth_window`
(also :kbd:`⌘+1`, :kbd:`⌘+2` ... :kbd:`⌘+9` on macOS)
(clockwise from the top-left)
======================== =======================
Additionally, you can define shortcuts in :file:`kitty.conf` to focus neighboring
windows and move windows around (similar to window movement in vim)::
map ctrl+left neighboring_window left
map shift+left move_window right
map ctrl+down neighboring_window down
map shift+down move_window up
...
You can also define a shortcut to switch to the previously active window::
map ctrl+p nth_window -1
``nth_window`` will focus the nth window for positive numbers and the
previously active windows for negative numbers.
.. _detach_window:
You can define shortcuts to detach the current window and
move it to another tab or another OS window::
# moves the window into a new OS window
map ctrl+f2 detach_window
# moves the window into a new Tab
map ctrl+f3 detach_window new-tab
# asks which tab to move the window into
map ctrl+f4 detach_window ask
Similarly, you can detach the current tab, with::
# moves the tab into a new OS window
map ctrl+f2 detach_tab
# asks which OS Window to move the tab into
map ctrl+f4 detach_tab ask
Finally, you can define a shortcut to close all windows in a tab other than
the currently active window::
map f9 close_other_windows_in_tab
Other keyboard shortcuts
----------------------------------
================================== =======================
Action Shortcut
================================== =======================
Copy to clipboard :sc:`copy_to_clipboard` (also :kbd:`⌘+c` on macOS)
Paste from clipboard :sc:`paste_from_clipboard` (also :kbd:`⌘+v` on macOS)
Paste from selection :sc:`paste_from_selection`
Increase font size :sc:`increase_font_size` (also :kbd:`⌘++` on macOS)
Decrease font size :sc:`decrease_font_size` (also :kbd:`⌘+-` on macOS)
Restore font size :sc:`reset_font_size` (also :kbd:`⌘+0` on macOS)
Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`^+⌘+f` on macOS)
Toggle maximized :sc:`toggle_maximized`
Input unicode character :sc:`input_unicode_character` (also :kbd:`^+⌘+space` on macOS)
Click URL using the keyboard :sc:`open_url`
Reset the terminal :sc:`reset_terminal`
Pass current selection to program :sc:`pass_selection_to_program`
Edit |kitty| config file :sc:`edit_config_file`
Open a |kitty| shell :sc:`kitty_shell`
Increase background opacity :sc:`increase_background_opacity`
Decrease background opacity :sc:`decrease_background_opacity`
Full background opacity :sc:`full_background_opacity`
Reset background opacity :sc:`reset_background_opacity`
================================== =======================

View File

@@ -4,6 +4,46 @@ Changelog
|kitty| is a feature-rich, cross-platform, *fast*, GPU based terminal.
To update |kitty|, :doc:`follow the instructions <binary>`.
0.20.2 [2021-04-28]
----------------------
- A new protocol extension to :ref:`unscroll <unscroll>` text from the
scrollback buffer onto the screen. Useful, for example, to restore
the screen after showing completions below the shell prompt.
- A new remote control command :ref:`at_env` to change the default
environment passed to newly created windows (:iss:`3529`)
- Linux: Fix binary kitty builds not able to load fonts in WOFF2 format
(:iss:`3506`)
- macOS: Prevent :kbd:`option` based shortcuts for being used for global menu
actions (:iss:`3515`)
- Fix ``kitty @ close-tab`` not working with pipe based remote control
(:iss:`3510`)
- Fix removal of inactive tab that is before the currently active tab causing
the highlighted tab to be incorrect (:iss:`3516`)
- icat kitten: Respect EXIF orientation when displaying JPEG images
(:iss:`3518`)
- GNOME: Fix maximize state not being remembered when focus changes and window
decorations are hidden (:iss:`3507`)
- GNOME: Add a new :opt:`wayland_titlebar_color` option to control the color of the
kitty window title bar
- Fix reading :option:`kitty --session` from ``STDIN`` not working when the
:option:`kitty --detach` option is used (:iss:`3523`)
- Special case rendering of the few remaining Powerline box drawing chars
(:iss:`3535`)
- Fix ``kitty @ set-colors`` not working for the :opt:`active_tab_foreground`.
0.20.1 [2021-04-19]
----------------------

View File

@@ -167,8 +167,8 @@ html_show_sourcelink = False
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('invocation', 'kitty', 'kitty Documentation',
[author], 1)
('invocation', 'kitty', 'kitty Documentation', [author], 1),
('conf', 'kitty.conf', 'kitty.conf Documentation', [author], 5)
]

View File

@@ -39,6 +39,16 @@ expanded, so :code:`${USER}.conf` becomes :file:`name.conf` if
Sample kitty.conf
^^^^^^^^^^^^^^^^^^^^^
You can download a sample :file:`kitty.conf` file with all default settings and
comments describing each setting by clicking: :download:`sample kitty.conf
</generated/conf/kitty.conf>`.
.. only:: html
You can download a sample :file:`kitty.conf` file with all default settings and
comments describing each setting by clicking: :download:`sample kitty.conf
</generated/conf/kitty.conf>`.
.. only:: man
You can edit a fully commented sample kitty.conf by pressing the
:sc:`edit_config_file` shortcut in kitty. This will generate a config
file with full documentation and all settings commented out. If you
have a pre-existing kitty.conf, then that will be used instead, delete
it to see the sample file.

View File

@@ -99,133 +99,7 @@ styled (curly) underlines. One of the design goals of |kitty| is to be
easily extensible so that new features can be added in the future with
relatively little effort.
Tabs and Windows
-------------------
|kitty| is capable of running multiple programs organized into tabs and
windows. The top level of organization is the *Tab*. Each tab consists
of one or more *windows*. The windows can be arranged in multiple
different layouts, like windows are organized in a tiling window
manager. The keyboard controls (which are all customizable) for tabs and
windows are:
Scrolling
~~~~~~~~~~~~~~
======================== =======================
Action Shortcut
======================== =======================
Scroll line up :sc:`scroll_line_up` (also :kbd:`⌥+⌘+⇞` and :kbd:`⌘+↑` on macOS)
Scroll line down :sc:`scroll_line_down` (also :kbd:`⌥+⌘+⇟` and :kbd:`⌘+↓` on macOS)
Scroll page up :sc:`scroll_page_up` (also :kbd:`⌘+⇞` on macOS)
Scroll page down :sc:`scroll_page_down` (also :kbd:`⌘+⇟` on macOS)
Scroll to top :sc:`scroll_home` (also :kbd:`⌘+↖` on macOS)
Scroll to bottom :sc:`scroll_end` (also :kbd:`⌘+↘` on macOS)
======================== =======================
Tabs
~~~~~~~~~~~
======================== =======================
Action Shortcut
======================== =======================
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
Close tab :sc:`close_tab` (also :kbd:`⌘+w` on macOS)
Next tab :sc:`next_tab` (also :kbd:`^+⇥` and :kbd:`⇧+⌘+]` on macOS)
Previous tab :sc:`previous_tab` (also :kbd:`⇧+^+⇥` and :kbd:`⇧+⌘+[` on macOS)
Next layout :sc:`next_layout`
Move tab forward :sc:`move_tab_forward`
Move tab backward :sc:`move_tab_backward`
Set tab title :sc:`set_tab_title` (also :kbd:`⇧+⌘+i` on macOS)
======================== =======================
Windows
~~~~~~~~~~~~~~~~~~
======================== =======================
Action Shortcut
======================== =======================
New window :sc:`new_window` (also :kbd:`⌘+↩` on macOS)
New OS window :sc:`new_os_window` (also :kbd:`⌘+n` on macOS)
Close window :sc:`close_window` (also :kbd:`⇧+⌘+d` on macOS)
Next window :sc:`next_window`
Previous window :sc:`previous_window`
Move window forward :sc:`move_window_forward`
Move window backward :sc:`move_window_backward`
Move window to top :sc:`move_window_to_top`
Focus specific window :sc:`first_window`, :sc:`second_window` ... :sc:`tenth_window`
(also :kbd:`⌘+1`, :kbd:`⌘+2` ... :kbd:`⌘+9` on macOS)
(clockwise from the top-left)
======================== =======================
Additionally, you can define shortcuts in :file:`kitty.conf` to focus neighboring
windows and move windows around (similar to window movement in vim)::
map ctrl+left neighboring_window left
map shift+left move_window right
map ctrl+down neighboring_window down
map shift+down move_window up
...
You can also define a shortcut to switch to the previously active window::
map ctrl+p nth_window -1
``nth_window`` will focus the nth window for positive numbers and the
previously active windows for negative numbers.
.. _detach_window:
You can define shortcuts to detach the current window and
move it to another tab or another OS window::
# moves the window into a new OS window
map ctrl+f2 detach_window
# moves the window into a new Tab
map ctrl+f3 detach_window new-tab
# asks which tab to move the window into
map ctrl+f4 detach_window ask
Similarly, you can detach the current tab, with::
# moves the tab into a new OS window
map ctrl+f2 detach_tab
# asks which OS Window to move the tab into
map ctrl+f4 detach_tab ask
Finally, you can define a shortcut to close all windows in a tab other than
the currently active window::
map f9 close_other_windows_in_tab
Other keyboard shortcuts
----------------------------------
================================== =======================
Action Shortcut
================================== =======================
Copy to clipboard :sc:`copy_to_clipboard` (also :kbd:`⌘+c` on macOS)
Paste from clipboard :sc:`paste_from_clipboard` (also :kbd:`⌘+v` on macOS)
Paste from selection :sc:`paste_from_selection`
Increase font size :sc:`increase_font_size` (also :kbd:`⌘++` on macOS)
Decrease font size :sc:`decrease_font_size` (also :kbd:`⌘+-` on macOS)
Restore font size :sc:`reset_font_size` (also :kbd:`⌘+0` on macOS)
Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`^+⌘+f` on macOS)
Toggle maximized :sc:`toggle_maximized`
Input unicode character :sc:`input_unicode_character` (also :kbd:`^+⌘+space` on macOS)
Click URL using the keyboard :sc:`open_url`
Reset the terminal :sc:`reset_terminal`
Pass current selection to program :sc:`pass_selection_to_program`
Edit |kitty| config file :sc:`edit_config_file`
Open a |kitty| shell :sc:`kitty_shell`
Increase background opacity :sc:`increase_background_opacity`
Decrease background opacity :sc:`decrease_background_opacity`
Full background opacity :sc:`full_background_opacity`
Reset background opacity :sc:`reset_background_opacity`
================================== =======================
.. include:: basic.rst
.. _layouts:
@@ -312,8 +186,9 @@ Configuring kitty
-------------------
|kitty| is highly configurable, everything from keyboard shortcuts to
painting frames-per-second. For details and a sample :file:`kitty.conf`,
see the :doc:`configuration docs <conf>`.
painting frames-per-second. Press :sc:`edit_config_file` in kitty
to open its fully commented sample config file in your text editor.
For details see the :doc:`configuration docs <conf>`.
Remote control

View File

@@ -4,3 +4,10 @@ The kitty command line interface
.. program:: kitty
.. include:: generated/cli-kitty.rst
.. include:: basic.rst
See also
-----------
See kitty.conf(5)

View File

@@ -19,12 +19,12 @@ If you want to make it case-insensitive, use::
To make it match only complete words, use::
map f1 toggle_marker regex 1 \bERROR\b
map f1 toggle_marker regex 1 \\bERROR\\b
Suppose you want to highlight both :code:`ERROR` and :code:`WARNING`, case
insensitively::
map f1 toggle_marker iregex 1 \bERROR\b 2 \bWARNING\b
map f1 toggle_marker iregex 1 \\bERROR\\b 2 \\bWARNING\\b
kitty supports up to 3 mark groups (the numbers in the commands above). You
can control the colors used for these groups in :file:`kitty.conf` with::

View File

@@ -157,6 +157,44 @@ protocol extension, it can be disabled by specifying ``no-append`` to the
:opt:`clipboard_control` setting.
.. _unscroll:
Unscrolling the screen
-----------------------
This is a small extension to the `SD (Pan up) escape code
<https://vt100.net/docs/vt510-rm/SD.html>`_ from the VT-420 terminal. The
``SD`` escape code normally causes the text on screen to scroll down by the
specified number of lines, with empty lines appearing at the top of the screen.
This extension allows the new lines to be filled in from the scrollback buffer
instead of being blank.
The motivation for this is that many modern shells will show completions in a
block of lines under the cursor, this causes some of the on-screen text to be
lost even after the completion is completed, because it has scrolled off
screen. This escape code allows that text to be restored.
If the scrollback buffer is empty or there is no scrollback buffer, such as for
the alternate screen, then the newly inserted lines must be empty, just as with
the original ``SD`` escape code. The maximum number of lines that can be
scrolled down is the height of the screen, i.e. the number of lines on the screen.
If the escape code requests more than that number of lines, the terminal *must*
clip the request to the current screen size.
The syntax of the escape code is identical to that of ``SD`` except that it has
a trailing ``+`` modifier. This is legal under the `ECMA 48 standard
<https://www.ecma-international.org/publications-and-standards/standards/ecma-48/>`_
and unused for any other purpose as far as I can tell. So for example, to
unscroll three lines, the escape code would be::
CSI 3 + T
See `discussion here
<https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/30>`_.
.. versionadded:: 0.20.2
.. _desktop_notifications:

View File

@@ -32,6 +32,12 @@
#include <float.h>
#include <string.h>
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 101300)
#define NSControlStateValueOn NSOnState
#define NSControlStateValueOff NSOffState
#define NSControlStateValueMixed NSMixedState
#endif
static uint32_t
vk_code_to_functional_key_code(uint8_t key_code) { // {{{
@@ -454,7 +460,8 @@ static void releaseMonitor(_GLFWwindow* window)
// Translates macOS key modifiers into GLFW ones
//
static int translateFlags(NSUInteger flags)
static int
translateFlags(NSUInteger flags)
{
int mods = 0;
@@ -472,7 +479,7 @@ static int translateFlags(NSUInteger flags)
return mods;
}
#define debug_key(...) if (_glfw.hints.init.debugKeyboard) NSLog(__VA_ARGS__)
#define debug_key(...) if (_glfw.hints.init.debugKeyboard) { fprintf(stderr, __VA_ARGS__); fflush(stderr); }
static inline const char*
format_mods(int mods) {
@@ -613,7 +620,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)toggle {
// Set _desired to the opposite of the current state.
_desired = !_desired;
debug_key(@"toggle called. Setting desired to %@", @(_desired));
debug_key("toggle called. Setting desired to %d", _desired);
// Try to set the system's state of secure input to the desired state.
[self update];
@@ -632,7 +639,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)applicationDidResignActive:(NSNotification *)notification {
(void)notification;
if (_count > 0) {
debug_key(@"Application resigning active.");
debug_key("Application resigning active.");
[self update];
}
}
@@ -640,7 +647,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)applicationDidBecomeActive:(NSNotification *)notification {
(void)notification;
if (self.isDesired) {
debug_key(@"Application became active.");
debug_key("Application became active.");
[self update];
}
}
@@ -652,39 +659,39 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
}
- (void)update {
debug_key(@"Update secure keyboard entry. desired=%@ active=%@",
@(self.isDesired), @([NSApp isActive]));
debug_key("Update secure keyboard entry. desired=%d active=%d\n",
(int)self.isDesired, (int)[NSApp isActive]);
const BOOL secure = self.isDesired && [self allowed];
if (secure && _count > 0) {
debug_key(@"Want to turn on secure input but it's already on");
debug_key("Want to turn on secure input but it's already on\n");
return;
}
if (!secure && _count == 0) {
debug_key(@"Want to turn off secure input but it's already off");
debug_key("Want to turn off secure input but it's already off\n");
return;
}
debug_key(@"Before: IsSecureEventInputEnabled returns %d", (int)self.isEnabled);
debug_key("Before: IsSecureEventInputEnabled returns %d ", (int)self.isEnabled);
if (secure) {
OSErr err = EnableSecureEventInput();
debug_key(@"EnableSecureEventInput err=%d", (int)err);
debug_key("EnableSecureEventInput err=%d ", (int)err);
if (err) {
debug_key(@"EnableSecureEventInput failed with error %d", (int)err);
debug_key("EnableSecureEventInput failed with error %d ", (int)err);
} else {
_count += 1;
}
} else {
OSErr err = DisableSecureEventInput();
debug_key(@"DisableSecureEventInput err=%d", (int)err);
debug_key("DisableSecureEventInput err=%d ", (int)err);
if (err) {
debug_key(@"DisableSecureEventInput failed with error %d", (int)err);
debug_key("DisableSecureEventInput failed with error %d ", (int)err);
} else {
_count -= 1;
}
}
debug_key(@"After: IsSecureEventInputEnabled returns %d", (int)self.isEnabled);
debug_key("After: IsSecureEventInputEnabled returns %d\n", (int)self.isEnabled);
}
@end
@@ -1200,7 +1207,7 @@ is_ascii_control_char(char x) {
}
} else {
if (input_source_changed) {
debug_key(@"Input source changed, clearing pre-edit text and resetting deadkey state\n");
debug_key("Input source changed, clearing pre-edit text and resetting deadkey state\n");
glfw_keyevent.text = NULL;
glfw_keyevent.ime_state = GLFW_IME_PREEDIT_CHANGED;
window->ns.deadKeyState = 0;
@@ -1222,13 +1229,13 @@ is_ascii_control_char(char x) {
&char_count,
text
) != noErr) {
debug_key(@"UCKeyTranslate failed for keycode: 0x%x (%@) %@\n",
keycode, @(safe_name_for_keycode(keycode)), @(format_mods(mods)));
debug_key("UCKeyTranslate failed for keycode: 0x%x (%s) %s\n",
keycode, safe_name_for_keycode(keycode), format_mods(mods));
window->ns.deadKeyState = 0;
return;
}
debug_key(@"keycode: 0x%x (%@) %@char_count: %lu deadKeyState: %u repeat: %d",
keycode, @(safe_name_for_keycode(keycode)), @(format_mods(mods)), char_count, window->ns.deadKeyState, event.ARepeat);
debug_key("\x1b[31mPress:\x1b[m native_key: 0x%x (%s) glfw_key: 0x%x %schar_count: %lu deadKeyState: %u repeat: %d ",
keycode, safe_name_for_keycode(keycode), key, format_mods(mods), char_count, window->ns.deadKeyState, event.ARepeat);
if (process_text) {
// this will call insertText which will fill up _glfw.ns.text
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
@@ -1237,22 +1244,22 @@ is_ascii_control_char(char x) {
}
if (window->ns.deadKeyState && (char_count == 0 || keycode == 0x75)) {
// 0x75 is the delete key which needs to be ignored during a compose sequence
debug_key(@"Sending pre-edit text for dead key (text: %@ markedText: %@).\n", @(format_text(_glfw.ns.text)), markedText);
glfw_keyevent.text = [[markedText string] UTF8String];
debug_key("Sending pre-edit text for dead key (text: %s markedText: %s).\n", format_text(_glfw.ns.text), glfw_keyevent.text);
glfw_keyevent.ime_state = GLFW_IME_PREEDIT_CHANGED;
_glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text
return;
}
if (in_compose_sequence) {
debug_key(@"Clearing pre-edit text at end of compose sequence\n");
debug_key("Clearing pre-edit text at end of compose sequence\n");
glfw_keyevent.text = NULL;
glfw_keyevent.ime_state = GLFW_IME_PREEDIT_CHANGED;
_glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text
}
}
if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes
debug_key(@"text: %@ glfw_key: %@ marked_text: %@\n",
@(format_text(_glfw.ns.text)), @(_glfwGetKeyName(key)), markedText);
debug_key("text: %s glfw_key: %s marked_text: %s\n",
format_text(_glfw.ns.text), _glfwGetKeyName(key), [[markedText string] UTF8String]);
if (!window->ns.deadKeyState) {
if ([self hasMarkedText]) {
glfw_keyevent.text = [[markedText string] UTF8String];
@@ -1310,6 +1317,8 @@ is_ascii_control_char(char x) {
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = keycode, .action = GLFW_RELEASE, .mods = mods};
add_alternate_keys(&glfw_keyevent, event);
debug_key("\x1b[32mRelease:\x1b[m native_key: 0x%x (%s) glfw_key: 0x%x %s\n",
keycode, safe_name_for_keycode(keycode), key, format_mods(mods));
_glfwInputKeyboard(window, &glfw_keyevent);
}
@@ -1439,7 +1448,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
top /= window->ns.yscale;
cellWidth /= window->ns.xscale;
cellHeight /= window->ns.yscale;
debug_key(@"updateIMEState: %f, %f, %f, %f\n", left, top, cellWidth, cellHeight);
debug_key("updateIMEState: %f, %f, %f, %f\n", left, top, cellWidth, cellHeight);
const NSRect frame = [window->ns.view frame];
const NSRect rectInView = NSMakeRect(left,
frame.size.height - top - cellHeight,

View File

@@ -218,6 +218,7 @@ def generate_wrappers(glfw_header: str) -> None:
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)

View File

@@ -146,6 +146,17 @@ static void
render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
const bool is_focused = window->id == _glfw.focusedWindowId;
uint32_t bg_color = is_focused ? active_bg_color : passive_bg_color;
uint32_t fg_color = is_focused ? 0xff444444 : 0xff888888;
if (decs.use_custom_titlebar_color) {
bg_color = 0xff000000 | (decs.titlebar_color & 0xffffff);
double red = ((bg_color >> 16) & 0xFF) / 255.0;
double green = ((bg_color >> 8) & 0xFF) / 255.0;
double blue = (bg_color & 0xFF) / 255.0;
double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
if (luma < 0.5) {
fg_color = is_focused ? 0xffeeeeee : 0xff888888;
}
}
uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back;
// render shadow part
@@ -169,7 +180,6 @@ render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
// render text part
output += decs.top.buffer.stride * margin;
if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) {
uint32_t fg_color = is_focused ? 0xff444444 : 0xff888888;
if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, fg_color, bg_color, output, decs.top.buffer.width, decs.top.buffer.height - margin, 0, 0, 0)) return;
}
for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) {
@@ -413,3 +423,16 @@ set_csd_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height) {
*height -= decs.metrics.visible_titlebar_height;
}
}
void
set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color) {
bool use_custom_color = !use_system_color;
if (use_custom_color != decs.use_custom_titlebar_color || color != decs.titlebar_color) {
decs.use_custom_titlebar_color = use_custom_color;
decs.titlebar_color = color;
}
if (window->decorated && decs.top.surface) {
update_title_bar(window);
damage_csd(top, decs.top.buffer.front);
}
}

View File

@@ -14,3 +14,4 @@ void free_csd_surfaces(_GLFWwindow *window);
void change_csd_title(_GLFWwindow *window);
bool ensure_csd_resources(_GLFWwindow *window);
void set_csd_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height);
void set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color);

3
glfw/wl_platform.h vendored
View File

@@ -195,6 +195,9 @@ typedef struct _GLFWwindowWayland
size_t for_decoration_size, stride, segments, corner_size;
} shadow_tile;
monotonic_t last_click_on_top_decoration_at;
uint32_t titlebar_color;
bool use_custom_titlebar_color;
} decorations;
struct {

11
glfw/wl_window.c vendored
View File

@@ -451,11 +451,11 @@ static void xdgToplevelHandleConfigure(void* data,
debug("final window content size: %dx%d\n", window->wl.width, window->wl.height);
_glfwInputWindowFocus(window, window->wl.toplevel_states & TOPLEVEL_STATE_ACTIVATED);
ensure_csd_resources(window);
wl_surface_commit(window->wl.surface);
#define geometry window->wl.decorations.geometry
debug("Setting window geometry: x=%d y=%d %dx%d\n", geometry.x, geometry.y, geometry.width, geometry.height);
xdg_surface_set_window_geometry(window->wl.xdg.surface, geometry.x, geometry.y, geometry.width, geometry.height);
#undef geometry
wl_surface_commit(window->wl.surface);
if (live_resize_done) _glfwInputLiveResize(window, false);
}
@@ -2001,3 +2001,12 @@ GLFWAPI unsigned long long glfwDBusUserNotify(const char *app_name, const char*
GLFWAPI void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler) {
glfw_dbus_set_user_notification_activated_handler(handler);
}
GLFWAPI bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color) {
_GLFWwindow* window = (_GLFWwindow*) handle;
if (!window->wl.decorations.serverSide) {
set_titlebar_color(window, color, use_system_color);
return true;
}
return false;
}

11
glfw/xkb_glfw.c vendored
View File

@@ -324,8 +324,14 @@ glfw_xkb_update_masks(_GLFWXKBData *xkb) {
unsigned used_bits = 0; /* To avoid using the same bit twice */
XkbDescPtr xkb_ptr = XkbGetMap( _glfw.x11.display, XkbVirtualModsMask | XkbVirtualModMapMask, XkbUseCoreKbd );
/* shift, control, and capsLock are special; they cannot be identified reliably on X11 */
#define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx; used_bits |= xkb->a##Mask;
S(control, XKB_MOD_NAME_CTRL);
S(shift, XKB_MOD_NAME_SHIFT);
S(capsLock, XKB_MOD_NAME_CAPS);
#undef S
#define S( a ) xkb->a##Idx = XKB_MOD_INVALID; xkb->a##Mask = 0
S(control); S(alt); S(shift); S(super); S(hyper); S(meta); S(capsLock); S(numLock);
S(alt); S(super); S(hyper); S(meta); S(numLock);
#undef S
if (xkb_ptr) {
Status status = XkbGetNames(_glfw.x11.display, XkbVirtualModNamesMask, xkb_ptr);
@@ -361,9 +367,6 @@ glfw_xkb_update_masks(_GLFWXKBData *xkb) {
}
}
#define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx;
S(control, XKB_MOD_NAME_CTRL);
S(shift, XKB_MOD_NAME_SHIFT);
S(capsLock, XKB_MOD_NAME_CAPS);
if (!succeeded) {
S(numLock, XKB_MOD_NAME_NUM);
S(alt, XKB_MOD_NAME_ALT);

View File

@@ -211,7 +211,7 @@ def render_image(
# we have to coalesce, resize and de-coalesce all frames
resize_cmd = ['-coalesce'] + resize_cmd + ['-deconstruct']
cmd += resize_cmd
cmd += ['-depth', '8', '-set', 'filename:f', '%w-%h-%g-%p']
cmd += ['-depth', '8', '-auto-orient', '-set', 'filename:f', '%w-%h-%g-%p']
ans = RenderedImage(m.fmt, width, height, m.mode)
if only_first_frame:
ans.frames = [Frame(m.frames[0])]

View File

@@ -1499,7 +1499,7 @@ talk_loop(void *data) {
ChildMonitor *self = (ChildMonitor*)data;
set_thread_name("KittyPeerMon");
if (!init_loop_data(&talk_data.loop_data)) { log_error("Failed to create wakeup fd for talk thread with error: %s", strerror(errno)); }
PollFD fds[PEER_LIMIT + 8] = {0};
PollFD fds[PEER_LIMIT + 8] = {{0}};
size_t num_listen_fds = 0, num_peer_fds = 0;
#define add_listener(which) \
if (self->which > -1) { \

View File

@@ -1260,6 +1260,14 @@ def macos_titlebar_color(x: str) -> int:
return (color_as_int(to_color(x)) << 8) | 2
o('wayland_titlebar_color', 'system', option_type=macos_titlebar_color, long_text=_('''
Change the color of the kitty window's titlebar on Wayland systems with client side window decorations such as GNOME.
A value of :code:`system` means to use the default system color,
a value of :code:`background` means to use the background color
of the currently active window and finally you can use
an arbitrary color, such as :code:`#12af59` or :code:`red`.
'''))
o('macos_titlebar_color', 'system', option_type=macos_titlebar_color, long_text=_('''
Change the color of the kitty window's titlebar on macOS. A value of :code:`system`
means to use the default system color, a value of :code:`background` means to use

View File

@@ -21,7 +21,7 @@ class Version(NamedTuple):
appname: str = 'kitty'
kitty_face = '🐱'
version: Version = Version(0, 20, 1)
version: Version = Version(0, 20, 2)
str_version: str = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos: bool = 'darwin' in _plat

View File

@@ -81,6 +81,22 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
return (PyObject*) self;
}
static int
open_cache_file_without_tmpfile(const char *cache_path) {
int fd = -1;
static const char *template = "%s/disk-cache-XXXXXXXXXXXX";
const size_t sz = strlen(cache_path) + sizeof(template) + 4;
FREE_AFTER_FUNCTION char *buf = calloc(1, sz);
if (!buf) { errno = ENOMEM; return -1; }
snprintf(buf, sz - 1, template, cache_path);
while (fd < 0) {
fd = mkostemp(buf, O_CLOEXEC);
if (fd > -1 || errno != EINTR) break;
}
if (fd > -1) unlink(buf);
return fd;
}
static int
open_cache_file(const char *cache_path) {
int fd = -1;
@@ -89,16 +105,9 @@ open_cache_file(const char *cache_path) {
fd = safe_open(cache_path, O_TMPFILE | O_CLOEXEC | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
if (fd > -1 || errno != EINTR) break;
}
if (fd == -1) fd = open_cache_file_without_tmpfile(cache_path);
#else
size_t sz = strlen(cache_path) + 16;
FREE_AFTER_FUNCTION char *buf = calloc(1, sz);
if (!buf) { errno = ENOMEM; return -1; }
snprintf(buf, sz - 1, "%s/disk-cache-XXXXXXXXXXXX", cache_path);
while (fd < 0) {
fd = mkostemp(buf, O_CLOEXEC);
if (fd > -1 || errno != EINTR) break;
}
if (fd > -1) unlink(buf);
fd = open_cache_file_without_tmpfile(cache_path);
#endif
return fd;
}

View File

@@ -437,7 +437,7 @@ def init_cell_program() -> None:
pass
def set_titlebar_color(os_window_id: int, color: int) -> bool:
def set_titlebar_color(os_window_id: int, color: int, use_system_color: bool = False) -> bool:
pass

View File

@@ -329,7 +329,7 @@ void
clear_sprite_map(Font *font) {
#define CLEAR(s) s->filled = false; s->rendered = false; s->colored = false; s->glyph = 0; zero_at_ptr(&s->extra_glyphs); s->x = 0; s->y = 0; s->z = 0; s->ligature_index = 0;
SpritePosition *s;
for (size_t i = 0; i < sizeof(font->sprite_map)/sizeof(font->sprite_map[0]); i++) {
for (size_t i = 0; i < arraysz(font->sprite_map); i++) {
s = font->sprite_map + i;
CLEAR(s);
while ((s = s->next)) {
@@ -343,7 +343,7 @@ void
clear_special_glyph_cache(Font *font) {
#define CLEAR(s) s->data = 0; s->glyph = 0;
SpecialGlyphCache *s;
for (size_t i = 0; i < sizeof(font->special_glyph_cache)/sizeof(font->special_glyph_cache[0]); i++) {
for (size_t i = 0; i < arraysz(font->special_glyph_cache); i++) {
s = font->special_glyph_cache + i;
CLEAR(s);
while ((s = s->next)) {
@@ -602,13 +602,8 @@ START_ALLOW_CASE_RANGE
return BLANK_FONT;
case 0x2500 ... 0x2573:
case 0x2574 ... 0x259f:
case 0xe0b0 ... 0xe0b4:
case 0x2800 ... 0x28ff:
case 0xe0b6:
case 0xe0b8: // 
case 0xe0ba: // 
case 0xe0bc: // 
case 0xe0be: // 
case 0xe0b0 ... 0xe0bf: // powerline box drawing
case 0x1fb00 ... 0x1fb8b: // symbols for legacy computing
case 0x1fba0 ... 0x1fbae:
return BOX_FONT;

View File

@@ -165,13 +165,14 @@ def downsample(src: BufType, dest: BufType, dest_width: int, dest_height: int, f
dest[offset + x] = min(255, dest[offset + x] + average_intensity_in_src(x, y))
class SSByteArray(bytearray):
supersample_factor = 1
def supersampled(supersample_factor: int = 4) -> Callable:
# Anti-alias the drawing performed by the wrapped function by
# using supersampling
class SSByteArray(bytearray):
supersample_factor = 1
def create_wrapper(f: Callable) -> Callable:
@wraps(f)
def supersampled_wrapper(buf: BufType, width: int, height: int, *args: Any, **kw: Any) -> None:
@@ -203,7 +204,7 @@ def line_equation(x1: int, y1: int, x2: int, y2: int) -> Callable[[int], float]:
@supersampled()
def triangle(buf: BufType, width: int, height: int, left: bool = True) -> None:
def triangle(buf: SSByteArray, width: int, height: int, left: bool = True) -> None:
ay1, by1, y2 = 0, height - 1, height // 2
if left:
x1, x2 = 0, width - 1
@@ -216,7 +217,7 @@ def triangle(buf: BufType, width: int, height: int, left: bool = True) -> None:
@supersampled()
def corner_triangle(buf: BufType, width: int, height: int, corner: str) -> None:
def corner_triangle(buf: SSByteArray, width: int, height: int, corner: str) -> None:
if corner == 'top-right' or corner == 'bottom-left':
diagonal_y = line_equation(0, 0, width - 1, height - 1)
if corner == 'top-right':
@@ -233,7 +234,7 @@ def corner_triangle(buf: BufType, width: int, height: int, corner: str) -> None:
@supersampled()
def half_triangle(buf: BufType, width: int, height: int, which: str = 'left', inverted: bool = False) -> None:
def half_triangle(buf: SSByteArray, width: int, height: int, which: str = 'left', inverted: bool = False) -> None:
mid_x, mid_y = width // 2, height // 2
if which == 'left':
upper_y = line_equation(0, 0, mid_x, mid_y)
@@ -274,19 +275,17 @@ def thick_line(buf: BufType, width: int, height: int, thickness_in_pixels: int,
@supersampled()
def cross_line(buf: BufType, width: int, height: int, left: bool = True, level: int = 1) -> None:
def cross_line(buf: SSByteArray, width: int, height: int, left: bool = True, level: int = 1) -> None:
if left:
p1, p2 = (0, 0), (width - 1, height - 1)
else:
p1, p2 = (width - 1, 0), (0, height - 1)
supersample_factor = getattr(buf, 'supersample_factor')
thick_line(buf, width, height, supersample_factor * thickness(level), p1, p2)
thick_line(buf, width, height, buf.supersample_factor * thickness(level), p1, p2)
@supersampled()
def half_cross_line(buf: BufType, width: int, height: int, which: str = 'tl', level: int = 1) -> None:
supersample_factor = getattr(buf, 'supersample_factor')
thickness_in_pixels = thickness(level) * supersample_factor
def half_cross_line(buf: SSByteArray, width: int, height: int, which: str = 'tl', level: int = 1) -> None:
thickness_in_pixels = thickness(level) * buf.supersample_factor
my = (height - 1) // 2
if which == 'tl':
p1 = 0, 0
@@ -304,9 +303,8 @@ def half_cross_line(buf: BufType, width: int, height: int, which: str = 'tl', le
@supersampled()
def mid_lines(buf: BufType, width: int, height: int, level: int = 1, pts: Iterable[str] = ('lt',)) -> None:
def mid_lines(buf: SSByteArray, width: int, height: int, level: int = 1, pts: Iterable[str] = ('lt',)) -> None:
mid_x, mid_y = width // 2, height // 2
supersample_factor = getattr(buf, 'supersample_factor')
def pt_to_coords(p: str) -> Tuple[int, int]:
if p == 'l':
@@ -320,7 +318,7 @@ def mid_lines(buf: BufType, width: int, height: int, level: int = 1, pts: Iterab
for x in pts:
p1, p2 = map(pt_to_coords, x)
thick_line(buf, width, height, supersample_factor * thickness(level), p1, p2)
thick_line(buf, width, height, buf.supersample_factor * thickness(level), p1, p2)
ParameterizedFunc = Callable[[float], float]
@@ -391,7 +389,7 @@ def get_bezier_limits(bezier_x: ParameterizedFunc, bezier_y: ParameterizedFunc)
@supersampled()
def D(buf: BufType, width: int, height: int, left: bool = True) -> None:
def D(buf: SSByteArray, width: int, height: int, left: bool = True) -> None:
c1x = find_bezier_for_D(width, height)
start = (0, 0)
end = (0, height - 1)
@@ -412,10 +410,10 @@ def D(buf: BufType, width: int, height: int, left: bool = True) -> None:
def draw_parametrized_curve(
buf: BufType, width: int, height: int, level: int,
buf: SSByteArray, width: int, height: int, level: int,
xfunc: ParameterizedFunc, yfunc: ParameterizedFunc
) -> None:
supersample_factor = getattr(buf, 'supersample_factor')
supersample_factor = buf.supersample_factor
num_samples = height * 8
delta, extra = divmod(thickness(level), 2)
delta *= supersample_factor
@@ -489,12 +487,33 @@ def rectircle_equations(
@supersampled()
def rounded_corner(buf: BufType, width: int, height: int, level: int = 1, which: str = '') -> None:
supersample_factor = getattr(buf, 'supersample_factor')
xfunc, yfunc = rectircle_equations(width, height, supersample_factor, which)
def rounded_corner(buf: SSByteArray, width: int, height: int, level: int = 1, which: str = '') -> None:
xfunc, yfunc = rectircle_equations(width, height, buf.supersample_factor, which)
draw_parametrized_curve(buf, width, height, level, xfunc, yfunc)
@supersampled()
def rounded_separator(buf: SSByteArray, width: int, height: int, level: int = 1, left: bool = True) -> None:
gap = thickness(level) * buf.supersample_factor
c1x = find_bezier_for_D(width - gap, height)
start = (0, 0)
end = (0, height - 1)
c1 = c1x, start[1]
c2 = c1x, end[1]
bezier_x, bezier_y = cubic_bezier(start, end, c1, c2)
if left:
draw_parametrized_curve(buf, width, height, level, bezier_x, bezier_y)
else:
mbuf = SSByteArray(width * height)
mbuf.supersample_factor = buf.supersample_factor
draw_parametrized_curve(mbuf, width, height, level, bezier_x, bezier_y)
for y in range(height):
offset = y * width
for src_x in range(width):
dest_x = width - 1 - src_x
buf[offset + dest_x] = mbuf[offset + src_x]
def half_dhline(buf: BufType, width: int, height: int, level: int = 1, which: str = 'left', only: Optional[str] = None) -> Tuple[int, int]:
x1, x2 = (0, width // 2) if which == 'left' else (width // 2, width)
gap = thickness(level + 1, horizontal=False)
@@ -678,7 +697,7 @@ def sextant(buf: BufType, width: int, height: int, level: int = 1, which: int =
@supersampled()
def smooth_mosaic(
buf: BufType, width: int, height: int, level: int = 1,
buf: SSByteArray, width: int, height: int, level: int = 1,
lower: bool = True, a: Tuple[float, float] = (0, 0), b: Tuple[float, float] = (0, 0)
) -> None:
ax, ay = int(a[0] * (width - 1)), int(a[1] * (height - 1))
@@ -792,15 +811,21 @@ box_chars: Dict[str, List[Callable]] = {
'': [p(half_hline, level=3), p(half_hline, which='right')],
'': [p(half_vline, level=3), p(half_vline, which='bottom')],
'': [triangle],
'': [p(triangle, left=False)],
'': [D],
'': [p(D, left=False)],
'': [p(half_cross_line, which='tl'), p(half_cross_line, which='bl')],
'': [p(triangle, left=False)],
'': [p(half_cross_line, which='tr'), p(half_cross_line, which='br')],
'': [D],
'': [rounded_separator],
'': [p(D, left=False)],
'': [p(rounded_separator, left=False)],
'': [p(corner_triangle, corner='bottom-left')],
'': [cross_line],
'': [p(corner_triangle, corner='bottom-right')],
'': [p(cross_line, left=False)],
'': [p(corner_triangle, corner='top-left')],
'': [p(cross_line, left=False)],
'': [p(corner_triangle, corner='top-right')],
'': [cross_line],
'': [dhline],
'': [dvline],
@@ -1037,7 +1062,7 @@ def test_char(ch: str, sz: int = 48) -> None:
set_send_sprite_to_gpu(None)
def test_drawing(sz: int = 48, family: str = 'monospace') -> None:
def test_drawing(sz: int = 48, family: str = 'monospace', start: int = 0x2500, num_rows: int = 10, num_cols: int = 16) -> None:
from .render import display_bitmap, setup_for_testing
from kitty.fast_data_types import concat_cells, set_send_sprite_to_gpu
@@ -1055,14 +1080,14 @@ def test_drawing(sz: int = 48, family: str = 'monospace') -> None:
return cell
return space
pos = 0x2500
pos = start
rows = []
space_row = join_cells(repeat(space, 32))
try:
for r in range(10):
for r in range(num_rows):
row = []
for i in range(16):
for i in range(num_cols):
row.append(render_chr(chr(pos)))
row.append(space)
pos += 1

View File

@@ -504,7 +504,7 @@ render_line(PyObject *self UNUSED, PyObject *args, PyObject *kw) {
if (!PyArg_ParseTupleAndKeywords(args, kw, "|sIIzppkkffI", (char**)kwlist, &text, &width, &height, &family, &bold, &italic, &fg, &bg, &x_offset, &y_offset, &right_margin)) return NULL;
PyObject *ans = PyBytes_FromStringAndSize(NULL, (Py_ssize_t)width * height * 4);
if (!ans) return NULL;
uint8_t *buffer = (u_int8_t*) PyBytes_AS_STRING(ans);
uint8_t *buffer = (uint8_t*) PyBytes_AS_STRING(ans);
RenderCtx *ctx = (RenderCtx*)create_freetype_render_context(family, bold, italic);
if (!ctx) return NULL;
if (!render_single_line((FreeTypeRenderCtx)ctx, text, 3 * height / 4, 0, 0xffffffff, buffer, width, height, x_offset, y_offset, right_margin)) {

3
kitty/glfw-wrapper.c generated
View File

@@ -432,6 +432,9 @@ load_glfw(const char* path) {
*(void **) (&glfwRequestWaylandFrameEvent_impl) = dlsym(handle, "glfwRequestWaylandFrameEvent");
if (glfwRequestWaylandFrameEvent_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwWaylandSetTitlebarColor_impl) = dlsym(handle, "glfwWaylandSetTitlebarColor");
if (glfwWaylandSetTitlebarColor_impl == NULL) dlerror(); // clear error indicator
*(void **) (&glfwDBusUserNotify_impl) = dlsym(handle, "glfwDBusUserNotify");
if (glfwDBusUserNotify_impl == NULL) dlerror(); // clear error indicator

4
kitty/glfw-wrapper.h generated
View File

@@ -2154,6 +2154,10 @@ typedef void (*glfwRequestWaylandFrameEvent_func)(GLFWwindow*, unsigned long lon
GFW_EXTERN glfwRequestWaylandFrameEvent_func glfwRequestWaylandFrameEvent_impl;
#define glfwRequestWaylandFrameEvent glfwRequestWaylandFrameEvent_impl
typedef bool (*glfwWaylandSetTitlebarColor_func)(GLFWwindow*, uint32_t, bool);
GFW_EXTERN glfwWaylandSetTitlebarColor_func glfwWaylandSetTitlebarColor_impl;
#define glfwWaylandSetTitlebarColor glfwWaylandSetTitlebarColor_impl
typedef unsigned long long (*glfwDBusUserNotify_func)(const char*, const char*, const char*, const char*, const char*, int32_t, GLFWDBusnotificationcreatedfun, void*);
GFW_EXTERN glfwDBusUserNotify_func glfwDBusUserNotify_impl;
#define glfwDBusUserNotify glfwDBusUserNotify_impl

View File

@@ -573,11 +573,13 @@ intercept_cocoa_fullscreen(GLFWwindow *w) {
#endif
void
set_titlebar_color(OSWindow *w, color_type color) {
set_titlebar_color(OSWindow *w, color_type color, bool use_system_color) {
if (w->handle && (!w->last_titlebar_color || (w->last_titlebar_color & 0xffffff) != (color & 0xffffff))) {
w->last_titlebar_color = (1 << 24) | (color & 0xffffff);
#ifdef __APPLE__
cocoa_set_titlebar_color(glfwGetCocoaWindow(w->handle), color);
if (!use_system_color) cocoa_set_titlebar_color(glfwGetCocoaWindow(w->handle), color);
#else
if (global_state.is_wayland && glfwWaylandSetTitlebarColor) glfwWaylandSetTitlebarColor(w->handle, color, use_system_color);
#endif
}
}

View File

@@ -369,7 +369,7 @@ get_free_client_id(const GraphicsManager *self) {
}
if (!count) { free(client_ids); return 1; }
#define int_lt(a, b) ((*a)<(*b))
QSORT(u_int32_t, client_ids, count, int_lt)
QSORT(uint32_t, client_ids, count, int_lt)
#undef int_lt
uint32_t prev_id = 0, ans = 1;
for (size_t i = 0; i < count; i++) {

View File

@@ -90,6 +90,28 @@ update_ime_position(OSWindow *os_window, Window* w, Screen *screen) {
glfwUpdateIMEState(global_state.callback_os_window->handle, &ev);
}
static inline const char*
format_mods(unsigned mods) {
static char buf[128];
char *p = buf, *s;
#define pr(x) p += snprintf(p, sizeof(buf) - (p - buf) - 1, x)
pr("mods: ");
s = p;
if (mods & GLFW_MOD_CONTROL) pr("ctrl+");
if (mods & GLFW_MOD_ALT) pr("alt+");
if (mods & GLFW_MOD_SHIFT) pr("shift+");
if (mods & GLFW_MOD_SUPER) pr("super+");
if (mods & GLFW_MOD_HYPER) pr("hyper+");
if (mods & GLFW_MOD_META) pr("meta+");
if (mods & GLFW_MOD_CAPS_LOCK) pr("capslock+");
if (mods & GLFW_MOD_NUM_LOCK) pr("numlock+");
if (p == s) pr("none");
else p--;
pr(" ");
#undef pr
return buf;
}
void
on_key_input(GLFWkeyevent *ev) {
Window *w = active_window();
@@ -97,10 +119,10 @@ on_key_input(GLFWkeyevent *ev) {
const uint32_t key = ev->key, native_key = ev->native_key;
const char *text = ev->text ? ev->text : "";
debug("\x1b[33mon_key_input\x1b[m: glfw key: %d native_code: 0x%x action: %s mods: 0x%x text: '%s' state: %d ",
debug("\x1b[33mon_key_input\x1b[m: glfw key: 0x%x native_code: 0x%x action: %s %stext: '%s' state: %d ",
key, native_key,
(action == GLFW_RELEASE ? "RELEASE" : (action == GLFW_PRESS ? "PRESS" : "REPEAT")),
mods, text, ev->ime_state);
format_mods(mods), text, ev->ime_state);
if (!w) { debug("no active window, ignoring\n"); return; }
if (OPT(mouse_hide_wait) < 0 && !is_modifier_key(key)) hide_mouse(global_state.callback_os_window);
Screen *screen = w->render_data.screen;
@@ -167,7 +189,7 @@ on_key_input(GLFWkeyevent *ev) {
if (!w) return;
} else if (w->last_special_key_pressed == key) {
w->last_special_key_pressed = 0;
debug("ignoring release event for previous press that was handled as shortcut");
debug("ignoring release event for previous press that was handled as shortcut\n");
return;
}
#undef create_key_event
@@ -187,7 +209,7 @@ on_key_input(GLFWkeyevent *ev) {
schedule_write_to_child(w->id, 1, encoded_key, size);
debug("sent key to child\n");
} else {
debug("ignoring as keyboard mode does not allow %s events\n", action == GLFW_RELEASE ? "release" : "repeat");
debug("ignoring as keyboard mode does not support encoding this event\n");
}
}

View File

@@ -13,7 +13,7 @@
#define KEY_BUFFER_SIZE 128
#define SEND_TEXT_TO_CHILD INT_MIN
#define debug(...) if (OPT(debug_keyboard)) printf(__VA_ARGS__);
#define debug(...) if (OPT(debug_keyboard)) { fprintf(stderr, __VA_ARGS__); fflush(stderr); }
int
encode_glfw_key_event(const GLFWkeyevent *e, const bool cursor_key_mode, const unsigned flags, char *output);

View File

@@ -21,9 +21,9 @@ from .constants import (
is_wayland, kitty_exe, logo_png_file, running_in_kitty
)
from .fast_data_types import (
GLFW_IBEAM_CURSOR, create_os_window, free_font_data, glfw_init,
glfw_terminate, load_png_data, set_custom_cursor, set_default_window_icon,
set_options
GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, create_os_window,
free_font_data, glfw_init, glfw_terminate, load_png_data,
set_custom_cursor, set_default_window_icon, set_options
)
from .fonts.box_drawing import set_scale
from .fonts.render import set_font_family
@@ -112,9 +112,14 @@ def get_macos_shortcut_for(opts: OptionsStub, function: str = 'new_os_window') -
candidates.append(k)
if candidates:
from .fast_data_types import cocoa_set_global_shortcut
alt_mods = GLFW_MOD_ALT, GLFW_MOD_ALT | GLFW_MOD_SHIFT
# Reverse list so that later defined keyboard shortcuts take priority over earlier defined ones
for candidate in reversed(candidates):
if candidate.mods in alt_mods:
# Option based shortcuts dont work in the global menubar,
# presumably because Apple reserves them for IME, see
# https://github.com/kovidgoyal/kitty/issues/3515
continue
if cocoa_set_global_shortcut(function, candidate[0], candidate[2]):
ans = candidate
break
@@ -301,6 +306,9 @@ def _main() -> None:
create_opts(cli_opts, debug_config=True)
return
if cli_opts.detach:
if cli_opts.session == '-':
from .session import PreReadSession
cli_opts.session = PreReadSession(sys.stdin.read())
detach()
if cli_opts.replay_commands:
from kitty.client import main as client_main

View File

@@ -932,7 +932,13 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
NO_MODIFIERS(end_modifier, ' ', "Select presentation directions escape code not implemented");
CALL_CSI_HANDLER1(screen_scroll, 1);
case SD:
CALL_CSI_HANDLER1(screen_reverse_scroll, 1);
if (!start_modifier && end_modifier == '+') {
CALL_CSI_HANDLER1(screen_reverse_scroll_and_fill_from_scrollback, 1);
} else {
NO_MODIFIERS(start_modifier, 0, "");
CALL_CSI_HANDLER1(screen_reverse_scroll, 1);
}
break;
case DECSTR:
if (end_modifier == '$') {
// DECRQM

View File

@@ -34,9 +34,8 @@ If specified close the tab this command is run in, rather than the active tab.
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
for tab in self.tabs_for_match_payload(boss, window, payload_get):
if window:
if tab:
boss.close_tab_no_confirm(tab)
if tab:
boss.close_tab_no_confirm(tab)
close_tab = CloseTab()

49
kitty/rc/env.py Normal file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from typing import Any, Optional
from .base import (
ArgsType, Boss, PayloadGetType, PayloadType, RCOptions, RemoteCommand,
ResponseType, Window
)
class Env(RemoteCommand):
'''
env+: dictionary of environment variables to values. Empty values cause the variable to be deleted.
'''
short_desc = 'Change environment variables seen by future children'
desc = (
'Change the environment variables seen by processing in newly launched windows.'
' Similar to the :opt:`env` option in kitty.conf, but affects running kitty instances.'
' Empty values cause the environment variable to be removed.'
)
argspec = 'env_var1=val env_var2=val ...'
def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType:
if len(args) < 1:
self.fatal('Must specify at least one env var to set')
env = {}
for x in args:
key, val = x.split('=', 1)
env[key] = val
return {'env': env}
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
from kitty.child import default_env, set_default_env
from kitty.utils import expandvars
new_env = payload_get('env') or {}
env = default_env().copy()
for k, v in new_env.items():
if v:
env[k] = expandvars(v, env)
else:
env.pop(k, None)
set_default_env(env)
env = Env()

View File

@@ -38,9 +38,10 @@ using this option means that you will not be notified of failures.
return {'match': opts.match}
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
tabs = self.tabs_for_match_payload(boss, window, payload_get)
if tabs:
boss.set_active_tab(tabs[0])
for tab in self.tabs_for_match_payload(boss, window, payload_get):
if tab:
boss.set_active_tab(tab)
break
focus_tab = FocusTab()

View File

@@ -3,7 +3,7 @@
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import json
from typing import Any, Dict, List, Optional, Set, Tuple
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
from kitty.constants import appname
@@ -12,6 +12,9 @@ from .base import (
ResponseType, Window
)
if TYPE_CHECKING:
from kitty.cli_stub import LSRCOptions as CLIOptions
class LS(RemoteCommand):
'''
@@ -36,7 +39,7 @@ Show all environment variables in output not just differing ones.
argspec = ''
def message_to_kitty(self, global_opts: RCOptions, opts: Any, args: ArgsType) -> PayloadType:
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
return {'all_env_vars': opts.all_env_vars}
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:

View File

@@ -773,9 +773,11 @@ void
screen_toggle_screen_buffer(Screen *self, bool save_cursor, bool clear_alt_screen) {
bool to_alt = self->linebuf == self->main_linebuf;
self->active_hyperlink_id = 0;
grman_clear(self->alt_grman, true, self->cell_size); // always clear the alt buffer graphics to free up resources, since it has to be cleared when switching back to it anyway
if (to_alt) {
if (clear_alt_screen) linebuf_clear(self->alt_linebuf, BLANK_CHAR);
if (clear_alt_screen) {
linebuf_clear(self->alt_linebuf, BLANK_CHAR);
grman_clear(self->alt_grman, true, self->cell_size);
}
if (save_cursor) screen_save_cursor(self);
self->linebuf = self->alt_linebuf;
self->tabstops = self->alt_tabstops;
@@ -1134,17 +1136,30 @@ screen_reverse_index(Screen *self) {
} else screen_cursor_up(self, 1, false, -1);
}
void
screen_reverse_scroll(Screen *self, unsigned int count) {
static void
_reverse_scroll(Screen *self, unsigned int count, bool fill_from_scrollback) {
// Scroll the screen down by count lines, not moving the cursor
count = MIN(self->lines, count);
unsigned int top = self->margin_top, bottom = self->margin_bottom;
while (count > 0) {
count--;
fill_from_scrollback = fill_from_scrollback && self->linebuf == self->main_linebuf;
while (count-- > 0) {
bool copied = false;
if (fill_from_scrollback) copied = historybuf_pop_line(self->historybuf, self->alt_linebuf->line);
INDEX_DOWN;
if (copied) linebuf_copy_line_to(self->main_linebuf, self->alt_linebuf->line, 0);
}
}
void
screen_reverse_scroll(Screen *self, unsigned int count) {
_reverse_scroll(self, count, false);
}
void
screen_reverse_scroll_and_fill_from_scrollback(Screen *self, unsigned int count) {
_reverse_scroll(self, count, true);
}
void
screen_carriage_return(Screen *self) {
@@ -2886,6 +2901,15 @@ hyperlink_at(Screen *self, PyObject *args) {
return Py_BuildValue("s", url);
}
static PyObject*
reverse_scroll(Screen *self, PyObject *args) {
int fill_from_scrollback = 0;
unsigned int amt;
if (!PyArg_ParseTuple(args, "I|p", &amt, &fill_from_scrollback)) return NULL;
_reverse_scroll(self, amt, fill_from_scrollback);
Py_RETURN_NONE;
}
#define MND(name, args) {#name, (PyCFunction)name, args, #name},
#define MODEFUNC(name) MND(name, METH_NOARGS) MND(set_##name, METH_O)
@@ -2909,6 +2933,7 @@ static PyMethodDef methods[] = {
MND(hyperlinks_as_list, METH_NOARGS)
MND(garbage_collect_hyperlink_pool, METH_NOARGS)
MND(hyperlink_for_id, METH_O)
MND(reverse_scroll, METH_VARARGS)
METHOD(current_char_width, METH_NOARGS)
MND(insert_lines, METH_VARARGS)
MND(delete_lines, METH_VARARGS)

View File

@@ -157,6 +157,7 @@ void screen_reverse_index(Screen *self);
void screen_index(Screen *self);
void screen_scroll(Screen *self, unsigned int count);
void screen_reverse_scroll(Screen *self, unsigned int count);
void screen_reverse_scroll_and_fill_from_scrollback(Screen *self, unsigned int count);
void screen_reset(Screen *self);
void screen_set_tab_stop(Screen *self);
void screen_tab(Screen *self);

View File

@@ -137,6 +137,14 @@ def parse_session(raw: str, opts: Options, default_title: Optional[str] = None)
yield finalize_session(ans)
class PreReadSession(str):
def __new__(cls, val: str) -> 'PreReadSession':
ans: PreReadSession = str.__new__(cls, val)
ans.pre_read = True # type: ignore
return ans
def create_sessions(
opts: Options,
args: Optional[CLIOptions] = None,
@@ -146,12 +154,15 @@ def create_sessions(
default_session: Optional[str] = None
) -> Generator[Session, None, None]:
if args and args.session:
if args.session == '-':
f = sys.stdin
if isinstance(args.session, PreReadSession):
session_data = '' + str(args.session)
else:
f = open(args.session)
with f:
session_data = f.read()
if args.session == '-':
f = sys.stdin
else:
f = open(args.session)
with f:
session_data = f.read()
yield from parse_session(session_data, opts, getattr(args, 'title', None))
return
if default_session and default_session != 'none':

View File

@@ -16,7 +16,7 @@ from .cli import (
title
)
from .cli_stub import RCOptions
from .constants import cache_dir, is_macos, version, kitty_face
from .constants import cache_dir, version, kitty_face
from .rc.base import (
RemoteCommand, all_command_names, command_for_name,
display_subcommand_help, parse_subcommand_cli
@@ -31,11 +31,8 @@ def match_commands() -> Tuple[str, ...]:
def init_readline(readline: Any) -> None:
try:
with suppress(OSError):
readline.read_init_file()
except OSError:
if not is_macos:
raise
if 'libedit' in readline.__doc__:
readline.parse_and_bind("bind ^I rl_complete")
else:

View File

@@ -918,9 +918,10 @@ PYWRAP1(focus_os_window) {
PYWRAP1(set_titlebar_color) {
id_type os_window_id;
unsigned int color;
PA("KI", &os_window_id, &color);
int use_system_color = 0;
PA("KI|p", &os_window_id, &color, &use_system_color);
WITH_OS_WINDOW(os_window_id)
set_titlebar_color(os_window, color);
set_titlebar_color(os_window, color, use_system_color);
Py_RETURN_TRUE;
END_WITH_OS_WINDOW
Py_RETURN_FALSE;

View File

@@ -256,7 +256,7 @@ void send_image_to_gpu(uint32_t*, const void*, int32_t, int32_t, bool, bool, boo
void send_sprite_to_gpu(FONTS_DATA_HANDLE fg, unsigned int, unsigned int, unsigned int, pixel*);
void blank_canvas(float, color_type);
void blank_os_window(OSWindow *);
void set_titlebar_color(OSWindow *w, color_type color);
void set_titlebar_color(OSWindow *w, color_type color, bool use_system_color);
FONTS_DATA_HANDLE load_fonts_data(double, double, double);
void send_prerendered_sprites_for_window(OSWindow *w);
#ifdef __APPLE__

View File

@@ -295,6 +295,7 @@ class TabBar:
def patch_colors(self, spec: Dict[str, Any]) -> None:
if 'active_tab_foreground' in spec:
self.active_fg = (spec['active_tab_foreground'] << 8) | 2
self.draw_data = self.draw_data._replace(active_fg=color_from_int(spec['active_tab_foreground']))
if 'active_tab_background' in spec:
self.active_bg = (spec['active_tab_background'] << 8) | 2
self.draw_data = self.draw_data._replace(active_bg=color_from_int(spec['active_tab_background']))

View File

@@ -687,7 +687,10 @@ class TabManager: # {{{
@property
def active_tab(self) -> Optional[Tab]:
return self.tabs[self.active_tab_idx] if self.tabs else None
try:
return self.tabs[self.active_tab_idx] if self.tabs else None
except Exception:
return None
@property
def active_window(self) -> Optional[Window]:
@@ -750,6 +753,7 @@ class TabManager: # {{{
return self.tabs[idx]
def remove(self, tab: Tab) -> None:
active_tab_before_removal = self.active_tab
self._remove_tab(tab)
try:
active_tab_needs_to_change = self.active_tab is None or self.active_tab is tab
@@ -779,6 +783,13 @@ class TabManager: # {{{
next_active_tab = max(0, min(self.active_tab_idx, len(self.tabs) - 1))
self._set_active_tab(next_active_tab)
elif active_tab_before_removal is not None:
try:
idx = self.tabs.index(active_tab_before_removal)
except Exception:
pass
else:
self._active_tab_idx = idx
self.mark_tab_bar_dirty()
tab.destroy()

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2003-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
Copyright (c) 2003-2021, Troy D. Hanson http://troydhanson.github.io/uthash/
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -24,12 +24,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef UTHASH_H
#define UTHASH_H
#define UTHASH_VERSION 2.1.0
#define UTHASH_VERSION 2.3.0
#include <string.h> /* memcmp, memset, strlen */
#include <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* exit */
#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT
/* This codepath is provided for backward compatibility, but I plan to remove it. */
#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead"
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT
#else
#include <stdint.h> /* uint8_t, uint32_t */
#endif
/* These macros use decltype or the earlier __typeof GNU extension.
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
when compiling c++ source) this code uses whatever method is needed
@@ -62,23 +72,6 @@ do {
} while (0)
#endif
/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1600
#include <stdint.h>
#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__)
#include <stdint.h>
#else
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#endif
#elif defined(__GNUC__) && !defined(__VXWORKS__)
#include <stdint.h>
#else
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#endif
#ifndef uthash_malloc
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
#endif
@@ -92,15 +85,12 @@ typedef unsigned char uint8_t;
#define uthash_strlen(s) strlen(s)
#endif
#ifdef uthash_memcmp
/* This warning will not catch programs that define uthash_memcmp AFTER including uthash.h. */
#warning "uthash_memcmp is deprecated; please use HASH_KEYCMP instead"
#else
#define uthash_memcmp(a,b,n) memcmp(a,b,n)
#ifndef HASH_FUNCTION
#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv)
#endif
#ifndef HASH_KEYCMP
#define HASH_KEYCMP(a,b,n) uthash_memcmp(a,b,n)
#define HASH_KEYCMP(a,b,n) memcmp(a,b,n)
#endif
#ifndef uthash_noexpand_fyi
@@ -144,7 +134,7 @@ typedef unsigned char uint8_t;
/* calculate the element whose hash handle address is hhp */
#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
/* calculate the hash handle from element address elp */
#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho)))
#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho)))
#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \
do { \
@@ -158,7 +148,7 @@ do {
#define HASH_VALUE(keyptr,keylen,hashv) \
do { \
HASH_FCN(keyptr, keylen, hashv); \
HASH_FUNCTION(keyptr, keylen, hashv); \
} while (0)
#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \
@@ -175,9 +165,12 @@ do {
#define HASH_FIND(hh,head,keyptr,keylen,out) \
do { \
unsigned _hf_hashv; \
HASH_VALUE(keyptr, keylen, _hf_hashv); \
HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \
(out) = NULL; \
if (head) { \
unsigned _hf_hashv; \
HASH_VALUE(keyptr, keylen, _hf_hashv); \
HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \
} \
} while (0)
#ifdef HASH_BLOOM
@@ -405,7 +398,7 @@ do {
do { \
IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
(add)->hh.hashv = (hashval); \
(add)->hh.key = (char*) (keyptr); \
(add)->hh.key = (const void*) (keyptr); \
(add)->hh.keylen = (unsigned) (keylen_in); \
if (!(head)) { \
(add)->hh.next = NULL; \
@@ -519,7 +512,8 @@ do {
* This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
*/
#ifdef HASH_DEBUG
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
#include <stdio.h> /* fprintf, stderr */
#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0)
#define HASH_FSCK(hh,head,where) \
do { \
struct UT_hash_handle *_thh; \
@@ -586,13 +580,6 @@ do {
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
#endif
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
#ifdef HASH_FUNCTION
#define HASH_FCN HASH_FUNCTION
#else
#define HASH_FCN HASH_JEN
#endif
/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
#define HASH_BER(key,keylen,hashv) \
do { \
@@ -691,7 +678,8 @@ do {
case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \
case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \
case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \
case 1: _hj_i += _hj_key[0]; \
case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \
default: ; \
} \
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
} while (0)
@@ -739,6 +727,8 @@ do {
case 1: hashv += *_sfh_key; \
hashv ^= hashv << 10; \
hashv += hashv >> 1; \
break; \
default: ; \
} \
\
/* Force "avalanching" of final 127 bits */ \
@@ -750,87 +740,6 @@ do {
hashv += hashv >> 6; \
} while (0)
#ifdef HASH_USING_NO_STRICT_ALIASING
/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
* MurmurHash uses the faster approach only on CPU's where we know it's safe.
*
* Note the preprocessor built-in defines can be emitted using:
*
* gcc -m64 -dM -E - < /dev/null (on gcc)
* cc -## a.c (where a.c is a simple test file) (Sun Studio)
*/
#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
#define MUR_GETBLOCK(p,i) p[i]
#else /* non intel */
#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL)
#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL)
#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL)
#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL)
#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
#else /* assume little endian non-intel */
#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
#endif
#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
(MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
(MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
MUR_ONE_THREE(p))))
#endif
#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
#define MUR_FMIX(_h) \
do { \
_h ^= _h >> 16; \
_h *= 0x85ebca6bu; \
_h ^= _h >> 13; \
_h *= 0xc2b2ae35u; \
_h ^= _h >> 16; \
} while (0)
#define HASH_MUR(key,keylen,hashv) \
do { \
const uint8_t *_mur_data = (const uint8_t*)(key); \
const int _mur_nblocks = (int)(keylen) / 4; \
uint32_t _mur_h1 = 0xf88D5353u; \
uint32_t _mur_c1 = 0xcc9e2d51u; \
uint32_t _mur_c2 = 0x1b873593u; \
uint32_t _mur_k1 = 0; \
const uint8_t *_mur_tail; \
const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \
int _mur_i; \
for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) { \
_mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
_mur_k1 *= _mur_c2; \
\
_mur_h1 ^= _mur_k1; \
_mur_h1 = MUR_ROTL32(_mur_h1,13); \
_mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \
} \
_mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \
_mur_k1=0; \
switch ((keylen) & 3U) { \
case 0: break; \
case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \
case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \
case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
_mur_k1 *= _mur_c2; \
_mur_h1 ^= _mur_k1; \
} \
_mur_h1 ^= (uint32_t)(keylen); \
MUR_FMIX(_mur_h1); \
hashv = _mur_h1; \
} while (0)
#endif /* HASH_USING_NO_STRICT_ALIASING */
/* iterate over items in a known bucket to find desired item */
#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \
do { \
@@ -841,7 +750,7 @@ do {
} \
while ((out) != NULL) { \
if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \
if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \
if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \
break; \
} \
} \
@@ -927,12 +836,12 @@ do {
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
_he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \
if (!_he_new_buckets) { \
HASH_RECORD_OOM(oomed); \
} else { \
uthash_bzero(_he_new_buckets, \
2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \
(tbl)->ideal_chain_maxlen = \
((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \
((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \
@@ -1080,7 +989,7 @@ do {
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
if (cond(_elt)) { \
IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \
_dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
_dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \
_dst_hh->key = _src_hh->key; \
_dst_hh->keylen = _src_hh->keylen; \
_dst_hh->hashv = _src_hh->hashv; \
@@ -1219,7 +1128,7 @@ typedef struct UT_hash_handle {
void *next; /* next element in app order */
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
struct UT_hash_handle *hh_next; /* next hh in bucket order */
void *key; /* ptr to enclosing struct's key */
const void *key; /* ptr to enclosing struct's key */
unsigned keylen; /* enclosing struct's key len */
unsigned hashv; /* result of hash-fcn(key) */
} UT_hash_handle;

View File

@@ -19,7 +19,7 @@ from typing import (
from .child import ProcessDesc
from .cli_stub import CLIOptions
from .config import build_ansi_color_table
from .constants import appname, wakeup
from .constants import appname, wakeup, is_macos
from .fast_data_types import (
BGIMAGE_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM,
CELL_PROGRAM, CELL_SPECIAL_PROGRAM, DCS, DECORATION, DIM, GLFW_MOD_CONTROL,
@@ -629,13 +629,15 @@ class Window:
tab.on_bell(self)
def change_titlebar_color(self) -> None:
val = self.opts.macos_titlebar_color
val = self.opts.macos_titlebar_color if is_macos else self.opts.wayland_titlebar_color
if val:
if (val & 0xff) == 1:
val = self.screen.color_profile.default_bg
else:
val = val >> 8
set_titlebar_color(self.os_window_id, val)
else:
set_titlebar_color(self.os_window_id, 0, True)
def change_colors(self, changes: Dict[DynamicColor, Optional[str]]) -> None:
dirtied = default_bg_changed = False

View File

@@ -184,6 +184,9 @@ class TestParser(BaseTest):
pb('\033[3 @', ('Shift left escape code not implemented',))
pb('\033[3 A', ('Shift right escape code not implemented',))
pb('\033[3;4 S', ('Select presentation directions escape code not implemented',))
pb('\033[1T', ('screen_reverse_scroll', 1))
pb('\033[T', ('screen_reverse_scroll', 1))
pb('\033[+T', ('screen_reverse_scroll_and_fill_from_scrollback', 1))
def test_csi_code_rep(self):
s = self.create_screen(8)

View File

@@ -315,6 +315,12 @@ class TestScreen(BaseTest):
def assert_lines(*lines):
return self.ae(lines, tuple(str(s.line(i)) for i in range(s.lines)))
# test the reverse scroll function
s = prepare_screen(map(str, range(6)))
assert_lines('2', '3', '4', '5', '')
s.reverse_scroll(2, True)
assert_lines('0', '1', '2', '3', '4')
# Height increased, width unchanged → pull down lines to fill new space at the top
s = prepare_screen(map(str, range(6)))
assert_lines('2', '3', '4', '5', '')

171
logo/kitty-framed.svg Normal file
View File

@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
height="256"
viewBox="0 0 239.99999 239.99999"
id="svg2"
version="1.1"
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
sodipodi:docname="kitty-framed.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="-88.462374"
inkscape:cy="123.36947"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2560"
inkscape:window-height="1400"
inkscape:window-x="0"
inkscape:window-y="40"
inkscape:window-maximized="0"
inkscape:document-rotation="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Kovid Goyal</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:rights>
<dc:publisher>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:publisher>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-812.36217)">
<path
fill="none"
stroke="#000000"
stroke-width="1.68332"
d="m 120.00001,1052.3622 c 52.58333,0 81.8151,0 100.90756,-19.0924 19.09242,-19.0924 19.09242,-48.32422 19.09242,-100.9076 0,-52.58334 0,-81.81515 -19.09242,-100.90762 -19.09246,-19.09241 -48.32423,-19.09241 -100.90756,-19.09241 -52.583346,0 -81.815144,0 -100.907602,19.09241 C 0,850.54705 0,879.77886 0,932.3622 c 0,52.58338 0,81.8152 19.092408,100.9076 19.092458,19.0924 48.324256,19.0924 100.907602,19.0924 z"
id="path4-36"
style="fill:#dddddd;fill-opacity:1;stroke:none" />
<g
id="g867"
transform="translate(0.16463248,0.18492414)">
<rect
style="fill:#dddddd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.86877;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4496"
width="100.44641"
height="161.55127"
x="72.823654"
y="850.13007"
ry="0" />
<path
inkscape:connector-curvature="0"
d="M 67.895761,1029.7093 H 172.10422 a 7.0649814,7.0649814 0 0 0 7.06499,-7.065 V 918.43587 a 7.0649814,7.0649814 0 0 0 -7.06499,-7.06499 H 67.895761 a 7.0649814,7.0649814 0 0 0 -7.064982,7.06499 v 104.20843 a 7.0649814,7.0649814 0 0 0 7.064982,7.065 z m 55.813329,-38.3487 h 37.4444 a 4.23899,4.23899 0 0 1 0,8.47798 h -37.4444 a 4.23899,4.23899 0 0 1 0,-8.47798 z M 78.676916,945.65018 a 4.2389889,4.2389889 0 0 1 5.991104,-5.99111 l 26.47954,26.46541 a 4.2389889,4.2389889 0 0 1 0,5.99111 l -26.47954,26.47955 a 4.2389889,4.2389889 0 0 1 -5.991104,-5.9911 l 23.483984,-23.484 z"
id="path4"
style="stroke-width:1.413" />
<path
d="m 96.085398,898.14342 c 1.881045,0 3.385879,-3.57421 3.385879,-8.16963 0,-4.59543 -1.504834,-8.16964 -3.385879,-8.16964 -1.881044,0 -3.385879,3.57421 -3.385879,8.16964 0,4.59542 1.504835,8.16963 3.385879,8.16963 z"
id="path4-3"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#c0c81f;fill-opacity:1;fill-rule:evenodd;stroke-width:3.09914" />
<path
d="m 193.12782,836.88644 c -4.59543,-4.85071 -25.53011,1.0212 -38.29517,8.93554 -9.95674,-5.10602 -21.95589,-8.16962 -34.72093,-8.16962 -13.02037,0 -25.01952,3.0636 -34.976266,8.16962 -12.765052,-7.91434 -33.95504,-14.04156 -38.295158,-8.93554 -4.595418,5.10602 3.318914,26.29601 12.765053,38.03987 0,0 0,0 0,0 -0.765903,3.0636 -1.276505,6.12722 -1.276505,9.44614 0,10.21204 4.340118,19.65818 11.743848,27.31721 h 42.124678 c -1.27651,-2.55301 0.51061,-4.08482 8.16963,-4.08482 7.65905,0.2553 9.19084,1.53181 8.16964,4.08482 h 42.12467 c 7.40374,-7.65903 11.74386,-17.36048 11.74386,-27.31721 0,-3.31892 -0.51061,-6.38254 -1.2765,-9.44614 8.93553,-11.74386 16.59456,-33.18914 11.99915,-38.03987 z m -97.014419,67.39949 c -8.935538,0 -16.339269,-7.40374 -16.339269,-16.33927 0,-8.93553 7.403731,-16.33927 16.339269,-16.33927 8.935529,0 16.339269,7.40374 16.339269,16.33927 0,8.93553 -7.40374,16.33927 -16.339269,16.33927 z m 47.996599,0 c -8.93553,0 -16.33926,-7.40374 -16.33926,-16.33927 0,-8.93553 7.40373,-16.33927 16.33926,-16.33927 8.93555,0 16.33927,7.40374 16.33927,16.33927 0,8.93553 -7.14842,16.33927 -16.33927,16.33927 z"
id="path6"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#784421;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301" />
<g
id="g4541"
style="fill:#2b1100;fill-opacity:1">
<path
style="clip-rule:evenodd;fill:#2b1100;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301"
inkscape:connector-curvature="0"
id="path10"
d="m 168.5072,903.26472 c 15.31805,-19.14757 46.72009,-28.33841 67.65477,-15.06276 -24.50889,-3.82951 -46.72009,2.55301 -67.65477,15.06276 z" />
<path
style="clip-rule:evenodd;fill:#2b1100;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301"
inkscape:connector-curvature="0"
id="path12"
d="m 167.486,898.66931 c 8.68022,-20.42409 34.46564,-33.69975 55.14502,-26.55131 -21.70058,2.80831 -39.31636,11.23323 -55.14502,26.55131 z" />
<path
style="clip-rule:evenodd;fill:#2b1100;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301"
inkscape:connector-curvature="0"
id="path14"
d="m 167.23069,908.62604 c 15.82867,-15.06275 50.80491,-20.16879 61.52756,-4.34011 -21.70059,-6.89313 -40.59288,-3.82953 -61.52756,4.34011 z" />
</g>
<g
id="g4536"
style="fill:#2b1100;fill-opacity:1">
<path
style="clip-rule:evenodd;fill:#2b1100;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301"
inkscape:connector-curvature="0"
id="path16"
d="M 71.492797,903.26472 C 56.174733,884.11715 24.772703,874.92631 3.8380177,888.20196 28.346918,884.37245 50.55811,890.75497 71.492797,903.26472 Z" />
<path
style="clip-rule:evenodd;fill:#2b1100;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301"
inkscape:connector-curvature="0"
id="path18"
d="M 72.514,898.66931 C 63.833764,878.24522 38.048358,864.96956 17.368973,872.118 c 21.70059,2.80831 39.316362,11.23323 55.145027,26.55131 z" />
<path
style="clip-rule:evenodd;fill:#2b1100;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301"
inkscape:connector-curvature="0"
id="path20"
d="m 72.769301,908.62604 c -15.828665,-15.06275 -50.80491,-20.16879 -61.527553,-4.34011 21.70059,-6.89313 40.592868,-3.82953 61.527553,4.34011 z" />
</g>
<path
d="m 52.600515,893.56329 c -6.382526,0 -11.743849,3.3189 -14.29686,8.42492 -0.255301,0 -0.510602,0 -0.765903,0 -6.893128,0 -12.765052,5.10602 -12.765052,11.48856 0,8.93553 9.190838,13.78625 17.615773,10.72264 5.10602,7.40373 16.083966,7.91434 20.168783,0 6.127225,-0.2553 16.083966,-1.2765 17.615773,-10.72264 1.021204,-6.38254 -5.616623,-11.48856 -12.765052,-11.48856 -0.255303,0 -0.510604,0 -0.765905,0 -2.042407,-5.10602 -7.659031,-8.42492 -14.041557,-8.42492 z m 134.798965,0 c 6.38252,0 11.74384,3.3189 14.29685,8.42492 0.2553,0 -2.80831,0 0.7659,0 3.57422,0 12.76506,5.10602 12.76506,11.48856 0,8.93553 -9.19084,13.78625 -17.61578,10.72264 -5.10602,7.40373 -16.08397,7.91434 -20.16878,0 -6.12722,-0.2553 -16.08397,-1.2765 -17.61576,-10.72264 -1.02122,-6.38254 9.19083,-11.48856 12.76504,-11.48856 3.57421,0 0.51061,0 0.7659,0 2.04242,-5.10602 7.65904,-8.42492 14.04157,-8.42492 z"
id="path8"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#483737;fill-opacity:1;fill-rule:evenodd;stroke-width:2.55301" />
<path
d="m 143.54212,898.14341 c 1.88105,0 3.38588,-3.57421 3.38588,-8.16963 0,-4.59543 -1.50483,-8.16964 -3.38588,-8.16964 -1.88104,0 -3.38588,3.57421 -3.38588,8.16964 0,4.59542 1.50484,8.16963 3.38588,8.16963 z"
id="path4-3-3"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#c0c81f;fill-opacity:1;fill-rule:evenodd;stroke-width:3.09914" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -7,7 +7,8 @@ import subprocess
import shutil
base = os.path.dirname(os.path.abspath(__file__))
src = os.path.join(base, 'kitty.svg')
unframed_src = os.path.join(base, 'kitty.svg')
framed_src = os.path.join(base, 'kitty-framed.svg')
def abspath(x):
@@ -21,14 +22,15 @@ def run(*args):
raise SystemExit('You are missing the {} program needed to generate the kitty logo'.format(args[0]))
def render(output, sz=256):
print('Rendering at {0}x{0}...'.format(sz))
def render(output, sz=256, src=unframed_src):
print(f'Rendering {os.path.basename(src)} at {sz}x{sz}...')
run('rsvg-convert', '-w', str(sz), '-h', str(sz), '-o', output, src)
run('optipng', '-quiet', '-o7', '-strip', 'all', output)
def main():
render(abspath('kitty.png'))
render(abspath('kitty-128.png'), sz=128)
iconset = abspath('kitty.iconset')
if os.path.exists(iconset):
shutil.rmtree(iconset)
@@ -37,9 +39,7 @@ def main():
for sz in (16, 32, 64, 128, 256, 512, 1024):
iname = os.path.join(iconset, 'icon_{0}x{0}.png'.format(sz))
iname2x = 'icon_{0}x{0}@2x.png'.format(sz // 2)
render(iname, sz)
if sz == 128:
shutil.copyfile(iname, abspath('kitty-128.png'))
render(iname, sz, src=framed_src)
if sz > 16 and sz != 128:
shutil.copy2(iname, iname2x)
if sz in (64, 1024):

View File

@@ -261,6 +261,7 @@ def init_env(
canberra_library: Optional[str] = None,
extra_logging: Iterable[str] = (),
extra_include_dirs: Iterable[str] = (),
ignore_compiler_warnings: bool = False
) -> Env:
native_optimizations = native_optimizations and not sanitize and not debug
if native_optimizations and is_macos and is_arm:
@@ -287,19 +288,15 @@ def init_env(
cppflags = shlex.split(cppflags_)
for el in extra_logging:
cppflags.append('-DDEBUG_{}'.format(el.upper().replace('-', '_')))
werror = '' if ignore_compiler_warnings else '-Werror'
std = '' if is_openbsd else '-std=c11'
sanitize_flag = ' '.join(sanitize_args)
march = '-march=native' if native_optimizations else ''
cflags_ = os.environ.get(
'OVERRIDE_CFLAGS', (
'-Wextra {} -Wno-missing-field-initializers -Wall -Wstrict-prototypes {}'
' -pedantic-errors -Werror {} {} -fwrapv {} {} -pipe {} -fvisibility=hidden {}'
).format(
float_conversion,
'' if is_openbsd else '-std=c11',
optimize,
' '.join(sanitize_args),
stack_protector,
missing_braces,
'-march=native' if native_optimizations else '',
fortify_source
f'-Wextra {float_conversion} -Wno-missing-field-initializers -Wall -Wstrict-prototypes {std}'
f' -pedantic-errors {werror} {optimize} {sanitize_flag} -fwrapv {stack_protector} {missing_braces}'
f' -pipe {march} -fvisibility=hidden {fortify_source}'
)
)
cflags = shlex.split(cflags_) + shlex.split(
@@ -754,7 +751,7 @@ def init_env_from_args(args: Options, native_optimizations: bool = False) -> Non
env = init_env(
args.debug, args.sanitize, native_optimizations, args.link_time_optimization, args.profile,
args.egl_library, args.startup_notification_library, args.canberra_library,
args.extra_logging, args.extra_include_dirs
args.extra_logging, args.extra_include_dirs, args.ignore_compiler_warnings
)
@@ -1234,6 +1231,11 @@ def option_parser() -> argparse.ArgumentParser: # {{{
action='store_false',
help='Turn off Link Time Optimization (LTO).'
)
p.add_argument(
'--ignore-compiler-warnings',
default=False, action='store_true',
help='Ignore any warnings from the compiler while building'
)
return p
# }}}