diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index c2bf9228d6df2..a6ca322e1aaea 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -52,6 +52,7 @@ #include "xdg-output-unstable-v1-client-protocol.h" #include "viewporter-client-protocol.h" #include "primary-selection-unstable-v1-client-protocol.h" +#include "fractional-scale-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -884,7 +885,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, Wayland_init_xdg_output(d); } else if (SDL_strcmp(interface, "wp_viewporter") == 0) { d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1); - + } else if (SDL_strcmp(interface, "wp_fractional_scale_manager_v1") == 0) { + d->fractional_scale_manager = wl_registry_bind(d->registry, id, &wp_fractional_scale_manager_v1_interface, 1); #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH } else if (SDL_strcmp(interface, "qt_touch_extension") == 0) { Wayland_touch_create(d, id); @@ -1136,6 +1138,11 @@ Wayland_VideoCleanup(_THIS) data->primary_selection_device_manager = NULL; } + if (data->fractional_scale_manager) { + wp_fractional_scale_manager_v1_destroy(data->fractional_scale_manager); + data->fractional_scale_manager = NULL; + } + if (data->compositor) { wl_compositor_destroy(data->compositor); data->compositor = NULL; diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index d08c2643b2ef8..e574a8476dcd1 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -75,6 +75,7 @@ typedef struct { struct zwp_text_input_manager_v3 *text_input_manager; struct zxdg_output_manager_v1 *xdg_output_manager; struct wp_viewporter *viewporter; + struct wp_fractional_scale_manager_v1 *fractional_scale_manager; EGLDisplay edpy; EGLContext context; diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index c3835ce318fe6..2b1cb53fa6a67 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -38,6 +38,7 @@ #include "idle-inhibit-unstable-v1-client-protocol.h" #include "xdg-activation-v1-client-protocol.h" #include "viewporter-client-protocol.h" +#include "fractional-scale-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -1104,7 +1105,10 @@ 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); - update_scale_factor(window); + + if (!window->fractional_scale) { + update_scale_factor(window); + } } static void @@ -1142,7 +1146,9 @@ handle_surface_leave(void *data, struct wl_surface *surface, window->outputs[window->num_outputs - 1]); } - update_scale_factor(window); + if (!window->fractional_scale) { + update_scale_factor(window); + } } static const struct wl_surface_listener surface_listener = { @@ -1581,6 +1587,29 @@ Wayland_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation) return 0; } +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->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)) { + Wayland_HandleResize(window->sdlwindow, window->sdlwindow->w, window->sdlwindow->h, new_factor); + } +} + +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, @@ -1999,6 +2028,12 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) Wayland_input_lock_pointer(c->input); } + if (c->fractional_scale_manager) { + data->fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale(c->fractional_scale_manager, data->surface); + wp_fractional_scale_v1_add_listener(data->fractional_scale, + &fractional_scale_listener, data); + } + /* Moved this call to ShowWindow: wl_surface_commit(data->surface); */ WAYLAND_wl_display_flush(c->display); @@ -2192,6 +2227,10 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window) wp_viewport_destroy(wind->draw_viewport); } + if (wind->fractional_scale) { + wp_fractional_scale_v1_destroy(wind->fractional_scale); + } + SDL_free(wind->outputs); if (wind->gles_swap_frame_callback) { diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index cfdb4dff12a93..adc2a3527c932 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -83,6 +83,7 @@ typedef struct { struct zwp_idle_inhibitor_v1 *idle_inhibitor; struct xdg_activation_token_v1 *activation_token; struct wp_viewport *draw_viewport; + struct wp_fractional_scale_v1 *fractional_scale; /* floating dimensions for restoring from maximized and fullscreen */ int floating_width, floating_height; diff --git a/wayland-protocols/fractional-scale-v1.xml b/wayland-protocols/fractional-scale-v1.xml new file mode 100644 index 0000000000000..350bfc01eafa0 --- /dev/null +++ b/wayland-protocols/fractional-scale-v1.xml @@ -0,0 +1,102 @@ + + + + Copyright © 2022 Kenny Levinsen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol allows a compositor to suggest for surfaces to render at + fractional scales. + + A client can submit scaled content by utilizing wp_viewport. This is done by + creating a wp_viewport object for the surface and setting the destination + rectangle to the surface size before the scale factor is applied. + + The buffer size is calculated by multiplying the surface size by the + intended scale. + + The wl_surface buffer scale should remain set to 1. + + If a surface has a surface-local size of 100 px by 50 px and wishes to + submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should + be used and the wp_viewport destination rectangle should be 100 px by 50 px. + + For toplevel surfaces, the size is rounded halfway away from zero. The + rounding algorithm for subsurface position and size is not defined. + + + + + A global interface for requesting surfaces to use fractional scales. + + + + + Informs the server that the client will not be using this protocol + object anymore. This does not affect any other objects, + wp_fractional_scale_v1 objects included. + + + + + + + + + + Create an add-on object for the the wl_surface to let the compositor + request fractional scales. If the given wl_surface already has a + wp_fractional_scale_v1 object associated, the fractional_scale_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object which allows the compositor + to inform the client of the preferred scale. + + + + + Destroy the fractional scale object. When this object is destroyed, + preferred_scale events will no longer be sent. + + + + + + Notification of a new preferred scale for this surface that the + compositor suggests that the client should use. + + The sent scale is the numerator of a fraction with a denominator of 120. + + + + +