Skip to content

Commit 0e38ca2

Browse files
committed
Merge branch 'wayland-initial-window-size' of https://github.com/egnor/kitty
2 parents 5b4ea1b + db14d7c commit 0e38ca2

6 files changed

Lines changed: 86 additions & 7 deletions

File tree

glfw/glfw.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ def generate_wrappers(glfw_header: str) -> None:
318318
void glfwCocoaSetWindowChrome(GLFWwindow* window, unsigned int color, bool use_system_color, unsigned int system_color,\
319319
int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable)
320320
void glfwCocoaRegisterMIMETypes(GLFWwindow *window, const char **mimes, size_t count)
321+
void glfwCocoaSetWindowLevel(GLFWwindow *window, const char *level_spec)
321322
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
322323
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
323324
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
@@ -326,6 +327,7 @@ def generate_wrappers(glfw_header: str) -> None:
326327
void glfwWaylandRunWithActivationToken(GLFWwindow *handle, GLFWactivationcallback cb, void *cb_data)
327328
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
328329
void glfwWaylandSetTitlebarHidden(GLFWwindow *handle, bool hidden)
330+
void glfwWaylandSetInitialWindowSizeCallback(GLFWwaylandinitialsizefun callback)
329331
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
330332
bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle)
331333
bool glfwWaylandBeep(GLFWwindow *handle)

glfw/glfw3.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,7 @@ typedef void (* GLFWjoystickfun)(int,int);
19331933
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
19341934
typedef void (* GLFWtickcallback)(void*);
19351935
typedef void (* GLFWactivationcallback)(GLFWwindow *window, const char *token, void *data);
1936+
typedef void (* GLFWwaylandinitialsizefun)(GLFWwindow *window, float xscale, float yscale, int *width, int *height);
19361937
typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin, bool is_single_glyph);
19371938
typedef char* (* GLFWcurrentselectionfun)(void);
19381939
typedef bool (* GLFWhascurrentselectionfun)(void);

glfw/wl_window.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,41 @@ clipboard_mime(void) {
440440
return buf;
441441
}
442442

443+
static GLFWwaylandinitialsizefun initial_window_size_callback = NULL;
444+
445+
GLFWAPI void
446+
glfwWaylandSetInitialWindowSizeCallback(GLFWwaylandinitialsizefun callback) {
447+
initial_window_size_callback = callback;
448+
}
449+
450+
static void
451+
maybe_recompute_initial_window_size(_GLFWwindow *window) {
452+
// Before the initial window is mapped, the compositor tells us the real
453+
// (possibly fractional) scale. For sizes specified in cells this changes
454+
// the correct logical window size, because cell metrics are not a linear
455+
// function of scale (integer-pixel rounding). Ask the embedder to recompute
456+
// the logical size now, while the window is still unmapped, so it is mapped
457+
// at the right size and the compositor's authoritative configure agrees.
458+
if (window->wl.window_fully_created) return;
459+
if (!initial_window_size_callback) return;
460+
if (!window->wl.xdg.toplevel) return; // only ordinary toplevels have cell-based sizes
461+
if (window->wl.layer_shell.zwlr_layer_surface_v1) return; // layer-shell surfaces size themselves
462+
double scale = _glfwWaylandWindowScale(window);
463+
int w = window->wl.width, h = window->wl.height;
464+
initial_window_size_callback((GLFWwindow*)window, (float)scale, (float)scale, &w, &h);
465+
if (w > 0 && h > 0 && (w != window->wl.width || h != window->wl.height)) {
466+
debug("Recomputed initial size of window %llu for scale %.3f: %dx%d -> %dx%d\n",
467+
window->id, scale, window->wl.width, window->wl.height, w, h);
468+
window->wl.width = w; window->wl.height = h;
469+
window->wl.user_requested_content_size.width = w;
470+
window->wl.user_requested_content_size.height = h;
471+
update_regions(window);
472+
}
473+
}
474+
443475
static void
444476
apply_scale_changes(_GLFWwindow *window, bool resize_framebuffer, bool update_csd) {
477+
maybe_recompute_initial_window_size(window);
445478
double scale = _glfwWaylandWindowScale(window);
446479
if (resize_framebuffer) resizeFramebuffer(window);
447480
_glfwInputWindowContentScale(window, (float)scale, (float)scale);

kitty/glfw-wrapper.c

Lines changed: 6 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kitty/glfw-wrapper.h

Lines changed: 9 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kitty/glfw.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,32 @@ os_window_update_size_increments(OSWindow *window) {
17051705
}
17061706

17071707

1708+
// Borrowed reference to the get_window_size callable, valid only for the
1709+
// duration of a create_os_window() call. Used by the Wayland initial-size hook
1710+
// below, which fires synchronously from inside glfwCreateWindow().
1711+
static PyObject *initial_window_size_py_callback = NULL;
1712+
1713+
static void
1714+
wayland_initial_size_callback(GLFWwindow *window UNUSED, float xscale, float yscale, int *width, int *height) {
1715+
// The compositor has told us the real scale before the window is mapped;
1716+
// recompute the cell-based logical size for that scale so the window is
1717+
// mapped at the correct size in the first place.
1718+
if (!initial_window_size_py_callback) return;
1719+
double xdpi, ydpi;
1720+
dpi_from_scale(xscale, yscale, &xdpi, &ydpi);
1721+
FONTS_DATA_HANDLE fonts_data = load_fonts_data(OPT(font_size), xdpi, ydpi);
1722+
if (!fonts_data) return;
1723+
PyObject *ret = PyObject_CallFunction(initial_window_size_py_callback, "IIddff",
1724+
fonts_data->fcm.cell_width, fonts_data->fcm.cell_height,
1725+
fonts_data->logical_dpi_x, fonts_data->logical_dpi_y, xscale, yscale);
1726+
if (ret) {
1727+
int w = PyLong_AsLong(PyTuple_GET_ITEM(ret, 0)), h = PyLong_AsLong(PyTuple_GET_ITEM(ret, 1));
1728+
if (!PyErr_Occurred() && w > 0 && h > 0) { *width = w; *height = h; }
1729+
else PyErr_Clear();
1730+
Py_DECREF(ret);
1731+
} else PyErr_Clear();
1732+
}
1733+
17081734
static PyObject*
17091735
create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
17101736
int x = INT_MIN, y = INT_MIN, window_state = WINDOW_NORMAL, disallow_override_title = 0;
@@ -1822,7 +1848,16 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
18221848
if (!layer_shell_config_from_python(layer_shell_config, lsc)) return NULL;
18231849
lsc->expected.xscale = xscale; lsc->expected.yscale = yscale;
18241850
}
1851+
// On Wayland the true (fractional) scale is only known after the surface
1852+
// exists. Register a hook so the window is mapped at the correct cell-based
1853+
// size once the compositor reveals the scale, rather than being resized
1854+
// afterwards (which loses to the compositor's authoritative configure).
1855+
if (global_state.is_wayland && glfwWaylandSetInitialWindowSizeCallback) {
1856+
glfwWaylandSetInitialWindowSizeCallback(wayland_initial_size_callback);
1857+
initial_window_size_py_callback = get_window_size;
1858+
}
18251859
GLFWwindow *glfw_window = glfwCreateWindow(width, height, title, NULL, temp_window ? temp_window : common_context, lsc);
1860+
initial_window_size_py_callback = NULL;
18261861
if (temp_window) { glfwDestroyWindow(temp_window); temp_window = NULL; }
18271862
if (glfw_window == NULL) glfw_failure;
18281863
#undef glfw_failure

0 commit comments

Comments
 (0)