Merge branch 'master' of github:kovidgoyal/kitty into system_double_click_interval
This commit is contained in:
commit
facb2df3f6
@ -106,7 +106,7 @@ install: |
|
||||
if [[ "$TRAVIS_OS_NAME" == 'osx' ]]; then
|
||||
if [[ "$USE_BREW" == "1" ]]; then
|
||||
brew update;
|
||||
brew upgrade python;
|
||||
# brew upgrade python;
|
||||
brew install harfbuzz --without-graphite2 --without-icu4c --without-freetype;
|
||||
brew install imagemagick
|
||||
brew install optipng
|
||||
|
||||
@ -20,6 +20,9 @@ Changelog
|
||||
``goto_tab`` now accepts negative numbers to go to previously active tabs
|
||||
(: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
|
||||
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 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
|
||||
(:iss:`1075`)
|
||||
|
||||
4
glfw/cocoa_platform.h
vendored
4
glfw/cocoa_platform.h
vendored
@ -27,12 +27,10 @@
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
typedef void* id;
|
||||
#endif
|
||||
|
||||
|
||||
@ -568,6 +568,16 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
|
||||
[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 {
|
||||
return window;
|
||||
}
|
||||
@ -1791,7 +1801,7 @@ void _glfwPlatformPollEvents(void)
|
||||
for (;;)
|
||||
{
|
||||
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
||||
untilDate:nil
|
||||
untilDate:[NSDate distantPast]
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES];
|
||||
if (event == nil)
|
||||
@ -1813,7 +1823,7 @@ void _glfwPlatformWaitEvents(void)
|
||||
untilDate:[NSDate distantFuture]
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES];
|
||||
[NSApp sendEvent:event];
|
||||
if ([event type] != NSEventTypeApplicationDefined) [NSApp sendEvent:event];
|
||||
|
||||
_glfwPlatformPollEvents();
|
||||
}
|
||||
@ -1825,8 +1835,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
untilDate:date
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES];
|
||||
if (event)
|
||||
[NSApp sendEvent:event];
|
||||
if (event && [event type] != NSEventTypeApplicationDefined) [NSApp sendEvent:event];
|
||||
|
||||
_glfwPlatformPollEvents();
|
||||
}
|
||||
|
||||
51
glfw/glfw.py
51
glfw/glfw.py
@ -5,7 +5,6 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
_plat = sys.platform.lower()
|
||||
@ -188,7 +187,7 @@ class Function:
|
||||
return ans
|
||||
|
||||
|
||||
def generate_wrappers(glfw_header, glfw_native_header):
|
||||
def generate_wrappers(glfw_header):
|
||||
src = open(glfw_header).read()
|
||||
functions = []
|
||||
first = None
|
||||
@ -268,53 +267,9 @@ unload_glfw() {
|
||||
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():
|
||||
glfw_dir = os.path.abspath(os.path.join(base, '../../glfw'))
|
||||
q = sys.argv[1].lower().replace('_', '-')
|
||||
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')
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
generate_wrappers('glfw3.h')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@ -984,7 +984,8 @@ io_loop(void *data) {
|
||||
// The I/O thread loop
|
||||
size_t i;
|
||||
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;
|
||||
ChildMonitor *self = (ChildMonitor*)data;
|
||||
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);
|
||||
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 (fds[0].revents && POLLIN) drain_fd(fds[0].fd); // wakeup
|
||||
if (fds[1].revents && POLLIN) {
|
||||
@ -1047,8 +1055,17 @@ io_loop(void *data) {
|
||||
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);
|
||||
for (i = 0; i < self->count; i++) children[i].needs_removal = true;
|
||||
remove_children(self);
|
||||
|
||||
@ -99,12 +99,6 @@ cocoa_set_new_window_trigger(PyObject *self UNUSED, PyObject *args) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_update_nsgl_context(void* id) {
|
||||
NSOpenGLContext *ctx = id;
|
||||
[ctx update];
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_create_global_menu(void) {
|
||||
NSString* app_name = find_app_name();
|
||||
|
||||
@ -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=_('''
|
||||
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=_('''
|
||||
The tab bar style, can be one of: :code:`fade` or :code:`separator`. In the fade style,
|
||||
o('tab_bar_style', 'fade', option_type=choices('fade', 'separator', 'hidden'), long_text=_('''
|
||||
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
|
||||
separated by a configurable separator.
|
||||
'''))
|
||||
|
||||
@ -114,6 +114,7 @@ _fc_match(FcPattern *pat) {
|
||||
FcResult result;
|
||||
FcConfigSubstitute(NULL, pat, FcMatchPattern);
|
||||
FcDefaultSubstitute(pat);
|
||||
/* printf("fc_match = %s\n", FcNameUnparse(pat)); */
|
||||
match = FcFontMatch(NULL, pat, &result);
|
||||
if (match == NULL) { PyErr_SetString(PyExc_KeyError, "FcFontMatch() failed"); goto end; }
|
||||
ans = pattern_as_dict(match);
|
||||
@ -145,16 +146,22 @@ end:
|
||||
static PyObject*
|
||||
fc_match(PyObject UNUSED *self, PyObject *args) {
|
||||
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;
|
||||
FcPattern *pat = 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();
|
||||
if (pat == NULL) return PyErr_NoMemory();
|
||||
|
||||
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) {
|
||||
AP(FcPatternAddBool, FC_OUTLINE, true, "outline");
|
||||
AP(FcPatternAddBool, FC_SCALABLE, true, "scalable");
|
||||
|
||||
@ -44,8 +44,12 @@ def list_fonts():
|
||||
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):
|
||||
q = re.sub(r'\s+', ' ', family.lower())
|
||||
q = family_name_to_key(family)
|
||||
font_map = all_fonts_map(monospaced)
|
||||
|
||||
def score(candidate):
|
||||
@ -61,6 +65,16 @@ def find_best_match(family, bold=False, italic=False, monospaced=True):
|
||||
candidates.sort(key=score)
|
||||
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
|
||||
family = 'monospace' if monospaced else 'sans-serif'
|
||||
return fc_match(family, bold, italic)
|
||||
|
||||
@ -16,6 +16,10 @@
|
||||
#define HARFBUZZ_HAS_CHANGE_FONT
|
||||
#endif
|
||||
|
||||
#if FREETYPE_MAJOR == 2 && FREETYPE_MINOR < 7
|
||||
#define FT_Bitmap_Init FT_Bitmap_New
|
||||
#endif
|
||||
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_BITMAP_H
|
||||
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 error = FT_Load_Glyph(self->face, glyph_index, flags);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -307,6 +290,14 @@ typedef struct {
|
||||
unsigned int factor, right_edge;
|
||||
} 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
|
||||
trim_borders(ProcessedBitmap *ans, size_t extra) {
|
||||
bool column_has_text = false;
|
||||
@ -324,17 +315,47 @@ trim_borders(ProcessedBitmap *ans, size_t 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
|
||||
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;
|
||||
unsigned int max_width = cell_width * num_cells;
|
||||
FT_Bitmap *bitmap = &self->face->glyph->bitmap;
|
||||
ans->buf = bitmap->buffer;
|
||||
ans->start_x = 0; ans->width = bitmap->width;
|
||||
ans->stride = bitmap->pitch < 0 ? -bitmap->pitch : bitmap->pitch;
|
||||
ans->rows = bitmap->rows;
|
||||
ans->pixel_mode = bitmap->pixel_mode;
|
||||
|
||||
// Embedded bitmap glyph?
|
||||
if (self->face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
|
||||
FT_Bitmap bitmap;
|
||||
FT_Bitmap_Init(&bitmap);
|
||||
|
||||
// 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) {
|
||||
size_t extra = ans->width - max_width;
|
||||
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
|
||||
} else if (rescale && self->is_scalable && extra > 1) {
|
||||
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)) {
|
||||
free_processed_bitmap(ans);
|
||||
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;
|
||||
} 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;
|
||||
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;
|
||||
if (bm.needs_free) free(bm.buf);
|
||||
free_processed_bitmap(&bm);
|
||||
}
|
||||
|
||||
// center the glyphs in the canvas
|
||||
|
||||
11
kitty/glfw.c
11
kitty/glfw.c
@ -14,7 +14,6 @@ extern bool cocoa_toggle_fullscreen(void *w, bool);
|
||||
extern void cocoa_create_global_menu(void);
|
||||
extern void cocoa_set_hide_from_tasks(void);
|
||||
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
|
||||
@ -344,6 +343,9 @@ get_window_dpi(GLFWwindow *w, double *x, double *y) {
|
||||
if (monitor == NULL) { PyErr_Print(); monitor = glfwGetPrimaryMonitor(); }
|
||||
float xscale = 1, yscale = 1;
|
||||
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__
|
||||
double factor = 72.0;
|
||||
#else
|
||||
@ -816,13 +818,6 @@ is_mouse_hidden(OSWindow *w) {
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -249,7 +249,7 @@ add_borders_rect(id_type os_window_id, id_type tab_id, uint32_t left, uint32_t t
|
||||
|
||||
void
|
||||
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)) {
|
||||
case TOP_EDGE:
|
||||
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_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");
|
||||
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++) {
|
||||
|
||||
@ -127,7 +127,6 @@ typedef struct {
|
||||
FONTS_DATA_HANDLE fonts_data;
|
||||
id_type temp_font_group_id;
|
||||
double pending_scroll_pixels;
|
||||
unsigned int nsgl_ctx_updated;
|
||||
} OSWindow;
|
||||
|
||||
|
||||
@ -144,6 +143,7 @@ typedef struct {
|
||||
bool debug_gl, debug_font_fallback;
|
||||
bool has_pending_resizes;
|
||||
bool in_sequence_mode;
|
||||
bool tab_bar_hidden;
|
||||
double font_sz_in_pts;
|
||||
struct { double x, y; } default_dpi;
|
||||
id_type active_drag_in_window;
|
||||
|
||||
@ -358,6 +358,7 @@ class TabManager: # {{{
|
||||
self.os_window_id = os_window_id
|
||||
self.last_active_tab_id = None
|
||||
self.opts, self.args = opts, args
|
||||
self.tab_bar_hidden = self.opts.tab_bar_style == 'hidden'
|
||||
self.tabs = []
|
||||
self.active_tab_history = deque()
|
||||
self.tab_bar = TabBar(self.os_window_id, opts)
|
||||
@ -395,7 +396,8 @@ class TabManager: # {{{
|
||||
w.focus_changed(True)
|
||||
|
||||
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):
|
||||
before = len(self.tabs)
|
||||
@ -415,12 +417,13 @@ class TabManager: # {{{
|
||||
set_active_tab(self.os_window_id, idx)
|
||||
|
||||
def tabbar_visibility_changed(self):
|
||||
self.tab_bar.layout()
|
||||
self.resize(only_tabs=True)
|
||||
glfw_post_empty_event()
|
||||
if not self.tab_bar_hidden:
|
||||
self.tab_bar.layout()
|
||||
self.resize(only_tabs=True)
|
||||
glfw_post_empty_event()
|
||||
|
||||
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)
|
||||
|
||||
def update_tab_bar_data(self):
|
||||
@ -428,8 +431,9 @@ class TabManager: # {{{
|
||||
|
||||
def resize(self, only_tabs=False):
|
||||
if not only_tabs:
|
||||
self.tab_bar.layout()
|
||||
self.mark_tab_bar_dirty()
|
||||
if not self.tab_bar_hidden:
|
||||
self.tab_bar.layout()
|
||||
self.mark_tab_bar_dirty()
|
||||
for tab in self.tabs:
|
||||
tab.relayout()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user