implement support for wp-fractional-scale-v1

This commit is contained in:
Xaver Hugl 2022-11-06 13:30:48 +01:00
parent dd8a678a66
commit 32d7f3a54c
5 changed files with 116 additions and 32 deletions

View File

@ -113,6 +113,9 @@ if (GLFW_BUILD_WAYLAND)
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
"${GLFW_BINARY_DIR}/src/wayland-idle-inhibit-unstable-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/staging/fractional-scale/fractional-scale-v1.xml"
"${GLFW_BINARY_DIR}/src/wayland-fractional-scale-v1-client-protocol")
endif()
if (WIN32 AND GLFW_BUILD_SHARED_LIBRARY)

View File

@ -48,6 +48,7 @@
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
#include "wayland-fractional-scale-v1-client-protocol.h"
// NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of
// wl_interface pointers 'types', making it impossible to combine several unmodified
@ -82,6 +83,10 @@
#include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
#undef types
#define types _glfw_fractional_scale_types
#include "wayland-fractional-scale-v1-client-protocol-code.h"
#undef types
static void wmBaseHandlePing(void* userData,
struct xdg_wm_base* wmBase,
uint32_t serial)
@ -180,6 +185,13 @@ static void registryHandleGlobal(void* userData,
&zwp_idle_inhibit_manager_v1_interface,
1);
}
else if (strcmp(interface, "wp_fractional_scale_manager_v1") == 0)
{
_glfw.wl.fractionalScaleManager =
wl_registry_bind(registry, name,
&wp_fractional_scale_manager_v1_interface,
1);
}
}
static void registryHandleGlobalRemove(void* userData,

View File

@ -122,7 +122,7 @@ static void outputHandleScale(void* userData,
{
if (window->wl.monitors[i] == monitor)
{
_glfwUpdateContentScaleWayland(window);
_glfwUpdateIntegerContentScaleWayland(window);
break;
}
}

View File

@ -212,6 +212,7 @@ typedef struct _GLFWdecorationWayland
struct wl_surface* surface;
struct wl_subsurface* subsurface;
struct wp_viewport* viewport;
struct wp_fractional_scale_v1* fractionalScale;
} _GLFWdecorationWayland;
typedef struct _GLFWofferWayland
@ -262,7 +263,7 @@ typedef struct _GLFWwindowWayland
// We need to track the monitors the window spans on to calculate the
// optimal scaling factor.
int scale;
int integerScale;
_GLFWmonitor** monitors;
int monitorsCount;
int monitorsSize;
@ -278,6 +279,9 @@ typedef struct _GLFWwindowWayland
_GLFWdecorationWayland top, left, right, bottom;
_GLFWdecorationSideWayland focus;
} decorations;
double fractionalScale;
struct wp_fractional_scale_v1* fractionalScaling;
} _GLFWwindowWayland;
// Wayland-specific global data
@ -300,6 +304,7 @@ typedef struct _GLFWlibraryWayland
struct zwp_relative_pointer_manager_v1* relativePointerManager;
struct zwp_pointer_constraints_v1* pointerConstraints;
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
struct wp_fractional_scale_manager_v1* fractionalScaleManager;
_GLFWofferWayland* offers;
unsigned int offerCount;
@ -514,7 +519,7 @@ GLFWbool _glfwGetGammaRampWayland(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwAddOutputWayland(uint32_t name, uint32_t version);
void _glfwUpdateContentScaleWayland(_GLFWwindow* window);
void _glfwUpdateIntegerContentScaleWayland(_GLFWwindow* window);
void _glfwAddSeatListenerWayland(struct wl_seat* seat);
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);

View File

@ -50,6 +50,7 @@
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
#include "wayland-fractional-scale-v1-client-protocol.h"
#define GLFW_BORDER_SIZE 4
#define GLFW_CAPTION_HEIGHT 24
@ -192,7 +193,8 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
return buffer;
}
static void createFallbackDecoration(_GLFWdecorationWayland* decoration,
static void createFallbackDecoration(_GLFWwindow *window,
_GLFWdecorationWayland* decoration,
struct wl_surface* parent,
struct wl_buffer* buffer,
int x, int y,
@ -203,6 +205,11 @@ static void createFallbackDecoration(_GLFWdecorationWayland* decoration,
wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,
decoration->surface, parent);
wl_subsurface_set_position(decoration->subsurface, x, y);
if (_glfw.wl.fractionalScaleManager)
{
decoration->fractionalScale = wp_fractional_scale_manager_v1_get_fractional_scale(_glfw.wl.fractionalScaleManager, decoration->surface);
wp_fractional_scale_v1_set_scale_factor(decoration->fractionalScale, (uint32_t)(window->wl.fractionalScale * (double)(1UL << 24)));
}
decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,
decoration->surface);
wp_viewport_set_destination(decoration->viewport, width, height);
@ -228,19 +235,19 @@ static void createFallbackDecorations(_GLFWwindow* window)
if (!window->wl.decorations.buffer)
return;
createFallbackDecoration(&window->wl.decorations.top, window->wl.surface,
createFallbackDecoration(window, &window->wl.decorations.top, window->wl.surface,
window->wl.decorations.buffer,
0, -GLFW_CAPTION_HEIGHT,
window->wl.width, GLFW_CAPTION_HEIGHT);
createFallbackDecoration(&window->wl.decorations.left, window->wl.surface,
createFallbackDecoration(window, &window->wl.decorations.left, window->wl.surface,
window->wl.decorations.buffer,
-GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
createFallbackDecoration(&window->wl.decorations.right, window->wl.surface,
createFallbackDecoration(window, &window->wl.decorations.right, window->wl.surface,
window->wl.decorations.buffer,
window->wl.width, -GLFW_CAPTION_HEIGHT,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
createFallbackDecoration(&window->wl.decorations.bottom, window->wl.surface,
createFallbackDecoration(window, &window->wl.decorations.bottom, window->wl.surface,
window->wl.decorations.buffer,
-GLFW_BORDER_SIZE, window->wl.height,
window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);
@ -306,9 +313,9 @@ static void setContentAreaOpaque(_GLFWwindow* window)
static void resizeWindow(_GLFWwindow* window)
{
int scale = window->wl.scale;
int scaledWidth = window->wl.width * scale;
int scaledHeight = window->wl.height * scale;
int integerScale = window->wl.integerScale;
int scaledWidth = window->wl.width * integerScale;
int scaledHeight = window->wl.height * integerScale;
if (window->wl.egl.window)
wl_egl_window_resize(window->wl.egl.window, scaledWidth, scaledHeight, 0, 0);
@ -319,30 +326,44 @@ static void resizeWindow(_GLFWwindow* window)
if (!window->wl.decorations.top.surface)
return;
const uint32_t scale_8_24 = (uint32_t)(window->wl.fractionalScale * (double)(1UL << 24));
wl_subsurface_set_position(window->wl.decorations.top.subsurface,
0, -GLFW_CAPTION_HEIGHT);
if (window->wl.decorations.top.fractionalScale)
wp_fractional_scale_v1_set_scale_factor(window->wl.decorations.top.fractionalScale, scale_8_24);
wp_viewport_set_destination(window->wl.decorations.top.viewport,
window->wl.width, GLFW_CAPTION_HEIGHT);
wl_surface_commit(window->wl.decorations.top.surface);
wl_subsurface_set_position(window->wl.decorations.left.subsurface,
-GLFW_BORDER_SIZE, -GLFW_CAPTION_HEIGHT);
if (window->wl.decorations.left.fractionalScale)
wp_fractional_scale_v1_set_scale_factor(window->wl.decorations.left.fractionalScale, scale_8_24);
wp_viewport_set_destination(window->wl.decorations.left.viewport,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
wl_surface_commit(window->wl.decorations.left.surface);
wl_subsurface_set_position(window->wl.decorations.right.subsurface,
window->wl.width, -GLFW_CAPTION_HEIGHT);
if (window->wl.decorations.right.fractionalScale)
wp_fractional_scale_v1_set_scale_factor(window->wl.decorations.right.fractionalScale, scale_8_24);
wp_viewport_set_destination(window->wl.decorations.right.viewport,
GLFW_BORDER_SIZE, window->wl.height + GLFW_CAPTION_HEIGHT);
wl_surface_commit(window->wl.decorations.right.surface);
wl_subsurface_set_position(window->wl.decorations.bottom.subsurface,
-GLFW_BORDER_SIZE, window->wl.height);
if (window->wl.decorations.bottom.fractionalScale)
wp_fractional_scale_v1_set_scale_factor(window->wl.decorations.bottom.fractionalScale, scale_8_24);
wp_viewport_set_destination(window->wl.decorations.bottom.viewport,
window->wl.width + GLFW_BORDER_SIZE * 2, GLFW_BORDER_SIZE);
wl_surface_commit(window->wl.decorations.bottom.surface);
}
void _glfwUpdateContentScaleWayland(_GLFWwindow* window)
void _glfwUpdateIntegerContentScaleWayland(_GLFWwindow* window)
{
if (_glfw.wl.compositorVersion < WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
if (_glfw.wl.compositorVersion < WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION || window->wl.fractionalScaling)
return;
// Get the scale factor from the highest scale monitor.
@ -352,9 +373,9 @@ void _glfwUpdateContentScaleWayland(_GLFWwindow* window)
maxScale = _glfw_max(window->wl.monitors[i]->wl.scale, maxScale);
// Only change the framebuffer size if the scale changed.
if (window->wl.scale != maxScale)
if (window->wl.integerScale != maxScale)
{
window->wl.scale = maxScale;
window->wl.integerScale = maxScale;
wl_surface_set_buffer_scale(window->wl.surface, maxScale);
_glfwInputWindowContentScale(window, maxScale, maxScale);
resizeWindow(window);
@ -378,7 +399,7 @@ static void surfaceHandleEnter(void* userData,
window->wl.monitors[window->wl.monitorsCount++] = monitor;
_glfwUpdateContentScaleWayland(window);
_glfwUpdateIntegerContentScaleWayland(window);
}
static void surfaceHandleLeave(void* userData,
@ -398,7 +419,7 @@ static void surfaceHandleLeave(void* userData,
}
window->wl.monitors[--window->wl.monitorsCount] = NULL;
_glfwUpdateContentScaleWayland(window);
_glfwUpdateIntegerContentScaleWayland(window);
}
static const struct wl_surface_listener surfaceListener =
@ -407,6 +428,31 @@ static const struct wl_surface_listener surfaceListener =
surfaceHandleLeave
};
void handleScaleFactor(void *userData,
struct wp_fractional_scale_v1 *wp_fractional_scale_v1,
uint32_t scale_8_24)
{
_GLFWwindow* window = userData;
const double oldScale = window->wl.fractionalScale;
const double newScale = scale_8_24 / (double)(1UL << 24);
if (newScale != oldScale) {
window->wl.fractionalScale = newScale;
wp_fractional_scale_v1_set_scale_factor(wp_fractional_scale_v1, scale_8_24);
_glfwInputWindowContentScale(window, newScale, newScale);
// keep the effective size of the window the same
window->wl.width = round(window->wl.width * newScale / oldScale);
window->wl.height = round(window->wl.height * newScale / oldScale);
resizeWindow(window);
}
}
static const struct wp_fractional_scale_v1_listener scaleListener =
{
handleScaleFactor
};
static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
{
if (enable && !window->wl.idleInhibitor && _glfw.wl.idleInhibitManager)
@ -731,16 +777,24 @@ static GLFWbool createNativeSurface(_GLFWwindow* window,
window->wl.width = wndconfig->width;
window->wl.height = wndconfig->height;
window->wl.scale = 1;
window->wl.integerScale = 1;
window->wl.title = _glfw_strdup(wndconfig->title);
window->wl.appId = _glfw_strdup(wndconfig->wl.appId);
window->wl.fractionalScale = 1;
window->wl.maximized = wndconfig->maximized;
window->wl.transparent = fbconfig->transparent;
if (!window->wl.transparent)
setContentAreaOpaque(window);
if (_glfw.wl.fractionalScaleManager)
{
window->wl.fractionalScaling = wp_fractional_scale_manager_v1_get_fractional_scale(_glfw.wl.fractionalScaleManager, window->wl.surface);
wp_fractional_scale_v1_add_listener(window->wl.fractionalScaling, &scaleListener, window);
}
return GLFW_TRUE;
}
@ -758,7 +812,7 @@ static void setCursorImage(_GLFWwindow* window,
buffer = cursorWayland->buffer;
else
{
if (window->wl.scale > 1 && cursorWayland->cursorHiDPI)
if (window->wl.integerScale > 1 && cursorWayland->cursorHiDPI)
{
wlCursor = cursorWayland->cursorHiDPI;
scale = 2;
@ -1106,7 +1160,7 @@ static void setCursor(_GLFWwindow* window, const char* name)
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1;
if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)
if (window->wl.integerScale > 1 && _glfw.wl.cursorThemeHiDPI)
{
// We only support up to scale=2 for now, since libwayland-cursor
// requires us to load a different theme for each size.
@ -1995,10 +2049,13 @@ void _glfwSetWindowAspectRatioWayland(_GLFWwindow* window, int numer, int denom)
void _glfwGetFramebufferSizeWayland(_GLFWwindow* window, int* width, int* height)
{
_glfwGetWindowSizeWayland(window, width, height);
if (width)
*width *= window->wl.scale;
if (height)
*height *= window->wl.scale;
if (!window->wl.fractionalScaling)
{
if (width)
*width *= window->wl.integerScale;
if (height)
*height *= window->wl.integerScale;
}
}
void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window,
@ -2021,10 +2078,17 @@ void _glfwGetWindowFrameSizeWayland(_GLFWwindow* window,
void _glfwGetWindowContentScaleWayland(_GLFWwindow* window,
float* xscale, float* yscale)
{
if (xscale)
*xscale = (float) window->wl.scale;
if (yscale)
*yscale = (float) window->wl.scale;
if (window->wl.fractionalScaling) {
if (xscale)
*xscale = window->wl.fractionalScale;
if (yscale)
*yscale = window->wl.fractionalScale;
} else {
if (xscale)
*xscale = (float) window->wl.integerScale;
if (yscale)
*yscale = (float) window->wl.integerScale;
}
}
void _glfwIconifyWindowWayland(_GLFWwindow* window)
@ -2467,13 +2531,13 @@ static void relativePointerHandleRelativeMotion(void* userData,
if (window->rawMouseMotion)
{
xpos += wl_fixed_to_double(dxUnaccel);
ypos += wl_fixed_to_double(dyUnaccel);
xpos += wl_fixed_to_double(dxUnaccel) / window->wl.fractionalScale;
ypos += wl_fixed_to_double(dyUnaccel) / window->wl.fractionalScale;
}
else
{
xpos += wl_fixed_to_double(dx);
ypos += wl_fixed_to_double(dy);
xpos += wl_fixed_to_double(dx) / window->wl.fractionalScale;
ypos += wl_fixed_to_double(dy) / window->wl.fractionalScale;
}
_glfwInputCursorPos(window, xpos, ypos);