diff options
author | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
commit | 6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch) | |
tree | 34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/docs/README-wayland.md | |
parent | 8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff) |
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/docs/README-wayland.md')
-rw-r--r-- | src/contrib/SDL-3.2.20/docs/README-wayland.md | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/docs/README-wayland.md b/src/contrib/SDL-3.2.20/docs/README-wayland.md new file mode 100644 index 0000000..75a9b90 --- /dev/null +++ b/src/contrib/SDL-3.2.20/docs/README-wayland.md | |||
@@ -0,0 +1,242 @@ | |||
1 | Wayland | ||
2 | ======= | ||
3 | Wayland is a replacement for the X11 window system protocol and architecture and is favored over X11 by default in SDL3 | ||
4 | for communicating with desktop compositors. It works well for the majority of applications, however, applications may | ||
5 | encounter limitations or behavior that is different from other windowing systems. | ||
6 | |||
7 | ## Common issues: | ||
8 | |||
9 | ### Legacy, DPI-unaware applications are blurry | ||
10 | |||
11 | - Wayland handles high-DPI displays by scaling the desktop, which causes applications that are not designed to be | ||
12 | DPI-aware to be automatically scaled by the window manager, which results in them being blurry. SDL can _attempt_ to | ||
13 | scale these applications such that they will be output with a 1:1 pixel aspect, however this may be buggy, especially | ||
14 | with odd-sized windows and/or scale factors that aren't quarter-increments (125%, 150%, etc...). To enable this, set | ||
15 | the environment variable `SDL_VIDEO_WAYLAND_SCALE_TO_DISPLAY=1` | ||
16 | |||
17 | ### Window decorations are missing, or the decorations look strange | ||
18 | |||
19 | - On some desktops (i.e. GNOME), Wayland applications use a library | ||
20 | called [libdecor](https://gitlab.freedesktop.org/libdecor/libdecor) to provide window decorations. If this library is | ||
21 | not installed, the decorations will be missing. This library uses plugins to generate different decoration styles, and | ||
22 | if a plugin to generate native-looking decorations is not installed (i.e. the GTK plugin), the decorations will not | ||
23 | appear to be 'native'. | ||
24 | |||
25 | ### Windows do not appear immediately after creation | ||
26 | |||
27 | - Wayland requires that the application initially present a buffer before the window becomes visible. Additionally, | ||
28 | applications _must_ have an event loop and processes messages on a regular basis, or the application can appear | ||
29 | unresponsive to both the user and desktop compositor. | ||
30 | |||
31 | ### The display reported as the primary by ```SDL_GetPrimaryDisplay()``` is incorrect | ||
32 | |||
33 | - Wayland doesn't natively have the concept of a primary display, so SDL attempts to determine it by querying various | ||
34 | system settings, and falling back to a selection algorithm if this fails. If it is incorrect, it can be manually | ||
35 | overridden by setting the ```SDL_VIDEO_DISPLAY_PRIORITY``` hint. | ||
36 | |||
37 | ### ```SDL_SetWindowPosition()``` doesn't work on non-popup windows | ||
38 | |||
39 | - Wayland does not allow toplevel windows to position themselves programmatically. | ||
40 | |||
41 | ### Retrieving the global mouse cursor position when the cursor is outside a window doesn't work | ||
42 | |||
43 | - Wayland only provides applications with the cursor position within the borders of the application windows. Querying | ||
44 | the global position when an application window does not have mouse focus returns 0,0 as the actual cursor position is | ||
45 | unknown. In most cases, applications don't actually need the global cursor position and should use the window-relative | ||
46 | coordinates as provided by the mouse movement event or from ```SDL_GetMouseState()``` instead. | ||
47 | |||
48 | ### Warping the mouse cursor to or from a point outside the window doesn't work | ||
49 | |||
50 | - The cursor can be warped only within the window with mouse focus, provided that the `zwp_pointer_confinement_v1` | ||
51 | protocol is supported by the compositor. | ||
52 | |||
53 | ### The application icon can't be set via ```SDL_SetWindowIcon()``` | ||
54 | |||
55 | - Wayland requires compositor support for the `xdg-toplevel-icon-v1` protocol to set window icons programmatically. | ||
56 | Otherwise, the launcher icon from the associated desktop entry file, aka a `.desktop` file, will typically be used. | ||
57 | Please see the [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/) for | ||
58 | more information on the format of this file. Note that if your application manually sets the application ID via the | ||
59 | `SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your | ||
60 | application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`. | ||
61 | |||
62 | ### Keyboard grabs don't work when running under XWayland | ||
63 | |||
64 | - On GNOME based desktops, the dconf setting `org/gnome/mutter/wayland/xwayland-allow-grabs` must be enabled. | ||
65 | |||
66 | ## Using custom Wayland windowing protocols with SDL windows | ||
67 | |||
68 | Under normal operation, an `SDL_Window` corresponds to an XDG toplevel window, which provides a standard desktop window. | ||
69 | If an application wishes to use a different windowing protocol with an SDL window (e.g. wlr_layer_shell) while still | ||
70 | having SDL handle input and rendering, it needs to create a custom, roleless surface and attach that surface to its own | ||
71 | toplevel window. | ||
72 | |||
73 | This is done by using `SDL_CreateWindowWithProperties()` and setting the | ||
74 | `SDL_PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN` property to `true`. Once the window has been | ||
75 | successfully created, the `wl_display` and `wl_surface` objects can then be retrieved from the | ||
76 | `SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER` and `SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER` properties respectively. | ||
77 | |||
78 | Surfaces don't receive any size change notifications, so if an application changes the window size, it must inform SDL | ||
79 | that the surface size has changed by calling SDL_SetWindowSize() with the new dimensions. | ||
80 | |||
81 | Custom surfaces will automatically handle scaling internally if the window was created with the | ||
82 | `SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN` property set to `true`. In this case, applications should | ||
83 | not manually attach viewports or change the surface scale value, as SDL will handle this internally. Calls | ||
84 | to `SDL_SetWindowSize()` should use the logical size of the window, and `SDL_GetWindowSizeInPixels()` should be used to | ||
85 | query the size of the backbuffer surface in pixels. If this property is not set or is `false`, applications can | ||
86 | attach their own viewports or change the surface scale manually, and the SDL backend will not interfere or change any | ||
87 | values internally. In this case, calls to `SDL_SetWindowSize()` should pass the requested surface size in pixels, not | ||
88 | the logical window size, as no scaling calculations will be done internally. | ||
89 | |||
90 | All window functions that control window state aside from `SDL_SetWindowSize()` are no-ops with custom surfaces. | ||
91 | |||
92 | Please see the minimal example in `tests/testwaylandcustom.c` for an example of how to use a custom, roleless surface | ||
93 | and attach it to an application-managed toplevel window. | ||
94 | |||
95 | ## Importing external surfaces into SDL windows | ||
96 | |||
97 | Wayland windows and surfaces are more intrinsically tied to the client library than other windowing systems, therefore, | ||
98 | when importing surfaces, it is necessary for both SDL and the application or toolkit to use the same `wl_display` | ||
99 | object. This can be set/queried via the global `SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER` property. To | ||
100 | import an external `wl_display`, set this property before initializing the SDL video subsystem, and read the value to | ||
101 | export the internal `wl_display` after the video subsystem has been initialized. Setting this property after the video | ||
102 | subsystem has been initialized has no effect, and reading it when the video subsystem is uninitialized will either | ||
103 | return the user provided value, if one was set while in the uninitialized state, or NULL. | ||
104 | |||
105 | Once this is done, and the application has created or obtained the `wl_surface` to be wrapped in an `SDL_Window`, the | ||
106 | window is created with `SDL_CreateWindowWithProperties()` with the | ||
107 | `SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER` property to set to the `wl_surface` object that is to be | ||
108 | imported by SDL. | ||
109 | |||
110 | SDL receives no notification regarding size changes on external surfaces or toplevel windows, so if the external surface | ||
111 | needs to be resized, SDL must be informed by calling SDL_SetWindowSize() with the new dimensions. | ||
112 | |||
113 | If desired, SDL can automatically handle the scaling for the surface by setting the | ||
114 | `SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN` property to `true`, however, if the surface being imported | ||
115 | already has, or will have, a viewport/fractional scale manager attached to it by the application or an external toolkit, | ||
116 | a protocol violation will result. Avoid setting this property if importing surfaces from toolkits such as Qt or GTK. | ||
117 | |||
118 | If the window is flagged as high pixel density, calls to `SDL_SetWindowSize()` should pass the logical size of the | ||
119 | window and `SDL_GetWindowSizeInPixels()` should be used to retrieve the backbuffer size in pixels. Otherwise, calls to | ||
120 | `SDL_SetWindowSize()` should pass the requested surface size in pixels, not the logical window size, as no scaling | ||
121 | calculations will be done internally. | ||
122 | |||
123 | All window functions that control window state aside from `SDL_SetWindowSize()` are no-ops with external surfaces. | ||
124 | |||
125 | An example of how to use external surfaces with a `wl_display` owned by SDL can be seen in `tests/testnativewayland.c`, | ||
126 | and the following is a minimal example of interoperation with Qt 6, with Qt owning the `wl_display`: | ||
127 | |||
128 | ```c++ | ||
129 | #include <QApplication> | ||
130 | #include <QWindow> | ||
131 | #include <qpa/qplatformnativeinterface.h> | ||
132 | |||
133 | #include <SDL3/SDL.h> | ||
134 | |||
135 | int main(int argc, char *argv[]) | ||
136 | { | ||
137 | int ret = -1; | ||
138 | int done = 0; | ||
139 | SDL_PropertiesID props; | ||
140 | SDL_Event e; | ||
141 | SDL_Window *sdlWindow = NULL; | ||
142 | SDL_Renderer *sdlRenderer = NULL; | ||
143 | struct wl_display *display = NULL; | ||
144 | struct wl_surface *surface = NULL; | ||
145 | |||
146 | /* Initialize Qt */ | ||
147 | QApplication qtApp(argc, argv); | ||
148 | QWindow qtWindow; | ||
149 | |||
150 | /* The windowing system must be Wayland. */ | ||
151 | if (QApplication::platformName() != "wayland") { | ||
152 | goto exit; | ||
153 | } | ||
154 | |||
155 | { | ||
156 | /* Get the wl_display object from Qt */ | ||
157 | QNativeInterface::QWaylandApplication *qtWlApp = qtApp.nativeInterface<QNativeInterface::QWaylandApplication>(); | ||
158 | display = qtWlApp->display(); | ||
159 | |||
160 | if (!display) { | ||
161 | goto exit; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /* Set SDL to use the existing wl_display object from Qt and initialize. */ | ||
166 | SDL_SetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, display); | ||
167 | SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); | ||
168 | |||
169 | /* Create a basic, frameless QWindow */ | ||
170 | qtWindow.setFlags(Qt::FramelessWindowHint); | ||
171 | qtWindow.setGeometry(0, 0, 640, 480); | ||
172 | qtWindow.show(); | ||
173 | |||
174 | { | ||
175 | /* Get the native wl_surface backing resource for the window */ | ||
176 | QPlatformNativeInterface *qtNative = qtApp.platformNativeInterface(); | ||
177 | surface = (struct wl_surface *)qtNative->nativeResourceForWindow("surface", &qtWindow); | ||
178 | |||
179 | if (!surface) { | ||
180 | goto exit; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* Create a window that wraps the wl_surface from the QWindow. | ||
185 | * Qt objects should not be flagged as DPI-aware or protocol violations will result. | ||
186 | */ | ||
187 | props = SDL_CreateProperties(); | ||
188 | SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_WAYLAND_WL_SURFACE_POINTER, surface); | ||
189 | SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); | ||
190 | SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, 640); | ||
191 | SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, 480); | ||
192 | sdlWindow = SDL_CreateWindowWithProperties(props); | ||
193 | SDL_DestroyProperties(props); | ||
194 | if (!sdlWindow) { | ||
195 | goto exit; | ||
196 | } | ||
197 | |||
198 | /* Create a renderer */ | ||
199 | sdlRenderer = SDL_CreateRenderer(sdlWindow, NULL); | ||
200 | if (!sdlRenderer) { | ||
201 | goto exit; | ||
202 | } | ||
203 | |||
204 | /* Draw a blue screen for the window until ESC is pressed or the window is no longer visible. */ | ||
205 | while (!done) { | ||
206 | while (SDL_PollEvent(&e)) { | ||
207 | if (e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE) { | ||
208 | done = 1; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | qtApp.processEvents(); | ||
213 | |||
214 | /* Update the backbuffer size if the window scale changed. */ | ||
215 | qreal scale = qtWindow.devicePixelRatio(); | ||
216 | SDL_SetWindowSize(sdlWindow, SDL_lround(640. * scale), SDL_lround(480. * scale)); | ||
217 | |||
218 | if (qtWindow.isVisible()) { | ||
219 | SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 255, SDL_ALPHA_OPAQUE); | ||
220 | SDL_RenderClear(sdlRenderer); | ||
221 | SDL_RenderPresent(sdlRenderer); | ||
222 | } else { | ||
223 | done = 1; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | ret = 0; | ||
228 | |||
229 | exit: | ||
230 | /* Cleanup */ | ||
231 | if (sdlRenderer) { | ||
232 | SDL_DestroyRenderer(sdlRenderer); | ||
233 | } | ||
234 | if (sdlWindow) { | ||
235 | SDL_DestroyWindow(sdlWindow); | ||
236 | } | ||
237 | |||
238 | SDL_Quit(); | ||
239 | return ret; | ||
240 | } | ||
241 | ``` | ||
242 | |||