Skip to content

Commit 3f84db6

Browse files
committed
wayland: Handle min/max sizes in fixed-size windows with viewports
Wayland is sometimes at-odds with clients that want to enforce an aspect ratio or min/max window size, as certain window states have dimensions that either must be obeyed (maximized), or will give terrible results if they aren't (tiled). Use viewports and/or a masking subsurface to handle cases where surfaces are unable to match the exact window size. The masking system also allows for switching the emulated fullscreen modes to aspect-correct by default, as it will handle masking non-native aspect ratios on compositors that don't automatically mask around fullscreen windows.
1 parent 005cb20 commit 3f84db6

File tree

8 files changed

+568
-226
lines changed

8 files changed

+568
-226
lines changed

include/SDL3/SDL_hints.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,7 +3805,7 @@ extern "C" {
38053805
#define SDL_HINT_VIDEO_WAYLAND_MODE_EMULATION "SDL_VIDEO_WAYLAND_MODE_EMULATION"
38063806

38073807
/**
3808-
* A variable controlling how modes with a non-native aspect ratio are
3808+
* A variable controlling how video modes with a non-native aspect ratio are
38093809
* displayed under Wayland.
38103810
*
38113811
* When this hint is set, the requested scaling will be used when displaying
@@ -3815,9 +3815,8 @@ extern "C" {
38153815
* The variable can be set to the following values:
38163816
*
38173817
* - "aspect" - Video modes will be displayed scaled, in their proper aspect
3818-
* ratio, with black bars.
3818+
* ratio, with black bars. (default)
38193819
* - "stretch" - Video modes will be scaled to fill the entire display.
3820-
* (default)
38213820
* - "none" - Video modes will be displayed as 1:1 with no scaling.
38223821
*
38233822
* This hint should be set before creating a window.

src/video/wayland/SDL_waylandshmbuffer.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "SDL_waylandshmbuffer.h"
3434
#include "SDL_waylandvideo.h"
35+
#include "single-pixel-buffer-v1-client-protocol.h"
3536

3637
static bool SetTempFileSize(int fd, off_t size)
3738
{
@@ -186,4 +187,28 @@ void Wayland_ReleaseSHMPool(Wayland_SHMPool *shmPool)
186187
}
187188
}
188189

190+
struct wl_buffer *Wayland_CreateSinglePixelBuffer(Uint32 r, Uint32 g, Uint32 b, Uint32 a)
191+
{
192+
SDL_VideoData *viddata = SDL_GetVideoDevice()->internal;
193+
194+
// THe single-pixel buffer protocol is preferred, as the compositor can choose an optimal format.
195+
if (viddata->single_pixel_buffer_manager) {
196+
return wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(viddata->single_pixel_buffer_manager, r, g, b, a);
197+
} else {
198+
Wayland_SHMPool *pool = Wayland_AllocSHMPool(4);
199+
if (!pool) {
200+
return NULL;
201+
}
202+
203+
void *mem;
204+
struct wl_buffer *wl_buffer = Wayland_AllocBufferFromPool(pool, 1, 1, &mem);
205+
206+
const Uint8 pixel[4] = { r >> 24, g >> 24, b >> 24, a >> 24 };
207+
SDL_memcpy(mem, pixel, sizeof(pixel));
208+
209+
Wayland_ReleaseSHMPool(pool);
210+
return wl_buffer;
211+
}
212+
}
213+
189214
#endif

src/video/wayland/SDL_waylandshmbuffer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ extern Wayland_SHMPool *Wayland_AllocSHMPool(int size);
3030
extern struct wl_buffer *Wayland_AllocBufferFromPool(Wayland_SHMPool *shmPool, int width, int height, void **data);
3131
extern void Wayland_ReleaseSHMPool(Wayland_SHMPool *shmPool);
3232

33+
extern struct wl_buffer *Wayland_CreateSinglePixelBuffer(Uint32 r, Uint32 g, Uint32 b, Uint32 a);
34+
3335
#endif

src/video/wayland/SDL_waylandvideo.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include "color-management-v1-client-protocol.h"
6969
#include "pointer-warp-v1-client-protocol.h"
7070
#include "pointer-gestures-unstable-v1-client-protocol.h"
71+
#include "single-pixel-buffer-v1-client-protocol.h"
7172

7273
#ifdef HAVE_LIBDECOR_H
7374
#include <libdecor.h>
@@ -651,6 +652,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
651652
device->SetWindowResizable = Wayland_SetWindowResizable;
652653
device->SetWindowPosition = Wayland_SetWindowPosition;
653654
device->SetWindowSize = Wayland_SetWindowSize;
655+
device->SetWindowAspectRatio = Wayland_SetWindowAspectRatio;
654656
device->SetWindowMinimumSize = Wayland_SetWindowMinimumSize;
655657
device->SetWindowMaximumSize = Wayland_SetWindowMaximumSize;
656658
device->SetWindowParent = Wayland_SetWindowParent;
@@ -1272,6 +1274,8 @@ static void handle_registry_global(void *data, struct wl_registry *registry, uin
12721274

12731275
if (SDL_strcmp(interface, "wl_compositor") == 0) {
12741276
d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, SDL_min(SDL_WL_COMPOSITOR_VERSION, version));
1277+
} else if (SDL_strcmp(interface, "wl_subcompositor") == 0) {
1278+
d->subcompositor = wl_registry_bind(d->registry, id, &wl_subcompositor_interface, 1);
12751279
} else if (SDL_strcmp(interface, "wl_output") == 0) {
12761280
Wayland_add_display(d, id, SDL_min(version, SDL_WL_OUTPUT_VERSION));
12771281
} else if (SDL_strcmp(interface, "wl_seat") == 0) {
@@ -1337,6 +1341,8 @@ static void handle_registry_global(void *data, struct wl_registry *registry, uin
13371341
} else if (SDL_strcmp(interface, "zwp_pointer_gestures_v1") == 0) {
13381342
d->zwp_pointer_gestures = wl_registry_bind(d->registry, id, &zwp_pointer_gestures_v1_interface, SDL_min(version, 3));
13391343
Wayland_DisplayInitPointerGestureManager(d);
1344+
} else if (SDL_strcmp(interface, "wp_single_pixel_buffer_manager_v1") == 0) {
1345+
d->single_pixel_buffer_manager = wl_registry_bind(d->registry, id, &wp_single_pixel_buffer_manager_v1_interface, 1);
13401346
}
13411347
#ifdef SDL_WL_FIXES_VERSION
13421348
else if (SDL_strcmp(interface, "wl_fixes") == 0) {
@@ -1665,6 +1671,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
16651671
data->zwp_pointer_gestures = NULL;
16661672
}
16671673

1674+
if (data->single_pixel_buffer_manager) {
1675+
wp_single_pixel_buffer_manager_v1_destroy(data->single_pixel_buffer_manager);
1676+
data->single_pixel_buffer_manager = NULL;
1677+
}
1678+
16681679
if (data->compositor) {
16691680
wl_compositor_destroy(data->compositor);
16701681
data->compositor = NULL;

src/video/wayland/SDL_waylandvideo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct SDL_VideoData
6161
struct libdecor *libdecor;
6262
#endif
6363
} shell;
64+
struct wl_subcompositor *subcompositor;
6465
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
6566
struct zwp_pointer_constraints_v1 *pointer_constraints;
6667
struct wp_pointer_warp_v1 *wp_pointer_warp_v1;
@@ -85,6 +86,7 @@ struct SDL_VideoData
8586
struct zwp_tablet_manager_v2 *tablet_manager;
8687
struct wl_fixes *wl_fixes;
8788
struct zwp_pointer_gestures_v1 *zwp_pointer_gestures;
89+
struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer_manager;
8890

8991
struct xkb_context *xkb_context;
9092

0 commit comments

Comments
 (0)