Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57b5e493a4 | ||
|
|
fc184984a0 | ||
|
|
2178ff1c48 | ||
|
|
ae1df38c88 | ||
|
|
162e498347 | ||
|
|
172023afca | ||
|
|
18c7ea50b4 | ||
|
|
bdddb238f8 | ||
|
|
8d46237935 | ||
|
|
3fcf83e685 | ||
|
|
d374af4341 | ||
|
|
f32ad617a2 | ||
|
|
62656b24eb | ||
|
|
12763e19d8 | ||
|
|
89fd726e07 | ||
|
|
0b428987b1 | ||
|
|
1e29fad5f0 | ||
|
|
19524a4459 | ||
|
|
7043d565c9 | ||
|
|
d6f856f2f2 | ||
|
|
24f0451c10 | ||
|
|
3c4460ca98 | ||
|
|
cbf33fa14b | ||
|
|
d782654819 | ||
|
|
3c39cbf333 | ||
|
|
bd746e5151 | ||
|
|
b32c346eed | ||
|
|
77b8e204ad | ||
|
|
93dfe19c35 | ||
|
|
6dc8df5178 | ||
|
|
237fd73702 | ||
|
|
5f2d0142d1 | ||
|
|
572d576d5b | ||
|
|
6606f51636 | ||
|
|
36da65120a | ||
|
|
b6c1e1a609 | ||
|
|
5d003ec772 | ||
|
|
b9210a2ba4 | ||
|
|
f3c559ea13 | ||
|
|
6cee6b6429 | ||
|
|
84f6aabf5b | ||
|
|
9ce947d6ea | ||
|
|
0f23ad0d7e | ||
|
|
1b760b6c53 | ||
|
|
cdf64bf016 |
@@ -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:
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
@@ -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`
|
||||
================================== =======================
|
||||
@@ -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]
|
||||
----------------------
|
||||
|
||||
|
||||
@@ -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)
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
133
docs/index.rst
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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::
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
25
glfw/wl_client_side_decorations.c
vendored
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
1
glfw/wl_client_side_decorations.h
vendored
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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])]
|
||||
|
||||
@@ -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) { \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
30
kitty/keys.c
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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']))
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
161
kitty/uthash.h
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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 |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 677 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 52 KiB |
12
logo/make.py
@@ -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):
|
||||
|
||||
26
setup.py
@@ -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
|
||||
# }}}
|
||||
|
||||
|
||||