mirror of https://github.com/libsdl-org/SDL
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().
This commit is contained in:
parent
606903c02f
commit
716dc0e1bf
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
#include <wayland-util.h>
|
#include <wayland-util.h>
|
||||||
|
|
||||||
|
#include "alpha-modifier-v1-client-protocol.h"
|
||||||
#include "cursor-shape-v1-client-protocol.h"
|
#include "cursor-shape-v1-client-protocol.h"
|
||||||
#include "fractional-scale-v1-client-protocol.h"
|
#include "fractional-scale-v1-client-protocol.h"
|
||||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
||||||
|
@ -487,6 +488,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
|
||||||
device->SetWindowMinimumSize = Wayland_SetWindowMinimumSize;
|
device->SetWindowMinimumSize = Wayland_SetWindowMinimumSize;
|
||||||
device->SetWindowMaximumSize = Wayland_SetWindowMaximumSize;
|
device->SetWindowMaximumSize = Wayland_SetWindowMaximumSize;
|
||||||
device->SetWindowModalFor = Wayland_SetWindowModalFor;
|
device->SetWindowModalFor = Wayland_SetWindowModalFor;
|
||||||
|
device->SetWindowOpacity = Wayland_SetWindowOpacity;
|
||||||
device->SetWindowTitle = Wayland_SetWindowTitle;
|
device->SetWindowTitle = Wayland_SetWindowTitle;
|
||||||
device->GetWindowSizeInPixels = Wayland_GetWindowSizeInPixels;
|
device->GetWindowSizeInPixels = Wayland_GetWindowSizeInPixels;
|
||||||
device->GetDisplayForWindow = Wayland_GetDisplayForWindow;
|
device->GetDisplayForWindow = Wayland_GetDisplayForWindow;
|
||||||
|
@ -1107,6 +1109,8 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
|
||||||
d->zxdg_exporter_v2 = wl_registry_bind(d->registry, id, &zxdg_exporter_v2_interface, 1);
|
d->zxdg_exporter_v2 = wl_registry_bind(d->registry, id, &zxdg_exporter_v2_interface, 1);
|
||||||
} else if (SDL_strcmp(interface, "xdg_wm_dialog_v1") == 0) {
|
} else if (SDL_strcmp(interface, "xdg_wm_dialog_v1") == 0) {
|
||||||
d->xdg_wm_dialog_v1 = wl_registry_bind(d->registry, id, &xdg_wm_dialog_v1_interface, 1);
|
d->xdg_wm_dialog_v1 = wl_registry_bind(d->registry, id, &xdg_wm_dialog_v1_interface, 1);
|
||||||
|
} else if (SDL_strcmp(interface, "wp_alpha_modifier_v1") == 0) {
|
||||||
|
d->wp_alpha_modifier_v1 = wl_registry_bind(d->registry, id, &wp_alpha_modifier_v1_interface, 1);
|
||||||
} else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
|
} else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
|
||||||
d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
|
d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
|
||||||
kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
|
kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
|
||||||
|
@ -1369,6 +1373,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
|
||||||
data->xdg_wm_dialog_v1 = NULL;
|
data->xdg_wm_dialog_v1 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->wp_alpha_modifier_v1) {
|
||||||
|
wp_alpha_modifier_v1_destroy(data->wp_alpha_modifier_v1);
|
||||||
|
data->wp_alpha_modifier_v1 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (data->kde_output_order) {
|
if (data->kde_output_order) {
|
||||||
Wayland_FlushOutputOrder(data);
|
Wayland_FlushOutputOrder(data);
|
||||||
kde_output_order_v1_destroy(data->kde_output_order);
|
kde_output_order_v1_destroy(data->kde_output_order);
|
||||||
|
|
|
@ -81,6 +81,7 @@ struct SDL_VideoData
|
||||||
struct zwp_input_timestamps_manager_v1 *input_timestamps_manager;
|
struct zwp_input_timestamps_manager_v1 *input_timestamps_manager;
|
||||||
struct zxdg_exporter_v2 *zxdg_exporter_v2;
|
struct zxdg_exporter_v2 *zxdg_exporter_v2;
|
||||||
struct xdg_wm_dialog_v1 *xdg_wm_dialog_v1;
|
struct xdg_wm_dialog_v1 *xdg_wm_dialog_v1;
|
||||||
|
struct wp_alpha_modifier_v1 *wp_alpha_modifier_v1;
|
||||||
struct kde_output_order_v1 *kde_output_order;
|
struct kde_output_order_v1 *kde_output_order;
|
||||||
|
|
||||||
struct xkb_context *xkb_context;
|
struct xkb_context *xkb_context;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "SDL_waylandvideo.h"
|
#include "SDL_waylandvideo.h"
|
||||||
#include "../../SDL_hints_c.h"
|
#include "../../SDL_hints_c.h"
|
||||||
|
|
||||||
|
#include "alpha-modifier-v1-client-protocol.h"
|
||||||
#include "xdg-shell-client-protocol.h"
|
#include "xdg-shell-client-protocol.h"
|
||||||
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
#include "xdg-decoration-unstable-v1-client-protocol.h"
|
||||||
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
#include "idle-inhibit-unstable-v1-client-protocol.h"
|
||||||
|
@ -279,10 +280,24 @@ static void RepositionPopup(SDL_Window *window, SDL_bool use_current_position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetSurfaceOpaqueRegion(SDL_WindowData *wind, SDL_bool is_opaque)
|
||||||
|
{
|
||||||
|
SDL_VideoData *viddata = wind->waylandData;
|
||||||
|
|
||||||
|
if (is_opaque) {
|
||||||
|
struct wl_region *region = wl_compositor_create_region(viddata->compositor);
|
||||||
|
wl_region_add(region, 0, 0,
|
||||||
|
wind->current.logical_width, wind->current.logical_height);
|
||||||
|
wl_surface_set_opaque_region(wind->surface, region);
|
||||||
|
wl_region_destroy(region);
|
||||||
|
} else {
|
||||||
|
wl_surface_set_opaque_region(wind->surface, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ConfigureWindowGeometry(SDL_Window *window)
|
static void ConfigureWindowGeometry(SDL_Window *window)
|
||||||
{
|
{
|
||||||
SDL_WindowData *data = window->driverdata;
|
SDL_WindowData *data = window->driverdata;
|
||||||
SDL_VideoData *viddata = data->waylandData;
|
|
||||||
const int old_pixel_width = data->current.pixel_width;
|
const int old_pixel_width = data->current.pixel_width;
|
||||||
const int old_pixel_height = data->current.pixel_height;
|
const int old_pixel_height = data->current.pixel_height;
|
||||||
int window_width, window_height;
|
int window_width, window_height;
|
||||||
|
@ -391,20 +406,12 @@ static void ConfigureWindowGeometry(SDL_Window *window)
|
||||||
* need to be recalculated if the output size has changed.
|
* need to be recalculated if the output size has changed.
|
||||||
*/
|
*/
|
||||||
if (window_size_changed) {
|
if (window_size_changed) {
|
||||||
struct wl_region *region;
|
|
||||||
|
|
||||||
/* libdecor does this internally on frame commits, so it's only needed for xdg surfaces. */
|
/* libdecor does this internally on frame commits, so it's only needed for xdg surfaces. */
|
||||||
if (data->shell_surface_type != WAYLAND_SURFACE_LIBDECOR && data->shell_surface.xdg.surface) {
|
if (data->shell_surface_type != WAYLAND_SURFACE_LIBDECOR && data->shell_surface.xdg.surface) {
|
||||||
xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, data->current.logical_width, data->current.logical_height);
|
xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, data->current.logical_width, data->current.logical_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(window->flags & SDL_WINDOW_TRANSPARENT)) {
|
SetSurfaceOpaqueRegion(data, !(window->flags & SDL_WINDOW_TRANSPARENT) && window->opacity == 1.0f);
|
||||||
region = wl_compositor_create_region(viddata->compositor);
|
|
||||||
wl_region_add(region, 0, 0,
|
|
||||||
data->current.logical_width, data->current.logical_height);
|
|
||||||
wl_surface_set_opaque_region(data->surface, region);
|
|
||||||
wl_region_destroy(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure that child popup windows are still in bounds. */
|
/* Ensure that child popup windows are still in bounds. */
|
||||||
for (SDL_Window *child = window->first_child; child; child = child->next_sibling) {
|
for (SDL_Window *child = window->first_child; child; child = child->next_sibling) {
|
||||||
|
@ -2302,6 +2309,11 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!custom_surface_role && c->wp_alpha_modifier_v1) {
|
||||||
|
data->wp_alpha_modifier_surface_v1 = wp_alpha_modifier_v1_get_surface(c->wp_alpha_modifier_v1, data->surface);
|
||||||
|
wp_alpha_modifier_surface_v1_set_multiplier(data->wp_alpha_modifier_surface_v1, SDL_MAX_UINT32);
|
||||||
|
}
|
||||||
|
|
||||||
/* Must be called before EGL configuration to set the drawable backbuffer size. */
|
/* Must be called before EGL configuration to set the drawable backbuffer size. */
|
||||||
ConfigureWindowGeometry(window);
|
ConfigureWindowGeometry(window);
|
||||||
|
|
||||||
|
@ -2494,6 +2506,20 @@ SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *wi
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Wayland_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity)
|
||||||
|
{
|
||||||
|
SDL_WindowData *wind = window->driverdata;
|
||||||
|
|
||||||
|
if (wind->wp_alpha_modifier_surface_v1) {
|
||||||
|
SetSurfaceOpaqueRegion(wind, !(window->flags & SDL_WINDOW_TRANSPARENT) && opacity == 1.0f);
|
||||||
|
wp_alpha_modifier_surface_v1_set_multiplier(wind->wp_alpha_modifier_surface_v1, (Uint32)((double)SDL_MAX_UINT32 * (double)opacity));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDL_SetError("wayland: set window opacity failed; compositor lacks support for the required wp_alpha_modifier_v1 protocol");
|
||||||
|
}
|
||||||
|
|
||||||
void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
|
void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
{
|
{
|
||||||
SDL_WindowData *wind = window->driverdata;
|
SDL_WindowData *wind = window->driverdata;
|
||||||
|
@ -2614,6 +2640,10 @@ void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||||
wp_fractional_scale_v1_destroy(wind->fractional_scale);
|
wp_fractional_scale_v1_destroy(wind->fractional_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wind->wp_alpha_modifier_surface_v1) {
|
||||||
|
wp_alpha_modifier_surface_v1_destroy(wind->wp_alpha_modifier_surface_v1);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_free(wind->outputs);
|
SDL_free(wind->outputs);
|
||||||
SDL_free(wind->app_id);
|
SDL_free(wind->app_id);
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@ struct SDL_WindowData
|
||||||
struct wp_fractional_scale_v1 *fractional_scale;
|
struct wp_fractional_scale_v1 *fractional_scale;
|
||||||
struct zxdg_exported_v2 *exported;
|
struct zxdg_exported_v2 *exported;
|
||||||
struct xdg_dialog_v1 *xdg_dialog_v1;
|
struct xdg_dialog_v1 *xdg_dialog_v1;
|
||||||
|
struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1;
|
||||||
|
|
||||||
SDL_AtomicInt swap_interval_ready;
|
SDL_AtomicInt swap_interval_ready;
|
||||||
|
|
||||||
|
@ -193,6 +194,7 @@ extern void Wayland_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *win
|
||||||
extern void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
extern void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||||
extern SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
extern SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||||
extern int Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
extern int Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||||
|
extern int Wayland_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
|
||||||
extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||||
extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||||
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="alpha_modifier_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2024 Xaver Hugl
|
||||||
|
|
||||||
|
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.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="wp_alpha_modifier_v1" version="1">
|
||||||
|
<description summary="surface alpha modifier manager">
|
||||||
|
This interface allows a client to set a factor for the alpha values on a
|
||||||
|
surface, which can be used to offload such operations to the compositor,
|
||||||
|
which can in turn for example offload them to KMS.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is currently in the testing
|
||||||
|
phase. Backward compatible changes may be added together with the
|
||||||
|
corresponding interface version bump. Backward incompatible changes can
|
||||||
|
only be done by creating a new major version of the extension.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the alpha modifier manager object">
|
||||||
|
Destroy the alpha modifier manager. This doesn't destroy objects
|
||||||
|
created with the manager.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_constructed" value="0"
|
||||||
|
summary="wl_surface already has a alpha modifier object"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="get_surface">
|
||||||
|
<description summary="create a new toplevel decoration object">
|
||||||
|
Create a new alpha modifier surface object associated with the
|
||||||
|
given wl_surface. If there is already such an object associated with
|
||||||
|
the wl_surface, the already_constructed error will be raised.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="wp_alpha_modifier_surface_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="wp_alpha_modifier_surface_v1" version="1">
|
||||||
|
<description summary="alpha modifier object for a surface">
|
||||||
|
This interface allows the client to set a factor for the alpha values on
|
||||||
|
a surface, which can be used to offload such operations to the compositor.
|
||||||
|
The default factor is UINT32_MAX.
|
||||||
|
|
||||||
|
This object has to be destroyed before the associated wl_surface. Once the
|
||||||
|
wl_surface is destroyed, all request on this object will raise the
|
||||||
|
no_surface error.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="no_surface" value="0" summary="wl_surface was destroyed"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the alpha modifier object">
|
||||||
|
This destroys the object, and is equivalent to set_multiplier with
|
||||||
|
a value of UINT32_MAX, with the same double-buffered semantics as
|
||||||
|
set_multiplier.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="set_multiplier">
|
||||||
|
<description summary="specify the alpha multiplier">
|
||||||
|
Sets the alpha multiplier for the surface. The alpha multiplier is
|
||||||
|
double-buffered state, see wl_surface.commit for details.
|
||||||
|
|
||||||
|
This factor is applied in the compositor's blending space, as an
|
||||||
|
additional step after the processing of per-pixel alpha values for the
|
||||||
|
wl_surface. The exact meaning of the factor is thus undefined, unless
|
||||||
|
the blending space is specified in a different extension.
|
||||||
|
|
||||||
|
This multiplier is applied even if the buffer attached to the
|
||||||
|
wl_surface doesn't have an alpha channel; in that case an alpha value
|
||||||
|
of one is used instead.
|
||||||
|
|
||||||
|
Zero means completely transparent, UINT32_MAX means completely opaque.
|
||||||
|
</description>
|
||||||
|
<arg name="factor" type="uint"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
Loading…
Reference in New Issue