Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79b130ed23 | ||
|
|
75e8b16ea3 | ||
|
|
1b35708d89 | ||
|
|
ebff343a55 | ||
|
|
c7b91e5f19 | ||
|
|
b9d52dfaf7 | ||
|
|
2c8f66586f | ||
|
|
219bf564f7 | ||
|
|
291be6f5a6 | ||
|
|
1da2344aa3 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -22,7 +22,7 @@ If applicable, add screenshots to help explain your problem.
|
|||||||
|
|
||||||
**Environment details**
|
**Environment details**
|
||||||
```
|
```
|
||||||
Press Ctrl+Shift+F6 in kitty, to copy debug output about kitty and its
|
Press Ctrl+Shift+F6 (cmd+option+, on macOS) in kitty, to copy debug output about kitty and its
|
||||||
configuration to the clipboard and paste it here.
|
configuration to the clipboard and paste it here.
|
||||||
|
|
||||||
On older versions of kitty, run kitty --debug-config instead
|
On older versions of kitty, run kitty --debug-config instead
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ Toggle maximized :sc:`toggle_maximized`
|
|||||||
Input unicode character :sc:`input_unicode_character` (also :kbd:`^+⌘+space` on macOS)
|
Input unicode character :sc:`input_unicode_character` (also :kbd:`^+⌘+space` on macOS)
|
||||||
Click URL using the keyboard :sc:`open_url`
|
Click URL using the keyboard :sc:`open_url`
|
||||||
Reset the terminal :sc:`reset_terminal`
|
Reset the terminal :sc:`reset_terminal`
|
||||||
Reload :file:`kitty.conf` :sc:`reload_config_file`
|
Reload :file:`kitty.conf` :sc:`reload_config_file` (also :kbd:`^+⌘+f5` on macOS)
|
||||||
Debug :file:`kitty.conf` :sc:`debug_config`
|
Debug :file:`kitty.conf` :sc:`debug_config` (also :kbd:`⌘+option+f6` on macOS)
|
||||||
Pass current selection to program :sc:`pass_selection_to_program`
|
Pass current selection to program :sc:`pass_selection_to_program`
|
||||||
Edit |kitty| config file :sc:`edit_config_file`
|
Edit |kitty| config file :sc:`edit_config_file`
|
||||||
Open a |kitty| shell :sc:`kitty_shell`
|
Open a |kitty| shell :sc:`kitty_shell`
|
||||||
|
|||||||
@@ -4,6 +4,19 @@ Changelog
|
|||||||
|kitty| is a feature-rich, cross-platform, *fast*, GPU based terminal.
|
|kitty| is a feature-rich, cross-platform, *fast*, GPU based terminal.
|
||||||
To update |kitty|, :doc:`follow the instructions <binary>`.
|
To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||||
|
|
||||||
|
0.21.1 [2021-06-14]
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
- macOS: Fix a regression in the previous release that broke rendering of
|
||||||
|
strikeout (:iss:`3717`)
|
||||||
|
|
||||||
|
- macOS: Fix a crash when rendering ligatures larger than 128 characters
|
||||||
|
(:iss:`3724`)
|
||||||
|
|
||||||
|
- Fix a regression in the previous release that could cause a crash when
|
||||||
|
changing layouts and mousing (:iss:`3713`)
|
||||||
|
|
||||||
|
|
||||||
0.21.0 [2021-06-12]
|
0.21.0 [2021-06-12]
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ static char* getDisplayName(CGDirectDisplayID displayID)
|
|||||||
io_service_t service;
|
io_service_t service;
|
||||||
CFDictionaryRef info;
|
CFDictionaryRef info;
|
||||||
|
|
||||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
if (IOServiceGetMatchingServices(kIOMainPortDefault,
|
||||||
IOServiceMatching("IODisplayConnect"),
|
IOServiceMatching("IODisplayConnect"),
|
||||||
&it) != 0)
|
&it) != 0)
|
||||||
{
|
{
|
||||||
@@ -245,7 +245,7 @@ static double getFallbackRefreshRate(CGDirectDisplayID displayID)
|
|||||||
io_iterator_t it;
|
io_iterator_t it;
|
||||||
io_service_t service;
|
io_service_t service;
|
||||||
|
|
||||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
if (IOServiceGetMatchingServices(kIOMainPortDefault,
|
||||||
IOServiceMatching("IOFramebuffer"),
|
IOServiceMatching("IOFramebuffer"),
|
||||||
&it) != 0)
|
&it) != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
3
glfw/cocoa_platform.h
vendored
3
glfw/cocoa_platform.h
vendored
@@ -39,6 +39,9 @@ typedef void* CVDisplayLinkRef;
|
|||||||
// NOTE: Many Cocoa enum values have been renamed and we need to build across
|
// NOTE: Many Cocoa enum values have been renamed and we need to build across
|
||||||
// SDK versions where one is unavailable or the other deprecated
|
// SDK versions where one is unavailable or the other deprecated
|
||||||
// We use the newer names in code and these macros to handle compatibility
|
// We use the newer names in code and these macros to handle compatibility
|
||||||
|
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 120000) // Before macOS 12 Monterey
|
||||||
|
#define kIOMainPortDefault kIOMasterPortDefault
|
||||||
|
#endif
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||||
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
||||||
#define NSEventMaskAny NSAnyEventMask
|
#define NSEventMaskAny NSAnyEventMask
|
||||||
|
|||||||
@@ -944,7 +944,8 @@ process_pending_closes(ChildMonitor *self) {
|
|||||||
// If we create new OS windows during wait_events(), using global menu actions
|
// If we create new OS windows during wait_events(), using global menu actions
|
||||||
// via the mouse causes a crash because of the way autorelease pools work in
|
// via the mouse causes a crash because of the way autorelease pools work in
|
||||||
// glfw/cocoa. So we use a flag instead.
|
// glfw/cocoa. So we use a flag instead.
|
||||||
static CocoaPendingAction cocoa_pending_actions = NO_COCOA_PENDING_ACTION;
|
static bool cocoa_pending_actions[NUM_COCOA_PENDING_ACTIONS] = {0};
|
||||||
|
static bool has_cocoa_pending_actions = false;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* wd;
|
char* wd;
|
||||||
char **open_files;
|
char **open_files;
|
||||||
@@ -964,7 +965,8 @@ set_cocoa_pending_action(CocoaPendingAction action, const char *wd) {
|
|||||||
cocoa_pending_actions_data.wd = strdup(wd);
|
cocoa_pending_actions_data.wd = strdup(wd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cocoa_pending_actions |= action;
|
cocoa_pending_actions[action] = true;
|
||||||
|
has_cocoa_pending_actions = true;
|
||||||
// The main loop may be blocking on the event queue, if e.g. unfocused.
|
// The main loop may be blocking on the event queue, if e.g. unfocused.
|
||||||
// Unjam it so the pending action is processed right now.
|
// Unjam it so the pending action is processed right now.
|
||||||
wakeup_main_loop();
|
wakeup_main_loop();
|
||||||
@@ -997,21 +999,22 @@ process_global_state(void *data) {
|
|||||||
if (parse_input(self)) input_read = true;
|
if (parse_input(self)) input_read = true;
|
||||||
render(now, input_read);
|
render(now, input_read);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (cocoa_pending_actions) {
|
if (has_cocoa_pending_actions) {
|
||||||
if (cocoa_pending_actions & PREFERENCES_WINDOW) { call_boss(edit_config_file, NULL); }
|
if (cocoa_pending_actions[PREFERENCES_WINDOW]) { call_boss(edit_config_file, NULL); }
|
||||||
if (cocoa_pending_actions & NEW_OS_WINDOW) { call_boss(new_os_window, NULL); }
|
if (cocoa_pending_actions[NEW_OS_WINDOW]) { call_boss(new_os_window, NULL); }
|
||||||
if (cocoa_pending_actions & CLOSE_OS_WINDOW) { call_boss(close_os_window, NULL); }
|
if (cocoa_pending_actions[CLOSE_OS_WINDOW]) { call_boss(close_os_window, NULL); }
|
||||||
if (cocoa_pending_actions & CLOSE_TAB) { call_boss(close_tab, NULL); }
|
if (cocoa_pending_actions[CLOSE_TAB]) { call_boss(close_tab, NULL); }
|
||||||
if (cocoa_pending_actions & NEW_TAB) { call_boss(new_tab, NULL); }
|
if (cocoa_pending_actions[NEW_TAB]) { call_boss(new_tab, NULL); }
|
||||||
if (cocoa_pending_actions & NEXT_TAB) { call_boss(next_tab, NULL); }
|
if (cocoa_pending_actions[NEXT_TAB]) { call_boss(next_tab, NULL); }
|
||||||
if (cocoa_pending_actions & PREVIOUS_TAB) { call_boss(previous_tab, NULL); }
|
if (cocoa_pending_actions[PREVIOUS_TAB]) { call_boss(previous_tab, NULL); }
|
||||||
if (cocoa_pending_actions & DETACH_TAB) { call_boss(detach_tab, NULL); }
|
if (cocoa_pending_actions[DETACH_TAB]) { call_boss(detach_tab, NULL); }
|
||||||
if (cocoa_pending_actions & NEW_WINDOW) { call_boss(new_window, NULL); }
|
if (cocoa_pending_actions[NEW_WINDOW]) { call_boss(new_window, NULL); }
|
||||||
if (cocoa_pending_actions & CLOSE_WINDOW) { call_boss(close_window, NULL); }
|
if (cocoa_pending_actions[CLOSE_WINDOW]) { call_boss(close_window, NULL); }
|
||||||
if (cocoa_pending_actions & RESET_TERMINAL) { call_boss(clear_terminal, "sO", "reset", Py_True ); }
|
if (cocoa_pending_actions[RESET_TERMINAL]) { call_boss(clear_terminal, "sO", "reset", Py_True ); }
|
||||||
|
if (cocoa_pending_actions[RELOAD_CONFIG]) { call_boss(load_config_file, NULL); }
|
||||||
if (cocoa_pending_actions_data.wd) {
|
if (cocoa_pending_actions_data.wd) {
|
||||||
if (cocoa_pending_actions & NEW_OS_WINDOW_WITH_WD) { call_boss(new_os_window_with_wd, "s", cocoa_pending_actions_data.wd); }
|
if (cocoa_pending_actions[NEW_OS_WINDOW_WITH_WD]) { call_boss(new_os_window_with_wd, "s", cocoa_pending_actions_data.wd); }
|
||||||
if (cocoa_pending_actions & NEW_TAB_WITH_WD) { call_boss(new_tab_with_wd, "s", cocoa_pending_actions_data.wd); }
|
if (cocoa_pending_actions[NEW_TAB_WITH_WD]) { call_boss(new_tab_with_wd, "s", cocoa_pending_actions_data.wd); }
|
||||||
free(cocoa_pending_actions_data.wd);
|
free(cocoa_pending_actions_data.wd);
|
||||||
cocoa_pending_actions_data.wd = NULL;
|
cocoa_pending_actions_data.wd = NULL;
|
||||||
}
|
}
|
||||||
@@ -1025,7 +1028,8 @@ process_global_state(void *data) {
|
|||||||
}
|
}
|
||||||
cocoa_pending_actions_data.open_files_count = 0;
|
cocoa_pending_actions_data.open_files_count = 0;
|
||||||
}
|
}
|
||||||
cocoa_pending_actions = 0;
|
memset(cocoa_pending_actions, 0, sizeof(cocoa_pending_actions));
|
||||||
|
has_cocoa_pending_actions = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
report_reaped_pids();
|
report_reaped_pids();
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ PENDING(previous_tab, PREVIOUS_TAB)
|
|||||||
PENDING(new_window, NEW_WINDOW)
|
PENDING(new_window, NEW_WINDOW)
|
||||||
PENDING(close_window, CLOSE_WINDOW)
|
PENDING(close_window, CLOSE_WINDOW)
|
||||||
PENDING(reset_terminal, RESET_TERMINAL)
|
PENDING(reset_terminal, RESET_TERMINAL)
|
||||||
|
PENDING(reload_config, RELOAD_CONFIG)
|
||||||
|
|
||||||
- (void)open_kitty_website_url:(id)sender {
|
- (void)open_kitty_website_url:(id)sender {
|
||||||
(void)sender;
|
(void)sender;
|
||||||
@@ -117,7 +118,7 @@ typedef struct {
|
|||||||
NSEventModifierFlags mods;
|
NSEventModifierFlags mods;
|
||||||
} GlobalShortcut;
|
} GlobalShortcut;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GlobalShortcut new_os_window, close_os_window, close_tab, edit_config_file;
|
GlobalShortcut new_os_window, close_os_window, close_tab, edit_config_file, reload_config;
|
||||||
GlobalShortcut previous_tab, next_tab, new_tab, new_window, close_window, reset_terminal;
|
GlobalShortcut previous_tab, next_tab, new_tab, new_window, close_window, reset_terminal;
|
||||||
} GlobalShortcuts;
|
} GlobalShortcuts;
|
||||||
static GlobalShortcuts global_shortcuts;
|
static GlobalShortcuts global_shortcuts;
|
||||||
@@ -132,7 +133,7 @@ cocoa_set_global_shortcut(PyObject *self UNUSED, PyObject *args) {
|
|||||||
#define Q(x) if (strcmp(name, #x) == 0) gs = &global_shortcuts.x
|
#define Q(x) if (strcmp(name, #x) == 0) gs = &global_shortcuts.x
|
||||||
Q(new_os_window); else Q(close_os_window); else Q(close_tab); else Q(edit_config_file);
|
Q(new_os_window); else Q(close_os_window); else Q(close_tab); else Q(edit_config_file);
|
||||||
else Q(new_tab); else Q(next_tab); else Q(previous_tab);
|
else Q(new_tab); else Q(next_tab); else Q(previous_tab);
|
||||||
else Q(new_window); else Q(close_window); else Q(reset_terminal);
|
else Q(new_window); else Q(close_window); else Q(reset_terminal); else Q(reload_config);
|
||||||
#undef Q
|
#undef Q
|
||||||
if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; }
|
if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; }
|
||||||
int cocoa_mods;
|
int cocoa_mods;
|
||||||
@@ -380,6 +381,7 @@ cocoa_create_global_menu(void) {
|
|||||||
keyEquivalent:@""];
|
keyEquivalent:@""];
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
MENU_ITEM(appMenu, @"Preferences…", edit_config_file);
|
MENU_ITEM(appMenu, @"Preferences…", edit_config_file);
|
||||||
|
MENU_ITEM(appMenu, @"Reload preferences", reload_config);
|
||||||
|
|
||||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", app_name]
|
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", app_name]
|
||||||
action:@selector(hide:)
|
action:@selector(hide:)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Version(NamedTuple):
|
|||||||
|
|
||||||
appname: str = 'kitty'
|
appname: str = 'kitty'
|
||||||
kitty_face = '🐱'
|
kitty_face = '🐱'
|
||||||
version: Version = Version(0, 21, 0)
|
version: Version = Version(0, 21, 1)
|
||||||
str_version: str = '.'.join(map(str, version))
|
str_version: str = '.'.join(map(str, version))
|
||||||
_plat = sys.platform.lower()
|
_plat = sys.platform.lower()
|
||||||
is_macos: bool = 'darwin' in _plat
|
is_macos: bool = 'darwin' in _plat
|
||||||
|
|||||||
@@ -342,7 +342,6 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
|||||||
}
|
}
|
||||||
*cell_width = MAX(1u, width);
|
*cell_width = MAX(1u, width);
|
||||||
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
||||||
*strikethrough_position = (unsigned int)floor(*baseline * 0.65);
|
|
||||||
*strikethrough_thickness = *underline_thickness;
|
*strikethrough_thickness = *underline_thickness;
|
||||||
// float line_height = MAX(1, floor(self->ascent + self->descent + MAX(0, self->leading) + 0.5));
|
// float line_height = MAX(1, floor(self->ascent + self->descent + MAX(0, self->leading) + 0.5));
|
||||||
// Let CoreText's layout engine calculate the line height. Slower, but hopefully more accurate.
|
// Let CoreText's layout engine calculate the line height. Slower, but hopefully more accurate.
|
||||||
@@ -373,6 +372,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
|||||||
// Not sure if we should add this to bounds ascent and then round it or add
|
// Not sure if we should add this to bounds ascent and then round it or add
|
||||||
// it to already rounded baseline and round again.
|
// it to already rounded baseline and round again.
|
||||||
*underline_position = (unsigned int)floor(bounds_ascent - self->underline_position + 0.5);
|
*underline_position = (unsigned int)floor(bounds_ascent - self->underline_position + 0.5);
|
||||||
|
*strikethrough_position = (unsigned int)floor(*baseline * 0.65);
|
||||||
|
|
||||||
debug("Cell height calculation:\n");
|
debug("Cell height calculation:\n");
|
||||||
debug("\tline height from line origins: %f\n", line_height);
|
debug("\tline height from line origins: %f\n", line_height);
|
||||||
@@ -381,7 +381,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
|||||||
debug("\tbounds metrics: ascent: %f\n", bounds_ascent);
|
debug("\tbounds metrics: ascent: %f\n", bounds_ascent);
|
||||||
debug("\tline metrics: ascent: %f descent: %f leading: %f\n", typographic_ascent, typographic_descent, typographic_leading);
|
debug("\tline metrics: ascent: %f descent: %f leading: %f\n", typographic_ascent, typographic_descent, typographic_leading);
|
||||||
debug("\tfont metrics: ascent: %f descent: %f leading: %f underline_position: %f\n", self->ascent, self->descent, self->leading, self->underline_position);
|
debug("\tfont metrics: ascent: %f descent: %f leading: %f underline_position: %f\n", self->ascent, self->descent, self->leading, self->underline_position);
|
||||||
debug("\tcell_height: %u baseline: %u underline_position: %u\n", *cell_height, *baseline, *underline_position);
|
debug("\tcell_height: %u baseline: %u underline_position: %u strikethrough_position: %u\n", *cell_height, *baseline, *underline_position, *strikethrough_position);
|
||||||
|
|
||||||
CFRelease(test_frame); CFRelease(path); CFRelease(framesetter);
|
CFRelease(test_frame); CFRelease(path); CFRelease(framesetter);
|
||||||
|
|
||||||
@@ -415,16 +415,20 @@ specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE fg UNUSE
|
|||||||
return base_descriptor;
|
return base_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t *render_buf = NULL;
|
struct RenderBuffers {
|
||||||
static size_t render_buf_sz = 0;
|
uint8_t *render_buf;
|
||||||
static CGGlyph glyphs[128];
|
size_t render_buf_sz, sz;
|
||||||
static CGRect boxes[128];
|
CGGlyph *glyphs;
|
||||||
static CGPoint positions[128];
|
CGRect *boxes;
|
||||||
static CGSize advances[128];
|
CGPoint *positions;
|
||||||
|
CGSize *advances;
|
||||||
|
};
|
||||||
|
static struct RenderBuffers buffers = {0};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
finalize(void) {
|
finalize(void) {
|
||||||
free(render_buf);
|
free(buffers.render_buf); free(buffers.glyphs); free(buffers.boxes); free(buffers.positions); free(buffers.advances);
|
||||||
|
memset(&buffers, 0, sizeof(struct RenderBuffers));
|
||||||
if (all_fonts_collection_data) CFRelease(all_fonts_collection_data);
|
if (all_fonts_collection_data) CFRelease(all_fonts_collection_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,7 +446,7 @@ render_color_glyph(CTFontRef font, uint8_t *buf, int glyph_id, unsigned int widt
|
|||||||
CGContextSetTextDrawingMode(ctx, kCGTextFill);
|
CGContextSetTextDrawingMode(ctx, kCGTextFill);
|
||||||
CGGlyph glyph = glyph_id;
|
CGGlyph glyph = glyph_id;
|
||||||
CGContextSetTextMatrix(ctx, transform);
|
CGContextSetTextMatrix(ctx, transform);
|
||||||
CGContextSetTextPosition(ctx, -boxes[0].origin.x, MAX(2, height - baseline));
|
CGContextSetTextPosition(ctx, -buffers.boxes[0].origin.x, MAX(2, height - baseline));
|
||||||
CGPoint p = CGPointMake(0, 0);
|
CGPoint p = CGPointMake(0, 0);
|
||||||
CTFontDrawGlyphs(font, &glyph, &p, 1, ctx);
|
CTFontDrawGlyphs(font, &glyph, &p, 1, ctx);
|
||||||
CGContextRelease(ctx);
|
CGContextRelease(ctx);
|
||||||
@@ -455,21 +459,30 @@ render_color_glyph(CTFontRef font, uint8_t *buf, int glyph_id, unsigned int widt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
ensure_render_space(size_t width, size_t height) {
|
ensure_render_space(size_t width, size_t height, size_t num_glyphs) {
|
||||||
if (render_buf_sz >= width * height) return;
|
if (buffers.render_buf_sz < width * height) {
|
||||||
free(render_buf);
|
free(buffers.render_buf); buffers.render_buf = NULL;
|
||||||
render_buf_sz = width * height;
|
buffers.render_buf_sz = width * height;
|
||||||
render_buf = malloc(render_buf_sz);
|
buffers.render_buf = malloc(buffers.render_buf_sz);
|
||||||
if (render_buf == NULL) fatal("Out of memory");
|
if (buffers.render_buf == NULL) fatal("Out of memory");
|
||||||
|
}
|
||||||
|
if (buffers.sz < num_glyphs) {
|
||||||
|
buffers.sz = MAX(128, num_glyphs * 2);
|
||||||
|
buffers.advances = calloc(sizeof(buffers.advances[0]), buffers.sz);
|
||||||
|
buffers.boxes = calloc(sizeof(buffers.boxes[0]), buffers.sz);
|
||||||
|
buffers.glyphs = calloc(sizeof(buffers.glyphs[0]), buffers.sz);
|
||||||
|
buffers.positions = calloc(sizeof(buffers.positions[0]), buffers.sz);
|
||||||
|
if (!buffers.advances || !buffers.boxes || !buffers.glyphs || !buffers.positions) fatal("Out of memory");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
render_glyphs(CTFontRef font, unsigned int width, unsigned int height, unsigned int baseline, unsigned int num_glyphs) {
|
render_glyphs(CTFontRef font, unsigned int width, unsigned int height, unsigned int baseline, unsigned int num_glyphs) {
|
||||||
memset(render_buf, 0, width * height);
|
memset(buffers.render_buf, 0, width * height);
|
||||||
CGColorSpaceRef gray_color_space = CGColorSpaceCreateDeviceGray();
|
CGColorSpaceRef gray_color_space = CGColorSpaceCreateDeviceGray();
|
||||||
if (gray_color_space == NULL) fatal("Out of memory");
|
if (gray_color_space == NULL) fatal("Out of memory");
|
||||||
CGContextRef render_ctx = CGBitmapContextCreate(render_buf, width, height, 8, width, gray_color_space, (kCGBitmapAlphaInfoMask & kCGImageAlphaNone));
|
CGContextRef render_ctx = CGBitmapContextCreate(buffers.render_buf, width, height, 8, width, gray_color_space, (kCGBitmapAlphaInfoMask & kCGImageAlphaNone));
|
||||||
if (render_ctx == NULL) fatal("Out of memory");
|
if (render_ctx == NULL) fatal("Out of memory");
|
||||||
CGContextSetShouldAntialias(render_ctx, true);
|
CGContextSetShouldAntialias(render_ctx, true);
|
||||||
CGContextSetShouldSmoothFonts(render_ctx, true);
|
CGContextSetShouldSmoothFonts(render_ctx, true);
|
||||||
@@ -479,7 +492,7 @@ render_glyphs(CTFontRef font, unsigned int width, unsigned int height, unsigned
|
|||||||
CGContextSetTextDrawingMode(render_ctx, kCGTextFillStroke);
|
CGContextSetTextDrawingMode(render_ctx, kCGTextFillStroke);
|
||||||
CGContextSetTextMatrix(render_ctx, CGAffineTransformIdentity);
|
CGContextSetTextMatrix(render_ctx, CGAffineTransformIdentity);
|
||||||
CGContextSetTextPosition(render_ctx, 0, height - baseline);
|
CGContextSetTextPosition(render_ctx, 0, height - baseline);
|
||||||
CTFontDrawGlyphs(font, glyphs, positions, num_glyphs, render_ctx);
|
CTFontDrawGlyphs(font, buffers.glyphs, buffers.positions, num_glyphs, render_ctx);
|
||||||
CGContextRelease(render_ctx);
|
CGContextRelease(render_ctx);
|
||||||
CGColorSpaceRelease(gray_color_space);
|
CGColorSpaceRelease(gray_color_space);
|
||||||
}
|
}
|
||||||
@@ -492,19 +505,20 @@ render_simple_text_impl(PyObject *s, const char *text, unsigned int baseline) {
|
|||||||
unichar chars[num_chars];
|
unichar chars[num_chars];
|
||||||
CGSize local_advances[num_chars];
|
CGSize local_advances[num_chars];
|
||||||
for (size_t i = 0; i < num_chars; i++) chars[i] = text[i];
|
for (size_t i = 0; i < num_chars; i++) chars[i] = text[i];
|
||||||
CTFontGetGlyphsForCharacters(font, chars, glyphs, num_chars);
|
ensure_render_space(0, 0, num_chars);
|
||||||
CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, glyphs, local_advances, num_chars);
|
CTFontGetGlyphsForCharacters(font, chars, buffers.glyphs, num_chars);
|
||||||
CGRect bounding_box = CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationDefault, glyphs, boxes, num_chars);
|
CTFontGetAdvancesForGlyphs(font, kCTFontOrientationDefault, buffers.glyphs, local_advances, num_chars);
|
||||||
|
CGRect bounding_box = CTFontGetBoundingRectsForGlyphs(font, kCTFontOrientationDefault, buffers.glyphs, buffers.boxes, num_chars);
|
||||||
CGFloat x = 0, y = 0;
|
CGFloat x = 0, y = 0;
|
||||||
for (size_t i = 0; i < num_chars; i++) {
|
for (size_t i = 0; i < num_chars; i++) {
|
||||||
positions[i] = CGPointMake(x, y);
|
buffers.positions[i] = CGPointMake(x, y);
|
||||||
x += local_advances[i].width; y += local_advances[i].height;
|
x += local_advances[i].width; y += local_advances[i].height;
|
||||||
}
|
}
|
||||||
StringCanvas ans = { .width = (size_t)ceil(x), .height = (size_t)(2 * bounding_box.size.height) };
|
StringCanvas ans = { .width = (size_t)ceil(x), .height = (size_t)(2 * bounding_box.size.height) };
|
||||||
ensure_render_space(ans.width, ans.height);
|
ensure_render_space(ans.width, ans.height, num_chars);
|
||||||
render_glyphs(font, ans.width, ans.height, baseline, num_chars);
|
render_glyphs(font, ans.width, ans.height, baseline, num_chars);
|
||||||
ans.canvas = malloc(ans.width * ans.height);
|
ans.canvas = malloc(ans.width * ans.height);
|
||||||
if (ans.canvas) memcpy(ans.canvas, render_buf, ans.width * ans.height);
|
if (ans.canvas) memcpy(ans.canvas, buffers.render_buf, ans.width * ans.height);
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,12 +526,13 @@ render_simple_text_impl(PyObject *s, const char *text, unsigned int baseline) {
|
|||||||
static inline bool
|
static inline bool
|
||||||
do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, bool allow_resize, FONTS_DATA_HANDLE fg, bool center_glyph) {
|
do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, bool allow_resize, FONTS_DATA_HANDLE fg, bool center_glyph) {
|
||||||
unsigned int canvas_width = cell_width * num_cells;
|
unsigned int canvas_width = cell_width * num_cells;
|
||||||
CGRect br = CTFontGetBoundingRectsForGlyphs(ct_font, kCTFontOrientationHorizontal, glyphs, boxes, num_glyphs);
|
ensure_render_space(canvas_width, cell_height, num_glyphs);
|
||||||
|
CGRect br = CTFontGetBoundingRectsForGlyphs(ct_font, kCTFontOrientationHorizontal, buffers.glyphs, buffers.boxes, num_glyphs);
|
||||||
const bool debug_rendering = false;
|
const bool debug_rendering = false;
|
||||||
if (allow_resize) {
|
if (allow_resize) {
|
||||||
// Resize glyphs that would bleed into neighboring cells, by scaling the font size
|
// Resize glyphs that would bleed into neighboring cells, by scaling the font size
|
||||||
float right = 0;
|
float right = 0;
|
||||||
for (unsigned i=0; i < num_glyphs; i++) right = MAX(right, boxes[i].origin.x + boxes[i].size.width);
|
for (unsigned i=0; i < num_glyphs; i++) right = MAX(right, buffers.boxes[i].origin.x + buffers.boxes[i].size.width);
|
||||||
if (!bold && !italic && right > canvas_width + 1) {
|
if (!bold && !italic && right > canvas_width + 1) {
|
||||||
if (debug_rendering) printf("resizing glyphs, right: %f canvas_width: %u\n", right, canvas_width);
|
if (debug_rendering) printf("resizing glyphs, right: %f canvas_width: %u\n", right, canvas_width);
|
||||||
CGFloat sz = CTFontGetSize(ct_font);
|
CGFloat sz = CTFontGetSize(ct_font);
|
||||||
@@ -529,19 +544,18 @@ do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_g
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CGFloat x = 0, y = 0;
|
CGFloat x = 0, y = 0;
|
||||||
CTFontGetAdvancesForGlyphs(ct_font, kCTFontOrientationDefault, glyphs, advances, num_glyphs);
|
CTFontGetAdvancesForGlyphs(ct_font, kCTFontOrientationDefault, buffers.glyphs, buffers.advances, num_glyphs);
|
||||||
for (unsigned i=0; i < num_glyphs; i++) {
|
for (unsigned i=0; i < num_glyphs; i++) {
|
||||||
positions[i].x = x; positions[i].y = y;
|
buffers.positions[i].x = x; buffers.positions[i].y = y;
|
||||||
if (debug_rendering) printf("x=%f origin=%f width=%f advance=%f\n", x, boxes[i].origin.x, boxes[i].size.width, advances[i].width);
|
if (debug_rendering) printf("x=%f origin=%f width=%f advance=%f\n", x, buffers.boxes[i].origin.x, buffers.boxes[i].size.width, buffers.advances[i].width);
|
||||||
x += advances[i].width; y += advances[i].height;
|
x += buffers.advances[i].width; y += buffers.advances[i].height;
|
||||||
}
|
}
|
||||||
if (*was_colored) {
|
if (*was_colored) {
|
||||||
render_color_glyph(ct_font, (uint8_t*)canvas, info[0].codepoint, cell_width * num_cells, cell_height, baseline);
|
render_color_glyph(ct_font, (uint8_t*)canvas, info[0].codepoint, cell_width * num_cells, cell_height, baseline);
|
||||||
} else {
|
} else {
|
||||||
ensure_render_space(canvas_width, cell_height);
|
|
||||||
render_glyphs(ct_font, canvas_width, cell_height, baseline, num_glyphs);
|
render_glyphs(ct_font, canvas_width, cell_height, baseline, num_glyphs);
|
||||||
Region src = {.bottom=cell_height, .right=canvas_width}, dest = {.bottom=cell_height, .right=canvas_width};
|
Region src = {.bottom=cell_height, .right=canvas_width}, dest = {.bottom=cell_height, .right=canvas_width};
|
||||||
render_alpha_mask(render_buf, canvas, &src, &dest, canvas_width, canvas_width);
|
render_alpha_mask(buffers.render_buf, canvas, &src, &dest, canvas_width, canvas_width);
|
||||||
}
|
}
|
||||||
if (num_cells && (center_glyph || (num_cells == 2 && *was_colored))) {
|
if (num_cells && (center_glyph || (num_cells == 2 && *was_colored))) {
|
||||||
if (debug_rendering) printf("centering glyphs: center_glyph: %d\n", center_glyph);
|
if (debug_rendering) printf("centering glyphs: center_glyph: %d\n", center_glyph);
|
||||||
@@ -557,7 +571,8 @@ do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_g
|
|||||||
bool
|
bool
|
||||||
render_glyphs_in_cells(PyObject *s, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE fg, bool center_glyph) {
|
render_glyphs_in_cells(PyObject *s, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE fg, bool center_glyph) {
|
||||||
CTFace *self = (CTFace*)s;
|
CTFace *self = (CTFace*)s;
|
||||||
for (unsigned i=0; i < num_glyphs; i++) glyphs[i] = info[i].codepoint;
|
ensure_render_space(128, 128, num_glyphs);
|
||||||
|
for (unsigned i=0; i < num_glyphs; i++) buffers.glyphs[i] = info[i].codepoint;
|
||||||
return do_render(self->ct_font, bold, italic, info, hb_positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, was_colored, true, fg, center_glyph);
|
return do_render(self->ct_font, bold, italic, info, hb_positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, was_colored, true, fg, center_glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -560,10 +560,10 @@ END_ALLOW_CASE_RANGE
|
|||||||
static PyObject* box_drawing_function = NULL, *prerender_function = NULL, *descriptor_for_idx = NULL;
|
static PyObject* box_drawing_function = NULL, *prerender_function = NULL, *descriptor_for_idx = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
render_alpha_mask(uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *dest_rect, size_t src_stride, size_t dest_stride) {
|
render_alpha_mask(const uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *dest_rect, size_t src_stride, size_t dest_stride) {
|
||||||
for (size_t sr = src_rect->top, dr = dest_rect->top; sr < src_rect->bottom && dr < dest_rect->bottom; sr++, dr++) {
|
for (size_t sr = src_rect->top, dr = dest_rect->top; sr < src_rect->bottom && dr < dest_rect->bottom; sr++, dr++) {
|
||||||
pixel *d = dest + dest_stride * dr;
|
pixel *d = dest + dest_stride * dr;
|
||||||
uint8_t *s = alpha_mask + src_stride * sr;
|
const uint8_t *s = alpha_mask + src_stride * sr;
|
||||||
for(size_t sc = src_rect->left, dc = dest_rect->left; sc < src_rect->right && dc < dest_rect->right; sc++, dc++) {
|
for(size_t sc = src_rect->left, dc = dest_rect->left; sc < src_rect->right && dc < dest_rect->right; sc++, dc++) {
|
||||||
uint8_t src_alpha = d[dc] & 0xff;
|
uint8_t src_alpha = d[dc] & 0xff;
|
||||||
uint8_t alpha = s[sc];
|
uint8_t alpha = s[sc];
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ PyObject* face_from_descriptor(PyObject*, FONTS_DATA_HANDLE);
|
|||||||
const char* postscript_name_for_face(const PyObject*);
|
const char* postscript_name_for_face(const PyObject*);
|
||||||
|
|
||||||
void sprite_tracker_current_layout(FONTS_DATA_HANDLE data, unsigned int *x, unsigned int *y, unsigned int *z);
|
void sprite_tracker_current_layout(FONTS_DATA_HANDLE data, unsigned int *x, unsigned int *y, unsigned int *z);
|
||||||
void render_alpha_mask(uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *dest_rect, size_t src_stride, size_t dest_stride);
|
void render_alpha_mask(const uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *dest_rect, size_t src_stride, size_t dest_stride);
|
||||||
void render_line(FONTS_DATA_HANDLE, Line *line, index_type lnum, Cursor *cursor, DisableLigature);
|
void render_line(FONTS_DATA_HANDLE, Line *line, index_type lnum, Cursor *cursor, DisableLigature);
|
||||||
void sprite_tracker_set_limits(size_t max_texture_size, size_t max_array_len);
|
void sprite_tracker_set_limits(size_t max_texture_size, size_t max_array_len);
|
||||||
typedef void (*free_extra_data_func)(void*);
|
typedef void (*free_extra_data_func)(void*);
|
||||||
|
|||||||
@@ -143,6 +143,9 @@ def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ())
|
|||||||
val = get_macos_shortcut_for(opts, 'clear_terminal', args=('reset', True), lookup_name='reset_terminal')
|
val = get_macos_shortcut_for(opts, 'clear_terminal', args=('reset', True), lookup_name='reset_terminal')
|
||||||
if val is not None:
|
if val is not None:
|
||||||
global_shortcuts['reset_terminal'] = val
|
global_shortcuts['reset_terminal'] = val
|
||||||
|
val = get_macos_shortcut_for(opts, 'load_config_file', args=(), lookup_name='reload_config')
|
||||||
|
if val is not None:
|
||||||
|
global_shortcuts['reload_config'] = val
|
||||||
if is_macos and opts.macos_custom_beam_cursor:
|
if is_macos and opts.macos_custom_beam_cursor:
|
||||||
set_custom_ibeam_cursor()
|
set_custom_ibeam_cursor()
|
||||||
if not is_wayland() and not is_macos: # no window icons on wayland
|
if not is_wayland() and not is_macos: # no window icons on wayland
|
||||||
|
|||||||
@@ -3329,6 +3329,11 @@ the new conf settings *replace* the old ones.
|
|||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
map('Reload kitty.conf',
|
||||||
|
'reload_config_file cmd+control+, load_config_file',
|
||||||
|
only='macos'
|
||||||
|
)
|
||||||
|
|
||||||
map('Debug kitty configuration',
|
map('Debug kitty configuration',
|
||||||
'debug_config kitty_mod+f6 debug_config',
|
'debug_config kitty_mod+f6 debug_config',
|
||||||
long_text='''
|
long_text='''
|
||||||
@@ -3337,6 +3342,12 @@ its host environment. Useful for debugging issues.
|
|||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
map('Debug kitty configuration',
|
||||||
|
'debug_config cmd+option+, debug_config',
|
||||||
|
only='macos'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
map('Send arbitrary text on key presses',
|
map('Send arbitrary text on key presses',
|
||||||
'send_text ctrl+shift+alt+h send_text all Hello World',
|
'send_text ctrl+shift+alt+h send_text all Hello World',
|
||||||
add_to_default=False,
|
add_to_default=False,
|
||||||
|
|||||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@@ -848,6 +848,8 @@ if is_macos:
|
|||||||
defaults.map.append(KeyDefinition(False, KeyAction('kitten', ('unicode_input',)), 12, False, 32, ()))
|
defaults.map.append(KeyDefinition(False, KeyAction('kitten', ('unicode_input',)), 12, False, 32, ()))
|
||||||
defaults.map.append(KeyDefinition(False, KeyAction('edit_config_file'), 8, False, 44, ()))
|
defaults.map.append(KeyDefinition(False, KeyAction('edit_config_file'), 8, False, 44, ()))
|
||||||
defaults.map.append(KeyDefinition(False, KeyAction('clear_terminal', ('reset', True)), 10, False, 114, ()))
|
defaults.map.append(KeyDefinition(False, KeyAction('clear_terminal', ('reset', True)), 10, False, 114, ()))
|
||||||
|
defaults.map.append(KeyDefinition(False, KeyAction('load_config_file'), 12, False, 44, ()))
|
||||||
|
defaults.map.append(KeyDefinition(False, KeyAction('debug_config'), 10, False, 44, ()))
|
||||||
defaults.mouse_map = [
|
defaults.mouse_map = [
|
||||||
# click_url_or_select
|
# click_url_or_select
|
||||||
MouseMapping(0, 0, -2, False, KeyAction('mouse_click_url_or_select')),
|
MouseMapping(0, 0, -2, False, KeyAction('mouse_click_url_or_select')),
|
||||||
|
|||||||
@@ -2167,11 +2167,12 @@ screen_detect_url(Screen *screen, unsigned int x, unsigned int y) {
|
|||||||
bool has_url = false;
|
bool has_url = false;
|
||||||
index_type url_start, url_end = 0;
|
index_type url_start, url_end = 0;
|
||||||
Line *line = screen_visual_line(screen, y);
|
Line *line = screen_visual_line(screen, y);
|
||||||
|
if (!line || x >= screen->columns) return false;
|
||||||
if (line->cpu_cells[x].hyperlink_id) {
|
if (line->cpu_cells[x].hyperlink_id) {
|
||||||
screen_mark_hyperlink(screen, x, y);
|
screen_mark_hyperlink(screen, x, y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
char_type sentinel;
|
char_type sentinel = 0;
|
||||||
if (line) {
|
if (line) {
|
||||||
url_start = line_url_start_at(line, x);
|
url_start = line_url_start_at(line, x);
|
||||||
if (url_start < line->xnum) {
|
if (url_start < line->xnum) {
|
||||||
|
|||||||
@@ -263,21 +263,23 @@ void send_prerendered_sprites_for_window(OSWindow *w);
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
void get_cocoa_key_equivalent(uint32_t, int, char *key, size_t key_sz, int*);
|
void get_cocoa_key_equivalent(uint32_t, int, char *key, size_t key_sz, int*);
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NO_COCOA_PENDING_ACTION = 0,
|
PREFERENCES_WINDOW,
|
||||||
PREFERENCES_WINDOW = 1,
|
NEW_OS_WINDOW,
|
||||||
NEW_OS_WINDOW = 2,
|
NEW_OS_WINDOW_WITH_WD,
|
||||||
NEW_OS_WINDOW_WITH_WD = 4,
|
NEW_TAB_WITH_WD,
|
||||||
NEW_TAB_WITH_WD = 8,
|
CLOSE_OS_WINDOW,
|
||||||
CLOSE_OS_WINDOW = 16,
|
CLOSE_TAB,
|
||||||
CLOSE_TAB = 32,
|
NEW_TAB,
|
||||||
NEW_TAB = 64,
|
NEXT_TAB,
|
||||||
NEXT_TAB = 128,
|
PREVIOUS_TAB,
|
||||||
PREVIOUS_TAB = 256,
|
DETACH_TAB,
|
||||||
DETACH_TAB = 512,
|
OPEN_FILE,
|
||||||
OPEN_FILE = 1024,
|
NEW_WINDOW,
|
||||||
NEW_WINDOW = 2048,
|
CLOSE_WINDOW,
|
||||||
CLOSE_WINDOW = 4096,
|
RESET_TERMINAL,
|
||||||
RESET_TERMINAL = 8192,
|
RELOAD_CONFIG,
|
||||||
|
|
||||||
|
NUM_COCOA_PENDING_ACTIONS
|
||||||
} CocoaPendingAction;
|
} CocoaPendingAction;
|
||||||
void set_cocoa_pending_action(CocoaPendingAction action, const char*);
|
void set_cocoa_pending_action(CocoaPendingAction action, const char*);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user