From 684a2e05f42011b6e5a055eebaa178c9aaaaeff5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 14 Dec 2017 18:30:53 +0530 Subject: [PATCH] Move logical DPI calculation into glfw module Now DPI state is maintained in only one central place. --- kitty/fonts/box_drawing.py | 5 +-- kitty/fonts/render.py | 2 - kitty/glfw.c | 90 +++++++++++++++++++++++--------------- kitty/main.py | 6 +-- kitty/state.c | 10 ++++- kitty/utils.py | 17 +------ kitty_tests/fonts.py | 2 - 7 files changed, 70 insertions(+), 62 deletions(-) diff --git a/kitty/fonts/box_drawing.py b/kitty/fonts/box_drawing.py index 5ef073ded..0ed5ed5b5 100644 --- a/kitty/fonts/box_drawing.py +++ b/kitty/fonts/box_drawing.py @@ -7,7 +7,7 @@ import os from functools import partial as p from itertools import repeat -from kitty.utils import get_logical_dpi +from kitty.fast_data_types import pt_to_px_ceil scale = (0.001, 1, 1.5, 2) @@ -18,9 +18,8 @@ def set_scale(new_scale): def thickness(level=1, horizontal=True): - dpi = get_logical_dpi()[0 if horizontal else 1] pts = scale[level] - return int(math.ceil(pts * dpi / 72.0)) + return pt_to_px_ceil(pts) def draw_hline(buf, width, x1, x2, y, level): diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index 0ee85254f..839f733d2 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -170,7 +170,6 @@ def render_box_drawing(codepoint): def setup_for_testing(family='monospace', size=11.0, dpi=96.0): - from kitty.utils import get_logical_dpi opts = defaults._replace(font_family=family) set_options(opts) sprites = {} @@ -181,7 +180,6 @@ def setup_for_testing(family='monospace', size=11.0, dpi=96.0): sprite_map_set_limits(100000, 100) set_send_sprite_to_gpu(send_to_gpu) set_logical_dpi(dpi, dpi) - get_logical_dpi((dpi, dpi)) cell_width, cell_height = set_font_family(opts, override_font_size=size) prerender() return sprites, cell_width, cell_height diff --git a/kitty/glfw.c b/kitty/glfw.c index 1cf7f37b5..c7a8ef086 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -209,6 +209,60 @@ make_os_window_context_current(OSWindow *w) { } } + +static GLFWmonitor* +current_monitor(GLFWwindow *window) { + // Find the monitor that has the maximum overlap with this window + int nmonitors, i; + int wx, wy, ww, wh; + int mx, my, mw, mh; + int overlap = 0, bestoverlap = 0; + GLFWmonitor *bestmonitor = NULL; + GLFWmonitor **monitors = NULL; + const GLFWvidmode *mode; + + glfwGetWindowPos(window, &wx, &wy); + glfwGetWindowSize(window, &ww, &wh); + monitors = glfwGetMonitors(&nmonitors); + if (monitors == NULL || nmonitors < 1) { PyErr_SetString(PyExc_ValueError, "No monitors connected"); return NULL; } + + for (i = 0; i < nmonitors; i++) { + mode = glfwGetVideoMode(monitors[i]); + glfwGetMonitorPos(monitors[i], &mx, &my); + mw = mode->width; + mh = mode->height; + + overlap = + MAX(0, MIN(wx + ww, mx + mw) - MAX(wx, mx)) * + MAX(0, MIN(wy + wh, my + mh) - MAX(wy, my)); + + if (bestoverlap < overlap || bestmonitor == NULL) { + bestoverlap = overlap; + bestmonitor = monitors[i]; + } + } + + return bestmonitor; +} + + +static inline void +set_dpi_from_window(OSWindow *w) { + GLFWmonitor *monitor = NULL; + if (w) { monitor = current_monitor(w->handle); } + if (monitor == NULL) monitor = glfwGetPrimaryMonitor(); + float xscale = 1, yscale = 1; + if (monitor) glfwGetMonitorContentScale(monitor, &xscale, &yscale); +#ifdef __APPLE__ + double factor = 72.0; +#else + double factor = 96.0; +#endif + global_state.logical_dpi_x = xscale * factor; + global_state.logical_dpi_y = yscale * factor; +} + + static PyObject* create_os_window(PyObject UNUSED *self, PyObject *args) { int width, height, visible = 1, swap_interval = 0, x = -1, y = -1; @@ -256,6 +310,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) { current_os_window_ctx = glfw_window; glfwSwapInterval(swap_interval); // a value of 1 makes mouse selection laggy if (is_first_window) { + set_dpi_from_window(NULL); gl_init(); PyObject *ret = PyObject_CallFunction(load_programs, "i", glfwGetWindowAttrib(glfw_window, GLFW_TRANSPARENT_FRAMEBUFFER)); if (ret == NULL) return NULL; @@ -443,41 +498,6 @@ set_clipboard_string(PyObject UNUSED *self, PyObject *args) { Py_RETURN_NONE; } -static GLFWmonitor* -current_monitor(GLFWwindow *window) { - // Find the monitor that has the maximum overlap with this window - int nmonitors, i; - int wx, wy, ww, wh; - int mx, my, mw, mh; - int overlap = 0, bestoverlap = 0; - GLFWmonitor *bestmonitor = NULL; - GLFWmonitor **monitors = NULL; - const GLFWvidmode *mode; - - glfwGetWindowPos(window, &wx, &wy); - glfwGetWindowSize(window, &ww, &wh); - monitors = glfwGetMonitors(&nmonitors); - if (monitors == NULL || nmonitors < 1) { PyErr_SetString(PyExc_ValueError, "No monitors connected"); return NULL; } - - for (i = 0; i < nmonitors; i++) { - mode = glfwGetVideoMode(monitors[i]); - glfwGetMonitorPos(monitors[i], &mx, &my); - mw = mode->width; - mh = mode->height; - - overlap = - MAX(0, MIN(wx + ww, mx + mw) - MAX(wx, mx)) * - MAX(0, MIN(wy + wh, my + mh) - MAX(wy, my)); - - if (bestoverlap < overlap || bestmonitor == NULL) { - bestoverlap = overlap; - bestmonitor = monitors[i]; - } - } - - return bestmonitor; -} - static PyObject* toggle_fullscreen(PyObject UNUSED *self) { GLFWmonitor *monitor; diff --git a/kitty/main.py b/kitty/main.py index 94df039c2..4d72b2131 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -15,12 +15,11 @@ from .config import initial_window_size, load_cached_values, save_cached_values from .constants import glfw_path, is_macos, is_wayland, logo_data_file from .fast_data_types import ( change_wcwidth, create_os_window, glfw_init, glfw_terminate, - install_sigchld_handler, set_default_window_icon, set_logical_dpi, - set_options, show_window + install_sigchld_handler, set_default_window_icon, set_options, show_window ) from .fonts.box_drawing import set_scale from .utils import ( - detach, encode_wm_class, end_startup_notification, get_logical_dpi, + detach, encode_wm_class, end_startup_notification, init_startup_notification, single_instance ) from .window import load_shader_programs @@ -49,7 +48,6 @@ def run_app(opts, args): if not is_wayland and not is_macos: # no window icons on wayland with open(logo_data_file, 'rb') as f: set_default_window_icon(f.read(), 256, 256) - set_logical_dpi(*get_logical_dpi()) boss = Boss(window_id, opts, args) boss.start() end_startup_notification(startup_ctx) diff --git a/kitty/state.c b/kitty/state.c index 6d74c5e1c..59b85fdf9 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -6,6 +6,7 @@ */ #include "state.h" +#include GlobalState global_state = {{0}}; @@ -424,7 +425,13 @@ PYWRAP1(set_logical_dpi) { PYWRAP1(pt_to_px) { long pt = PyLong_AsLong(args); double dpi = (global_state.logical_dpi_x + global_state.logical_dpi_y) / 2.f; - return PyLong_FromLong((long)(pt * (dpi / 72.0))); + return PyLong_FromLong((long)round((pt * (dpi / 72.0)))); +} + +PYWRAP1(pt_to_px_ceil) { + long pt = PyLong_AsLong(args); + double dpi = (global_state.logical_dpi_x + global_state.logical_dpi_y) / 2.f; + return PyLong_FromLong((long)ceil((pt * (dpi / 72.0)))); } @@ -468,6 +475,7 @@ static PyMethodDef module_methods[] = { MW(handle_for_window_id, METH_VARARGS), MW(set_logical_dpi, METH_VARARGS), MW(pt_to_px, METH_O), + MW(pt_to_px_ceil, METH_O), MW(add_tab, METH_O), MW(add_window, METH_VARARGS), MW(update_window_title, METH_VARARGS), diff --git a/kitty/utils.py b/kitty/utils.py index 27b825eb5..a018af262 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -19,8 +19,8 @@ from time import monotonic from .constants import appname, is_macos, is_wayland from .fast_data_types import ( - GLSL_VERSION, glfw_primary_monitor_content_scale, - redirect_std_streams, wcwidth as wcwidth_impl, x11_display, x11_window_id + GLSL_VERSION, redirect_std_streams, wcwidth as wcwidth_impl, x11_display, + x11_window_id ) from .rgb import Color, to_color @@ -65,19 +65,6 @@ def sanitize_title(x): return re.sub(r'\s+', ' ', re.sub(r'[\0-\x19]', '', x)) -def get_logical_dpi(override_dpi=None): - # See https://github.com/glfw/glfw/issues/1019 for why we cant use - # glfw_get_physical_dpi() - if override_dpi is not None: - get_logical_dpi.ans = override_dpi - if not hasattr(get_logical_dpi, 'ans'): - factor = 72.0 if is_macos else 96.0 - xscale, yscale = glfw_primary_monitor_content_scale() - xdpi, ydpi = xscale * factor, yscale * factor - get_logical_dpi.ans = xdpi, ydpi - return get_logical_dpi.ans - - def color_as_int(val): return val[0] << 16 | val[1] << 8 | val[2] diff --git a/kitty_tests/fonts.py b/kitty_tests/fonts.py index 335e9a867..d2d6c8eae 100644 --- a/kitty_tests/fonts.py +++ b/kitty_tests/fonts.py @@ -14,7 +14,6 @@ from kitty.fonts.box_drawing import box_chars from kitty.fonts.render import ( prerender, render_string, set_font_family, shape_string ) -from kitty.utils import get_logical_dpi from . import BaseTest @@ -30,7 +29,6 @@ class Rendering(BaseTest): set_send_sprite_to_gpu(send_to_gpu) set_logical_dpi(96.0, 96.0) - get_logical_dpi((96.0, 96.0)) self.cell_width, self.cell_height = set_font_family() prerender() self.assertEqual([k[0] for k in self.sprites], [0, 1, 2, 3, 4, 5])