Simple Directmedia Layer
fork

Configure Feed

Select the types of activity you want to include in your feed.

wayland: Implement SetWindowOpacity via the alpha modifier protocol

The wp_alpha_modifier_v1 protocol allows for a global blending factor to be specified for an entire surface. Use this to add support for SDL_SetWindowOpacity().

+155 -10
+9
src/video/wayland/SDL_waylandvideo.c
··· 43 43 44 44 #include <wayland-util.h> 45 45 46 + #include "alpha-modifier-v1-client-protocol.h" 46 47 #include "cursor-shape-v1-client-protocol.h" 47 48 #include "fractional-scale-v1-client-protocol.h" 48 49 #include "idle-inhibit-unstable-v1-client-protocol.h" ··· 487 488 device->SetWindowMinimumSize = Wayland_SetWindowMinimumSize; 488 489 device->SetWindowMaximumSize = Wayland_SetWindowMaximumSize; 489 490 device->SetWindowModalFor = Wayland_SetWindowModalFor; 491 + device->SetWindowOpacity = Wayland_SetWindowOpacity; 490 492 device->SetWindowTitle = Wayland_SetWindowTitle; 491 493 device->GetWindowSizeInPixels = Wayland_GetWindowSizeInPixels; 492 494 device->GetDisplayForWindow = Wayland_GetDisplayForWindow; ··· 1107 1109 d->zxdg_exporter_v2 = wl_registry_bind(d->registry, id, &zxdg_exporter_v2_interface, 1); 1108 1110 } else if (SDL_strcmp(interface, "xdg_wm_dialog_v1") == 0) { 1109 1111 d->xdg_wm_dialog_v1 = wl_registry_bind(d->registry, id, &xdg_wm_dialog_v1_interface, 1); 1112 + } else if (SDL_strcmp(interface, "wp_alpha_modifier_v1") == 0) { 1113 + d->wp_alpha_modifier_v1 = wl_registry_bind(d->registry, id, &wp_alpha_modifier_v1_interface, 1); 1110 1114 } else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) { 1111 1115 d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1); 1112 1116 kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d); ··· 1367 1371 if (data->xdg_wm_dialog_v1) { 1368 1372 xdg_wm_dialog_v1_destroy(data->xdg_wm_dialog_v1); 1369 1373 data->xdg_wm_dialog_v1 = NULL; 1374 + } 1375 + 1376 + if (data->wp_alpha_modifier_v1) { 1377 + wp_alpha_modifier_v1_destroy(data->wp_alpha_modifier_v1); 1378 + data->wp_alpha_modifier_v1 = NULL; 1370 1379 } 1371 1380 1372 1381 if (data->kde_output_order) {
+1
src/video/wayland/SDL_waylandvideo.h
··· 81 81 struct zwp_input_timestamps_manager_v1 *input_timestamps_manager; 82 82 struct zxdg_exporter_v2 *zxdg_exporter_v2; 83 83 struct xdg_wm_dialog_v1 *xdg_wm_dialog_v1; 84 + struct wp_alpha_modifier_v1 *wp_alpha_modifier_v1; 84 85 struct kde_output_order_v1 *kde_output_order; 85 86 86 87 struct xkb_context *xkb_context;
+40 -10
src/video/wayland/SDL_waylandwindow.c
··· 32 32 #include "SDL_waylandvideo.h" 33 33 #include "../../SDL_hints_c.h" 34 34 35 + #include "alpha-modifier-v1-client-protocol.h" 35 36 #include "xdg-shell-client-protocol.h" 36 37 #include "xdg-decoration-unstable-v1-client-protocol.h" 37 38 #include "idle-inhibit-unstable-v1-client-protocol.h" ··· 279 280 } 280 281 } 281 282 283 + static void SetSurfaceOpaqueRegion(SDL_WindowData *wind, SDL_bool is_opaque) 284 + { 285 + SDL_VideoData *viddata = wind->waylandData; 286 + 287 + if (is_opaque) { 288 + struct wl_region *region = wl_compositor_create_region(viddata->compositor); 289 + wl_region_add(region, 0, 0, 290 + wind->current.logical_width, wind->current.logical_height); 291 + wl_surface_set_opaque_region(wind->surface, region); 292 + wl_region_destroy(region); 293 + } else { 294 + wl_surface_set_opaque_region(wind->surface, NULL); 295 + } 296 + } 297 + 282 298 static void ConfigureWindowGeometry(SDL_Window *window) 283 299 { 284 300 SDL_WindowData *data = window->driverdata; 285 - SDL_VideoData *viddata = data->waylandData; 286 301 const int old_pixel_width = data->current.pixel_width; 287 302 const int old_pixel_height = data->current.pixel_height; 288 303 int window_width, window_height; ··· 391 406 * need to be recalculated if the output size has changed. 392 407 */ 393 408 if (window_size_changed) { 394 - struct wl_region *region; 395 - 396 409 /* libdecor does this internally on frame commits, so it's only needed for xdg surfaces. */ 397 410 if (data->shell_surface_type != WAYLAND_SURFACE_LIBDECOR && data->shell_surface.xdg.surface) { 398 411 xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, data->current.logical_width, data->current.logical_height); 399 412 } 400 413 401 - if (!(window->flags & SDL_WINDOW_TRANSPARENT)) { 402 - region = wl_compositor_create_region(viddata->compositor); 403 - wl_region_add(region, 0, 0, 404 - data->current.logical_width, data->current.logical_height); 405 - wl_surface_set_opaque_region(data->surface, region); 406 - wl_region_destroy(region); 407 - } 414 + SetSurfaceOpaqueRegion(data, !(window->flags & SDL_WINDOW_TRANSPARENT) && window->opacity == 1.0f); 408 415 409 416 /* Ensure that child popup windows are still in bounds. */ 410 417 for (SDL_Window *child = window->first_child; child; child = child->next_sibling) { ··· 2302 2309 } 2303 2310 } 2304 2311 2312 + if (!custom_surface_role && c->wp_alpha_modifier_v1) { 2313 + data->wp_alpha_modifier_surface_v1 = wp_alpha_modifier_v1_get_surface(c->wp_alpha_modifier_v1, data->surface); 2314 + wp_alpha_modifier_surface_v1_set_multiplier(data->wp_alpha_modifier_surface_v1, SDL_MAX_UINT32); 2315 + } 2316 + 2305 2317 /* Must be called before EGL configuration to set the drawable backbuffer size. */ 2306 2318 ConfigureWindowGeometry(window); 2307 2319 ··· 2494 2506 return 0; 2495 2507 } 2496 2508 2509 + int Wayland_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity) 2510 + { 2511 + SDL_WindowData *wind = window->driverdata; 2512 + 2513 + if (wind->wp_alpha_modifier_surface_v1) { 2514 + SetSurfaceOpaqueRegion(wind, !(window->flags & SDL_WINDOW_TRANSPARENT) && opacity == 1.0f); 2515 + wp_alpha_modifier_surface_v1_set_multiplier(wind->wp_alpha_modifier_surface_v1, (Uint32)((double)SDL_MAX_UINT32 * (double)opacity)); 2516 + 2517 + return 0; 2518 + } 2519 + 2520 + return SDL_SetError("wayland: set window opacity failed; compositor lacks support for the required wp_alpha_modifier_v1 protocol"); 2521 + } 2522 + 2497 2523 void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) 2498 2524 { 2499 2525 SDL_WindowData *wind = window->driverdata; ··· 2612 2638 2613 2639 if (wind->fractional_scale) { 2614 2640 wp_fractional_scale_v1_destroy(wind->fractional_scale); 2641 + } 2642 + 2643 + if (wind->wp_alpha_modifier_surface_v1) { 2644 + wp_alpha_modifier_surface_v1_destroy(wind->wp_alpha_modifier_surface_v1); 2615 2645 } 2616 2646 2617 2647 SDL_free(wind->outputs);
+2
src/video/wayland/SDL_waylandwindow.h
··· 97 97 struct wp_fractional_scale_v1 *fractional_scale; 98 98 struct zxdg_exported_v2 *exported; 99 99 struct xdg_dialog_v1 *xdg_dialog_v1; 100 + struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1; 100 101 101 102 SDL_AtomicInt swap_interval_ready; 102 103 ··· 193 194 extern void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h); 194 195 extern SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window); 195 196 extern int Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window); 197 + extern int Wayland_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity); 196 198 extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window); 197 199 extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y); 198 200 extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
+103
wayland-protocols/alpha-modifier-v1.xml
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <protocol name="alpha_modifier_v1"> 3 + <copyright> 4 + Copyright © 2024 Xaver Hugl 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 + <interface name="wp_alpha_modifier_v1" version="1"> 27 + <description summary="surface alpha modifier manager"> 28 + This interface allows a client to set a factor for the alpha values on a 29 + surface, which can be used to offload such operations to the compositor, 30 + which can in turn for example offload them to KMS. 31 + 32 + Warning! The protocol described in this file is currently in the testing 33 + phase. Backward compatible changes may be added together with the 34 + corresponding interface version bump. Backward incompatible changes can 35 + only be done by creating a new major version of the extension. 36 + </description> 37 + 38 + <request name="destroy" type="destructor"> 39 + <description summary="destroy the alpha modifier manager object"> 40 + Destroy the alpha modifier manager. This doesn't destroy objects 41 + created with the manager. 42 + </description> 43 + </request> 44 + 45 + <enum name="error"> 46 + <entry name="already_constructed" value="0" 47 + summary="wl_surface already has a alpha modifier object"/> 48 + </enum> 49 + 50 + <request name="get_surface"> 51 + <description summary="create a new toplevel decoration object"> 52 + Create a new alpha modifier surface object associated with the 53 + given wl_surface. If there is already such an object associated with 54 + the wl_surface, the already_constructed error will be raised. 55 + </description> 56 + <arg name="id" type="new_id" interface="wp_alpha_modifier_surface_v1"/> 57 + <arg name="surface" type="object" interface="wl_surface"/> 58 + </request> 59 + </interface> 60 + 61 + <interface name="wp_alpha_modifier_surface_v1" version="1"> 62 + <description summary="alpha modifier object for a surface"> 63 + This interface allows the client to set a factor for the alpha values on 64 + a surface, which can be used to offload such operations to the compositor. 65 + The default factor is UINT32_MAX. 66 + 67 + This object has to be destroyed before the associated wl_surface. Once the 68 + wl_surface is destroyed, all request on this object will raise the 69 + no_surface error. 70 + </description> 71 + 72 + <enum name="error"> 73 + <entry name="no_surface" value="0" summary="wl_surface was destroyed"/> 74 + </enum> 75 + 76 + <request name="destroy" type="destructor"> 77 + <description summary="destroy the alpha modifier object"> 78 + This destroys the object, and is equivalent to set_multiplier with 79 + a value of UINT32_MAX, with the same double-buffered semantics as 80 + set_multiplier. 81 + </description> 82 + </request> 83 + 84 + <request name="set_multiplier"> 85 + <description summary="specify the alpha multiplier"> 86 + Sets the alpha multiplier for the surface. The alpha multiplier is 87 + double-buffered state, see wl_surface.commit for details. 88 + 89 + This factor is applied in the compositor's blending space, as an 90 + additional step after the processing of per-pixel alpha values for the 91 + wl_surface. The exact meaning of the factor is thus undefined, unless 92 + the blending space is specified in a different extension. 93 + 94 + This multiplier is applied even if the buffer attached to the 95 + wl_surface doesn't have an alpha channel; in that case an alpha value 96 + of one is used instead. 97 + 98 + Zero means completely transparent, UINT32_MAX means completely opaque. 99 + </description> 100 + <arg name="factor" type="uint"/> 101 + </request> 102 + </interface> 103 + </protocol>