From 6aaedb813fa11ba0679c3051bc2eb28646b9506c Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 30 Aug 2025 16:53:58 -0700 Subject: Update to SDL3 --- src/contrib/SDL-3.2.20/test/testnativewayland.c | 226 ++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 src/contrib/SDL-3.2.20/test/testnativewayland.c (limited to 'src/contrib/SDL-3.2.20/test/testnativewayland.c') 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 @@ +/* + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +#include "testnative.h" + +#ifdef TEST_NATIVE_WAYLAND + +#include +#include +#include + +static void *native_userdata_ptr = (void *)0xBAADF00D; +static const char *native_surface_tag = "SDL_NativeSurfaceTag"; + +static void *CreateWindowWayland(int w, int h); +static void DestroyWindowWayland(void *window); + +NativeWindowFactory WaylandWindowFactory = { + "wayland", + CreateWindowWayland, + DestroyWindowWayland +}; + +/* Encapsulated in a struct to silence shadow variable warnings */ +static struct _state +{ + struct wl_display *wl_display; + struct wl_registry *wl_registry; + struct wl_compositor *wl_compositor; + struct xdg_wm_base *xdg_wm_base; + struct wl_surface *wl_surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; +} state; + +static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial) +{ + xdg_surface_ack_configure(state.xdg_surface, serial); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_configure, +}; + +static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states) +{ + /* NOP */ +} + +static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) +{ + SDL_Event event; + SDL_zero(event); + + event.type = SDL_EVENT_QUIT; + SDL_PushEvent(&event); +} + +static void xdg_toplevel_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height) +{ + /* NOP */ +} + +static void xdg_toplevel_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities) +{ + /* NOP */ +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_configure, + .close = xdg_toplevel_close, + .configure_bounds = xdg_toplevel_configure_bounds, + .wm_capabilities = xdg_toplevel_wm_capabilities +}; + +static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial) +{ + xdg_wm_base_pong(state.xdg_wm_base, serial); +} + +static const struct xdg_wm_base_listener xdg_wm_base_listener = { + .ping = xdg_wm_base_ping, +}; + +static void registry_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version) +{ + if (SDL_strcmp(interface, wl_compositor_interface.name) == 0) { + state.wl_compositor = wl_registry_bind(state.wl_registry, name, &wl_compositor_interface, SDL_min(version, 4)); + } else if (SDL_strcmp(interface, xdg_wm_base_interface.name) == 0) { + state.xdg_wm_base = wl_registry_bind(state.wl_registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(state.xdg_wm_base, &xdg_wm_base_listener, NULL); + } +} + +static void registry_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) +{ + /* NOP */ +} + +static const struct wl_registry_listener wl_registry_listener = { + .global = registry_global, + .global_remove = registry_global_remove, +}; + +static void *CreateWindowWayland(int w, int h) +{ + /* Export the display object from SDL and use it to create a registry object, + * which will enumerate the wl_compositor and xdg_wm_base protocols. + */ + state.wl_display = SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, NULL); + + if (!state.wl_display) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid 'wl_display' object!"); + goto error; + } + + state.wl_registry = wl_display_get_registry(state.wl_display); + wl_registry_add_listener(state.wl_registry, &wl_registry_listener, NULL); + + /* Roundtrip to enumerate registry objects. */ + wl_display_roundtrip(state.wl_display); + + /* Protocol sanity check */ + if (!state.wl_compositor) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "'wl_compositor' protocol not found!"); + goto error; + } + if (!state.xdg_wm_base) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "'xdg_wm_base' protocol not found!"); + goto error; + } + + /* Crate the backing wl_surface for the window. */ + state.wl_surface = wl_compositor_create_surface(state.wl_compositor); + + /* Set the native tag and userdata values, which should be the same at exit. */ + wl_proxy_set_tag((struct wl_proxy *)state.wl_surface, &native_surface_tag); + wl_surface_set_user_data(state.wl_surface, native_userdata_ptr); + + /* Create the xdg_surface from the wl_surface. */ + state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.wl_surface); + xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, NULL); + + /* Create the xdg_toplevel from the xdg_surface. */ + state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface); + xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_listener, NULL); + xdg_toplevel_set_title(state.xdg_toplevel, "Native Wayland Window"); + + /* Return the wl_surface to be wrapped in an SDL_Window. */ + return state.wl_surface; + +error: + if (state.xdg_toplevel) { + xdg_toplevel_destroy(state.xdg_toplevel); + state.xdg_toplevel = NULL; + } + if (state.xdg_surface) { + xdg_surface_destroy(state.xdg_surface); + state.xdg_surface = NULL; + } + if (state.wl_surface) { + wl_surface_destroy(state.wl_surface); + state.wl_surface = NULL; + } + if (state.xdg_wm_base) { + xdg_wm_base_destroy(state.xdg_wm_base); + state.xdg_wm_base = NULL; + } + if (state.wl_compositor) { + wl_compositor_destroy(state.wl_compositor); + state.wl_compositor = NULL; + } + if (state.wl_registry) { + wl_registry_destroy(state.wl_registry); + state.wl_registry = NULL; + } + + return NULL; +} + +static void DestroyWindowWayland(void *window) +{ + if (state.xdg_toplevel) { + xdg_toplevel_destroy(state.xdg_toplevel); + state.xdg_toplevel = NULL; + } + if (state.xdg_surface) { + xdg_surface_destroy(state.xdg_surface); + state.xdg_surface = NULL; + } + if (state.wl_surface) { + /* Surface sanity check; these should be unmodified. */ + if (wl_proxy_get_tag((struct wl_proxy *)state.wl_surface) != &native_surface_tag) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "The wl_surface tag was modified, this indicates a problem inside of SDL."); + } + if (wl_surface_get_user_data(state.wl_surface) != native_userdata_ptr) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "The wl_surface user data was modified, this indicates a problem inside of SDL."); + } + + wl_surface_destroy(state.wl_surface); + state.wl_surface = NULL; + } + if (state.xdg_wm_base) { + xdg_wm_base_destroy(state.xdg_wm_base); + state.xdg_wm_base = NULL; + } + if (state.wl_compositor) { + wl_compositor_destroy(state.wl_compositor); + state.wl_compositor = NULL; + } + if (state.wl_registry) { + wl_registry_destroy(state.wl_registry); + state.wl_registry = NULL; + } +} + +#endif -- cgit v1.2.3