Merge branch 'master' of github:kovidgoyal/kitty into system_double_click_interval

This commit is contained in:
Luflosi
2018-10-25 13:18:43 +02:00
15 changed files with 152 additions and 117 deletions

View File

@@ -106,7 +106,7 @@ install: |
if [[ "$TRAVIS_OS_NAME" == 'osx' ]]; then if [[ "$TRAVIS_OS_NAME" == 'osx' ]]; then
if [[ "$USE_BREW" == "1" ]]; then if [[ "$USE_BREW" == "1" ]]; then
brew update; brew update;
brew upgrade python; # brew upgrade python;
brew install harfbuzz --without-graphite2 --without-icu4c --without-freetype; brew install harfbuzz --without-graphite2 --without-icu4c --without-freetype;
brew install imagemagick brew install imagemagick
brew install optipng brew install optipng

View File

@@ -20,6 +20,9 @@ Changelog
``goto_tab`` now accepts negative numbers to go to previously active tabs ``goto_tab`` now accepts negative numbers to go to previously active tabs
(:iss:`1040`) (:iss:`1040`)
- Allow hiding the tab bar completely, by setting :opt:`tab_bar_style` to
``hidden``. (:iss:`1014`)
- Fix the ``*_with_cwd`` actions using the cwd of the overlay window rather - Fix the ``*_with_cwd`` actions using the cwd of the overlay window rather
than the underlying window's cwd (:iss:`1045`) than the underlying window's cwd (:iss:`1045`)
@@ -27,7 +30,19 @@ Changelog
- macOS: Fix drag and drop of files not working on mojave (:iss:`1058`) - macOS: Fix drag and drop of files not working on mojave (:iss:`1058`)
- macOS: Fix IME input for east asian languages (:iss:`910`) - macOS: Fix IME input for East Asian languages (:iss:`910`)
- macOS: Fix rendering frames-per-second very low when processing
large amounts of input in small chunks (:pull:`1082`)
- macOS: Fix incorrect text sizes calculated when using an external display
that is set to mirror the main display (:iss:`1056`)
- Linux: Fix match rules used as aliases in Fontconfig configuration not being
respected (:iss:`1085`)
- Linux: Fix a crash when using the GNU Unifont as a fallback font
(:iss:`1087`)
- Fix expansion of env vars not working in the :opt:`env` directive - Fix expansion of env vars not working in the :opt:`env` directive
(:iss:`1075`) (:iss:`1075`)

View File

@@ -27,12 +27,10 @@
#include <stdint.h> #include <stdint.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <Carbon/Carbon.h>
#if defined(__OBJC__) #if defined(__OBJC__)
#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#else #else
#include <Carbon/Carbon.h>
#include <ApplicationServices/ApplicationServices.h>
typedef void* id; typedef void* id;
#endif #endif

View File

@@ -568,6 +568,16 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
[super dealloc]; [super dealloc];
} }
-(void)setLayer:(CALayer*)layer
{
[super setLayer:layer];
if (window->context.client != GLFW_NO_API) {
// this is needed for initial rendering on mojave, see
// https://github.com/kovidgoyal/kitty/issues/887
[window->context.nsgl.object update];
}
}
- (_GLFWwindow*)glfwWindow { - (_GLFWwindow*)glfwWindow {
return window; return window;
} }
@@ -1791,7 +1801,7 @@ void _glfwPlatformPollEvents(void)
for (;;) for (;;)
{ {
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode inMode:NSDefaultRunLoopMode
dequeue:YES]; dequeue:YES];
if (event == nil) if (event == nil)
@@ -1813,7 +1823,7 @@ void _glfwPlatformWaitEvents(void)
untilDate:[NSDate distantFuture] untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode inMode:NSDefaultRunLoopMode
dequeue:YES]; dequeue:YES];
[NSApp sendEvent:event]; if ([event type] != NSEventTypeApplicationDefined) [NSApp sendEvent:event];
_glfwPlatformPollEvents(); _glfwPlatformPollEvents();
} }
@@ -1825,8 +1835,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
untilDate:date untilDate:date
inMode:NSDefaultRunLoopMode inMode:NSDefaultRunLoopMode
dequeue:YES]; dequeue:YES];
if (event) if (event && [event type] != NSEventTypeApplicationDefined) [NSApp sendEvent:event];
[NSApp sendEvent:event];
_glfwPlatformPollEvents(); _glfwPlatformPollEvents();
} }

View File

@@ -5,7 +5,6 @@
import json import json
import os import os
import re import re
import shutil
import sys import sys
_plat = sys.platform.lower() _plat = sys.platform.lower()
@@ -188,7 +187,7 @@ class Function:
return ans return ans
def generate_wrappers(glfw_header, glfw_native_header): def generate_wrappers(glfw_header):
src = open(glfw_header).read() src = open(glfw_header).read()
functions = [] functions = []
first = None first = None
@@ -268,53 +267,9 @@ unload_glfw() {
f.write(code) f.write(code)
def from_glfw(glfw_dir):
os.chdir(glfw_dir)
sinfo = collect_source_information()
files_to_copy = set()
for x in sinfo.values():
if isinstance(x, dict):
headers, sources = x['headers'], x['sources']
for name in headers + sources:
files_to_copy.add(os.path.abspath(os.path.join('src', name)))
glfw_header = os.path.abspath('include/GLFW/glfw3.h')
glfw_native_header = os.path.abspath('include/GLFW/glfw3native.h')
os.chdir(base)
for x in os.listdir('.'):
if x.rpartition('.') in ('c', 'h'):
os.unlink(x)
for src in files_to_copy:
shutil.copy2(src, '.')
shutil.copy2(glfw_header, '.')
json.dump(
sinfo,
open('source-info.json', 'w'),
indent=2,
ensure_ascii=False,
sort_keys=True
)
generate_wrappers(glfw_header, glfw_native_header)
def to_glfw(glfw_dir):
src = base
for x in os.listdir(src):
if x in ('glfw.py', 'glfw3.h', '__pycache__', 'source-info.json') or x.startswith('wayland-'):
continue
xp = os.path.join(src, x)
shutil.copyfile(xp, os.path.join(glfw_dir, 'src', x))
shutil.copyfile(os.path.join(src, 'glfw3.h'), os.path.join(glfw_dir, 'include/GLFW/glfw3.h'))
def main(): def main():
glfw_dir = os.path.abspath(os.path.join(base, '../../glfw')) os.chdir(os.path.dirname(os.path.abspath(__file__)))
q = sys.argv[1].lower().replace('_', '-') generate_wrappers('glfw3.h')
if q == 'from-glfw':
from_glfw(glfw_dir)
elif q == 'to-glfw':
to_glfw(glfw_dir)
else:
raise SystemExit('First argument must be one of to-glfw or from-glfw')
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -984,7 +984,8 @@ io_loop(void *data) {
// The I/O thread loop // The I/O thread loop
size_t i; size_t i;
int ret; int ret;
bool has_more, data_received; bool has_more, data_received, has_pending_wakeups = false;
double last_main_loop_wakeup_at = -1, now = -1;
Screen *screen; Screen *screen;
ChildMonitor *self = (ChildMonitor*)data; ChildMonitor *self = (ChildMonitor*)data;
set_thread_name("KittyChildMon"); set_thread_name("KittyChildMon");
@@ -1003,7 +1004,14 @@ io_loop(void *data) {
fds[EXTRA_FDS + i].events = (screen->read_buf_sz < READ_BUF_SZ ? POLLIN : 0) | (screen->write_buf_used ? POLLOUT : 0); fds[EXTRA_FDS + i].events = (screen->read_buf_sz < READ_BUF_SZ ? POLLIN : 0) | (screen->write_buf_used ? POLLOUT : 0);
screen_mutex(unlock, read); screen_mutex(unlock, write); screen_mutex(unlock, read); screen_mutex(unlock, write);
} }
ret = poll(fds, self->count + EXTRA_FDS, -1); if (has_pending_wakeups) {
now = monotonic();
double time_delta = OPT(input_delay) - (now - last_main_loop_wakeup_at);
if (time_delta >= 0) ret = poll(fds, self->count + EXTRA_FDS, (int)ceil(1000 * time_delta));
else ret = 0;
} else {
ret = poll(fds, self->count + EXTRA_FDS, -1);
}
if (ret > 0) { if (ret > 0) {
if (fds[0].revents && POLLIN) drain_fd(fds[0].fd); // wakeup if (fds[0].revents && POLLIN) drain_fd(fds[0].fd); // wakeup
if (fds[1].revents && POLLIN) { if (fds[1].revents && POLLIN) {
@@ -1047,8 +1055,17 @@ io_loop(void *data) {
perror("Call to poll() failed"); perror("Call to poll() failed");
} }
} }
if (data_received) wakeup_main_loop(); #define WAKEUP { wakeup_main_loop(); last_main_loop_wakeup_at = now; has_pending_wakeups = false; }
// we only wakeup the main loop after input_delay as wakeup is an expensive operation
// on some platforms, such as cocoa
if (data_received) {
if ((now = monotonic()) - last_main_loop_wakeup_at > OPT(input_delay)) WAKEUP
else has_pending_wakeups = true;
} else {
if (has_pending_wakeups && (now = monotonic()) - last_main_loop_wakeup_at > OPT(input_delay)) WAKEUP
}
} }
#undef WAKEUP
children_mutex(lock); children_mutex(lock);
for (i = 0; i < self->count; i++) children[i].needs_removal = true; for (i = 0; i < self->count; i++) children[i].needs_removal = true;
remove_children(self); remove_children(self);

View File

@@ -99,12 +99,6 @@ cocoa_set_new_window_trigger(PyObject *self UNUSED, PyObject *args) {
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
void
cocoa_update_nsgl_context(void* id) {
NSOpenGLContext *ctx = id;
[ctx update];
}
void void
cocoa_create_global_menu(void) { cocoa_create_global_menu(void) {
NSString* app_name = find_app_name(); NSString* app_name = find_app_name();

View File

@@ -580,8 +580,8 @@ Which edge to show the tab bar on, top or bottom'''))
o('tab_bar_margin_width', 0.0, option_type=positive_float, long_text=_(''' o('tab_bar_margin_width', 0.0, option_type=positive_float, long_text=_('''
The margin to the left and right of the tab bar (in pts)''')) The margin to the left and right of the tab bar (in pts)'''))
o('tab_bar_style', 'fade', option_type=choices('fade', 'separator'), long_text=_(''' o('tab_bar_style', 'fade', option_type=choices('fade', 'separator', 'hidden'), long_text=_('''
The tab bar style, can be one of: :code:`fade` or :code:`separator`. In the fade style, The tab bar style, can be one of: :code:`fade`, :code:`separator` or :code:`hidden`. In the fade style,
each tab's edges fade into the background color, in the separator style, tabs are each tab's edges fade into the background color, in the separator style, tabs are
separated by a configurable separator. separated by a configurable separator.
''')) '''))

View File

@@ -114,6 +114,7 @@ _fc_match(FcPattern *pat) {
FcResult result; FcResult result;
FcConfigSubstitute(NULL, pat, FcMatchPattern); FcConfigSubstitute(NULL, pat, FcMatchPattern);
FcDefaultSubstitute(pat); FcDefaultSubstitute(pat);
/* printf("fc_match = %s\n", FcNameUnparse(pat)); */
match = FcFontMatch(NULL, pat, &result); match = FcFontMatch(NULL, pat, &result);
if (match == NULL) { PyErr_SetString(PyExc_KeyError, "FcFontMatch() failed"); goto end; } if (match == NULL) { PyErr_SetString(PyExc_KeyError, "FcFontMatch() failed"); goto end; }
ans = pattern_as_dict(match); ans = pattern_as_dict(match);
@@ -145,16 +146,22 @@ end:
static PyObject* static PyObject*
fc_match(PyObject UNUSED *self, PyObject *args) { fc_match(PyObject UNUSED *self, PyObject *args) {
char *family = NULL; char *family = NULL;
int bold = 0, italic = 0, allow_bitmapped_fonts = 0; int bold = 0, italic = 0, allow_bitmapped_fonts = 0, monospaced = 0;
double size_in_pts = 0, dpi = 0; double size_in_pts = 0, dpi = 0;
FcPattern *pat = NULL; FcPattern *pat = NULL;
PyObject *ans = NULL; PyObject *ans = NULL;
if (!PyArg_ParseTuple(args, "|zpppdd", &family, &bold, &italic, &allow_bitmapped_fonts, &size_in_pts, &dpi)) return NULL; if (!PyArg_ParseTuple(args, "|zppppdd", &family, &bold, &italic, &monospaced, &allow_bitmapped_fonts, &size_in_pts, &dpi)) return NULL;
pat = FcPatternCreate(); pat = FcPatternCreate();
if (pat == NULL) return PyErr_NoMemory(); if (pat == NULL) return PyErr_NoMemory();
if (family && strlen(family) > 0) AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)family, "family"); if (family && strlen(family) > 0) AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)family, "family");
if (monospaced) {
// pass the family,monospace as the family parameter to fc-match,
// which will fallback to using monospace if the family does not match.
AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)"monospace", "family");
AP(FcPatternAddInteger, FC_SPACING, FC_MONO, "spacing");
}
if (!allow_bitmapped_fonts) { if (!allow_bitmapped_fonts) {
AP(FcPatternAddBool, FC_OUTLINE, true, "outline"); AP(FcPatternAddBool, FC_OUTLINE, true, "outline");
AP(FcPatternAddBool, FC_SCALABLE, true, "scalable"); AP(FcPatternAddBool, FC_SCALABLE, true, "scalable");

View File

@@ -44,8 +44,12 @@ def list_fonts():
yield {'family': f, 'full_name': fn, 'is_monospace': is_mono} yield {'family': f, 'full_name': fn, 'is_monospace': is_mono}
def family_name_to_key(family):
return re.sub(r'\s+', ' ', family.lower())
def find_best_match(family, bold=False, italic=False, monospaced=True): def find_best_match(family, bold=False, italic=False, monospaced=True):
q = re.sub(r'\s+', ' ', family.lower()) q = family_name_to_key(family)
font_map = all_fonts_map(monospaced) font_map = all_fonts_map(monospaced)
def score(candidate): def score(candidate):
@@ -61,6 +65,16 @@ def find_best_match(family, bold=False, italic=False, monospaced=True):
candidates.sort(key=score) candidates.sort(key=score)
return candidates[0] return candidates[0]
# Use fc-match to see if we can find a monospaced font that matches family
possibility = fc_match(family, False, False)
for key, map_key in (('postscript_name', 'ps_map'), ('full_name', 'full_map'), ('family', 'family_map')):
val = possibility.get(key)
if val:
candidates = font_map[map_key].get(family_name_to_key(val))
if candidates:
candidates.sort(key=score)
return candidates[0]
# Use fc-match with a generic family # Use fc-match with a generic family
family = 'monospace' if monospaced else 'sans-serif' family = 'monospace' if monospaced else 'sans-serif'
return fc_match(family, bold, italic) return fc_match(family, bold, italic)

View File

@@ -16,6 +16,10 @@
#define HARFBUZZ_HAS_CHANGE_FONT #define HARFBUZZ_HAS_CHANGE_FONT
#endif #endif
#if FREETYPE_MAJOR == 2 && FREETYPE_MINOR < 7
#define FT_Bitmap_Init FT_Bitmap_New
#endif
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_BITMAP_H #include FT_BITMAP_H
typedef struct { typedef struct {
@@ -232,27 +236,6 @@ load_glyph(Face *self, int glyph_index, int load_type) {
int flags = get_load_flags(self->hinting, self->hintstyle, load_type); int flags = get_load_flags(self->hinting, self->hintstyle, load_type);
int error = FT_Load_Glyph(self->face, glyph_index, flags); int error = FT_Load_Glyph(self->face, glyph_index, flags);
if (error) { set_freetype_error("Failed to load glyph, with error:", error); return false; } if (error) { set_freetype_error("Failed to load glyph, with error:", error); return false; }
// Embedded bitmap glyph?
if (self->face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && load_type != FT_LOAD_DEFAULT) {
FT_Bitmap bitmap;
FT_Bitmap_New(&bitmap);
// This also sets pixel_mode to FT_PIXEL_MODE_GRAY so we don't have to
error = FT_Bitmap_Convert(library, &self->face->glyph->bitmap, &bitmap, 1);
if (error) { set_freetype_error("Failed to convert bitmap, with error:", error); return false; }
// Normalize gray levels to the range [0..255]
bitmap.num_grays = 256;
unsigned int stride = bitmap.pitch < 0 ? -bitmap.pitch : bitmap.pitch;
for (unsigned int i = 0; i < bitmap.rows; ++i) {
// We only have 2 levels
for (unsigned int j = 0; j < bitmap.width; ++j) bitmap.buffer[i * stride + j] *= 255;
}
error = FT_Bitmap_Copy(library, &bitmap, &self->face->glyph->bitmap);
if (error) { set_freetype_error("Failed to copy bitmap, with error:", error); return false; }
FT_Bitmap_Done(library, &bitmap);
}
return true; return true;
} }
@@ -307,6 +290,14 @@ typedef struct {
unsigned int factor, right_edge; unsigned int factor, right_edge;
} ProcessedBitmap; } ProcessedBitmap;
static inline void
free_processed_bitmap(ProcessedBitmap *bm) {
if (bm->needs_free) {
bm->needs_free = false;
free(bm->buf); bm->buf = NULL;
}
}
static inline void static inline void
trim_borders(ProcessedBitmap *ans, size_t extra) { trim_borders(ProcessedBitmap *ans, size_t extra) {
bool column_has_text = false; bool column_has_text = false;
@@ -324,17 +315,47 @@ trim_borders(ProcessedBitmap *ans, size_t extra) {
ans->width -= extra; ans->width -= extra;
} }
static inline void
populate_processed_bitmap(FT_Bitmap *bitmap, ProcessedBitmap *ans, bool copy_buf) {
ans->stride = bitmap->pitch < 0 ? -bitmap->pitch : bitmap->pitch;
ans->rows = bitmap->rows;
if (copy_buf) {
ans->buf = calloc(ans->rows, ans->stride);
if (!ans->buf) fatal("Out of memory");
ans->needs_free = true;
memcpy(ans->buf, bitmap->buffer, ans->rows * ans->stride);
} else ans->buf = bitmap->buffer;
ans->start_x = 0; ans->width = bitmap->width;
ans->pixel_mode = bitmap->pixel_mode;
}
static inline bool static inline bool
render_bitmap(Face *self, int glyph_id, ProcessedBitmap *ans, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, bool bold, bool italic, bool rescale, FONTS_DATA_HANDLE fg) { render_bitmap(Face *self, int glyph_id, ProcessedBitmap *ans, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, bool bold, bool italic, bool rescale, FONTS_DATA_HANDLE fg) {
if (!load_glyph(self, glyph_id, FT_LOAD_RENDER)) return false; if (!load_glyph(self, glyph_id, FT_LOAD_RENDER)) return false;
unsigned int max_width = cell_width * num_cells; unsigned int max_width = cell_width * num_cells;
FT_Bitmap *bitmap = &self->face->glyph->bitmap;
ans->buf = bitmap->buffer; // Embedded bitmap glyph?
ans->start_x = 0; ans->width = bitmap->width; if (self->face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
ans->stride = bitmap->pitch < 0 ? -bitmap->pitch : bitmap->pitch; FT_Bitmap bitmap;
ans->rows = bitmap->rows; FT_Bitmap_Init(&bitmap);
ans->pixel_mode = bitmap->pixel_mode;
// This also sets pixel_mode to FT_PIXEL_MODE_GRAY so we don't have to
int error = FT_Bitmap_Convert(library, &self->face->glyph->bitmap, &bitmap, 1);
if (error) { set_freetype_error("Failed to convert bitmap, with error:", error); return false; }
// Normalize gray levels to the range [0..255]
bitmap.num_grays = 256;
unsigned int stride = bitmap.pitch < 0 ? -bitmap.pitch : bitmap.pitch;
for (unsigned int i = 0; i < bitmap.rows; ++i) {
// We only have 2 levels
for (unsigned int j = 0; j < bitmap.width; ++j) bitmap.buffer[i * stride + j] *= 255;
}
populate_processed_bitmap(&bitmap, ans, true);
FT_Bitmap_Done(library, &bitmap);
} else {
populate_processed_bitmap(&self->face->glyph->bitmap, ans, false);
}
if (ans->width > max_width) { if (ans->width > max_width) {
size_t extra = ans->width - max_width; size_t extra = ans->width - max_width;
if (italic && extra < cell_width / 2) { if (italic && extra < cell_width / 2) {
@@ -345,8 +366,9 @@ render_bitmap(Face *self, int glyph_id, ProcessedBitmap *ans, unsigned int cell_
// bad, we just crop the bitmap on the right. See https://github.com/kovidgoyal/kitty/issues/352 // bad, we just crop the bitmap on the right. See https://github.com/kovidgoyal/kitty/issues/352
} else if (rescale && self->is_scalable && extra > 1) { } else if (rescale && self->is_scalable && extra > 1) {
FT_F26Dot6 char_width = self->char_width, char_height = self->char_height; FT_F26Dot6 char_width = self->char_width, char_height = self->char_height;
float ar = (float)max_width / (float)bitmap->width; float ar = (float)max_width / (float)ans->width;
if (set_font_size(self, (FT_F26Dot6)((float)self->char_width * ar), (FT_F26Dot6)((float)self->char_height * ar), self->xdpi, self->ydpi, 0, fg->cell_height)) { if (set_font_size(self, (FT_F26Dot6)((float)self->char_width * ar), (FT_F26Dot6)((float)self->char_height * ar), self->xdpi, self->ydpi, 0, fg->cell_height)) {
free_processed_bitmap(ans);
if (!render_bitmap(self, glyph_id, ans, cell_width, cell_height, num_cells, bold, italic, false, fg)) return false; if (!render_bitmap(self, glyph_id, ans, cell_width, cell_height, num_cells, bold, italic, false, fg)) return false;
if (!set_font_size(self, char_width, char_height, self->xdpi, self->ydpi, 0, fg->cell_height)) return false; if (!set_font_size(self, char_width, char_height, self->xdpi, self->ydpi, 0, fg->cell_height)) return false;
} else return false; } else return false;
@@ -504,7 +526,7 @@ render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *inf
y = (float)positions[i].y_offset / 64.0f; y = (float)positions[i].y_offset / 64.0f;
if ((*was_colored || self->face->glyph->metrics.width > 0) && bm.width > 0) place_bitmap_in_canvas(canvas, &bm, canvas_width, cell_height, x_offset, y, &self->face->glyph->metrics, baseline); if ((*was_colored || self->face->glyph->metrics.width > 0) && bm.width > 0) place_bitmap_in_canvas(canvas, &bm, canvas_width, cell_height, x_offset, y, &self->face->glyph->metrics, baseline);
x += (float)positions[i].x_advance / 64.0f; x += (float)positions[i].x_advance / 64.0f;
if (bm.needs_free) free(bm.buf); free_processed_bitmap(&bm);
} }
// center the glyphs in the canvas // center the glyphs in the canvas

View File

@@ -14,7 +14,6 @@ extern bool cocoa_toggle_fullscreen(void *w, bool);
extern void cocoa_create_global_menu(void); extern void cocoa_create_global_menu(void);
extern void cocoa_set_hide_from_tasks(void); extern void cocoa_set_hide_from_tasks(void);
extern void cocoa_set_titlebar_color(void *w, color_type color); extern void cocoa_set_titlebar_color(void *w, color_type color);
extern void cocoa_update_nsgl_context(void* id);
#if GLFW_KEY_LAST >= MAX_KEY_COUNT #if GLFW_KEY_LAST >= MAX_KEY_COUNT
@@ -344,6 +343,9 @@ get_window_dpi(GLFWwindow *w, double *x, double *y) {
if (monitor == NULL) { PyErr_Print(); monitor = glfwGetPrimaryMonitor(); } if (monitor == NULL) { PyErr_Print(); monitor = glfwGetPrimaryMonitor(); }
float xscale = 1, yscale = 1; float xscale = 1, yscale = 1;
if (monitor) glfwGetMonitorContentScale(monitor, &xscale, &yscale); if (monitor) glfwGetMonitorContentScale(monitor, &xscale, &yscale);
if (!xscale || !yscale) glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale);
if (!xscale) xscale = 1.0;
if (!yscale) yscale = 1.0;
#ifdef __APPLE__ #ifdef __APPLE__
double factor = 72.0; double factor = 72.0;
#else #else
@@ -816,13 +818,6 @@ is_mouse_hidden(OSWindow *w) {
void void
swap_window_buffers(OSWindow *w) { swap_window_buffers(OSWindow *w) {
#ifdef __APPLE__
if (w->nsgl_ctx_updated++ < 2) {
// Needed on Mojave for initial window render, see
// https://github.com/kovidgoyal/kitty/issues/887
cocoa_update_nsgl_context(glfwGetNSGLContext(w->handle));
}
#endif
glfwSwapBuffers(w->handle); glfwSwapBuffers(w->handle);
} }

View File

@@ -249,7 +249,7 @@ add_borders_rect(id_type os_window_id, id_type tab_id, uint32_t left, uint32_t t
void void
os_window_regions(OSWindow *os_window, Region *central, Region *tab_bar) { os_window_regions(OSWindow *os_window, Region *central, Region *tab_bar) {
if (os_window->num_tabs > 1) { if (!global_state.tab_bar_hidden && os_window->num_tabs > 1) {
switch(OPT(tab_bar_edge)) { switch(OPT(tab_bar_edge)) {
case TOP_EDGE: case TOP_EDGE:
central->left = 0; central->top = os_window->fonts_data->cell_height; central->right = os_window->viewport_width - 1; central->left = 0; central->top = os_window->fonts_data->cell_height; central->right = os_window->viewport_width - 1;
@@ -395,6 +395,11 @@ PYWRAP1(set_options) {
S(macos_hide_from_tasks, PyObject_IsTrue); S(macos_hide_from_tasks, PyObject_IsTrue);
S(macos_thicken_font, PyFloat_AsDouble); S(macos_thicken_font, PyFloat_AsDouble);
GA(tab_bar_style); if (!ret) return NULL;
global_state.tab_bar_hidden = PyUnicode_CompareWithASCIIString(ret, "hidden") == 0 ? true: false;
Py_CLEAR(ret);
if (PyErr_Occurred()) return NULL;
PyObject *chars = PyObject_GetAttrString(opts, "select_by_word_characters"); PyObject *chars = PyObject_GetAttrString(opts, "select_by_word_characters");
if (chars == NULL) return NULL; if (chars == NULL) return NULL;
for (size_t i = 0; i < MIN((size_t)PyUnicode_GET_LENGTH(chars), sizeof(OPT(select_by_word_characters))/sizeof(OPT(select_by_word_characters[0]))); i++) { for (size_t i = 0; i < MIN((size_t)PyUnicode_GET_LENGTH(chars), sizeof(OPT(select_by_word_characters))/sizeof(OPT(select_by_word_characters[0]))); i++) {

View File

@@ -127,7 +127,6 @@ typedef struct {
FONTS_DATA_HANDLE fonts_data; FONTS_DATA_HANDLE fonts_data;
id_type temp_font_group_id; id_type temp_font_group_id;
double pending_scroll_pixels; double pending_scroll_pixels;
unsigned int nsgl_ctx_updated;
} OSWindow; } OSWindow;
@@ -144,6 +143,7 @@ typedef struct {
bool debug_gl, debug_font_fallback; bool debug_gl, debug_font_fallback;
bool has_pending_resizes; bool has_pending_resizes;
bool in_sequence_mode; bool in_sequence_mode;
bool tab_bar_hidden;
double font_sz_in_pts; double font_sz_in_pts;
struct { double x, y; } default_dpi; struct { double x, y; } default_dpi;
id_type active_drag_in_window; id_type active_drag_in_window;

View File

@@ -358,6 +358,7 @@ class TabManager: # {{{
self.os_window_id = os_window_id self.os_window_id = os_window_id
self.last_active_tab_id = None self.last_active_tab_id = None
self.opts, self.args = opts, args self.opts, self.args = opts, args
self.tab_bar_hidden = self.opts.tab_bar_style == 'hidden'
self.tabs = [] self.tabs = []
self.active_tab_history = deque() self.active_tab_history = deque()
self.tab_bar = TabBar(self.os_window_id, opts) self.tab_bar = TabBar(self.os_window_id, opts)
@@ -395,7 +396,8 @@ class TabManager: # {{{
w.focus_changed(True) w.focus_changed(True)
def refresh_sprite_positions(self): def refresh_sprite_positions(self):
self.tab_bar.screen.refresh_sprite_positions() if not self.tab_bar_hidden:
self.tab_bar.screen.refresh_sprite_positions()
def _add_tab(self, tab): def _add_tab(self, tab):
before = len(self.tabs) before = len(self.tabs)
@@ -415,12 +417,13 @@ class TabManager: # {{{
set_active_tab(self.os_window_id, idx) set_active_tab(self.os_window_id, idx)
def tabbar_visibility_changed(self): def tabbar_visibility_changed(self):
self.tab_bar.layout() if not self.tab_bar_hidden:
self.resize(only_tabs=True) self.tab_bar.layout()
glfw_post_empty_event() self.resize(only_tabs=True)
glfw_post_empty_event()
def mark_tab_bar_dirty(self): def mark_tab_bar_dirty(self):
if len(self.tabs) > 1: if len(self.tabs) > 1 and not self.tab_bar_hidden:
mark_tab_bar_dirty(self.os_window_id) mark_tab_bar_dirty(self.os_window_id)
def update_tab_bar_data(self): def update_tab_bar_data(self):
@@ -428,8 +431,9 @@ class TabManager: # {{{
def resize(self, only_tabs=False): def resize(self, only_tabs=False):
if not only_tabs: if not only_tabs:
self.tab_bar.layout() if not self.tab_bar_hidden:
self.mark_tab_bar_dirty() self.tab_bar.layout()
self.mark_tab_bar_dirty()
for tab in self.tabs: for tab in self.tabs:
tab.relayout() tab.relayout()