diff options
author | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
commit | 6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch) | |
tree | 34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/test/testnativewayland.c | |
parent | 8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (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.c | 226 |
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 | |||
21 | static void *native_userdata_ptr = (void *)0xBAADF00D; | ||
22 | static const char *native_surface_tag = "SDL_NativeSurfaceTag"; | ||
23 | |||
24 | static void *CreateWindowWayland(int w, int h); | ||
25 | static void DestroyWindowWayland(void *window); | ||
26 | |||
27 | NativeWindowFactory WaylandWindowFactory = { | ||
28 | "wayland", | ||
29 | CreateWindowWayland, | ||
30 | DestroyWindowWayland | ||
31 | }; | ||
32 | |||
33 | /* Encapsulated in a struct to silence shadow variable warnings */ | ||
34 | static 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 | |||
45 | static 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 | |||
50 | static const struct xdg_surface_listener xdg_surface_listener = { | ||
51 | .configure = xdg_surface_configure, | ||
52 | }; | ||
53 | |||
54 | static 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 | |||
59 | static 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 | |||
68 | static void xdg_toplevel_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) | ||
69 | { | ||
70 | /* NOP */ | ||
71 | } | ||
72 | |||
73 | static void xdg_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities) | ||
74 | { | ||
75 | /* NOP */ | ||
76 | } | ||
77 | |||
78 | static 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 | |||
85 | static 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 | |||
90 | static const struct xdg_wm_base_listener xdg_wm_base_listener = { | ||
91 | .ping = xdg_wm_base_ping, | ||
92 | }; | ||
93 | |||
94 | static 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 | |||
104 | static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) | ||
105 | { | ||
106 | /* NOP */ | ||
107 | } | ||
108 | |||
109 | static const struct wl_registry_listener wl_registry_listener = { | ||
110 | .global = registry_global, | ||
111 | .global_remove = registry_global_remove, | ||
112 | }; | ||
113 | |||
114 | static 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 | |||
161 | error: | ||
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 | |||
190 | static 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 | ||