mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-24 01:08:10 +02:00
Wayland: map first window at correct size with fractional scaling
The first OS window on Wayland is created at scale 1 because the compositor only sends the fractional scale after the surface exists. The initial size in cells is therefore computed with scale-1 cell metrics and the window is mapped a few cells too small. The existing post-map recompute calls glfwSetWindowSize(), but on Wayland that loses to the compositor's authoritative configure, which re-asserts the size it recorded at map time. So a window that receives focus (the normal interactive case) stays too small; a background window that never gets an activated configure happens to keep the resized value, which is why it can look fixed. Correct the size while the window is still unmapped instead. GLFW gains a hook (glfwWaylandSetInitialWindowSizeCallback) that it invokes when the fractional scale is applied during creation -- mutter, kwin and niri send the scale before the first configure -- letting the embedder recompute the cell-based logical size for the real scale before the window is mapped. The compositor then records the correct size and its activation configure agrees, so there is nothing to race. The existing post-map recompute is kept as a fallback for compositors that only send the scale after the first configure (sway, Hyprland). Also add glfwCocoaSetWindowLevel to the glfw.py wrapper generator list: it was present in the committed glfw-wrapper but missing from the generator, so regenerating the wrapper (required to add the hook above) would otherwise drop it and break the macOS build.
This commit is contained in:
@@ -318,6 +318,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
void glfwCocoaSetWindowChrome(GLFWwindow* window, unsigned int color, bool use_system_color, unsigned int system_color,\
|
||||
int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable)
|
||||
void glfwCocoaRegisterMIMETypes(GLFWwindow *window, const char **mimes, size_t count)
|
||||
void glfwCocoaSetWindowLevel(GLFWwindow *window, const char *level_spec)
|
||||
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
|
||||
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
|
||||
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
|
||||
@@ -326,6 +327,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
void glfwWaylandRunWithActivationToken(GLFWwindow *handle, GLFWactivationcallback cb, void *cb_data)
|
||||
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
|
||||
void glfwWaylandSetTitlebarHidden(GLFWwindow *handle, bool hidden)
|
||||
void glfwWaylandSetInitialWindowSizeCallback(GLFWwaylandinitialsizefun callback)
|
||||
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
|
||||
bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle)
|
||||
bool glfwWaylandBeep(GLFWwindow *handle)
|
||||
|
||||
1
glfw/glfw3.h
vendored
1
glfw/glfw3.h
vendored
@@ -1933,6 +1933,7 @@ typedef void (* GLFWjoystickfun)(int,int);
|
||||
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
||||
typedef void (* GLFWtickcallback)(void*);
|
||||
typedef void (* GLFWactivationcallback)(GLFWwindow *window, const char *token, void *data);
|
||||
typedef void (* GLFWwaylandinitialsizefun)(GLFWwindow *window, float xscale, float yscale, int *width, int *height);
|
||||
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);
|
||||
typedef char* (* GLFWcurrentselectionfun)(void);
|
||||
typedef bool (* GLFWhascurrentselectionfun)(void);
|
||||
|
||||
33
glfw/wl_window.c
vendored
33
glfw/wl_window.c
vendored
@@ -440,8 +440,41 @@ clipboard_mime(void) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static GLFWwaylandinitialsizefun initial_window_size_callback = NULL;
|
||||
|
||||
GLFWAPI void
|
||||
glfwWaylandSetInitialWindowSizeCallback(GLFWwaylandinitialsizefun callback) {
|
||||
initial_window_size_callback = callback;
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_recompute_initial_window_size(_GLFWwindow *window) {
|
||||
// Before the initial window is mapped, the compositor tells us the real
|
||||
// (possibly fractional) scale. For sizes specified in cells this changes
|
||||
// the correct logical window size, because cell metrics are not a linear
|
||||
// function of scale (integer-pixel rounding). Ask the embedder to recompute
|
||||
// the logical size now, while the window is still unmapped, so it is mapped
|
||||
// at the right size and the compositor's authoritative configure agrees.
|
||||
if (window->wl.window_fully_created) return;
|
||||
if (!initial_window_size_callback) return;
|
||||
if (!window->wl.xdg.toplevel) return; // only ordinary toplevels have cell-based sizes
|
||||
if (window->wl.layer_shell.zwlr_layer_surface_v1) return; // layer-shell surfaces size themselves
|
||||
double scale = _glfwWaylandWindowScale(window);
|
||||
int w = window->wl.width, h = window->wl.height;
|
||||
initial_window_size_callback((GLFWwindow*)window, (float)scale, (float)scale, &w, &h);
|
||||
if (w > 0 && h > 0 && (w != window->wl.width || h != window->wl.height)) {
|
||||
debug("Recomputed initial size of window %llu for scale %.3f: %dx%d -> %dx%d\n",
|
||||
window->id, scale, window->wl.width, window->wl.height, w, h);
|
||||
window->wl.width = w; window->wl.height = h;
|
||||
window->wl.user_requested_content_size.width = w;
|
||||
window->wl.user_requested_content_size.height = h;
|
||||
update_regions(window);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
apply_scale_changes(_GLFWwindow *window, bool resize_framebuffer, bool update_csd) {
|
||||
maybe_recompute_initial_window_size(window);
|
||||
double scale = _glfwWaylandWindowScale(window);
|
||||
if (resize_framebuffer) resizeFramebuffer(window);
|
||||
_glfwInputWindowContentScale(window, (float)scale, (float)scale);
|
||||
|
||||
Reference in New Issue
Block a user