summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/test/testnativewayland.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/testnativewayland.c
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testnativewayland.c')
-rw-r--r--src/contrib/SDL-3.2.20/test/testnativewayland.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testnativewayland.c b/src/contrib/SDL-3.2.20/test/testnativewayland.c
new file mode 100644
index 0000000..30db971
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/test/testnativewayland.c
@@ -0,0 +1,226 @@
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 "testnative.h"
14
15#ifdef TEST_NATIVE_WAYLAND
16
17#include <SDL3/SDL.h>
18#include <wayland-client.h>
19#include <xdg-shell-client-protocol.h>
20
21static void *native_userdata_ptr = (void *)0xBAADF00D;
22static const char *native_surface_tag = "SDL_NativeSurfaceTag";
23
24static void *CreateWindowWayland(int w, int h);
25static void DestroyWindowWayland(void *window);
26
27NativeWindowFactory WaylandWindowFactory = {
28 "wayland",
29 CreateWindowWayland,
30 DestroyWindowWayland
31};
32
33/* Encapsulated in a struct to silence shadow variable warnings */
34static struct _state
35{
36 struct wl_display *wl_display;
37 struct wl_registry *wl_registry;
38 struct wl_compositor *wl_compositor;
39 struct xdg_wm_base *xdg_wm_base;
40 struct wl_surface *wl_surface;
41 struct xdg_surface *xdg_surface;
42 struct xdg_toplevel *xdg_toplevel;
43} state;
44
45static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
46{
47 xdg_surface_ack_configure(state.xdg_surface, serial);
48}
49
50static const struct xdg_surface_listener xdg_surface_listener = {
51 .configure = xdg_surface_configure,
52};
53
54static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states)
55{
56 /* NOP */
57}
58
59static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
60{
61 SDL_Event event;
62 SDL_zero(event);
63
64 event.type = SDL_EVENT_QUIT;
65 SDL_PushEvent(&event);
66}
67
68static void xdg_toplevel_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
69{
70 /* NOP */
71}
72
73static void xdg_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities)
74{
75 /* NOP */
76}
77
78static const struct xdg_toplevel_listener xdg_toplevel_listener = {
79 .configure = xdg_toplevel_configure,
80 .close = xdg_toplevel_close,
81 .configure_bounds = xdg_toplevel_configure_bounds,
82 .wm_capabilities = xdg_toplevel_wm_capabilities
83};
84
85static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
86{
87 xdg_wm_base_pong(state.xdg_wm_base, serial);
88}
89
90static const struct xdg_wm_base_listener xdg_wm_base_listener = {
91 .ping = xdg_wm_base_ping,
92};
93
94static void registry_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version)
95{
96 if (SDL_strcmp(interface, wl_compositor_interface.name) == 0) {
97 state.wl_compositor = wl_registry_bind(state.wl_registry, name, &wl_compositor_interface, SDL_min(version, 4));
98 } else if (SDL_strcmp(interface, xdg_wm_base_interface.name) == 0) {
99 state.xdg_wm_base = wl_registry_bind(state.wl_registry, name, &xdg_wm_base_interface, 1);
100 xdg_wm_base_add_listener(state.xdg_wm_base, &xdg_wm_base_listener, NULL);
101 }
102}
103
104static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
105{
106 /* NOP */
107}
108
109static const struct wl_registry_listener wl_registry_listener = {
110 .global = registry_global,
111 .global_remove = registry_global_remove,
112};
113
114static void *CreateWindowWayland(int w, int h)
115{
116 /* Export the display object from SDL and use it to create a registry object,
117 * which will enumerate the wl_compositor and xdg_wm_base protocols.
118 */
119 state.wl_display = SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, NULL);
120
121 if (!state.wl_display) {
122 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid 'wl_display' object!");
123 goto error;
124 }
125
126 state.wl_registry = wl_display_get_registry(state.wl_display);
127 wl_registry_add_listener(state.wl_registry, &wl_registry_listener, NULL);
128
129 /* Roundtrip to enumerate registry objects. */
130 wl_display_roundtrip(state.wl_display);
131
132 /* Protocol sanity check */
133 if (!state.wl_compositor) {
134 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "'wl_compositor' protocol not found!");
135 goto error;
136 }
137 if (!state.xdg_wm_base) {
138 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "'xdg_wm_base' protocol not found!");
139 goto error;
140 }
141
142 /* Crate the backing wl_surface for the window. */
143 state.wl_surface = wl_compositor_create_surface(state.wl_compositor);
144
145 /* Set the native tag and userdata values, which should be the same at exit. */
146 wl_proxy_set_tag((struct wl_proxy *)state.wl_surface, &native_surface_tag);
147 wl_surface_set_user_data(state.wl_surface, native_userdata_ptr);
148
149 /* Create the xdg_surface from the wl_surface. */
150 state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.wl_surface);
151 xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, NULL);
152
153 /* Create the xdg_toplevel from the xdg_surface. */
154 state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
155 xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_listener, NULL);
156 xdg_toplevel_set_title(state.xdg_toplevel, "Native Wayland Window");
157
158 /* Return the wl_surface to be wrapped in an SDL_Window. */
159 return state.wl_surface;
160
161error:
162 if (state.xdg_toplevel) {
163 xdg_toplevel_destroy(state.xdg_toplevel);
164 state.xdg_toplevel = NULL;
165 }
166 if (state.xdg_surface) {
167 xdg_surface_destroy(state.xdg_surface);
168 state.xdg_surface = NULL;
169 }
170 if (state.wl_surface) {
171 wl_surface_destroy(state.wl_surface);
172 state.wl_surface = NULL;
173 }
174 if (state.xdg_wm_base) {
175 xdg_wm_base_destroy(state.xdg_wm_base);
176 state.xdg_wm_base = NULL;
177 }
178 if (state.wl_compositor) {
179 wl_compositor_destroy(state.wl_compositor);
180 state.wl_compositor = NULL;
181 }
182 if (state.wl_registry) {
183 wl_registry_destroy(state.wl_registry);
184 state.wl_registry = NULL;
185 }
186
187 return NULL;
188}
189
190static void DestroyWindowWayland(void *window)
191{
192 if (state.xdg_toplevel) {
193 xdg_toplevel_destroy(state.xdg_toplevel);
194 state.xdg_toplevel = NULL;
195 }
196 if (state.xdg_surface) {
197 xdg_surface_destroy(state.xdg_surface);
198 state.xdg_surface = NULL;
199 }
200 if (state.wl_surface) {
201 /* Surface sanity check; these should be unmodified. */
202 if (wl_proxy_get_tag((struct wl_proxy *)state.wl_surface) != &native_surface_tag) {
203 SDL_LogError(SDL_LOG_CATEGORY_ERROR, "The wl_surface tag was modified, this indicates a problem inside of SDL.");
204 }
205 if (wl_surface_get_user_data(state.wl_surface) != native_userdata_ptr) {
206 SDL_LogError(SDL_LOG_CATEGORY_ERROR, "The wl_surface user data was modified, this indicates a problem inside of SDL.");
207 }
208
209 wl_surface_destroy(state.wl_surface);
210 state.wl_surface = NULL;
211 }
212 if (state.xdg_wm_base) {
213 xdg_wm_base_destroy(state.xdg_wm_base);
214 state.xdg_wm_base = NULL;
215 }
216 if (state.wl_compositor) {
217 wl_compositor_destroy(state.wl_compositor);
218 state.wl_compositor = NULL;
219 }
220 if (state.wl_registry) {
221 wl_registry_destroy(state.wl_registry);
222 state.wl_registry = NULL;
223 }
224}
225
226#endif