Simple Directmedia Layer

Support wayland fractional scale protocol

The new protocol adds support for more native communication of
fractional scaling.

Everything in the wayland backend already existed only our fractional
scale was calculated implicitly through a combination of output size
guesswork for fullscreen windows.

This new protocol makes that explicit, providing a more robust solution
and a solution for non-fullscreen surfaces. The fallback code is still
left in place for now whilst compositors gain support.

authored by

David Edmundson and committed by
Ethan Lee
6d2b74db 71d5f510

+153 -3
+8 -1
src/video/wayland/SDL_waylandvideo.c
··· 52 52 #include "xdg-output-unstable-v1-client-protocol.h" 53 53 #include "viewporter-client-protocol.h" 54 54 #include "primary-selection-unstable-v1-client-protocol.h" 55 + #include "fractional-scale-v1-client-protocol.h" 55 56 56 57 #ifdef HAVE_LIBDECOR_H 57 58 #include <libdecor.h> ··· 884 885 Wayland_init_xdg_output(d); 885 886 } else if (SDL_strcmp(interface, "wp_viewporter") == 0) { 886 887 d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1); 887 - 888 + } else if (SDL_strcmp(interface, "wp_fractional_scale_manager_v1") == 0) { 889 + d->fractional_scale_manager = wl_registry_bind(d->registry, id, &wp_fractional_scale_manager_v1_interface, 1); 888 890 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH 889 891 } else if (SDL_strcmp(interface, "qt_touch_extension") == 0) { 890 892 Wayland_touch_create(d, id); ··· 1134 1136 if (data->primary_selection_device_manager) { 1135 1137 zwp_primary_selection_device_manager_v1_destroy(data->primary_selection_device_manager); 1136 1138 data->primary_selection_device_manager = NULL; 1139 + } 1140 + 1141 + if (data->fractional_scale_manager) { 1142 + wp_fractional_scale_manager_v1_destroy(data->fractional_scale_manager); 1143 + data->fractional_scale_manager = NULL; 1137 1144 } 1138 1145 1139 1146 if (data->compositor) {
+1
src/video/wayland/SDL_waylandvideo.h
··· 75 75 struct zwp_text_input_manager_v3 *text_input_manager; 76 76 struct zxdg_output_manager_v1 *xdg_output_manager; 77 77 struct wp_viewporter *viewporter; 78 + struct wp_fractional_scale_manager_v1 *fractional_scale_manager; 78 79 79 80 EGLDisplay edpy; 80 81 EGLContext context;
+41 -2
src/video/wayland/SDL_waylandwindow.c
··· 38 38 #include "idle-inhibit-unstable-v1-client-protocol.h" 39 39 #include "xdg-activation-v1-client-protocol.h" 40 40 #include "viewporter-client-protocol.h" 41 + #include "fractional-scale-v1-client-protocol.h" 41 42 42 43 #ifdef HAVE_LIBDECOR_H 43 44 #include <libdecor.h> ··· 1104 1105 1105 1106 /* Update the scale factor after the move so that fullscreen outputs are updated. */ 1106 1107 Wayland_move_window(window->sdlwindow, driverdata); 1107 - update_scale_factor(window); 1108 + 1109 + if (!window->fractional_scale) { 1110 + update_scale_factor(window); 1111 + } 1108 1112 } 1109 1113 1110 1114 static void ··· 1142 1146 window->outputs[window->num_outputs - 1]); 1143 1147 } 1144 1148 1145 - update_scale_factor(window); 1149 + if (!window->fractional_scale) { 1150 + update_scale_factor(window); 1151 + } 1146 1152 } 1147 1153 1148 1154 static const struct wl_surface_listener surface_listener = { ··· 1581 1587 return 0; 1582 1588 } 1583 1589 1590 + void handle_preferred_scale_changed(void *data, 1591 + struct wp_fractional_scale_v1 *wp_fractional_scale_v1, 1592 + uint preferred_scale) 1593 + { 1594 + SDL_WindowData *window = data; 1595 + float old_factor = window->scale_factor; 1596 + float new_factor = preferred_scale / 120.; /* 120 is a magic number defined in the spec as a common denominator*/ 1597 + 1598 + if (!(window->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) { 1599 + /* Scale will always be 1, just ignore this */ 1600 + return; 1601 + } 1602 + 1603 + if (!FloatEqual(new_factor, old_factor)) { 1604 + Wayland_HandleResize(window->sdlwindow, window->sdlwindow->w, window->sdlwindow->h, new_factor); 1605 + } 1606 + } 1607 + 1608 + static const struct wp_fractional_scale_v1_listener fractional_scale_listener = { 1609 + handle_preferred_scale_changed 1610 + }; 1611 + 1612 + 1584 1613 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH 1585 1614 static void SDLCALL 1586 1615 QtExtendedSurface_OnHintChanged(void *userdata, const char *name, ··· 1999 2028 Wayland_input_lock_pointer(c->input); 2000 2029 } 2001 2030 2031 + if (c->fractional_scale_manager) { 2032 + data->fractional_scale = wp_fractional_scale_manager_v1_get_fractional_scale(c->fractional_scale_manager, data->surface); 2033 + wp_fractional_scale_v1_add_listener(data->fractional_scale, 2034 + &fractional_scale_listener, data); 2035 + } 2036 + 2002 2037 /* Moved this call to ShowWindow: wl_surface_commit(data->surface); */ 2003 2038 WAYLAND_wl_display_flush(c->display); 2004 2039 ··· 2190 2225 2191 2226 if (wind->draw_viewport) { 2192 2227 wp_viewport_destroy(wind->draw_viewport); 2228 + } 2229 + 2230 + if (wind->fractional_scale) { 2231 + wp_fractional_scale_v1_destroy(wind->fractional_scale); 2193 2232 } 2194 2233 2195 2234 SDL_free(wind->outputs);
+1
src/video/wayland/SDL_waylandwindow.h
··· 83 83 struct zwp_idle_inhibitor_v1 *idle_inhibitor; 84 84 struct xdg_activation_token_v1 *activation_token; 85 85 struct wp_viewport *draw_viewport; 86 + struct wp_fractional_scale_v1 *fractional_scale; 86 87 87 88 /* floating dimensions for restoring from maximized and fullscreen */ 88 89 int floating_width, floating_height;
+102
wayland-protocols/fractional-scale-v1.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <protocol name="fractional_scale_v1"> 3 + <copyright> 4 + Copyright © 2022 Kenny Levinsen 5 + 6 + Permission is hereby granted, free of charge, to any person obtaining a 7 + copy of this software and associated documentation files (the "Software"), 8 + to deal in the Software without restriction, including without limitation 9 + the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 + and/or sell copies of the Software, and to permit persons to whom the 11 + Software is furnished to do so, subject to the following conditions: 12 + 13 + The above copyright notice and this permission notice (including the next 14 + paragraph) shall be included in all copies or substantial portions of the 15 + Software. 16 + 17 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 + DEALINGS IN THE SOFTWARE. 24 + </copyright> 25 + 26 + <description summary="Protocol for requesting fractional surface scales"> 27 + This protocol allows a compositor to suggest for surfaces to render at 28 + fractional scales. 29 + 30 + A client can submit scaled content by utilizing wp_viewport. This is done by 31 + creating a wp_viewport object for the surface and setting the destination 32 + rectangle to the surface size before the scale factor is applied. 33 + 34 + The buffer size is calculated by multiplying the surface size by the 35 + intended scale. 36 + 37 + The wl_surface buffer scale should remain set to 1. 38 + 39 + If a surface has a surface-local size of 100 px by 50 px and wishes to 40 + submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should 41 + be used and the wp_viewport destination rectangle should be 100 px by 50 px. 42 + 43 + For toplevel surfaces, the size is rounded halfway away from zero. The 44 + rounding algorithm for subsurface position and size is not defined. 45 + </description> 46 + 47 + <interface name="wp_fractional_scale_manager_v1" version="1"> 48 + <description summary="fractional surface scale information"> 49 + A global interface for requesting surfaces to use fractional scales. 50 + </description> 51 + 52 + <request name="destroy" type="destructor"> 53 + <description summary="unbind the fractional surface scale interface"> 54 + Informs the server that the client will not be using this protocol 55 + object anymore. This does not affect any other objects, 56 + wp_fractional_scale_v1 objects included. 57 + </description> 58 + </request> 59 + 60 + <enum name="error"> 61 + <entry name="fractional_scale_exists" value="0" 62 + summary="the surface already has a fractional_scale object associated"/> 63 + </enum> 64 + 65 + <request name="get_fractional_scale"> 66 + <description summary="extend surface interface for scale information"> 67 + Create an add-on object for the the wl_surface to let the compositor 68 + request fractional scales. If the given wl_surface already has a 69 + wp_fractional_scale_v1 object associated, the fractional_scale_exists 70 + protocol error is raised. 71 + </description> 72 + <arg name="id" type="new_id" interface="wp_fractional_scale_v1" 73 + summary="the new surface scale info interface id"/> 74 + <arg name="surface" type="object" interface="wl_surface" 75 + summary="the surface"/> 76 + </request> 77 + </interface> 78 + 79 + <interface name="wp_fractional_scale_v1" version="1"> 80 + <description summary="fractional scale interface to a wl_surface"> 81 + An additional interface to a wl_surface object which allows the compositor 82 + to inform the client of the preferred scale. 83 + </description> 84 + 85 + <request name="destroy" type="destructor"> 86 + <description summary="remove surface scale information for surface"> 87 + Destroy the fractional scale object. When this object is destroyed, 88 + preferred_scale events will no longer be sent. 89 + </description> 90 + </request> 91 + 92 + <event name="preferred_scale"> 93 + <description summary="notify of new preferred scale"> 94 + Notification of a new preferred scale for this surface that the 95 + compositor suggests that the client should use. 96 + 97 + The sent scale is the numerator of a fraction with a denominator of 120. 98 + </description> 99 + <arg name="scale" type="uint" summary="the new preferred scale"/> 100 + </event> 101 + </interface> 102 + </protocol>