Atlas - testnativewayland.c
Home / ext / SDL / test Lines: 1 | Size: 7506 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 227[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.