mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-04 14:46:03 +00:00
Wayland: get initial window size in cells working in most cases on hyprland/sway with fractional scaling by using the fractional scale of the primary monitor
This commit is contained in:
parent
a7d7183681
commit
6ed833e163
9 changed files with 163 additions and 13 deletions
|
|
@ -186,6 +186,9 @@ Detailed list of changes
|
|||
|
||||
- Wayland: fix a regression in 0.47.3 that broke dragging on the Niri compositor (:iss:`10271`)
|
||||
|
||||
- Wayland: get initial window size in cells working in most cases on hyprland/sway with fractional scaling by using the fractional scale of the primary monitor
|
||||
|
||||
|
||||
0.48.0 [2026-07-18]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
|||
bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle)
|
||||
bool glfwWaylandBeep(GLFWwindow *handle)
|
||||
pid_t glfwWaylandCompositorPID(void)
|
||||
double glfwGetWaylandPrimaryMonitorFractionalScale(void)
|
||||
void glfwConfigureMomentumScroller(double friction, double min_velocity, double max_velocity, unsigned timer_interval)
|
||||
unsigned long long glfwDBusUserNotify(const GLFWDBUSNotificationData *n, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@
|
|||
"staging/ext-background-effect/ext-background-effect-v1.xml",
|
||||
"staging/xdg-toplevel-drag/xdg-toplevel-drag-v1.xml",
|
||||
"unstable/pointer-gestures/pointer-gestures-unstable-v1.xml",
|
||||
"unstable/xdg-output/xdg-output-unstable-v1.xml",
|
||||
|
||||
"kwin-blur-v1.xml",
|
||||
"wlr-layer-shell-unstable-v1.xml"
|
||||
|
|
|
|||
8
glfw/wl_init.c
vendored
8
glfw/wl_init.c
vendored
|
|
@ -728,6 +728,10 @@ static void registryHandleGlobal(void* data UNUSED,
|
|||
_glfw.wl.xdg_toplevel_tag_manager_v1 = wl_registry_bind(registry, name, &xdg_toplevel_tag_manager_v1_interface, 1);
|
||||
} else if (is(xdg_toplevel_drag_manager_v1)) {
|
||||
_glfw.wl.xdg_toplevel_drag_manager_v1 = wl_registry_bind(registry, name, &xdg_toplevel_drag_manager_v1_interface, 1);
|
||||
} else if (is(zxdg_output_manager_v1)) {
|
||||
_glfw.wl.xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, MIN(version, 3u));
|
||||
for (int i = 0; i < _glfw.monitorCount; i++)
|
||||
_glfwCreateXdgOutputWayland(_glfw.monitors[i]);
|
||||
}
|
||||
#undef is
|
||||
}
|
||||
|
|
@ -840,7 +844,7 @@ get_compositor_missing_capabilities(void) {
|
|||
C(single_pixel_buffer, wp_single_pixel_buffer_manager_v1); C(preferred_scale, has_preferred_buffer_scale);
|
||||
C(idle_inhibit, idle_inhibit_manager); C(icon, xdg_toplevel_icon_manager_v1); C(bell, xdg_system_bell_v1);
|
||||
C(window-tag, xdg_toplevel_tag_manager_v1); C(keyboard_shortcuts_inhibit, keyboard_shortcuts_inhibit_manager);
|
||||
C(key-repeat, has_key_repeat_events); C(top_level_drag, xdg_toplevel_drag_manager_v1);
|
||||
C(key-repeat, has_key_repeat_events); C(top_level_drag, xdg_toplevel_drag_manager_v1); C(output_manager, xdg_output_manager);
|
||||
C(pointer_gestures, pointer_gestures);
|
||||
#define P(x) p += snprintf(p, sizeof(buf) - (p - buf), "%s ", x);
|
||||
if (_glfw.wl.xdg_wm_base_version < 6) P("window-state-suspended");
|
||||
|
|
@ -1031,6 +1035,8 @@ void _glfwPlatformTerminate(void)
|
|||
xdg_toplevel_tag_manager_v1_destroy(_glfw.wl.xdg_toplevel_tag_manager_v1);
|
||||
if (_glfw.wl.xdg_toplevel_drag_manager_v1)
|
||||
xdg_toplevel_drag_manager_v1_destroy(_glfw.wl.xdg_toplevel_drag_manager_v1);
|
||||
if (_glfw.wl.xdg_output_manager)
|
||||
zxdg_output_manager_v1_destroy(_glfw.wl.xdg_output_manager);
|
||||
if (_glfw.wl.wp_single_pixel_buffer_manager_v1)
|
||||
wp_single_pixel_buffer_manager_v1_destroy(_glfw.wl.wp_single_pixel_buffer_manager_v1);
|
||||
if (_glfw.wl.wp_cursor_shape_manager_v1)
|
||||
|
|
|
|||
122
glfw/wl_monitor.c
vendored
122
glfw/wl_monitor.c
vendored
|
|
@ -43,13 +43,14 @@ static void outputHandleGeometry(void* data,
|
|||
int32_t subpixel UNUSED,
|
||||
const char* make UNUSED,
|
||||
const char* model UNUSED,
|
||||
int32_t transform UNUSED)
|
||||
int32_t transform)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
monitor->wl.x = x;
|
||||
monitor->wl.y = y;
|
||||
monitor->widthMM = physicalWidth;
|
||||
monitor->heightMM = physicalHeight;
|
||||
monitor->wl.transform = transform;
|
||||
}
|
||||
|
||||
static void outputHandleMode(void* data,
|
||||
|
|
@ -126,10 +127,93 @@ static const struct wl_output_listener outputListener = {
|
|||
};
|
||||
|
||||
|
||||
static void xdgOutputHandleLogicalPosition(void *data,
|
||||
struct zxdg_output_v1 *xdg_output UNUSED,
|
||||
int32_t x,
|
||||
int32_t y)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
monitor->wl.x = x;
|
||||
monitor->wl.y = y;
|
||||
}
|
||||
|
||||
static void xdgOutputHandleLogicalSize(void *data,
|
||||
struct zxdg_output_v1 *xdg_output UNUSED,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
monitor->wl.xdg_logical_width = width;
|
||||
monitor->wl.xdg_logical_height = height;
|
||||
}
|
||||
|
||||
static void computeXdgFractionalScale(struct _GLFWmonitor *monitor)
|
||||
{
|
||||
if (monitor->wl.xdg_logical_width <= 0 || monitor->wl.xdg_logical_height <= 0) return;
|
||||
if (monitor->modeCount == 0 || monitor->wl.currentMode < 0) return;
|
||||
GLFWvidmode *mode = &monitor->modes[monitor->wl.currentMode];
|
||||
if (mode->width <= 0 || mode->height <= 0) return;
|
||||
|
||||
// For 90° and 270° rotations the compositor maps physical width↔height,
|
||||
// so use the swapped axis when dividing by the logical size.
|
||||
int phys_w = mode->width, phys_h = mode->height;
|
||||
int32_t t = monitor->wl.transform;
|
||||
if (t == WL_OUTPUT_TRANSFORM_90 || t == WL_OUTPUT_TRANSFORM_270 ||
|
||||
t == WL_OUTPUT_TRANSFORM_FLIPPED_90 || t == WL_OUTPUT_TRANSFORM_FLIPPED_270)
|
||||
{
|
||||
int tmp = phys_w; phys_w = phys_h; phys_h = tmp;
|
||||
}
|
||||
|
||||
double sx = (double)phys_w / monitor->wl.xdg_logical_width;
|
||||
double sy = (double)phys_h / monitor->wl.xdg_logical_height;
|
||||
// Use the average in case of minor rounding differences between axes.
|
||||
monitor->wl.fractional_scale = (sx + sy) * 0.5;
|
||||
}
|
||||
|
||||
static void xdgOutputHandleDone(void *data,
|
||||
struct zxdg_output_v1 *xdg_output UNUSED)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
computeXdgFractionalScale(monitor);
|
||||
}
|
||||
|
||||
static void xdgOutputHandleName(void *data,
|
||||
struct zxdg_output_v1 *xdg_output UNUSED,
|
||||
const char *name)
|
||||
{
|
||||
// wl_output already provides the name; skip to avoid duplicate frees.
|
||||
(void)data; (void)name;
|
||||
}
|
||||
|
||||
static void xdgOutputHandleDescription(void *data,
|
||||
struct zxdg_output_v1 *xdg_output UNUSED,
|
||||
const char *description)
|
||||
{
|
||||
(void)data; (void)description;
|
||||
}
|
||||
|
||||
static const struct zxdg_output_v1_listener xdgOutputListener = {
|
||||
xdgOutputHandleLogicalPosition,
|
||||
xdgOutputHandleLogicalSize,
|
||||
xdgOutputHandleDone,
|
||||
xdgOutputHandleName,
|
||||
xdgOutputHandleDescription,
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwCreateXdgOutputWayland(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (!_glfw.wl.xdg_output_manager || monitor->wl.xdg_output) return;
|
||||
monitor->wl.xdg_output = zxdg_output_manager_v1_get_xdg_output(
|
||||
_glfw.wl.xdg_output_manager, monitor->wl.output);
|
||||
if (monitor->wl.xdg_output)
|
||||
zxdg_output_v1_add_listener(monitor->wl.xdg_output, &xdgOutputListener, monitor);
|
||||
}
|
||||
|
||||
void _glfwAddOutputWayland(uint32_t name, uint32_t version)
|
||||
{
|
||||
_GLFWmonitor *monitor;
|
||||
|
|
@ -160,6 +244,7 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
|
|||
monitor->wl.name = name;
|
||||
|
||||
wl_output_add_listener(output, &outputListener, monitor);
|
||||
_glfwCreateXdgOutputWayland(monitor);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -169,6 +254,8 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
|
|||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (monitor->wl.xdg_output)
|
||||
zxdg_output_v1_destroy(monitor->wl.xdg_output);
|
||||
if (monitor->wl.output)
|
||||
wl_output_destroy(monitor->wl.output);
|
||||
}
|
||||
|
|
@ -184,10 +271,11 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
|||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
*xscale = (float) monitor->wl.scale;
|
||||
if (yscale)
|
||||
*yscale = (float) monitor->wl.scale;
|
||||
float scale = monitor->wl.fractional_scale > 0.0
|
||||
? (float)monitor->wl.fractional_scale
|
||||
: (float)monitor->wl.scale;
|
||||
if (xscale) *xscale = scale;
|
||||
if (yscale) *yscale = scale;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
||||
|
|
@ -246,3 +334,27 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle)
|
|||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->wl.output;
|
||||
}
|
||||
|
||||
GLFWAPI double glfwGetWaylandPrimaryMonitorFractionalScale(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(1.0);
|
||||
if (!_glfw.wl.xdg_output_manager || _glfw.monitorCount == 0)
|
||||
return 1.0;
|
||||
|
||||
_GLFWmonitor *monitor = _glfw.monitors[0];
|
||||
if (!monitor->wl.xdg_output)
|
||||
return monitor->wl.scale > 0 ? (double)monitor->wl.scale : 1.0;
|
||||
|
||||
// Block until the compositor has delivered xdg_output logical_size.
|
||||
while (monitor->wl.xdg_logical_width <= 0 || monitor->wl.xdg_logical_height <= 0)
|
||||
{
|
||||
if (wl_display_roundtrip(_glfw.wl.display) < 0) break;
|
||||
}
|
||||
|
||||
if (monitor->wl.fractional_scale <= 0.0)
|
||||
computeXdgFractionalScale(monitor);
|
||||
|
||||
return monitor->wl.fractional_scale > 0.0
|
||||
? monitor->wl.fractional_scale
|
||||
: (monitor->wl.scale > 0 ? (double)monitor->wl.scale : 1.0);
|
||||
}
|
||||
|
|
|
|||
9
glfw/wl_platform.h
vendored
9
glfw/wl_platform.h
vendored
|
|
@ -72,6 +72,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
|||
#include "wayland-xdg-system-bell-v1-client-protocol.h"
|
||||
#include "wayland-xdg-toplevel-tag-v1-client-protocol.h"
|
||||
#include "wayland-xdg-toplevel-drag-v1-client-protocol.h"
|
||||
#include "wayland-xdg-output-unstable-v1-client-protocol.h"
|
||||
|
||||
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||
#define _glfw_dlclose(handle) dlclose(handle)
|
||||
|
|
@ -366,6 +367,7 @@ typedef struct _GLFWlibraryWayland
|
|||
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit_manager;
|
||||
struct zwp_pointer_gestures_v1* pointer_gestures;
|
||||
struct zwp_pointer_gesture_hold_v1* pointer_gesture_hold;
|
||||
struct zxdg_output_manager_v1* xdg_output_manager;
|
||||
|
||||
int compositorVersion;
|
||||
int seatVersion;
|
||||
|
|
@ -470,12 +472,18 @@ typedef struct _GLFWlibraryWayland
|
|||
typedef struct _GLFWmonitorWayland
|
||||
{
|
||||
struct wl_output* output;
|
||||
struct zxdg_output_v1* xdg_output;
|
||||
uint32_t name;
|
||||
int currentMode;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int scale;
|
||||
int32_t transform;
|
||||
|
||||
int32_t xdg_logical_width;
|
||||
int32_t xdg_logical_height;
|
||||
double fractional_scale;
|
||||
|
||||
} _GLFWmonitorWayland;
|
||||
|
||||
|
|
@ -496,6 +504,7 @@ typedef struct _GLFWcursorWayland
|
|||
|
||||
|
||||
void _glfwAddOutputWayland(uint32_t name, uint32_t version);
|
||||
void _glfwCreateXdgOutputWayland(_GLFWmonitor* monitor);
|
||||
void _glfwWaylandBeforeBufferSwap(_GLFWwindow *window);
|
||||
void _glfwWaylandAfterBufferSwap(_GLFWwindow *window);
|
||||
void _glfwSetupWaylandDataDevice(void);
|
||||
|
|
|
|||
3
kitty/glfw-wrapper.c
generated
3
kitty/glfw-wrapper.c
generated
|
|
@ -545,6 +545,9 @@ load_glfw(const char* path) {
|
|||
*(void **) (&glfwWaylandCompositorPID_impl) = dlsym(handle, "glfwWaylandCompositorPID");
|
||||
if (glfwWaylandCompositorPID_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
*(void **) (&glfwGetWaylandPrimaryMonitorFractionalScale_impl) = dlsym(handle, "glfwGetWaylandPrimaryMonitorFractionalScale");
|
||||
if (glfwGetWaylandPrimaryMonitorFractionalScale_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
*(void **) (&glfwConfigureMomentumScroller_impl) = dlsym(handle, "glfwConfigureMomentumScroller");
|
||||
if (glfwConfigureMomentumScroller_impl == NULL) dlerror(); // clear error indicator
|
||||
|
||||
|
|
|
|||
4
kitty/glfw-wrapper.h
generated
4
kitty/glfw-wrapper.h
generated
|
|
@ -2544,6 +2544,10 @@ typedef pid_t (*glfwWaylandCompositorPID_func)(void);
|
|||
GFW_EXTERN glfwWaylandCompositorPID_func glfwWaylandCompositorPID_impl;
|
||||
#define glfwWaylandCompositorPID glfwWaylandCompositorPID_impl
|
||||
|
||||
typedef double (*glfwGetWaylandPrimaryMonitorFractionalScale_func)(void);
|
||||
GFW_EXTERN glfwGetWaylandPrimaryMonitorFractionalScale_func glfwGetWaylandPrimaryMonitorFractionalScale_impl;
|
||||
#define glfwGetWaylandPrimaryMonitorFractionalScale glfwGetWaylandPrimaryMonitorFractionalScale_impl
|
||||
|
||||
typedef void (*glfwConfigureMomentumScroller_func)(double, double, double, unsigned);
|
||||
GFW_EXTERN glfwConfigureMomentumScroller_func glfwConfigureMomentumScroller_impl;
|
||||
#define glfwConfigureMomentumScroller glfwConfigureMomentumScroller_impl
|
||||
|
|
|
|||
25
kitty/glfw.c
25
kitty/glfw.c
|
|
@ -1821,13 +1821,24 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
|
|||
float xscale, yscale;
|
||||
double xdpi, ydpi;
|
||||
if (global_state.is_wayland) {
|
||||
// Cannot use temp window on Wayland as scale is only sent by compositor after window is displayed
|
||||
get_window_content_scale(NULL, &xscale, &yscale, &xdpi, &ydpi);
|
||||
for (unsigned i = 0; i < global_state.num_os_windows; i++) {
|
||||
OSWindow *osw = global_state.os_windows + i;
|
||||
if (osw->handle && glfwGetWindowAttrib(osw->handle, GLFW_FOCUSED)) {
|
||||
get_window_content_scale(osw->handle, &xscale, &yscale, &xdpi, &ydpi);
|
||||
break;
|
||||
// Cannot use temp window on Wayland as scale is only sent by compositor after window is displayed.
|
||||
// For the first window, query the xdg-output fractional scale of the primary monitor directly;
|
||||
// this blocks until the compositor has sent size information so we get the true fractional scale
|
||||
// before creating any window.
|
||||
if (is_first_window && glfwGetWaylandPrimaryMonitorFractionalScale) {
|
||||
debug_rendering("Querying Wayland compositor for primary monitor scale\n");
|
||||
double fscale = glfwGetWaylandPrimaryMonitorFractionalScale();
|
||||
debug_rendering("Primary monitor scale reported as: %.5f\n", fscale);
|
||||
xscale = yscale = (float)fscale;
|
||||
dpi_from_scale(xscale, yscale, &xdpi, &ydpi);
|
||||
} else {
|
||||
get_window_content_scale(NULL, &xscale, &yscale, &xdpi, &ydpi);
|
||||
for (unsigned i = 0; i < global_state.num_os_windows; i++) {
|
||||
OSWindow *osw = global_state.os_windows + i;
|
||||
if (osw->handle && glfwGetWindowAttrib(osw->handle, GLFW_FOCUSED)) {
|
||||
get_window_content_scale(osw->handle, &xscale, &yscale, &xdpi, &ydpi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue