Move logical DPI calculation into glfw module
Now DPI state is maintained in only one central place.
This commit is contained in:
parent
c7e1a12eb6
commit
684a2e05f4
7 changed files with 70 additions and 62 deletions
|
|
@ -7,7 +7,7 @@
|
||||||
from functools import partial as p
|
from functools import partial as p
|
||||||
from itertools import repeat
|
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)
|
scale = (0.001, 1, 1.5, 2)
|
||||||
|
|
||||||
|
|
@ -18,9 +18,8 @@ def set_scale(new_scale):
|
||||||
|
|
||||||
|
|
||||||
def thickness(level=1, horizontal=True):
|
def thickness(level=1, horizontal=True):
|
||||||
dpi = get_logical_dpi()[0 if horizontal else 1]
|
|
||||||
pts = scale[level]
|
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):
|
def draw_hline(buf, width, x1, x2, y, level):
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,6 @@ def render_box_drawing(codepoint):
|
||||||
|
|
||||||
|
|
||||||
def setup_for_testing(family='monospace', size=11.0, dpi=96.0):
|
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)
|
opts = defaults._replace(font_family=family)
|
||||||
set_options(opts)
|
set_options(opts)
|
||||||
sprites = {}
|
sprites = {}
|
||||||
|
|
@ -181,7 +180,6 @@ def send_to_gpu(x, y, z, data):
|
||||||
sprite_map_set_limits(100000, 100)
|
sprite_map_set_limits(100000, 100)
|
||||||
set_send_sprite_to_gpu(send_to_gpu)
|
set_send_sprite_to_gpu(send_to_gpu)
|
||||||
set_logical_dpi(dpi, dpi)
|
set_logical_dpi(dpi, dpi)
|
||||||
get_logical_dpi((dpi, dpi))
|
|
||||||
cell_width, cell_height = set_font_family(opts, override_font_size=size)
|
cell_width, cell_height = set_font_family(opts, override_font_size=size)
|
||||||
prerender()
|
prerender()
|
||||||
return sprites, cell_width, cell_height
|
return sprites, cell_width, cell_height
|
||||||
|
|
|
||||||
90
kitty/glfw.c
90
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*
|
static PyObject*
|
||||||
create_os_window(PyObject UNUSED *self, PyObject *args) {
|
create_os_window(PyObject UNUSED *self, PyObject *args) {
|
||||||
int width, height, visible = 1, swap_interval = 0, x = -1, y = -1;
|
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;
|
current_os_window_ctx = glfw_window;
|
||||||
glfwSwapInterval(swap_interval); // a value of 1 makes mouse selection laggy
|
glfwSwapInterval(swap_interval); // a value of 1 makes mouse selection laggy
|
||||||
if (is_first_window) {
|
if (is_first_window) {
|
||||||
|
set_dpi_from_window(NULL);
|
||||||
gl_init();
|
gl_init();
|
||||||
PyObject *ret = PyObject_CallFunction(load_programs, "i", glfwGetWindowAttrib(glfw_window, GLFW_TRANSPARENT_FRAMEBUFFER));
|
PyObject *ret = PyObject_CallFunction(load_programs, "i", glfwGetWindowAttrib(glfw_window, GLFW_TRANSPARENT_FRAMEBUFFER));
|
||||||
if (ret == NULL) return NULL;
|
if (ret == NULL) return NULL;
|
||||||
|
|
@ -443,41 +498,6 @@ set_clipboard_string(PyObject UNUSED *self, PyObject *args) {
|
||||||
Py_RETURN_NONE;
|
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*
|
static PyObject*
|
||||||
toggle_fullscreen(PyObject UNUSED *self) {
|
toggle_fullscreen(PyObject UNUSED *self) {
|
||||||
GLFWmonitor *monitor;
|
GLFWmonitor *monitor;
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,11 @@
|
||||||
from .constants import glfw_path, is_macos, is_wayland, logo_data_file
|
from .constants import glfw_path, is_macos, is_wayland, logo_data_file
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
change_wcwidth, create_os_window, glfw_init, glfw_terminate,
|
change_wcwidth, create_os_window, glfw_init, glfw_terminate,
|
||||||
install_sigchld_handler, set_default_window_icon, set_logical_dpi,
|
install_sigchld_handler, set_default_window_icon, set_options, show_window
|
||||||
set_options, show_window
|
|
||||||
)
|
)
|
||||||
from .fonts.box_drawing import set_scale
|
from .fonts.box_drawing import set_scale
|
||||||
from .utils import (
|
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
|
init_startup_notification, single_instance
|
||||||
)
|
)
|
||||||
from .window import load_shader_programs
|
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
|
if not is_wayland and not is_macos: # no window icons on wayland
|
||||||
with open(logo_data_file, 'rb') as f:
|
with open(logo_data_file, 'rb') as f:
|
||||||
set_default_window_icon(f.read(), 256, 256)
|
set_default_window_icon(f.read(), 256, 256)
|
||||||
set_logical_dpi(*get_logical_dpi())
|
|
||||||
boss = Boss(window_id, opts, args)
|
boss = Boss(window_id, opts, args)
|
||||||
boss.start()
|
boss.start()
|
||||||
end_startup_notification(startup_ctx)
|
end_startup_notification(startup_ctx)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
GlobalState global_state = {{0}};
|
GlobalState global_state = {{0}};
|
||||||
|
|
||||||
|
|
@ -424,7 +425,13 @@ PYWRAP1(set_logical_dpi) {
|
||||||
PYWRAP1(pt_to_px) {
|
PYWRAP1(pt_to_px) {
|
||||||
long pt = PyLong_AsLong(args);
|
long pt = PyLong_AsLong(args);
|
||||||
double dpi = (global_state.logical_dpi_x + global_state.logical_dpi_y) / 2.f;
|
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(handle_for_window_id, METH_VARARGS),
|
||||||
MW(set_logical_dpi, METH_VARARGS),
|
MW(set_logical_dpi, METH_VARARGS),
|
||||||
MW(pt_to_px, METH_O),
|
MW(pt_to_px, METH_O),
|
||||||
|
MW(pt_to_px_ceil, METH_O),
|
||||||
MW(add_tab, METH_O),
|
MW(add_tab, METH_O),
|
||||||
MW(add_window, METH_VARARGS),
|
MW(add_window, METH_VARARGS),
|
||||||
MW(update_window_title, METH_VARARGS),
|
MW(update_window_title, METH_VARARGS),
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
from .constants import appname, is_macos, is_wayland
|
from .constants import appname, is_macos, is_wayland
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
GLSL_VERSION, glfw_primary_monitor_content_scale,
|
GLSL_VERSION, redirect_std_streams, wcwidth as wcwidth_impl, x11_display,
|
||||||
redirect_std_streams, wcwidth as wcwidth_impl, x11_display, x11_window_id
|
x11_window_id
|
||||||
)
|
)
|
||||||
from .rgb import Color, to_color
|
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))
|
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):
|
def color_as_int(val):
|
||||||
return val[0] << 16 | val[1] << 8 | val[2]
|
return val[0] << 16 | val[1] << 8 | val[2]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
from kitty.fonts.render import (
|
from kitty.fonts.render import (
|
||||||
prerender, render_string, set_font_family, shape_string
|
prerender, render_string, set_font_family, shape_string
|
||||||
)
|
)
|
||||||
from kitty.utils import get_logical_dpi
|
|
||||||
|
|
||||||
from . import BaseTest
|
from . import BaseTest
|
||||||
|
|
||||||
|
|
@ -30,7 +29,6 @@ def send_to_gpu(x, y, z, data):
|
||||||
|
|
||||||
set_send_sprite_to_gpu(send_to_gpu)
|
set_send_sprite_to_gpu(send_to_gpu)
|
||||||
set_logical_dpi(96.0, 96.0)
|
set_logical_dpi(96.0, 96.0)
|
||||||
get_logical_dpi((96.0, 96.0))
|
|
||||||
self.cell_width, self.cell_height = set_font_family()
|
self.cell_width, self.cell_height = set_font_family()
|
||||||
prerender()
|
prerender()
|
||||||
self.assertEqual([k[0] for k in self.sprites], [0, 1, 2, 3, 4, 5])
|
self.assertEqual([k[0] for k in self.sprites], [0, 1, 2, 3, 4, 5])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue