summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/test/testwaylandcustom.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/test/testwaylandcustom.c
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testwaylandcustom.c')
-rw-r--r--src/contrib/SDL-3.2.20/test/testwaylandcustom.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testwaylandcustom.c b/src/contrib/SDL-3.2.20/test/testwaylandcustom.c
new file mode 100644
index 0000000..b77464a
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/test/testwaylandcustom.c
@@ -0,0 +1,330 @@
1/*
2 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely.
11*/
12
13#include <SDL3/SDL.h>
14#include <wayland-client.h>
15#include <xdg-shell-client-protocol.h>
16
17#include "icon.h"
18
19#define WINDOW_WIDTH 640
20#define WINDOW_HEIGHT 480
21#define NUM_SPRITES 100
22#define MAX_SPEED 1
23
24static SDL_Window *window;
25static SDL_Renderer *renderer;
26static SDL_Texture *sprite;
27static SDL_FRect positions[NUM_SPRITES];
28static SDL_FRect velocities[NUM_SPRITES];
29static int sprite_w, sprite_h;
30static int done;
31
32static SDL_Texture *CreateTexture(SDL_Renderer *r, unsigned char *data, unsigned int len, int *w, int *h)
33{
34 SDL_Texture *texture = NULL;
35 SDL_Surface *surface;
36 SDL_IOStream *src = SDL_IOFromConstMem(data, len);
37 if (src) {
38 surface = SDL_LoadBMP_IO(src, true);
39 if (surface) {
40 /* Treat white as transparent */
41 SDL_SetSurfaceColorKey(surface, true, SDL_MapSurfaceRGB(surface, 255, 255, 255));
42
43 texture = SDL_CreateTextureFromSurface(r, surface);
44 *w = surface->w;
45 *h = surface->h;
46 SDL_DestroySurface(surface);
47 }
48 }
49 return texture;
50}
51
52static void MoveSprites(void)
53{
54 int i;
55 int window_w;
56 int window_h;
57 SDL_FRect *position, *velocity;
58
59 /* Get the window size */
60 SDL_GetWindowSizeInPixels(window, &window_w, &window_h);
61
62 /* Draw a gray background */
63 SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
64 SDL_RenderClear(renderer);
65
66 /* Move the sprite, bounce at the wall, and draw */
67 for (i = 0; i < NUM_SPRITES; ++i) {
68 position = &positions[i];
69 velocity = &velocities[i];
70 position->x += velocity->x;
71 if ((position->x < 0) || (position->x >= (window_w - sprite_w))) {
72 velocity->x = -velocity->x;
73 position->x += velocity->x;
74 }
75 position->y += velocity->y;
76 if ((position->y < 0) || (position->y >= (window_h - sprite_h))) {
77 velocity->y = -velocity->y;
78 position->y += velocity->y;
79 }
80
81 /* Blit the sprite onto the screen */
82 SDL_RenderTexture(renderer, sprite, NULL, position);
83 }
84
85 /* Update the screen! */
86 SDL_RenderPresent(renderer);
87}
88
89static int InitSprites(void)
90{
91 /* Create the sprite texture and initialize the sprite positions */
92 sprite = CreateTexture(renderer, icon_bmp, icon_bmp_len, &sprite_w, &sprite_h);
93
94 if (!sprite) {
95 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite texture");
96 return -1;
97 }
98
99 for (int i = 0; i < NUM_SPRITES; ++i) {
100 positions[i].x = (float)SDL_rand(WINDOW_WIDTH - sprite_w);
101 positions[i].y = (float)SDL_rand(WINDOW_HEIGHT - sprite_h);
102 positions[i].w = (float)sprite_w;
103 positions[i].h = (float)sprite_h;
104 velocities[i].x = 0.0f;
105 velocities[i].y = 0.0f;
106 while (velocities[i].x == 0.f && velocities[i].y == 0.f) {
107 velocities[i].x = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
108 velocities[i].y = (float)(SDL_rand(MAX_SPEED * 2 + 1) - MAX_SPEED);
109 }
110 }
111
112 return 0;
113}
114
115/* Encapsulated in a struct to silence shadow variable warnings */
116static struct _state
117{
118 /* These are owned by SDL and must not be destroyed! */
119 struct wl_display *wl_display;
120 struct wl_surface *wl_surface;
121
122 /* These are owned by the application and need to be cleaned up on exit. */
123 struct wl_registry *wl_registry;
124 struct xdg_wm_base *xdg_wm_base;
125 struct xdg_surface *xdg_surface;
126 struct xdg_toplevel *xdg_toplevel;
127} state;
128
129static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
130{
131 xdg_surface_ack_configure(state.xdg_surface, serial);
132}
133
134static const struct xdg_surface_listener xdg_surface_listener = {
135 .configure = xdg_surface_configure,
136};
137
138static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states)
139{
140 /* NOP */
141}
142
143static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
144{
145 done = 1;
146}
147
148static void xdg_toplevel_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
149{
150 /* NOP */
151}
152
153static void xdg_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities)
154{
155 /* NOP */
156}
157
158static const struct xdg_toplevel_listener xdg_toplevel_listener = {
159 .configure = xdg_toplevel_configure,
160 .close = xdg_toplevel_close,
161 .configure_bounds = xdg_toplevel_configure_bounds,
162 .wm_capabilities = xdg_toplevel_wm_capabilities
163};
164
165static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
166{
167 xdg_wm_base_pong(state.xdg_wm_base, serial);
168}
169
170static const struct xdg_wm_base_listener xdg_wm_base_listener = {
171 .ping = xdg_wm_base_ping,
172};
173
174static void registry_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version)
175{
176 if (SDL_strcmp(interface, xdg_wm_base_interface.name) == 0) {
177 state.xdg_wm_base = wl_registry_bind(state.wl_registry, name, &xdg_wm_base_interface, 1);
178 xdg_wm_base_add_listener(state.xdg_wm_base, &xdg_wm_base_listener, NULL);
179 }
180}
181
182static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
183{
184 /* NOP */
185}
186
187static const struct wl_registry_listener wl_registry_listener = {
188 .global = registry_global,
189 .global_remove = registry_global_remove,
190};
191
192int main(int argc, char **argv)
193{
194 int ret = -1;
195 SDL_PropertiesID props;
196
197 if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
198 return -1;
199 }
200
201 if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") != 0) {
202 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Video driver must be 'wayland', not '%s'", SDL_GetCurrentVideoDriver());
203 goto exit;
204 }
205
206 /* Create a window with the custom surface role property set. */
207 props = SDL_CreateProperties();
208 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN, true); /* Roleless surface */
209 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); /* OpenGL enabled */
210 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, WINDOW_WIDTH); /* Default width */
211 SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, WINDOW_HEIGHT); /* Default height */
212 SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true); /* Handle DPI scaling internally */
213 SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, "Wayland custom surface role test"); /* Default title */
214
215 window = SDL_CreateWindowWithProperties(props);
216 SDL_DestroyProperties(props);
217 if (!window) {
218 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Window creation failed");
219 goto exit;
220 }
221
222 /* Create the renderer */
223 renderer = SDL_CreateRenderer(window, NULL);
224 if (!renderer) {
225 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Renderer creation failed");
226 goto exit;
227 }
228
229 /* Get the display object and use it to create a registry object, which will enumerate the xdg_wm_base protocol. */
230 state.wl_display = SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
231 state.wl_registry = wl_display_get_registry(state.wl_display);
232 wl_registry_add_listener(state.wl_registry, &wl_registry_listener, NULL);
233
234 /* Roundtrip to enumerate registry objects. */
235 wl_display_roundtrip(state.wl_display);
236
237 if (!state.xdg_wm_base) {
238 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "'xdg_wm_base' protocol not found!");
239 goto exit;
240 }
241
242 /* Get the wl_surface object from the SDL_Window, and create a toplevel window with it. */
243 state.wl_surface = SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL);
244
245 /* Create the xdg_surface from the wl_surface. */
246 state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.wl_surface);
247 xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, NULL);
248
249 /* Create the xdg_toplevel from the xdg_surface. */
250 state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
251 xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_listener, NULL);
252 xdg_toplevel_set_title(state.xdg_toplevel, SDL_GetWindowTitle(window));
253
254 /* Initialize the sprites. */
255 if (InitSprites() < 0) {
256 goto exit;
257 }
258
259 while (!done) {
260 SDL_Event event;
261 while (SDL_PollEvent(&event)) {
262 if (event.type == SDL_EVENT_KEY_DOWN) {
263 switch (event.key.key) {
264 case SDLK_ESCAPE:
265 done = 1;
266 break;
267 case SDLK_EQUALS:
268 /* Ctrl+ enlarges the window */
269 if (event.key.mod & SDL_KMOD_CTRL) {
270 int w, h;
271 SDL_GetWindowSize(window, &w, &h);
272 SDL_SetWindowSize(window, w * 2, h * 2);
273 }
274 break;
275 case SDLK_MINUS:
276 /* Ctrl- shrinks the window */
277 if (event.key.mod & SDL_KMOD_CTRL) {
278 int w, h;
279 SDL_GetWindowSize(window, &w, &h);
280 SDL_SetWindowSize(window, w / 2, h / 2);
281 }
282 break;
283 default:
284 break;
285 }
286 }
287 }
288
289 /* Draw the sprites */
290 MoveSprites();
291 }
292
293 ret = 0;
294
295exit:
296 /* The display and surface handles obtained from SDL are owned by SDL and must *NOT* be destroyed here! */
297 if (state.xdg_toplevel) {
298 xdg_toplevel_destroy(state.xdg_toplevel);
299 state.xdg_toplevel = NULL;
300 }
301 if (state.xdg_surface) {
302 xdg_surface_destroy(state.xdg_surface);
303 state.xdg_surface = NULL;
304 }
305 if (state.xdg_wm_base) {
306 xdg_wm_base_destroy(state.xdg_wm_base);
307 state.xdg_wm_base = NULL;
308 }
309 if (state.wl_registry) {
310 wl_registry_destroy(state.wl_registry);
311 state.wl_registry = NULL;
312 }
313
314 /* Destroy the SDL resources */
315 if (sprite) {
316 SDL_DestroyTexture(sprite);
317 sprite = NULL;
318 }
319 if (renderer) {
320 SDL_DestroyRenderer(renderer);
321 renderer = NULL;
322 }
323 if (window) {
324 SDL_DestroyWindow(window);
325 window = NULL;
326 }
327
328 SDL_Quit();
329 return ret;
330}