From 8162d6659af506ac4d65e090667c30c0617ca17e Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Fri, 7 Apr 2023 17:27:50 -0400 Subject: [PATCH] wayland: Use the integer buffer scale event when applicable wl_compositor v6 introduces the preferred buffer scale event, which serves a similar function to the fractional scale protocol, but deals in integer scale factors. Listen to this event when the wl_compositor version is >= 6 and the fractional scale protocol is not present to set the scale factor for surfaces. --- src/video/wayland/SDL_waylandvideo.c | 8 +- src/video/wayland/SDL_waylandwindow.c | 101 +++++++++++++++----------- 2 files changed, 66 insertions(+), 43 deletions(-) diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index c919e8314e..de63c6bcb8 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -62,6 +62,12 @@ #define WAYLANDVID_DRIVER_NAME "wayland" +#if SDL_WAYLAND_CHECK_VERSION(1, 22, 0) +#define SDL_WL_COMPOSITOR_VERSION 6 +#else +#define SDL_WL_COMPOSITOR_VERSION 4 +#endif + #if SDL_WAYLAND_CHECK_VERSION(1, 20, 0) #define SDL_WL_OUTPUT_VERSION 4 #else @@ -792,7 +798,7 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint /*printf("WAYLAND INTERFACE: %s\n", interface);*/ if (SDL_strcmp(interface, "wl_compositor") == 0) { - d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, SDL_min(4, version)); + d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, SDL_min(SDL_WL_COMPOSITOR_VERSION, version)); } else if (SDL_strcmp(interface, "wl_output") == 0) { Wayland_add_display(d, id, SDL_min(version, SDL_WL_OUTPUT_VERSION)); } else if (SDL_strcmp(interface, "wl_seat") == 0) { diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 0e7da693a6..aadbf1760e 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -968,33 +968,48 @@ static const struct qt_extended_surface_listener extended_surface_listener = { }; #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ -static void update_scale_factor(SDL_WindowData *window) +static void Wayland_HandlePreferredScaleChanged(SDL_WindowData *window_data, float factor) { - float old_factor = window->windowed_scale_factor; - float new_factor; + const float old_factor = window_data->windowed_scale_factor; + + if (!(window_data->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) { + /* Scale will always be 1, just ignore this */ + return; + } + + if (!FloatEqual(factor, old_factor)) { + window_data->windowed_scale_factor = factor; + ConfigureWindowGeometry(window_data->sdlwindow); + } +} + +static void Wayland_MaybeUpdateScaleFactor(SDL_WindowData *window) +{ + float factor; int i; - if (!(window->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) { - /* Scale will always be 1, just ignore this */ + /* If the fractional scale protocol is present or the core protocol supports the + * preferred buffer scale event, the compositor will tell explicitly the application + * what scale it wants via these events, so don't try to determine the scale factor + * from which displays the surface has entered. + */ + if (window->fractional_scale || wl_surface_get_version(window->surface) >= WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION) { return; } if (window->num_outputs != 0) { /* Check every display's factor, use the highest */ - new_factor = 0.0f; + factor = 0.0f; for (i = 0; i < window->num_outputs; i++) { SDL_DisplayData *driverdata = window->outputs[i]; - new_factor = SDL_max(new_factor, driverdata->scale_factor); + factor = SDL_max(factor, driverdata->scale_factor); } } else { /* No monitor (somehow)? Just fall back. */ - new_factor = old_factor; + factor = window->windowed_scale_factor; } - if (!FloatEqual(new_factor, old_factor)) { - window->windowed_scale_factor = new_factor; - ConfigureWindowGeometry(window->sdlwindow); - } + Wayland_HandlePreferredScaleChanged(window, factor); } /* While we can't get window position from the compositor, we do at least know @@ -1060,10 +1075,7 @@ static void handle_surface_enter(void *data, struct wl_surface *surface, /* Update the scale factor after the move so that fullscreen outputs are updated. */ Wayland_move_window(window->sdlwindow, driverdata); - - if (!window->fractional_scale) { - update_scale_factor(window); - } + Wayland_MaybeUpdateScaleFactor(window); } static void handle_surface_leave(void *data, struct wl_surface *surface, @@ -1100,14 +1112,42 @@ static void handle_surface_leave(void *data, struct wl_surface *surface, window->outputs[window->num_outputs - 1]); } - if (!window->fractional_scale) { - update_scale_factor(window); + Wayland_MaybeUpdateScaleFactor(window); +} + +static void handle_preferred_buffer_scale(void *data, struct wl_surface *wl_surface, int32_t factor) +{ + SDL_WindowData *wind = data; + + /* The spec is unclear on how this interacts with the fractional scaling protocol, + * so, for now, assume that the fractional scaling protocol takes priority and + * only listen to this event if the fractional scaling protocol is not present. + */ + if (!wind->fractional_scale) { + Wayland_HandlePreferredScaleChanged(data, (float)factor); } } +static void handle_preferred_buffer_transform(void *data, struct wl_surface *wl_surface, uint32_t transform) +{ + /* Nothing to do here. */ +} + static const struct wl_surface_listener surface_listener = { handle_surface_enter, - handle_surface_leave + handle_surface_leave, + handle_preferred_buffer_scale, + handle_preferred_buffer_transform +}; + +static void handle_preferred_fractional_scale(void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale) +{ + const float factor = scale / 120.; /* 120 is a magic number defined in the spec as a common denominator */ + Wayland_HandlePreferredScaleChanged(data, factor); +} + +static const struct wp_fractional_scale_v1_listener fractional_scale_listener = { + handle_preferred_fractional_scale }; static void SetKeyboardFocus(SDL_Window *window) @@ -1605,29 +1645,6 @@ int Wayland_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation) return 0; } -static void handle_preferred_scale_changed(void *data, - struct wp_fractional_scale_v1 *wp_fractional_scale_v1, - uint preferred_scale) -{ - SDL_WindowData *window = data; - float old_factor = window->windowed_scale_factor; - float new_factor = preferred_scale / 120.; /* 120 is a magic number defined in the spec as a common denominator*/ - - if (!(window->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) { - /* Scale will always be 1, just ignore this */ - return; - } - - if (!FloatEqual(new_factor, old_factor)) { - window->windowed_scale_factor = new_factor; - ConfigureWindowGeometry(window->sdlwindow); - } -} - -static const struct wp_fractional_scale_v1_listener fractional_scale_listener = { - handle_preferred_scale_changed -}; - #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH static void SDLCALL QtExtendedSurface_OnHintChanged(void *userdata, const char *name, const char *oldValue, const char *newValue)