From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- contrib/SDL-3.2.8/src/video/SDL_video.c | 6130 ------------------------------- 1 file changed, 6130 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/video/SDL_video.c (limited to 'contrib/SDL-3.2.8/src/video/SDL_video.c') diff --git a/contrib/SDL-3.2.8/src/video/SDL_video.c b/contrib/SDL-3.2.8/src/video/SDL_video.c deleted file mode 100644 index 3ed4994..0000000 --- a/contrib/SDL-3.2.8/src/video/SDL_video.c +++ /dev/null @@ -1,6130 +0,0 @@ -/* - Simple DirectMedia Layer - 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, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "SDL_internal.h" - -// The high-level video driver subsystem - -#include "SDL_sysvideo.h" -#include "SDL_clipboard_c.h" -#include "SDL_egl_c.h" -#include "SDL_surface_c.h" -#include "SDL_pixels_c.h" -#include "SDL_rect_c.h" -#include "SDL_video_c.h" -#include "../events/SDL_events_c.h" -#include "../SDL_hints_c.h" -#include "../SDL_properties_c.h" -#include "../timer/SDL_timer_c.h" -#include "../camera/SDL_camera_c.h" -#include "../render/SDL_sysrender.h" -#include "../main/SDL_main_callbacks.h" - -#ifdef SDL_VIDEO_OPENGL -#include -#endif // SDL_VIDEO_OPENGL - -#if defined(SDL_VIDEO_OPENGL_ES) && !defined(SDL_VIDEO_OPENGL) -#include -#endif // SDL_VIDEO_OPENGL_ES && !SDL_VIDEO_OPENGL - -// GL and GLES2 headers conflict on Linux 32 bits -#if defined(SDL_VIDEO_OPENGL_ES2) && !defined(SDL_VIDEO_OPENGL) -#include -#endif // SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL - -// GL_CONTEXT_RELEASE_BEHAVIOR and GL_CONTEXT_RELEASE_BEHAVIOR_KHR have the same number. -#ifndef GL_CONTEXT_RELEASE_BEHAVIOR -#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB -#endif - -// GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH and GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR have the same number. -#ifndef GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH -#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC -#endif - -#ifdef SDL_PLATFORM_EMSCRIPTEN -#include -#endif - -#ifdef SDL_PLATFORM_3DS -#include <3ds.h> -#endif - -#ifdef SDL_PLATFORM_LINUX -#include -#include -#include -#endif - -// Available video drivers -static VideoBootStrap *bootstrap[] = { -#ifdef SDL_VIDEO_DRIVER_PRIVATE - &PRIVATE_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_COCOA - &COCOA_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_X11 -#ifdef SDL_VIDEO_DRIVER_WAYLAND - &Wayland_preferred_bootstrap, -#endif - &X11_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_WAYLAND - &Wayland_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_VIVANTE - &VIVANTE_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_WINDOWS - &WINDOWS_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_HAIKU - &HAIKU_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_UIKIT - &UIKIT_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_ANDROID - &Android_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_PS2 - &PS2_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_PSP - &PSP_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_VITA - &VITA_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_N3DS - &N3DS_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_KMSDRM - &KMSDRM_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_RISCOS - &RISCOS_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_RPI - &RPI_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN - &Emscripten_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_QNX - &QNX_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_OFFSCREEN - &OFFSCREEN_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_DUMMY - &DUMMY_bootstrap, -#ifdef SDL_INPUT_LINUXEV - &DUMMY_evdev_bootstrap, -#endif -#endif -#ifdef SDL_VIDEO_DRIVER_OPENVR - &OPENVR_bootstrap, -#endif - NULL -}; - -#define CHECK_WINDOW_MAGIC(window, result) \ - if (!_this) { \ - SDL_UninitializedVideo(); \ - return result; \ - } \ - if (!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW)) { \ - SDL_SetError("Invalid window"); \ - return result; \ - } - -#define CHECK_DISPLAY_MAGIC(display, result) \ - if (!display) { \ - return result; \ - } \ - -#define CHECK_WINDOW_NOT_POPUP(window, result) \ - if (SDL_WINDOW_IS_POPUP(window)) { \ - SDL_SetError("Operation invalid on popup windows"); \ - return result; \ - } - -#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA) -// Support for macOS fullscreen spaces -extern bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window); -extern bool Cocoa_SetWindowFullscreenSpace(SDL_Window *window, bool state, bool blocking); -#endif - -#ifdef SDL_VIDEO_DRIVER_UIKIT -extern void SDL_UpdateLifecycleObserver(void); -#endif - -static void SDL_CheckWindowDisplayChanged(SDL_Window *window); -static void SDL_CheckWindowDisplayScaleChanged(SDL_Window *window); -static void SDL_CheckWindowSafeAreaChanged(SDL_Window *window); - -// Convenience functions for reading driver flags -static bool SDL_ModeSwitchingEmulated(SDL_VideoDevice *_this) -{ - if (_this->device_caps & VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED) { - return true; - } - return false; -} - -static bool SDL_SendsFullscreenDimensions(SDL_VideoDevice *_this) -{ - return !!(_this->device_caps & VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS); -} - -static bool IsFullscreenOnly(SDL_VideoDevice *_this) -{ - return !!(_this->device_caps & VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY); -} - -static bool SDL_SendsDisplayChanges(SDL_VideoDevice *_this) -{ - return !!(_this->device_caps & VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES); -} - -static bool SDL_DisableMouseWarpOnFullscreenTransitions(SDL_VideoDevice *_this) -{ - return !!(_this->device_caps & VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS); -} - -static bool SDL_DriverSendsHDRChanges(SDL_VideoDevice *_this) -{ - return !!(_this->device_caps & VIDEO_DEVICE_CAPS_SENDS_HDR_CHANGES); -} - -// Hint to treat all window ops as synchronous -static bool syncHint; - -static void SDL_SyncHintWatcher(void *userdata, const char *name, const char *oldValue, const char *newValue) -{ - syncHint = SDL_GetStringBoolean(newValue, false); -} - -static void SDL_SyncIfRequired(SDL_Window *window) -{ - if (syncHint) { - SDL_SyncWindow(window); - } -} - -static void SDL_UpdateWindowHierarchy(SDL_Window *window, SDL_Window *parent) -{ - // Unlink the window from the existing parent. - if (window->parent) { - if (window->next_sibling) { - window->next_sibling->prev_sibling = window->prev_sibling; - } - if (window->prev_sibling) { - window->prev_sibling->next_sibling = window->next_sibling; - } else { - window->parent->first_child = window->next_sibling; - } - - window->parent = NULL; - } - - if (parent) { - window->parent = parent; - - window->next_sibling = parent->first_child; - if (parent->first_child) { - parent->first_child->prev_sibling = window; - } - parent->first_child = window; - } -} - -// Support for framebuffer emulation using an accelerated renderer - -#define SDL_PROP_WINDOW_TEXTUREDATA_POINTER "SDL.internal.window.texturedata" - -typedef struct -{ - SDL_Renderer *renderer; - SDL_Texture *texture; - void *pixels; - int pitch; - int bytes_per_pixel; -} SDL_WindowTextureData; - -static Uint32 SDL_DefaultGraphicsBackends(SDL_VideoDevice *_this) -{ -#if (defined(SDL_VIDEO_OPENGL) && defined(SDL_PLATFORM_MACOS)) || (defined(SDL_PLATFORM_IOS) && !TARGET_OS_MACCATALYST) - if (_this->GL_CreateContext) { - return SDL_WINDOW_OPENGL; - } -#endif -#if defined(SDL_VIDEO_METAL) && (TARGET_OS_MACCATALYST || defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS)) - if (_this->Metal_CreateView) { - return SDL_WINDOW_METAL; - } -#endif -#if defined(SDL_VIDEO_OPENGL) && defined(SDL_VIDEO_DRIVER_OPENVR) - if (SDL_strcmp(_this->name, "openvr") == 0) { - return SDL_WINDOW_OPENGL; - } -#endif - return 0; -} - -static void SDLCALL SDL_CleanupWindowTextureData(void *userdata, void *value) -{ - SDL_WindowTextureData *data = (SDL_WindowTextureData *)value; - - if (data->texture) { - SDL_DestroyTexture(data->texture); - } - if (data->renderer) { - SDL_DestroyRenderer(data->renderer); - } - SDL_free(data->pixels); - SDL_free(data); -} - -static bool SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format, void **pixels, int *pitch) -{ - SDL_PropertiesID props = SDL_GetWindowProperties(window); - SDL_WindowTextureData *data = (SDL_WindowTextureData *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_TEXTUREDATA_POINTER, NULL); - const bool transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? true : false; - int i; - int w, h; - const SDL_PixelFormat *texture_formats; - - SDL_GetWindowSizeInPixels(window, &w, &h); - - if (!data) { - SDL_Renderer *renderer = NULL; - const char *render_driver = NULL; - - // See if there's a render driver being requested - const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); - if (hint && *hint != '0' && *hint != '1' && - SDL_strcasecmp(hint, "true") != 0 && - SDL_strcasecmp(hint, "false") != 0 && - SDL_strcasecmp(hint, SDL_SOFTWARE_RENDERER) != 0) { - render_driver = hint; - } - - if (!render_driver) { - render_driver = SDL_GetHint(SDL_HINT_RENDER_DRIVER); - } - if (render_driver && SDL_strcasecmp(render_driver, SDL_SOFTWARE_RENDERER) == 0) { - render_driver = NULL; - } - - char *render_driver_copy = NULL; - if (render_driver && *render_driver) { - render_driver_copy = SDL_strdup(render_driver); - render_driver = render_driver_copy; - if (render_driver_copy) { // turn any "software" requests into "xxxxxxxx" so we don't end up in infinite recursion. - char *prev = render_driver_copy; - char *ptr = prev; - while ((ptr = SDL_strchr(ptr, ',')) != NULL) { - *ptr = '\0'; - const bool is_sw = (SDL_strcasecmp(prev, SDL_SOFTWARE_RENDERER) == 0); - *ptr = ','; - if (is_sw) { - SDL_memset(prev, 'x', SDL_strlen(SDL_SOFTWARE_RENDERER)); - ptr = prev; - } else { - ptr++; - prev = ptr; - } - } - - if (SDL_strcasecmp(prev, SDL_SOFTWARE_RENDERER) == 0) { - SDL_memset(prev, 'x', SDL_strlen(SDL_SOFTWARE_RENDERER)); - } - } - } - - // Check to see if there's a specific driver requested - if (render_driver) { - renderer = SDL_CreateRenderer(window, render_driver); - SDL_free(render_driver_copy); - if (!renderer) { - // The error for this specific renderer has already been set - return false; - } - } else { - SDL_assert(render_driver_copy == NULL); - const int total = SDL_GetNumRenderDrivers(); - for (i = 0; i < total; ++i) { - const char *name = SDL_GetRenderDriver(i); - if (name && SDL_strcmp(name, SDL_SOFTWARE_RENDERER) != 0) { - renderer = SDL_CreateRenderer(window, name); - if (renderer) { - break; // this will work. - } - } - } - if (!renderer) { - return SDL_SetError("No hardware accelerated renderers available"); - } - } - - SDL_assert(renderer != NULL); // should have explicitly checked this above. - - // Create the data after we successfully create the renderer (bug #1116) - data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_DestroyRenderer(renderer); - return false; - } - if (!SDL_SetPointerPropertyWithCleanup(props, SDL_PROP_WINDOW_TEXTUREDATA_POINTER, data, SDL_CleanupWindowTextureData, NULL)) { - SDL_DestroyRenderer(renderer); - return false; - } - - data->renderer = renderer; - } - - texture_formats = (const SDL_PixelFormat *)SDL_GetPointerProperty(SDL_GetRendererProperties(data->renderer), SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, NULL); - if (!texture_formats) { - return false; - } - - // Free any old texture and pixel data - if (data->texture) { - SDL_DestroyTexture(data->texture); - data->texture = NULL; - } - SDL_free(data->pixels); - data->pixels = NULL; - - // Find the first format with or without an alpha channel - *format = texture_formats[0]; - - for (i = 0; texture_formats[i] != SDL_PIXELFORMAT_UNKNOWN; ++i) { - SDL_PixelFormat texture_format = texture_formats[i]; - if (!SDL_ISPIXELFORMAT_FOURCC(texture_format) && - !SDL_ISPIXELFORMAT_10BIT(texture_format) && - !SDL_ISPIXELFORMAT_FLOAT(texture_format) && - transparent == SDL_ISPIXELFORMAT_ALPHA(texture_format)) { - *format = texture_format; - break; - } - } - - data->texture = SDL_CreateTexture(data->renderer, *format, - SDL_TEXTUREACCESS_STREAMING, - w, h); - if (!data->texture) { - // codechecker_false_positive [Malloc] Static analyzer doesn't realize allocated `data` is saved to SDL_PROP_WINDOW_TEXTUREDATA_POINTER and not leaked here. - return false; // NOLINT(clang-analyzer-unix.Malloc) - } - - // Create framebuffer data - data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format); - data->pitch = (((w * data->bytes_per_pixel) + 3) & ~3); - - { - // Make static analysis happy about potential SDL_malloc(0) calls. - const size_t allocsize = (size_t)h * data->pitch; - data->pixels = SDL_malloc((allocsize > 0) ? allocsize : 1); - if (!data->pixels) { - return false; - } - } - - *pixels = data->pixels; - *pitch = data->pitch; - - // Make sure we're not double-scaling the viewport - SDL_SetRenderViewport(data->renderer, NULL); - - return true; -} - -bool SDL_SetWindowTextureVSync(SDL_VideoDevice *_this, SDL_Window *window, int vsync) -{ - SDL_WindowTextureData *data; - - data = (SDL_WindowTextureData *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER, NULL); - if (!data) { - return false; - } - if (!data->renderer) { - return false; - } - return SDL_SetRenderVSync(data->renderer, vsync); -} - -static bool SDL_GetWindowTextureVSync(SDL_VideoDevice *_this, SDL_Window *window, int *vsync) -{ - SDL_WindowTextureData *data; - - data = (SDL_WindowTextureData *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER, NULL); - if (!data) { - return false; - } - if (!data->renderer) { - return false; - } - return SDL_GetRenderVSync(data->renderer, vsync); -} - -static bool SDL_UpdateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects) -{ - SDL_WindowTextureData *data; - SDL_Rect rect; - void *src; - int w, h; - - SDL_GetWindowSizeInPixels(window, &w, &h); - - data = (SDL_WindowTextureData *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER, NULL); - if (!data || !data->texture) { - return SDL_SetError("No window texture data"); - } - - // Update a single rect that contains subrects for best DMA performance - if (SDL_GetSpanEnclosingRect(w, h, numrects, rects, &rect)) { - src = (void *)((Uint8 *)data->pixels + - rect.y * data->pitch + - rect.x * data->bytes_per_pixel); - if (!SDL_UpdateTexture(data->texture, &rect, src, data->pitch)) { - return false; - } - - if (!SDL_RenderTexture(data->renderer, data->texture, NULL, NULL)) { - return false; - } - - SDL_RenderPresent(data->renderer); - } - return true; -} - -static void SDL_DestroyWindowTexture(SDL_VideoDevice *_this, SDL_Window *window) -{ - SDL_ClearProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_TEXTUREDATA_POINTER); -} - -static SDL_VideoDevice *_this = NULL; -static SDL_AtomicInt SDL_messagebox_count; - -static int SDLCALL cmpmodes(const void *A, const void *B) -{ - const SDL_DisplayMode *a = (const SDL_DisplayMode *)A; - const SDL_DisplayMode *b = (const SDL_DisplayMode *)B; - int a_refresh_rate = (int)(a->refresh_rate * 100); - int b_refresh_rate = (int)(b->refresh_rate * 100); - int a_pixel_density = (int)(a->pixel_density * 100); - int b_pixel_density = (int)(b->pixel_density * 100); - - if (a->w != b->w) { - return b->w - a->w; - } else if (a->h != b->h) { - return b->h - a->h; - } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) { - return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format); - } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) { - return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format); - } else if (a_refresh_rate != b_refresh_rate) { - return b_refresh_rate - a_refresh_rate; - } else if (a_pixel_density != b_pixel_density) { - return a_pixel_density - b_pixel_density; - } - return 0; -} - -bool SDL_UninitializedVideo(void) -{ - return SDL_SetError("Video subsystem has not been initialized"); -} - -// Deduplicated list of video bootstrap drivers. -static const VideoBootStrap *deduped_bootstrap[SDL_arraysize(bootstrap) - 1]; - -int SDL_GetNumVideoDrivers(void) -{ - static int num_drivers = -1; - - if (num_drivers >= 0) { - return num_drivers; - } - - num_drivers = 0; - - // Build a list of unique video drivers. - for (int i = 0; bootstrap[i] != NULL; ++i) { - bool duplicate = false; - for (int j = 0; j < i; ++j) { - if (SDL_strcmp(bootstrap[i]->name, bootstrap[j]->name) == 0) { - duplicate = true; - break; - } - } - - if (!duplicate) { - deduped_bootstrap[num_drivers++] = bootstrap[i]; - } - } - - return num_drivers; -} - -const char *SDL_GetVideoDriver(int index) -{ - if (index >= 0 && index < SDL_GetNumVideoDrivers()) { - return deduped_bootstrap[index]->name; - } - SDL_InvalidParamError("index"); - return NULL; -} - -/* - * Initialize the video and event subsystems -- determine native pixel format - */ -bool SDL_VideoInit(const char *driver_name) -{ - SDL_VideoDevice *video; - bool init_events = false; - bool init_keyboard = false; - bool init_mouse = false; - bool init_touch = false; - bool init_pen = false; - int i = 0; - - // Check to make sure we don't overwrite '_this' - if (_this) { - SDL_VideoQuit(); - } - - SDL_InitTicks(); - - // Start the event loop - if (!SDL_InitSubSystem(SDL_INIT_EVENTS)) { - goto pre_driver_error; - } - init_events = true; - if (!SDL_InitKeyboard()) { - goto pre_driver_error; - } - init_keyboard = true; - if (!SDL_PreInitMouse()) { - goto pre_driver_error; - } - init_mouse = true; - if (!SDL_InitTouch()) { - goto pre_driver_error; - } - init_touch = true; - if (!SDL_InitPen()) { - goto pre_driver_error; - } - init_pen = true; - - // Select the proper video driver - video = NULL; - if (!driver_name) { - driver_name = SDL_GetHint(SDL_HINT_VIDEO_DRIVER); - } - if (driver_name && *driver_name != 0) { - const char *driver_attempt = driver_name; - while (driver_attempt && *driver_attempt != 0 && !video) { - const char *driver_attempt_end = SDL_strchr(driver_attempt, ','); - size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt) - : SDL_strlen(driver_attempt); - - for (i = 0; bootstrap[i]; ++i) { - if (!bootstrap[i]->is_preferred && - (driver_attempt_len == SDL_strlen(bootstrap[i]->name)) && - (SDL_strncasecmp(bootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) { - video = bootstrap[i]->create(); - if (video) { - break; - } - } - } - - driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL; - } - } else { - for (i = 0; bootstrap[i]; ++i) { - video = bootstrap[i]->create(); - if (video) { - break; - } - } - } - if (!video) { - if (driver_name) { - SDL_SetError("%s not available", driver_name); - goto pre_driver_error; - } - SDL_SetError("No available video device"); - goto pre_driver_error; - } - - /* From this point on, use SDL_VideoQuit to cleanup on error, rather than - pre_driver_error. */ - _this = video; - _this->name = bootstrap[i]->name; - _this->thread = SDL_GetCurrentThreadID(); - - // Set some very sane GL defaults - _this->gl_config.driver_loaded = 0; - _this->gl_config.dll_handle = NULL; - SDL_GL_ResetAttributes(); - - // Initialize the video subsystem - if (!_this->VideoInit(_this)) { - SDL_VideoQuit(); - return false; - } - - // Make sure some displays were added - if (_this->num_displays == 0) { - SDL_VideoQuit(); - return SDL_SetError("The video driver did not add any displays"); - } - - SDL_AddHintCallback(SDL_HINT_VIDEO_SYNC_WINDOW_OPERATIONS, SDL_SyncHintWatcher, NULL); - - /* Disable the screen saver by default. This is a change from <= 2.0.1, - but most things using SDL are games or media players; you wouldn't - want a screensaver to trigger if you're playing exclusively with a - joystick, or passively watching a movie. Things that use SDL but - function more like a normal desktop app should explicitly reenable the - screensaver. */ - if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, false)) { - SDL_DisableScreenSaver(); - } - - SDL_PostInitMouse(); - - // We're ready to go! - return true; - -pre_driver_error: - SDL_assert(_this == NULL); - if (init_pen) { - SDL_QuitPen(); - } - if (init_touch) { - SDL_QuitTouch(); - } - if (init_mouse) { - SDL_QuitMouse(); - } - if (init_keyboard) { - SDL_QuitKeyboard(); - } - if (init_events) { - SDL_QuitSubSystem(SDL_INIT_EVENTS); - } - return false; -} - -const char *SDL_GetCurrentVideoDriver(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - return _this->name; -} - -SDL_VideoDevice *SDL_GetVideoDevice(void) -{ - return _this; -} - -bool SDL_OnVideoThread(void) -{ - return (_this && SDL_GetCurrentThreadID() == _this->thread); -} - -void SDL_SetSystemTheme(SDL_SystemTheme theme) -{ - if (_this && theme != _this->system_theme) { - _this->system_theme = theme; - SDL_SendSystemThemeChangedEvent(); - } -} - -SDL_SystemTheme SDL_GetSystemTheme(void) -{ - if (_this) { - return _this->system_theme; - } else { - return SDL_SYSTEM_THEME_UNKNOWN; - } -} - -void SDL_UpdateDesktopBounds(void) -{ - SDL_Rect rect; - SDL_zero(rect); - - SDL_DisplayID *displays = SDL_GetDisplays(NULL); - if (displays) { - for (int i = 0; displays[i]; ++i) { - SDL_Rect bounds; - if (SDL_GetDisplayBounds(displays[i], &bounds)) { - if (i == 0) { - SDL_copyp(&rect, &bounds); - } else { - SDL_GetRectUnion(&rect, &bounds, &rect); - } - } - } - SDL_free(displays); - } - SDL_copyp(&_this->desktop_bounds, &rect); -} - -static void SDL_FinalizeDisplayMode(SDL_DisplayMode *mode) -{ - // Make sure all the fields are set up correctly - if (mode->pixel_density <= 0.0f) { - mode->pixel_density = 1.0f; - } - - if (mode->refresh_rate_numerator > 0) { - if (mode->refresh_rate_denominator <= 0) { - mode->refresh_rate_denominator = 1; - } - mode->refresh_rate = ((100 * (Sint64)mode->refresh_rate_numerator) / mode->refresh_rate_denominator) / 100.0f; - } else { - SDL_CalculateFraction(mode->refresh_rate, &mode->refresh_rate_numerator, &mode->refresh_rate_denominator); - mode->refresh_rate = (int)(mode->refresh_rate * 100) / 100.0f; - } -} - -SDL_DisplayID SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode) -{ - SDL_VideoDisplay display; - - SDL_zero(display); - if (desktop_mode) { - SDL_memcpy(&display.desktop_mode, desktop_mode, sizeof(display.desktop_mode)); - } - return SDL_AddVideoDisplay(&display, false); -} - -SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, bool send_event) -{ - SDL_VideoDisplay **displays, *new_display; - SDL_DisplayID id; - SDL_PropertiesID props; - int i; - - new_display = (SDL_VideoDisplay *)SDL_malloc(sizeof(*new_display)); - if (!new_display) { - return true; - } - - displays = (SDL_VideoDisplay **)SDL_realloc(_this->displays, (_this->num_displays + 1) * sizeof(*displays)); - if (!displays) { - SDL_free(new_display); - return true; - } - _this->displays = displays; - _this->displays[_this->num_displays++] = new_display; - - id = SDL_GetNextObjectID(); - SDL_copyp(new_display, display); - new_display->id = id; - new_display->device = _this; - if (display->name) { - new_display->name = SDL_strdup(display->name); - } else { - char name[32]; - - SDL_itoa(id, name, 10); - new_display->name = SDL_strdup(name); - } - if (new_display->content_scale == 0.0f) { - new_display->content_scale = 1.0f; - } - - new_display->desktop_mode.displayID = id; - new_display->current_mode = &new_display->desktop_mode; - SDL_FinalizeDisplayMode(&new_display->desktop_mode); - - for (i = 0; i < new_display->num_fullscreen_modes; ++i) { - new_display->fullscreen_modes[i].displayID = id; - } - - new_display->HDR.HDR_headroom = SDL_max(display->HDR.HDR_headroom, 1.0f); - new_display->HDR.SDR_white_level = SDL_max(display->HDR.SDR_white_level, 1.0f); - - props = SDL_GetDisplayProperties(id); - SDL_SetBooleanProperty(props, SDL_PROP_DISPLAY_HDR_ENABLED_BOOLEAN, new_display->HDR.HDR_headroom > 1.0f); - - SDL_UpdateDesktopBounds(); - - if (send_event) { - SDL_SendDisplayEvent(new_display, SDL_EVENT_DISPLAY_ADDED, 0, 0); - } - - return id; -} - -void SDL_OnDisplayAdded(SDL_VideoDisplay *display) -{ - SDL_Window *window; - - // See if any windows have changed to the new display - for (window = _this->windows; window; window = window->next) { - SDL_CheckWindowDisplayChanged(window); - } -} - -void SDL_OnDisplayMoved(SDL_VideoDisplay *display) -{ - SDL_UpdateDesktopBounds(); -} - -void SDL_DelVideoDisplay(SDL_DisplayID displayID, bool send_event) -{ - SDL_VideoDisplay *display; - int display_index = SDL_GetDisplayIndex(displayID); - if (display_index < 0) { - return; - } - - display = _this->displays[display_index]; - - if (send_event) { - SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_REMOVED, 0, 0); - } - - SDL_DestroyProperties(display->props); - SDL_free(display->name); - SDL_ResetFullscreenDisplayModes(display); - SDL_free(display->desktop_mode.internal); - display->desktop_mode.internal = NULL; - SDL_free(display->internal); - display->internal = NULL; - SDL_free(display); - - if (display_index < (_this->num_displays - 1)) { - SDL_memmove(&_this->displays[display_index], &_this->displays[display_index + 1], (_this->num_displays - display_index - 1) * sizeof(_this->displays[display_index])); - } - --_this->num_displays; - - SDL_UpdateDesktopBounds(); -} - -SDL_DisplayID *SDL_GetDisplays(int *count) -{ - int i; - SDL_DisplayID *displays; - - if (!_this) { - if (count) { - *count = 0; - } - - SDL_UninitializedVideo(); - return NULL; - } - - displays = (SDL_DisplayID *)SDL_malloc((_this->num_displays + 1) * sizeof(*displays)); - if (displays) { - if (count) { - *count = _this->num_displays; - } - - for (i = 0; i < _this->num_displays; ++i) { - displays[i] = _this->displays[i]->id; - } - displays[i] = 0; - } else { - if (count) { - *count = 0; - } - } - return displays; -} - -SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID displayID) -{ - int display_index; - - display_index = SDL_GetDisplayIndex(displayID); - if (display_index < 0) { - return NULL; - } - return _this->displays[display_index]; -} - -SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window) -{ - return SDL_GetVideoDisplay(SDL_GetDisplayForWindow(window)); -} - -SDL_DisplayID SDL_GetPrimaryDisplay(void) -{ - if (!_this || _this->num_displays == 0) { - SDL_UninitializedVideo(); - return 0; - } - return _this->displays[0]->id; -} - -int SDL_GetDisplayIndex(SDL_DisplayID displayID) -{ - int display_index; - - if (!_this) { - SDL_UninitializedVideo(); - return -1; - } - - for (display_index = 0; display_index < _this->num_displays; ++display_index) { - if (displayID == _this->displays[display_index]->id) { - return display_index; - } - } - SDL_SetError("Invalid display"); - return -1; -} - -SDL_DisplayData *SDL_GetDisplayDriverData(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, NULL); - - return display->internal; -} - -SDL_DisplayData *SDL_GetDisplayDriverDataForWindow(SDL_Window *window) -{ - return SDL_GetDisplayDriverData(SDL_GetDisplayForWindow(window)); -} - -SDL_PropertiesID SDL_GetDisplayProperties(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, 0); - - if (display->props == 0) { - display->props = SDL_CreateProperties(); - } - return display->props; -} - -const char *SDL_GetDisplayName(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, NULL); - - return display->name; -} - -bool SDL_GetDisplayBounds(SDL_DisplayID displayID, SDL_Rect *rect) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, false); - - if (!rect) { - return SDL_InvalidParamError("rect"); - } - - if (_this->GetDisplayBounds) { - if (_this->GetDisplayBounds(_this, display, rect)) { - return true; - } - } - - // Assume that the displays are left to right - if (displayID == SDL_GetPrimaryDisplay()) { - rect->x = 0; - rect->y = 0; - } else { - SDL_GetDisplayBounds(_this->displays[SDL_GetDisplayIndex(displayID) - 1]->id, rect); - rect->x += rect->w; - } - rect->w = display->current_mode->w; - rect->h = display->current_mode->h; - return true; -} - -static int ParseDisplayUsableBoundsHint(SDL_Rect *rect) -{ - const char *hint = SDL_GetHint(SDL_HINT_DISPLAY_USABLE_BOUNDS); - return hint && (SDL_sscanf(hint, "%d,%d,%d,%d", &rect->x, &rect->y, &rect->w, &rect->h) == 4); -} - -bool SDL_GetDisplayUsableBounds(SDL_DisplayID displayID, SDL_Rect *rect) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, false); - - if (!rect) { - return SDL_InvalidParamError("rect"); - } - - if (displayID == SDL_GetPrimaryDisplay() && ParseDisplayUsableBoundsHint(rect)) { - return true; - } - - if (_this->GetDisplayUsableBounds) { - if (_this->GetDisplayUsableBounds(_this, display, rect)) { - return true; - } - } - - // Oh well, just give the entire display bounds. - return SDL_GetDisplayBounds(displayID, rect); -} - -SDL_DisplayOrientation SDL_GetNaturalDisplayOrientation(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, SDL_ORIENTATION_UNKNOWN); - - if (display->natural_orientation != SDL_ORIENTATION_UNKNOWN) { - return display->natural_orientation; - } else { - // Default to landscape if the driver hasn't set it - return SDL_ORIENTATION_LANDSCAPE; - } -} - -SDL_DisplayOrientation SDL_GetCurrentDisplayOrientation(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, SDL_ORIENTATION_UNKNOWN); - - if (display->current_orientation != SDL_ORIENTATION_UNKNOWN) { - return display->current_orientation; - } else { - // Default to landscape if the driver hasn't set it - return SDL_ORIENTATION_LANDSCAPE; - } -} - -void SDL_SetDisplayContentScale(SDL_VideoDisplay *display, float scale) -{ - if (scale != display->content_scale) { - SDL_Window *window; - - display->content_scale = scale; - SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED, 0, 0); - - // Check the windows on this display - for (window = _this->windows; window; window = window->next) { - if (display->id == window->last_displayID) { - SDL_CheckWindowDisplayScaleChanged(window); - } - } - } -} - -float SDL_GetDisplayContentScale(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, 0.0f); - - return display->content_scale; -} - -void SDL_SetWindowHDRProperties(SDL_Window *window, const SDL_HDROutputProperties *HDR, bool send_event) -{ - if (window->HDR.HDR_headroom != HDR->HDR_headroom || window->HDR.SDR_white_level != window->HDR.SDR_white_level) { - SDL_PropertiesID window_props = SDL_GetWindowProperties(window); - - SDL_SetFloatProperty(window_props, SDL_PROP_WINDOW_HDR_HEADROOM_FLOAT, SDL_max(HDR->HDR_headroom, 1.0f)); - SDL_SetFloatProperty(window_props, SDL_PROP_WINDOW_SDR_WHITE_LEVEL_FLOAT, SDL_max(HDR->SDR_white_level, 1.0f)); - SDL_SetBooleanProperty(window_props, SDL_PROP_WINDOW_HDR_ENABLED_BOOLEAN, HDR->HDR_headroom > 1.0f); - SDL_copyp(&window->HDR, HDR); - - if (send_event) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_HDR_STATE_CHANGED, HDR->HDR_headroom > 1.0f, 0); - } - } -} - -void SDL_SetDisplayHDRProperties(SDL_VideoDisplay *display, const SDL_HDROutputProperties *HDR) -{ - bool changed = false; - - if (HDR->SDR_white_level != display->HDR.SDR_white_level) { - display->HDR.SDR_white_level = SDL_max(HDR->SDR_white_level, 1.0f); - changed = true; - } - if (HDR->HDR_headroom != display->HDR.HDR_headroom) { - display->HDR.HDR_headroom = SDL_max(HDR->HDR_headroom, 1.0f); - changed = true; - } - SDL_copyp(&display->HDR, HDR); - - if (changed && !SDL_DriverSendsHDRChanges(_this)) { - for (SDL_Window *w = display->device->windows; w; w = w->next) { - if (SDL_GetDisplayForWindow(w) == display->id) { - SDL_SetWindowHDRProperties(w, &display->HDR, true); - } - } - } -} - -static void SDL_UpdateFullscreenDisplayModes(SDL_VideoDisplay *display) -{ - if (display->num_fullscreen_modes == 0 && _this->GetDisplayModes) { - _this->GetDisplayModes(_this, display); - } -} - -// Return the matching mode as a pointer into our current mode list -static const SDL_DisplayMode *SDL_GetFullscreenModeMatch(const SDL_DisplayMode *mode) -{ - SDL_VideoDisplay *display; - SDL_DisplayMode fullscreen_mode; - - if (mode->w <= 0 || mode->h <= 0) { - // Use the desktop mode - return NULL; - } - - SDL_memcpy(&fullscreen_mode, mode, sizeof(fullscreen_mode)); - if (fullscreen_mode.displayID == 0) { - fullscreen_mode.displayID = SDL_GetPrimaryDisplay(); - } - SDL_FinalizeDisplayMode(&fullscreen_mode); - - mode = NULL; - - display = SDL_GetVideoDisplay(fullscreen_mode.displayID); - if (display) { - SDL_UpdateFullscreenDisplayModes(display); - - // Search for an exact match - if (!mode) { - for (int i = 0; i < display->num_fullscreen_modes; ++i) { - if (SDL_memcmp(&fullscreen_mode, &display->fullscreen_modes[i], sizeof(fullscreen_mode)) == 0) { - mode = &display->fullscreen_modes[i]; - break; - } - } - } - - // Search for a mode with the same characteristics - if (!mode) { - for (int i = 0; i < display->num_fullscreen_modes; ++i) { - if (cmpmodes(&fullscreen_mode, &display->fullscreen_modes[i]) == 0) { - mode = &display->fullscreen_modes[i]; - break; - } - } - } - } - return mode; -} - -bool SDL_AddFullscreenDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode) -{ - SDL_DisplayMode *modes; - SDL_DisplayMode new_mode; - int i, nmodes; - - // Finalize the mode for the display - SDL_memcpy(&new_mode, mode, sizeof(new_mode)); - new_mode.displayID = display->id; - SDL_FinalizeDisplayMode(&new_mode); - - // Make sure we don't already have the mode in the list - modes = display->fullscreen_modes; - nmodes = display->num_fullscreen_modes; - for (i = 0; i < nmodes; ++i) { - if (cmpmodes(&new_mode, &modes[i]) == 0) { - return false; - } - } - - // Go ahead and add the new mode - if (nmodes == display->max_fullscreen_modes) { - modes = (SDL_DisplayMode *)SDL_malloc((display->max_fullscreen_modes + 32) * sizeof(*modes)); - if (!modes) { - return false; - } - - if (display->fullscreen_modes) { - // Copy the list and update the current mode pointer, if necessary. - SDL_memcpy(modes, display->fullscreen_modes, nmodes * sizeof(*modes)); - for (i = 0; i < nmodes; ++i) { - if (display->current_mode == &display->fullscreen_modes[i]) { - display->current_mode = &modes[i]; - } - } - - SDL_free(display->fullscreen_modes); - } - - display->fullscreen_modes = modes; - display->max_fullscreen_modes += 32; - } - SDL_memcpy(&modes[display->num_fullscreen_modes++], &new_mode, sizeof(new_mode)); - - // Re-sort video modes - SDL_qsort(display->fullscreen_modes, display->num_fullscreen_modes, - sizeof(SDL_DisplayMode), cmpmodes); - - return true; -} - -void SDL_ResetFullscreenDisplayModes(SDL_VideoDisplay *display) -{ - int i; - - for (i = display->num_fullscreen_modes; i--;) { - SDL_free(display->fullscreen_modes[i].internal); - display->fullscreen_modes[i].internal = NULL; - } - SDL_free(display->fullscreen_modes); - display->fullscreen_modes = NULL; - display->num_fullscreen_modes = 0; - display->max_fullscreen_modes = 0; - display->current_mode = &display->desktop_mode; -} - -SDL_DisplayMode **SDL_GetFullscreenDisplayModes(SDL_DisplayID displayID, int *count) -{ - int i; - int num_modes; - SDL_DisplayMode **result; - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - if (count) { - *count = 0; - } - - CHECK_DISPLAY_MAGIC(display, NULL); - - SDL_UpdateFullscreenDisplayModes(display); - - num_modes = display->num_fullscreen_modes; - result = (SDL_DisplayMode **)SDL_malloc((num_modes + 1) * sizeof(*result) + num_modes * sizeof(**result)); - if (result) { - SDL_DisplayMode *modes = (SDL_DisplayMode *)((Uint8 *)result + ((num_modes + 1) * sizeof(*result))); - SDL_memcpy(modes, display->fullscreen_modes, num_modes * sizeof(*modes)); - for (i = 0; i < num_modes; ++i) { - result[i] = modes++; - } - result[i] = NULL; - - if (count) { - *count = num_modes; - } - } else { - if (count) { - *count = 0; - } - } - return result; -} - -bool SDL_GetClosestFullscreenDisplayMode(SDL_DisplayID displayID, int w, int h, float refresh_rate, bool include_high_density_modes, SDL_DisplayMode *result) -{ - if (!result) { - return SDL_InvalidParamError("closest"); // Parameter `result` is called `closest` in the header. - } - - const SDL_DisplayMode *mode, *closest = NULL; - float aspect_ratio; - int i; - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - SDL_zerop(result); - - CHECK_DISPLAY_MAGIC(display, false); - - if (h > 0) { - aspect_ratio = (float)w / h; - } else { - aspect_ratio = 1.0f; - } - - if (refresh_rate == 0.0f) { - refresh_rate = display->desktop_mode.refresh_rate; - } - - SDL_UpdateFullscreenDisplayModes(display); - - for (i = 0; i < display->num_fullscreen_modes; ++i) { - mode = &display->fullscreen_modes[i]; - - if (w > mode->w) { - // Out of sorted modes large enough here - break; - } - if (h > mode->h) { - /* Wider, but not tall enough, due to a different aspect ratio. - * This mode must be skipped, but closer modes may still follow */ - continue; - } - if (mode->pixel_density > 1.0f && !include_high_density_modes) { - continue; - } - if (closest) { - float current_aspect_ratio = (float)mode->w / mode->h; - float closest_aspect_ratio = (float)closest->w / closest->h; - if (SDL_fabsf(aspect_ratio - closest_aspect_ratio) < SDL_fabsf(aspect_ratio - current_aspect_ratio)) { - // The mode we already found has a better aspect ratio match - continue; - } - - if (mode->w == closest->w && mode->h == closest->h && - SDL_fabsf(closest->refresh_rate - refresh_rate) < SDL_fabsf(mode->refresh_rate - refresh_rate)) { - /* We already found a mode and the new mode is further from our - * refresh rate target */ - continue; - } - } - - closest = mode; - } - if (!closest) { - return SDL_SetError("Couldn't find any matching video modes"); - } - - SDL_copyp(result, closest); - - return true; -} - -static bool DisplayModeChanged(const SDL_DisplayMode *old_mode, const SDL_DisplayMode *new_mode) -{ - return ((old_mode->displayID && old_mode->displayID != new_mode->displayID) || - (old_mode->format && old_mode->format != new_mode->format) || - (old_mode->w && old_mode->h && (old_mode->w != new_mode->w ||old_mode->h != new_mode->h)) || - (old_mode->pixel_density != 0.0f && old_mode->pixel_density != new_mode->pixel_density) || - (old_mode->refresh_rate != 0.0f && old_mode->refresh_rate != new_mode->refresh_rate)); -} - -void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode) -{ - SDL_DisplayMode last_mode; - - if (display->fullscreen_active) { - // This is a temporary mode change, don't save the desktop mode - return; - } - - SDL_copyp(&last_mode, &display->desktop_mode); - - if (display->desktop_mode.internal) { - SDL_free(display->desktop_mode.internal); - } - SDL_copyp(&display->desktop_mode, mode); - display->desktop_mode.displayID = display->id; - SDL_FinalizeDisplayMode(&display->desktop_mode); - - if (DisplayModeChanged(&last_mode, &display->desktop_mode)) { - SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED, mode->w, mode->h); - if (display->current_mode == &display->desktop_mode) { - SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED, mode->w, mode->h); - } - } -} - -const SDL_DisplayMode *SDL_GetDesktopDisplayMode(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, NULL); - - return &display->desktop_mode; -} - -void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode) -{ - SDL_DisplayMode last_mode; - - if (display->current_mode) { - SDL_copyp(&last_mode, display->current_mode); - } else { - SDL_zero(last_mode); - } - - display->current_mode = mode; - - if (DisplayModeChanged(&last_mode, mode)) { - SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED, mode->w, mode->h); - } -} - -const SDL_DisplayMode *SDL_GetCurrentDisplayMode(SDL_DisplayID displayID) -{ - SDL_VideoDisplay *display = SDL_GetVideoDisplay(displayID); - - CHECK_DISPLAY_MAGIC(display, NULL); - - // Make sure our mode list is updated - SDL_UpdateFullscreenDisplayModes(display); - - return display->current_mode; -} - -bool SDL_SetDisplayModeForDisplay(SDL_VideoDisplay *display, SDL_DisplayMode *mode) -{ - /* Mode switching is being emulated per-window; nothing to do and cannot fail, - * except for XWayland, which still needs the actual mode setting call since - * it's emulated via the XRandR interface. - */ - if (SDL_ModeSwitchingEmulated(_this) && SDL_strcmp(_this->name, "x11") != 0) { - return true; - } - - if (!mode) { - mode = &display->desktop_mode; - } - - if (mode == display->current_mode) { - return true; - } - - // Actually change the display mode - if (_this->SetDisplayMode) { - bool result; - - _this->setting_display_mode = true; - result = _this->SetDisplayMode(_this, display, mode); - _this->setting_display_mode = false; - if (!result) { - return false; - } - } - - SDL_SetCurrentDisplayMode(display, mode); - - return true; -} - -/** - * If x, y are outside of rect, snaps them to the closest point inside rect - * (between rect->x, rect->y, inclusive, and rect->x + w, rect->y + h, exclusive) - */ -static void SDL_GetClosestPointOnRect(const SDL_Rect *rect, SDL_Point *point) -{ - const int right = rect->x + rect->w - 1; - const int bottom = rect->y + rect->h - 1; - - if (point->x < rect->x) { - point->x = rect->x; - } else if (point->x > right) { - point->x = right; - } - - if (point->y < rect->y) { - point->y = rect->y; - } else if (point->y > bottom) { - point->y = bottom; - } -} - -static SDL_DisplayID GetDisplayForRect(int x, int y, int w, int h) -{ - int i, dist; - SDL_DisplayID closest = 0; - int closest_dist = 0x7FFFFFFF; - SDL_Point closest_point_on_display; - SDL_Point delta; - SDL_Point center; - center.x = x + w / 2; - center.y = y + h / 2; - - if (_this) { - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = _this->displays[i]; - SDL_Rect display_rect; - SDL_GetDisplayBounds(display->id, &display_rect); - - // Check if the window is fully enclosed - if (SDL_GetRectEnclosingPoints(¢er, 1, &display_rect, NULL)) { - return display->id; - } - - // Snap window center to the display rect - closest_point_on_display = center; - SDL_GetClosestPointOnRect(&display_rect, &closest_point_on_display); - - delta.x = center.x - closest_point_on_display.x; - delta.y = center.y - closest_point_on_display.y; - dist = (delta.x * delta.x + delta.y * delta.y); - if (dist < closest_dist) { - closest = display->id; - closest_dist = dist; - } - } - } - - if (closest == 0) { - SDL_SetError("Couldn't find any displays"); - } - - return closest; -} - -void SDL_RelativeToGlobalForWindow(SDL_Window *window, int rel_x, int rel_y, int *abs_x, int *abs_y) -{ - SDL_Window *w; - - if (SDL_WINDOW_IS_POPUP(window)) { - // Calculate the total offset of the popup from the parents - for (w = window->parent; w; w = w->parent) { - rel_x += w->x; - rel_y += w->y; - - if (!SDL_WINDOW_IS_POPUP(w)) { - break; - } - } - } - - if (abs_x) { - *abs_x = rel_x; - } - if (abs_y) { - *abs_y = rel_y; - } -} - -void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int *rel_x, int *rel_y) -{ - SDL_Window *w; - - if (SDL_WINDOW_IS_POPUP(window)) { - // Convert absolute window coordinates to relative for a popup - for (w = window->parent; w; w = w->parent) { - abs_x -= w->x; - abs_y -= w->y; - - if (!SDL_WINDOW_IS_POPUP(w)) { - break; - } - } - } - - if (rel_x) { - *rel_x = abs_x; - } - if (rel_y) { - *rel_y = abs_y; - } -} - -SDL_DisplayID SDL_GetDisplayForPoint(const SDL_Point *point) -{ - if (!point) { - SDL_InvalidParamError("point"); - return 0; - } - - return GetDisplayForRect(point->x, point->y, 1, 1); -} - -SDL_DisplayID SDL_GetDisplayForRect(const SDL_Rect *rect) -{ - if (!rect) { - SDL_InvalidParamError("rect"); - return 0; - } - - return GetDisplayForRect(rect->x, rect->y, rect->w, rect->h); -} - -SDL_DisplayID SDL_GetDisplayForWindowPosition(SDL_Window *window) -{ - int x, y; - SDL_DisplayID displayID = 0; - - CHECK_WINDOW_MAGIC(window, 0); - - if (_this->GetDisplayForWindow) { - displayID = _this->GetDisplayForWindow(_this, window); - } - - /* A backend implementation may fail to get a display for the window - * (for example if the window is off-screen), but other code may expect it - * to succeed in that situation, so we fall back to a generic position- - * based implementation in that case. */ - SDL_RelativeToGlobalForWindow(window, window->x, window->y, &x, &y); - - if (!displayID) { - /* Fullscreen windows may be larger than the display if they were moved between differently sized - * displays and the new position was received before the new size or vice versa. Using the center - * of the window rect in this case can report the wrong display, so use the origin. - */ - if (window->flags & SDL_WINDOW_FULLSCREEN) { - displayID = GetDisplayForRect(x, y, 1, 1); - } else { - displayID = GetDisplayForRect(x, y, window->w, window->h); - } - } - if (!displayID) { - // Use the primary display for a window if we can't find it anywhere else - displayID = SDL_GetPrimaryDisplay(); - } - return displayID; -} - -SDL_VideoDisplay *SDL_GetVideoDisplayForFullscreenWindow(SDL_Window *window) -{ - SDL_DisplayID displayID = 0; - - CHECK_WINDOW_MAGIC(window, 0); - - // An explicit fullscreen display overrides all - if (window->current_fullscreen_mode.displayID) { - displayID = window->current_fullscreen_mode.displayID; - } - - /* This is used to handle the very common pattern of SDL_SetWindowPosition() - * followed immediately by SDL_SetWindowFullscreen() to make the window fullscreen - * desktop on a specific display. If the backend doesn't support changing the - * window position, or an async window manager hasn't yet actually moved the window, - * the current position won't be updated at the time of the fullscreen call. - */ - if (!displayID) { - // Use the pending position and dimensions, if available, otherwise, use the current. - const int x = window->last_position_pending ? window->pending.x : window->x; - const int y = window->last_position_pending ? window->pending.y : window->y; - const int w = window->last_size_pending ? window->pending.w : window->w; - const int h = window->last_size_pending ? window->pending.h : window->h; - - displayID = GetDisplayForRect(x, y, w, h); - } - if (!displayID) { - // Use the primary display for a window if we can't find it anywhere else - displayID = SDL_GetPrimaryDisplay(); - } - return SDL_GetVideoDisplay(displayID); -} - -SDL_DisplayID SDL_GetDisplayForWindow(SDL_Window *window) -{ - SDL_DisplayID displayID = 0; - - CHECK_WINDOW_MAGIC(window, 0); - - // An explicit fullscreen display overrides all - if (window->flags & SDL_WINDOW_FULLSCREEN) { - displayID = window->current_fullscreen_mode.displayID; - } - - if (!displayID) { - displayID = SDL_GetDisplayForWindowPosition(window); - } - return displayID; -} - -static void SDL_CheckWindowDisplayChanged(SDL_Window *window) -{ - if (SDL_SendsDisplayChanges(_this)) { - return; - } - - SDL_DisplayID displayID = SDL_GetDisplayForWindowPosition(window); - - if (displayID != window->last_displayID) { - int i, display_index; - - // Sanity check our fullscreen windows - display_index = SDL_GetDisplayIndex(displayID); - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = _this->displays[i]; - - if (display->fullscreen_window == window) { - if (display_index != i) { - if (display_index < 0) { - display_index = i; - } else { - SDL_VideoDisplay *new_display = _this->displays[display_index]; - - // The window was moved to a different display - if (new_display->fullscreen_window && - new_display->fullscreen_window != window) { - // Uh oh, there's already a fullscreen window here; minimize it - SDL_MinimizeWindow(new_display->fullscreen_window); - } - new_display->fullscreen_window = window; - display->fullscreen_window = NULL; - } - } - break; - } - } - - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_CHANGED, (int)displayID, 0); - } -} - -float SDL_GetWindowPixelDensity(SDL_Window *window) -{ - int window_w, window_h, pixel_w, pixel_h; - float pixel_density = 1.0f; - - CHECK_WINDOW_MAGIC(window, 0.0f); - - if (SDL_GetWindowSize(window, &window_w, &window_h) && - SDL_GetWindowSizeInPixels(window, &pixel_w, &pixel_h)) { - pixel_density = (float)pixel_w / window_w; - } - return pixel_density; -} - -float SDL_GetWindowDisplayScale(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, 0.0f); - - return window->display_scale; -} - -static void SDL_CheckWindowDisplayScaleChanged(SDL_Window *window) -{ - float display_scale; - - if (_this->GetWindowContentScale) { - display_scale = _this->GetWindowContentScale(_this, window); - } else { - const float pixel_density = SDL_GetWindowPixelDensity(window); - const float content_scale = SDL_GetDisplayContentScale(SDL_GetDisplayForWindowPosition(window)); - - display_scale = pixel_density * content_scale; - } - - if (display_scale != window->display_scale) { - window->display_scale = display_scale; - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED, 0, 0); - } -} - -static void SDL_RestoreMousePosition(SDL_Window *window) -{ - float x, y; - SDL_Mouse *mouse = SDL_GetMouse(); - - if (window == SDL_GetMouseFocus()) { - const bool prev_warp_val = mouse->warp_emulation_prohibited; - SDL_GetMouseState(&x, &y); - - // Disable the warp emulation so it isn't accidentally activated on a fullscreen transitions. - mouse->warp_emulation_prohibited = true; - SDL_WarpMouseInWindow(window, x, y); - mouse->warp_emulation_prohibited = prev_warp_val; - } -} - -bool SDL_UpdateFullscreenMode(SDL_Window *window, SDL_FullscreenOp fullscreen, bool commit) -{ - SDL_VideoDisplay *display = NULL; - SDL_DisplayMode *mode = NULL; - int i; - - CHECK_WINDOW_MAGIC(window, false); - - window->fullscreen_exclusive = false; - - // If we are in the process of hiding don't go back to fullscreen - if (window->is_destroying || window->is_hiding) { - fullscreen = SDL_FULLSCREEN_OP_LEAVE; - } - - // Get the correct display for this operation - if (fullscreen) { - display = SDL_GetVideoDisplayForFullscreenWindow(window); - if (!display) { - // This should never happen, but it did... - goto done; - } - } else { - for (i = 0; i < _this->num_displays; ++i) { - display = _this->displays[i]; - if (display->fullscreen_window == window) { - break; - } - } - if (!display || i == _this->num_displays) { - // Already not fullscreen on any display - display = NULL; - } - } - - if (fullscreen) { - mode = (SDL_DisplayMode *)SDL_GetWindowFullscreenMode(window); - if (mode) { - window->fullscreen_exclusive = true; - } else { - // Make sure the current mode is zeroed for fullscreen desktop. - SDL_zero(window->current_fullscreen_mode); - } - } - -#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA) - /* if the window is going away and no resolution change is necessary, - do nothing, or else we may trigger an ugly double-transition - */ - if (SDL_strcmp(_this->name, "cocoa") == 0) { // don't do this for X11, etc - if (window->is_destroying && !window->last_fullscreen_exclusive_display) { - window->fullscreen_exclusive = false; - if (display) { - display->fullscreen_window = NULL; - } - goto done; - } - if (commit) { - // If we're switching between a fullscreen Space and exclusive fullscreen, we need to get back to normal first. - if (fullscreen && Cocoa_IsWindowInFullscreenSpace(window) && !window->last_fullscreen_exclusive_display && window->fullscreen_exclusive) { - if (!Cocoa_SetWindowFullscreenSpace(window, false, true)) { - goto error; - } - } else if (fullscreen && window->last_fullscreen_exclusive_display && !window->fullscreen_exclusive) { - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *last_display = _this->displays[i]; - if (last_display->fullscreen_window == window) { - SDL_SetDisplayModeForDisplay(last_display, NULL); - if (_this->SetWindowFullscreen) { - _this->SetWindowFullscreen(_this, window, last_display, false); - } - last_display->fullscreen_window = NULL; - } - } - } - - if (Cocoa_SetWindowFullscreenSpace(window, !!fullscreen, syncHint)) { - goto done; - } - } - } -#endif - - if (display) { - // Restore the video mode on other displays if needed - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *other = _this->displays[i]; - if (other != display && other->fullscreen_window == window) { - SDL_SetDisplayModeForDisplay(other, NULL); - other->fullscreen_window = NULL; - } - } - } - - if (fullscreen) { - int mode_w = 0, mode_h = 0; - bool resized = false; - - // Hide any other fullscreen window on this display - if (display->fullscreen_window && - display->fullscreen_window != window) { - SDL_MinimizeWindow(display->fullscreen_window); - } - - display->fullscreen_active = window->fullscreen_exclusive; - - if (!SDL_SetDisplayModeForDisplay(display, mode)) { - goto error; - } - if (commit) { - SDL_FullscreenResult ret = SDL_FULLSCREEN_SUCCEEDED; - if (_this->SetWindowFullscreen) { - ret = _this->SetWindowFullscreen(_this, window, display, fullscreen); - } else { - resized = true; - } - - if (ret == SDL_FULLSCREEN_SUCCEEDED) { - // Window is fullscreen immediately upon return. If the driver hasn't already sent the event, do so now. - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_ENTER_FULLSCREEN, 0, 0); - } - } else if (ret == SDL_FULLSCREEN_FAILED) { - display->fullscreen_active = false; - goto error; - } - } - - if (window->flags & SDL_WINDOW_FULLSCREEN) { - display->fullscreen_window = window; - - /* Android may not resize the window to exactly what our fullscreen mode is, - * especially on windowed Android environments like the Chromebook or Samsung DeX. - * Given this, we shouldn't use the mode size. Android's SetWindowFullscreen - * will generate the window event for us with the proper final size. - * - * This is also unnecessary on Cocoa, Wayland, Win32, and X11 (will send SDL_EVENT_WINDOW_RESIZED). - */ - if (!SDL_SendsFullscreenDimensions(_this)) { - SDL_Rect displayRect; - - if (mode) { - mode_w = mode->w; - mode_h = mode->h; - SDL_GetDisplayBounds(mode->displayID, &displayRect); - } else { - mode_w = display->desktop_mode.w; - mode_h = display->desktop_mode.h; - SDL_GetDisplayBounds(display->id, &displayRect); - } - - if (window->w != mode_w || window->h != mode_h) { - resized = true; - } - - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, displayRect.x, displayRect.y); - - if (resized) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, mode_w, mode_h); - } else { - SDL_OnWindowResized(window); - } - } - - // Restore the cursor position - if (!SDL_DisableMouseWarpOnFullscreenTransitions(_this)) { - SDL_RestoreMousePosition(window); - } - } - } else { - bool resized = false; - - // Restore the desktop mode - if (display) { - display->fullscreen_active = false; - - SDL_SetDisplayModeForDisplay(display, NULL); - } - if (commit) { - SDL_FullscreenResult ret = SDL_FULLSCREEN_SUCCEEDED; - if (_this->SetWindowFullscreen) { - SDL_VideoDisplay *full_screen_display = display ? display : SDL_GetVideoDisplayForFullscreenWindow(window); - if (full_screen_display) { - ret = _this->SetWindowFullscreen(_this, window, full_screen_display, SDL_FULLSCREEN_OP_LEAVE); - } - } else { - resized = true; - } - - if (ret == SDL_FULLSCREEN_SUCCEEDED) { - // Window left fullscreen immediately upon return. If the driver hasn't already sent the event, do so now. - if (window->flags & SDL_WINDOW_FULLSCREEN) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, 0, 0); - } - } else if (ret == SDL_FULLSCREEN_FAILED) { - goto error; - } - } - - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - if (display) { - display->fullscreen_window = NULL; - } - - if (!SDL_SendsFullscreenDimensions(_this)) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, window->windowed.x, window->windowed.y); - if (resized) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, window->windowed.w, window->windowed.h); - } else { - SDL_OnWindowResized(window); - } - } - - // Restore the cursor position if we've exited fullscreen on a display - if (display && !SDL_DisableMouseWarpOnFullscreenTransitions(_this)) { - SDL_RestoreMousePosition(window); - } - } - } - -done: - window->last_fullscreen_exclusive_display = display && (window->flags & SDL_WINDOW_FULLSCREEN) && window->fullscreen_exclusive ? display->id : 0; - return true; - -error: - if (fullscreen) { - // Something went wrong and the window is no longer fullscreen. - SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_LEAVE, commit); - } - return false; -} - -bool SDL_SetWindowFullscreenMode(SDL_Window *window, const SDL_DisplayMode *mode) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (mode) { - if (!SDL_GetFullscreenModeMatch(mode)) { - return SDL_SetError("Invalid fullscreen display mode"); - } - - // Save the mode so we can look up the closest match later - SDL_copyp(&window->requested_fullscreen_mode, mode); - } else { - SDL_zero(window->requested_fullscreen_mode); - } - - /* Copy to the current mode now, in case an asynchronous fullscreen window request - * is in progress. It will be overwritten if a new request is made. - */ - SDL_copyp(&window->current_fullscreen_mode, &window->requested_fullscreen_mode); - if (SDL_WINDOW_FULLSCREEN_VISIBLE(window)) { - SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_UPDATE, true); - SDL_SyncIfRequired(window); - } - - return true; -} - -const SDL_DisplayMode *SDL_GetWindowFullscreenMode(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, NULL); - CHECK_WINDOW_NOT_POPUP(window, NULL); - - if (window->flags & SDL_WINDOW_FULLSCREEN) { - return SDL_GetFullscreenModeMatch(&window->current_fullscreen_mode); - } else { - return SDL_GetFullscreenModeMatch(&window->requested_fullscreen_mode); - } -} - -void *SDL_GetWindowICCProfile(SDL_Window *window, size_t *size) -{ - if (!_this->GetWindowICCProfile) { - SDL_Unsupported(); - return NULL; - } - return _this->GetWindowICCProfile(_this, window, size); -} - -SDL_PixelFormat SDL_GetWindowPixelFormat(SDL_Window *window) -{ - SDL_DisplayID displayID; - const SDL_DisplayMode *mode; - - CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN); - - displayID = SDL_GetDisplayForWindow(window); - mode = SDL_GetCurrentDisplayMode(displayID); - if (mode) { - return mode->format; - } else { - return SDL_PIXELFORMAT_UNKNOWN; - } -} - -#define CREATE_FLAGS \ - (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT | SDL_WINDOW_NOT_FOCUSABLE) - -static SDL_INLINE bool IsAcceptingDragAndDrop(void) -{ - if (SDL_EventEnabled(SDL_EVENT_DROP_FILE) || SDL_EventEnabled(SDL_EVENT_DROP_TEXT)) { - return true; - } - return false; -} - -// prepare a newly-created window -static SDL_INLINE void PrepareDragAndDropSupport(SDL_Window *window) -{ - if (_this->AcceptDragAndDrop) { - _this->AcceptDragAndDrop(window, IsAcceptingDragAndDrop()); - } -} - -// toggle d'n'd for all existing windows. -void SDL_ToggleDragAndDropSupport(void) -{ - if (_this && _this->AcceptDragAndDrop) { - const bool enable = IsAcceptingDragAndDrop(); - SDL_Window *window; - for (window = _this->windows; window; window = window->next) { - _this->AcceptDragAndDrop(window, enable); - } - } -} - -SDL_Window ** SDLCALL SDL_GetWindows(int *count) -{ - if (count) { - *count = 0; - } - - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - - SDL_Window *window; - int num_added = 0; - int num_windows = 0; - for (window = _this->windows; window; window = window->next) { - ++num_windows; - } - - SDL_Window **windows = (SDL_Window **)SDL_malloc((num_windows + 1) * sizeof(*windows)); - if (!windows) { - return NULL; - } - - for (window = _this->windows; window; window = window->next) { - windows[num_added++] = window; - if (num_added == num_windows) { - // Race condition? Multi-threading not supported, ignore it - break; - } - } - windows[num_added] = NULL; - - if (count) { - *count = num_added; - } - return windows; -} - -static void ApplyWindowFlags(SDL_Window *window, SDL_WindowFlags flags) -{ - if (!SDL_WINDOW_IS_POPUP(window)) { - if (!(flags & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED))) { - SDL_RestoreWindow(window); - } - if (flags & SDL_WINDOW_MAXIMIZED) { - SDL_MaximizeWindow(window); - } - - SDL_SetWindowFullscreen(window, (flags & SDL_WINDOW_FULLSCREEN) != 0); - - if (flags & SDL_WINDOW_MINIMIZED) { - SDL_MinimizeWindow(window); - } - - if (flags & SDL_WINDOW_MODAL) { - SDL_SetWindowModal(window, true); - } - - if (flags & SDL_WINDOW_MOUSE_GRABBED) { - SDL_SetWindowMouseGrab(window, true); - } - if (flags & SDL_WINDOW_KEYBOARD_GRABBED) { - SDL_SetWindowKeyboardGrab(window, true); - } - } -} - -static void SDL_FinishWindowCreation(SDL_Window *window, SDL_WindowFlags flags) -{ - PrepareDragAndDropSupport(window); - - if (window->flags & SDL_WINDOW_EXTERNAL) { - // Whoever has created the window has already applied whatever flags are needed - } else { - ApplyWindowFlags(window, flags); - if (!(flags & SDL_WINDOW_HIDDEN)) { - SDL_ShowWindow(window); - } - } -} - -static bool SDL_ContextNotSupported(const char *name) -{ - return SDL_SetError("%s support is either not configured in SDL " - "or not available in current SDL video driver " - "(%s) or platform", - name, - _this->name); -} - -static bool SDL_DllNotSupported(const char *name) -{ - return SDL_SetError("No dynamic %s support in current SDL video driver (%s)", name, _this->name); -} - -static struct { - const char *property_name; - SDL_WindowFlags flag; - bool invert_value; -} SDL_WindowFlagProperties[] = { - { SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN, SDL_WINDOW_ALWAYS_ON_TOP, false }, - { SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, SDL_WINDOW_BORDERLESS, false }, - { SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, SDL_WINDOW_NOT_FOCUSABLE, true }, - { SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, SDL_WINDOW_FULLSCREEN, false }, - { SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, SDL_WINDOW_HIDDEN, false }, - { SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, SDL_WINDOW_HIGH_PIXEL_DENSITY, false }, - { SDL_PROP_WINDOW_CREATE_MAXIMIZED_BOOLEAN, SDL_WINDOW_MAXIMIZED, false }, - { SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, SDL_WINDOW_POPUP_MENU, false }, - { SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN, SDL_WINDOW_METAL, false }, - { SDL_PROP_WINDOW_CREATE_MINIMIZED_BOOLEAN, SDL_WINDOW_MINIMIZED, false }, - { SDL_PROP_WINDOW_CREATE_MODAL_BOOLEAN, SDL_WINDOW_MODAL, false }, - { SDL_PROP_WINDOW_CREATE_MOUSE_GRABBED_BOOLEAN, SDL_WINDOW_MOUSE_GRABBED, false }, - { SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, SDL_WINDOW_OPENGL, false }, - { SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, SDL_WINDOW_RESIZABLE, false }, - { SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, SDL_WINDOW_TRANSPARENT, false }, - { SDL_PROP_WINDOW_CREATE_TOOLTIP_BOOLEAN, SDL_WINDOW_TOOLTIP, false }, - { SDL_PROP_WINDOW_CREATE_UTILITY_BOOLEAN, SDL_WINDOW_UTILITY, false }, - { SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, SDL_WINDOW_VULKAN, false } -}; - -static SDL_WindowFlags SDL_GetWindowFlagProperties(SDL_PropertiesID props) -{ - unsigned i; - SDL_WindowFlags flags = (SDL_WindowFlags)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, 0); - - for (i = 0; i < SDL_arraysize(SDL_WindowFlagProperties); ++i) { - if (SDL_WindowFlagProperties[i].invert_value) { - if (!SDL_GetBooleanProperty(props, SDL_WindowFlagProperties[i].property_name, true)) { - flags |= SDL_WindowFlagProperties[i].flag; - } - } else { - if (SDL_GetBooleanProperty(props, SDL_WindowFlagProperties[i].property_name, false)) { - flags |= SDL_WindowFlagProperties[i].flag; - } - } - } - return flags; -} - -SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props) -{ - SDL_Window *window; - const char *title = SDL_GetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, NULL); - int x = (int)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_UNDEFINED); - int y = (int)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_UNDEFINED); - int w = (int)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, 0); - int h = (int)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, 0); - SDL_Window *parent = (SDL_Window *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, NULL); - SDL_WindowFlags flags = SDL_GetWindowFlagProperties(props); - SDL_WindowFlags type_flags, graphics_flags; - bool undefined_x = false; - bool undefined_y = false; - bool external_graphics_context = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_EXTERNAL_GRAPHICS_CONTEXT_BOOLEAN, false); - - if (!_this) { - // Initialize the video system if needed - if (!SDL_Init(SDL_INIT_VIDEO)) { - return NULL; - } - - // Make clang-tidy happy - if (!_this) { - return NULL; - } - } - - if ((flags & SDL_WINDOW_MODAL) && !SDL_ObjectValid(parent, SDL_OBJECT_TYPE_WINDOW)) { - SDL_SetError("Modal windows must specify a parent window"); - return NULL; - } - - if ((flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) != 0) { - if (!(_this->device_caps & VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT)) { - SDL_Unsupported(); - return NULL; - } - - // Tooltip and popup menu window must specify a parent window - if (!SDL_ObjectValid(parent, SDL_OBJECT_TYPE_WINDOW)) { - SDL_SetError("Tooltip and popup menu windows must specify a parent window"); - return NULL; - } - - // Remove invalid flags - flags &= ~(SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS); - } - - // Ensure no more than one of these flags is set - type_flags = flags & (SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_MODAL); - if (type_flags & (type_flags - 1)) { - SDL_SetError("Conflicting window type flags specified: 0x%.8x", (unsigned int)type_flags); - return NULL; - } - - // Make sure the display list is up to date for window placement - if (_this->RefreshDisplays) { - _this->RefreshDisplays(_this); - } - - // Some platforms can't create zero-sized windows - if (w < 1) { - w = 1; - } - if (h < 1) { - h = 1; - } - - if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) || - SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { - SDL_DisplayID displayID = 0; - SDL_Rect bounds; - - if ((SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) && (x & 0xFFFF)) { - displayID = (x & 0xFFFF); - } else if ((SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) && (y & 0xFFFF)) { - displayID = (y & 0xFFFF); - } - if (displayID == 0 || SDL_GetDisplayIndex(displayID) < 0) { - displayID = SDL_GetPrimaryDisplay(); - } - - SDL_zero(bounds); - SDL_GetDisplayUsableBounds(displayID, &bounds); - if (w > bounds.w || h > bounds.h) { - // This window is larger than the usable bounds, just center on the display - SDL_GetDisplayBounds(displayID, &bounds); - } - if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISUNDEFINED(x)) { - if (SDL_WINDOWPOS_ISUNDEFINED(x)) { - undefined_x = true; - } - x = bounds.x + (bounds.w - w) / 2; - } - if (SDL_WINDOWPOS_ISCENTERED(y) || SDL_WINDOWPOS_ISUNDEFINED(y)) { - if (SDL_WINDOWPOS_ISUNDEFINED(y)) { - undefined_y = true; - } - y = bounds.y + (bounds.h - h) / 2; - } - } - - // ensure no more than one of these flags is set - graphics_flags = flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN); - if (graphics_flags & (graphics_flags - 1)) { - SDL_SetError("Conflicting window graphics flags specified: 0x%.8x", (unsigned int)graphics_flags); - return NULL; - } - - // Some platforms have certain graphics backends enabled by default - if (!graphics_flags && !external_graphics_context) { - flags |= SDL_DefaultGraphicsBackends(_this); - } - - if (flags & SDL_WINDOW_OPENGL) { - if (!_this->GL_CreateContext) { - SDL_ContextNotSupported("OpenGL"); - return NULL; - } - if (!SDL_GL_LoadLibrary(NULL)) { - return NULL; - } - } - - if (flags & SDL_WINDOW_VULKAN) { - if (!_this->Vulkan_CreateSurface) { - SDL_ContextNotSupported("Vulkan"); - return NULL; - } - if (!SDL_Vulkan_LoadLibrary(NULL)) { - return NULL; - } - } - - if (flags & SDL_WINDOW_METAL) { - if (!_this->Metal_CreateView) { - SDL_ContextNotSupported("Metal"); - return NULL; - } - } - - window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); - if (!window) { - return NULL; - } - SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, true); - window->id = SDL_GetNextObjectID(); - window->floating.x = window->windowed.x = window->x = x; - window->floating.y = window->windowed.y = window->y = y; - window->floating.w = window->windowed.w = window->w = w; - window->floating.h = window->windowed.h = window->h = h; - window->undefined_x = undefined_x; - window->undefined_y = undefined_y; - - SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); - if (display) { - SDL_SetWindowHDRProperties(window, &display->HDR, false); - } - - if (flags & SDL_WINDOW_FULLSCREEN || IsFullscreenOnly(_this)) { - SDL_Rect bounds; - - SDL_GetDisplayBounds(display ? display->id : SDL_GetPrimaryDisplay(), &bounds); - window->x = bounds.x; - window->y = bounds.y; - window->w = bounds.w; - window->h = bounds.h; - window->pending_flags |= SDL_WINDOW_FULLSCREEN; - flags |= SDL_WINDOW_FULLSCREEN; - } - - window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); - window->display_scale = 1.0f; - window->opacity = 1.0f; - window->next = _this->windows; - window->is_destroying = false; - window->last_displayID = SDL_GetDisplayForWindow(window); - window->external_graphics_context = external_graphics_context; - - if (_this->windows) { - _this->windows->prev = window; - } - _this->windows = window; - - // Set the parent before creation. - SDL_UpdateWindowHierarchy(window, parent); - - if (_this->CreateSDLWindow && !_this->CreateSDLWindow(_this, window, props)) { - SDL_DestroyWindow(window); - return NULL; - } - - /* Clear minimized if not on windows, only windows handles it at create rather than FinishWindowCreation, - * but it's important or window focus will get broken on windows! - */ -#if !defined(SDL_PLATFORM_WINDOWS) - if (window->flags & SDL_WINDOW_MINIMIZED) { - window->flags &= ~SDL_WINDOW_MINIMIZED; - } -#endif - - if (title) { - SDL_SetWindowTitle(window, title); - } - SDL_FinishWindowCreation(window, flags); - - // Make sure window pixel size is up to date - SDL_CheckWindowPixelSizeChanged(window); - -#ifdef SDL_VIDEO_DRIVER_UIKIT - SDL_UpdateLifecycleObserver(); -#endif - - SDL_ClearError(); - - return window; -} - -SDL_Window *SDL_CreateWindow(const char *title, int w, int h, SDL_WindowFlags flags) -{ - SDL_Window *window; - SDL_PropertiesID props = SDL_CreateProperties(); - if (title && *title) { - SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title); - } - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags); - window = SDL_CreateWindowWithProperties(props); - SDL_DestroyProperties(props); - return window; -} - -SDL_Window *SDL_CreatePopupWindow(SDL_Window *parent, int offset_x, int offset_y, int w, int h, SDL_WindowFlags flags) -{ - SDL_Window *window; - SDL_PropertiesID props = SDL_CreateProperties(); - - // Popups must specify either the tooltip or popup menu window flags - if (!(flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU))) { - SDL_SetError("Popup windows must specify either the 'SDL_WINDOW_TOOLTIP' or the 'SDL_WINDOW_POPUP_MENU' flag"); - return NULL; - } - - SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, parent); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, offset_x); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, offset_y); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags); - window = SDL_CreateWindowWithProperties(props); - SDL_DestroyProperties(props); - return window; -} - -bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags) -{ - bool loaded_opengl = false; - bool need_gl_unload = false; - bool need_gl_load = false; - bool loaded_vulkan = false; - bool need_vulkan_unload = false; - bool need_vulkan_load = false; - SDL_WindowFlags graphics_flags; - - // ensure no more than one of these flags is set - graphics_flags = flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN); - if (graphics_flags & (graphics_flags - 1)) { - return SDL_SetError("Conflicting window flags specified"); - } - - if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) { - return SDL_ContextNotSupported("OpenGL"); - } - if ((flags & SDL_WINDOW_VULKAN) && !_this->Vulkan_CreateSurface) { - return SDL_ContextNotSupported("Vulkan"); - } - if ((flags & SDL_WINDOW_METAL) && !_this->Metal_CreateView) { - return SDL_ContextNotSupported("Metal"); - } - - if (window->flags & SDL_WINDOW_EXTERNAL) { - // Can't destroy and re-create external windows, hrm - flags |= SDL_WINDOW_EXTERNAL; - } else { - flags &= ~SDL_WINDOW_EXTERNAL; - } - - // If this is a modal dialog, clear the modal status. - if (window->flags & SDL_WINDOW_MODAL) { - SDL_SetWindowModal(window, false); - } - - // Restore video mode, etc. - if (!(window->flags & SDL_WINDOW_EXTERNAL)) { - const bool restore_on_show = window->restore_on_show; - SDL_HideWindow(window); - window->restore_on_show = restore_on_show; - } - - // Tear down the old native window - SDL_DestroyWindowSurface(window); - - if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) { - if (flags & SDL_WINDOW_OPENGL) { - need_gl_load = true; - } else { - need_gl_unload = true; - } - } else if (window->flags & SDL_WINDOW_OPENGL) { - need_gl_unload = true; - need_gl_load = true; - } - - if ((window->flags & SDL_WINDOW_VULKAN) != (flags & SDL_WINDOW_VULKAN)) { - if (flags & SDL_WINDOW_VULKAN) { - need_vulkan_load = true; - } else { - need_vulkan_unload = true; - } - } else if (window->flags & SDL_WINDOW_VULKAN) { - need_vulkan_unload = true; - need_vulkan_load = true; - } - - if (need_gl_unload) { - SDL_GL_UnloadLibrary(); - } - - if (need_vulkan_unload) { - SDL_Vulkan_UnloadLibrary(); - } - - if (_this->DestroyWindow && !(flags & SDL_WINDOW_EXTERNAL)) { - _this->DestroyWindow(_this, window); - } - - if (need_gl_load) { - if (!SDL_GL_LoadLibrary(NULL)) { - return false; - } - loaded_opengl = true; - } - - if (need_vulkan_load) { - if (!SDL_Vulkan_LoadLibrary(NULL)) { - return false; - } - loaded_vulkan = true; - } - - window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); - window->is_destroying = false; - - if (_this->CreateSDLWindow && !(flags & SDL_WINDOW_EXTERNAL)) { - /* Reset the window size to the original floating value, so the - * recreated window has the proper base size. - */ - window->x = window->windowed.x = window->floating.x; - window->y = window->windowed.y = window->floating.y; - window->w = window->windowed.w = window->floating.w; - window->h = window->windowed.h = window->floating.h; - - if (!_this->CreateSDLWindow(_this, window, 0)) { - if (loaded_opengl) { - SDL_GL_UnloadLibrary(); - window->flags &= ~SDL_WINDOW_OPENGL; - } - if (loaded_vulkan) { - SDL_Vulkan_UnloadLibrary(); - window->flags &= ~SDL_WINDOW_VULKAN; - } - return false; - } - } - - if (flags & SDL_WINDOW_EXTERNAL) { - window->flags |= SDL_WINDOW_EXTERNAL; - } - - if (_this->SetWindowTitle && window->title) { - _this->SetWindowTitle(_this, window); - } - - if (_this->SetWindowIcon && window->icon) { - _this->SetWindowIcon(_this, window, window->icon); - } - - if (_this->SetWindowMinimumSize && (window->min_w || window->min_h)) { - _this->SetWindowMinimumSize(_this, window); - } - - if (_this->SetWindowMaximumSize && (window->max_w || window->max_h)) { - _this->SetWindowMaximumSize(_this, window); - } - - if (_this->SetWindowAspectRatio && (window->min_aspect > 0.0f || window->max_aspect > 0.0f)) { - _this->SetWindowAspectRatio(_this, window); - } - - if (window->hit_test) { - _this->SetWindowHitTest(window, true); - } - - SDL_FinishWindowCreation(window, flags); - - return true; -} - -bool SDL_HasWindows(void) -{ - return _this && _this->windows; -} - -SDL_WindowID SDL_GetWindowID(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, 0); - - return window->id; -} - -SDL_Window *SDL_GetWindowFromID(SDL_WindowID id) -{ - SDL_Window *window; - - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - if (id) { - for (window = _this->windows; window; window = window->next) { - if (window->id == id) { - return window; - } - } - } - SDL_SetError("Invalid window ID"); \ - return NULL; -} - -SDL_Window *SDL_GetWindowParent(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, NULL); - - return window->parent; -} - -SDL_PropertiesID SDL_GetWindowProperties(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, 0); - - if (window->props == 0) { - window->props = SDL_CreateProperties(); - } - return window->props; -} - -SDL_WindowFlags SDL_GetWindowFlags(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, 0); - - return window->flags | window->pending_flags; -} - -bool SDL_SetWindowTitle(SDL_Window *window, const char *title) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (title == window->title) { - return true; - } - if (!title) { - title = ""; - } - if (window->title && SDL_strcmp(title, window->title) == 0) { - return true; - } - - SDL_free(window->title); - - window->title = SDL_strdup(title); - - if (_this->SetWindowTitle) { - _this->SetWindowTitle(_this, window); - } - return true; -} - -const char *SDL_GetWindowTitle(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, ""); - - return window->title ? window->title : ""; -} - -bool SDL_SetWindowIcon(SDL_Window *window, SDL_Surface *icon) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (!icon) { - return SDL_InvalidParamError("icon"); - } - - SDL_DestroySurface(window->icon); - - // Convert the icon into ARGB8888 - window->icon = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_ARGB8888); - if (!window->icon) { - return false; - } - - if (!_this->SetWindowIcon) { - return SDL_Unsupported(); - } - - return _this->SetWindowIcon(_this, window, window->icon); -} - -bool SDL_SetWindowPosition(SDL_Window *window, int x, int y) -{ - SDL_DisplayID original_displayID; - - CHECK_WINDOW_MAGIC(window, false); - - const int w = window->last_size_pending ? window->pending.w : window->windowed.w; - const int h = window->last_size_pending ? window->pending.h : window->windowed.h; - - original_displayID = SDL_GetDisplayForWindow(window); - - if (SDL_WINDOWPOS_ISUNDEFINED(x)) { - x = window->windowed.x; - } - if (SDL_WINDOWPOS_ISUNDEFINED(y)) { - y = window->windowed.y; - } - if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { - SDL_DisplayID displayID = original_displayID; - SDL_Rect bounds; - - if (SDL_WINDOWPOS_ISCENTERED(x) && (x & 0xFFFF)) { - displayID = (x & 0xFFFF); - } else if (SDL_WINDOWPOS_ISCENTERED(y) && (y & 0xFFFF)) { - displayID = (y & 0xFFFF); - } - if (displayID == 0 || SDL_GetDisplayIndex(displayID) < 0) { - displayID = SDL_GetPrimaryDisplay(); - } - - SDL_zero(bounds); - if (!SDL_GetDisplayUsableBounds(displayID, &bounds) || w > bounds.w || h > bounds.h) { - if (!SDL_GetDisplayBounds(displayID, &bounds)) { - return false; - } - } - if (SDL_WINDOWPOS_ISCENTERED(x)) { - x = bounds.x + (bounds.w - w) / 2; - } - if (SDL_WINDOWPOS_ISCENTERED(y)) { - y = bounds.y + (bounds.h - h) / 2; - } - } - - window->pending.x = x; - window->pending.y = y; - window->undefined_x = false; - window->undefined_y = false; - window->last_position_pending = true; - - if (_this->SetWindowPosition) { - const bool result = _this->SetWindowPosition(_this, window); - if (result) { - SDL_SyncIfRequired(window); - } - return result; - } - - return SDL_Unsupported(); -} - -bool SDL_GetWindowPosition(SDL_Window *window, int *x, int *y) -{ - CHECK_WINDOW_MAGIC(window, false); - - // Fullscreen windows are always at their display's origin - if (window->flags & SDL_WINDOW_FULLSCREEN) { - SDL_DisplayID displayID; - - if (x) { - *x = 0; - } - if (y) { - *y = 0; - } - - /* Find the window's monitor and update to the - monitor offset. */ - displayID = SDL_GetDisplayForWindow(window); - if (displayID != 0) { - SDL_Rect bounds; - - SDL_zero(bounds); - - SDL_GetDisplayBounds(displayID, &bounds); - if (x) { - *x = bounds.x; - } - if (y) { - *y = bounds.y; - } - } - } else { - if (x) { - *x = window->x; - } - if (y) { - *y = window->y; - } - } - return true; -} - -bool SDL_SetWindowBordered(SDL_Window *window, bool bordered) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - const bool want = (bordered != false); // normalize the flag. - const bool have = !(window->flags & SDL_WINDOW_BORDERLESS); - if ((want != have) && (_this->SetWindowBordered)) { - if (want) { - window->flags &= ~SDL_WINDOW_BORDERLESS; - } else { - window->flags |= SDL_WINDOW_BORDERLESS; - } - _this->SetWindowBordered(_this, window, want); - } - - return true; -} - -bool SDL_SetWindowResizable(SDL_Window *window, bool resizable) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - const bool want = (resizable != false); // normalize the flag. - const bool have = ((window->flags & SDL_WINDOW_RESIZABLE) != 0); - if ((want != have) && (_this->SetWindowResizable)) { - if (want) { - window->flags |= SDL_WINDOW_RESIZABLE; - } else { - window->flags &= ~SDL_WINDOW_RESIZABLE; - SDL_copyp(&window->windowed, &window->floating); - } - _this->SetWindowResizable(_this, window, want); - } - - return true; -} - -bool SDL_SetWindowAlwaysOnTop(SDL_Window *window, bool on_top) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - const bool want = (on_top != false); // normalize the flag. - const bool have = ((window->flags & SDL_WINDOW_ALWAYS_ON_TOP) != 0); - if ((want != have) && (_this->SetWindowAlwaysOnTop)) { - if (want) { - window->flags |= SDL_WINDOW_ALWAYS_ON_TOP; - } else { - window->flags &= ~SDL_WINDOW_ALWAYS_ON_TOP; - } - _this->SetWindowAlwaysOnTop(_this, window, want); - } - - return true; -} - -bool SDL_SetWindowSize(SDL_Window *window, int w, int h) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (w <= 0) { - return SDL_InvalidParamError("w"); - } - if (h <= 0) { - return SDL_InvalidParamError("h"); - } - - // It is possible for the aspect ratio constraints to not satisfy the size constraints. - // The size constraints will override the aspect ratio constraints so we will apply the - // the aspect ratio constraints first - float new_aspect = w / (float)h; - if (window->max_aspect > 0.0f && new_aspect > window->max_aspect) { - w = (int)SDL_roundf(h * window->max_aspect); - } else if (window->min_aspect > 0.0f && new_aspect < window->min_aspect) { - h = (int)SDL_roundf(w / window->min_aspect); - } - - // Make sure we don't exceed any window size limits - if (window->min_w && w < window->min_w) { - w = window->min_w; - } - if (window->max_w && w > window->max_w) { - w = window->max_w; - } - if (window->min_h && h < window->min_h) { - h = window->min_h; - } - if (window->max_h && h > window->max_h) { - h = window->max_h; - } - - window->last_size_pending = true; - window->pending.w = w; - window->pending.h = h; - - if (_this->SetWindowSize) { - _this->SetWindowSize(_this, window); - SDL_SyncIfRequired(window); - } else { - return SDL_Unsupported(); - } - return true; -} - -bool SDL_GetWindowSize(SDL_Window *window, int *w, int *h) -{ - CHECK_WINDOW_MAGIC(window, false); - if (w) { - *w = window->w; - } - if (h) { - *h = window->h; - } - return true; -} - -bool SDL_SetWindowAspectRatio(SDL_Window *window, float min_aspect, float max_aspect) -{ - CHECK_WINDOW_MAGIC(window, false); - - window->min_aspect = min_aspect; - window->max_aspect = max_aspect; - if (_this->SetWindowAspectRatio) { - _this->SetWindowAspectRatio(_this, window); - } - return SDL_SetWindowSize(window, window->floating.w, window->floating.h); -} - -bool SDL_GetWindowAspectRatio(SDL_Window *window, float *min_aspect, float *max_aspect) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (min_aspect) { - *min_aspect = window->min_aspect; - } - if (max_aspect) { - *max_aspect = window->max_aspect; - } - return true; -} - -bool SDL_GetWindowBordersSize(SDL_Window *window, int *top, int *left, int *bottom, int *right) -{ - int dummy = 0; - - if (!top) { - top = &dummy; - } - if (!left) { - left = &dummy; - } - if (!right) { - right = &dummy; - } - if (!bottom) { - bottom = &dummy; - } - - // Always initialize, so applications don't have to care - *top = *left = *bottom = *right = 0; - - CHECK_WINDOW_MAGIC(window, false); - - if (!_this->GetWindowBordersSize) { - return SDL_Unsupported(); - } - - return _this->GetWindowBordersSize(_this, window, top, left, bottom, right); -} - -bool SDL_GetWindowSizeInPixels(SDL_Window *window, int *w, int *h) -{ - int filter; - - CHECK_WINDOW_MAGIC(window, false); - - if (!w) { - w = &filter; - } - - if (!h) { - h = &filter; - } - - if (_this->GetWindowSizeInPixels) { - _this->GetWindowSizeInPixels(_this, window, w, h); - } else { - SDL_DisplayID displayID = SDL_GetDisplayForWindow(window); - const SDL_DisplayMode *mode; - - SDL_GetWindowSize(window, w, h); - - if ((window->flags & SDL_WINDOW_FULLSCREEN) && SDL_GetWindowFullscreenMode(window)) { - mode = SDL_GetCurrentDisplayMode(displayID); - } else { - mode = SDL_GetDesktopDisplayMode(displayID); - } - if (mode) { - *w = (int)SDL_ceilf(*w * mode->pixel_density); - *h = (int)SDL_ceilf(*h * mode->pixel_density); - } - } - return true; -} - -bool SDL_SetWindowMinimumSize(SDL_Window *window, int min_w, int min_h) -{ - CHECK_WINDOW_MAGIC(window, false); - if (min_w < 0) { - return SDL_InvalidParamError("min_w"); - } - if (min_h < 0) { - return SDL_InvalidParamError("min_h"); - } - - if ((window->max_w && min_w > window->max_w) || - (window->max_h && min_h > window->max_h)) { - return SDL_SetError("SDL_SetWindowMinimumSize(): Tried to set minimum size larger than maximum size"); - } - - window->min_w = min_w; - window->min_h = min_h; - - if (_this->SetWindowMinimumSize) { - _this->SetWindowMinimumSize(_this, window); - } - - // Ensure that window is not smaller than minimal size - int w = window->last_size_pending ? window->pending.w : window->floating.w; - int h = window->last_size_pending ? window->pending.h : window->floating.h; - w = window->min_w ? SDL_max(w, window->min_w) : w; - h = window->min_h ? SDL_max(h, window->min_h) : h; - return SDL_SetWindowSize(window, w, h); -} - -bool SDL_GetWindowMinimumSize(SDL_Window *window, int *min_w, int *min_h) -{ - CHECK_WINDOW_MAGIC(window, false); - if (min_w) { - *min_w = window->min_w; - } - if (min_h) { - *min_h = window->min_h; - } - return true; -} - -bool SDL_SetWindowMaximumSize(SDL_Window *window, int max_w, int max_h) -{ - CHECK_WINDOW_MAGIC(window, false); - if (max_w < 0) { - return SDL_InvalidParamError("max_w"); - } - if (max_h < 0) { - return SDL_InvalidParamError("max_h"); - } - - if ((max_w && max_w < window->min_w) || - (max_h && max_h < window->min_h)) { - return SDL_SetError("SDL_SetWindowMaximumSize(): Tried to set maximum size smaller than minimum size"); - } - - window->max_w = max_w; - window->max_h = max_h; - - if (_this->SetWindowMaximumSize) { - _this->SetWindowMaximumSize(_this, window); - } - - // Ensure that window is not larger than maximal size - int w = window->last_size_pending ? window->pending.w : window->floating.w; - int h = window->last_size_pending ? window->pending.h : window->floating.h; - w = window->max_w ? SDL_min(w, window->max_w) : w; - h = window->max_h ? SDL_min(h, window->max_h) : h; - return SDL_SetWindowSize(window, w, h); -} - -bool SDL_GetWindowMaximumSize(SDL_Window *window, int *max_w, int *max_h) -{ - CHECK_WINDOW_MAGIC(window, false); - if (max_w) { - *max_w = window->max_w; - } - if (max_h) { - *max_h = window->max_h; - } - return true; -} - -bool SDL_ShowWindow(SDL_Window *window) -{ - SDL_Window *child; - CHECK_WINDOW_MAGIC(window, false); - - if (!(window->flags & SDL_WINDOW_HIDDEN)) { - return true; - } - - // If the parent is hidden, set the flag to restore this when the parent is shown - if (window->parent && (window->parent->flags & SDL_WINDOW_HIDDEN)) { - window->restore_on_show = true; - return true; - } - - if (_this->ShowWindow) { - _this->ShowWindow(_this, window); - } else { - SDL_SetMouseFocus(window); - SDL_SetKeyboardFocus(window); - } - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SHOWN, 0, 0); - - // Restore child windows - for (child = window->first_child; child; child = child->next_sibling) { - if (!child->restore_on_show && (child->flags & SDL_WINDOW_HIDDEN)) { - break; - } - SDL_ShowWindow(child); - child->restore_on_show = false; - } - return true; -} - -bool SDL_HideWindow(SDL_Window *window) -{ - SDL_Window *child; - CHECK_WINDOW_MAGIC(window, false); - - if (window->flags & SDL_WINDOW_HIDDEN) { - window->restore_on_show = false; - return true; - } - - // Hide all child windows - for (child = window->first_child; child; child = child->next_sibling) { - if (child->flags & SDL_WINDOW_HIDDEN) { - break; - } - SDL_HideWindow(child); - child->restore_on_show = true; - } - - // Store the flags for restoration later. - const SDL_WindowFlags pending_mask = (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_KEYBOARD_GRABBED | SDL_WINDOW_MOUSE_GRABBED); - window->pending_flags = (window->flags & pending_mask); - - window->is_hiding = true; - if (_this->HideWindow) { - _this->HideWindow(_this, window); - } else { - SDL_SetMouseFocus(NULL); - SDL_SetKeyboardFocus(NULL); - } - window->is_hiding = false; - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_HIDDEN, 0, 0); - return true; -} - -bool SDL_RaiseWindow(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (window->flags & SDL_WINDOW_HIDDEN) { - return true; - } - if (_this->RaiseWindow) { - _this->RaiseWindow(_this, window); - } - return true; -} - -bool SDL_MaximizeWindow(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (!_this->MaximizeWindow) { - return SDL_Unsupported(); - } - - if (!(window->flags & SDL_WINDOW_RESIZABLE)) { - return SDL_SetError("A window without the 'SDL_WINDOW_RESIZABLE' flag can't be maximized"); - } - - if (window->flags & SDL_WINDOW_HIDDEN) { - window->pending_flags |= SDL_WINDOW_MAXIMIZED; - return true; - } - - _this->MaximizeWindow(_this, window); - SDL_SyncIfRequired(window); - return true; -} - -bool SDL_MinimizeWindow(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (!_this->MinimizeWindow) { - return SDL_Unsupported(); - } - - if (window->flags & SDL_WINDOW_HIDDEN) { - window->pending_flags |= SDL_WINDOW_MINIMIZED; - return true; - } - - _this->MinimizeWindow(_this, window); - SDL_SyncIfRequired(window); - return true; -} - -bool SDL_RestoreWindow(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (!_this->RestoreWindow) { - return SDL_Unsupported(); - } - - if (window->flags & SDL_WINDOW_HIDDEN) { - window->pending_flags &= ~(SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED); - return true; - } - - _this->RestoreWindow(_this, window); - SDL_SyncIfRequired(window); - return true; -} - -bool SDL_SetWindowFullscreen(SDL_Window *window, bool fullscreen) -{ - bool result; - - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (window->flags & SDL_WINDOW_HIDDEN) { - if (fullscreen) { - window->pending_flags |= SDL_WINDOW_FULLSCREEN; - } else { - window->pending_flags &= ~SDL_WINDOW_FULLSCREEN; - } - return true; - } - - if (fullscreen) { - // Set the current fullscreen mode to the desired mode - SDL_copyp(&window->current_fullscreen_mode, &window->requested_fullscreen_mode); - } - - result = SDL_UpdateFullscreenMode(window, fullscreen ? SDL_FULLSCREEN_OP_ENTER : SDL_FULLSCREEN_OP_LEAVE, true); - - if (!fullscreen || !result) { - // Clear the current fullscreen mode. - SDL_zero(window->current_fullscreen_mode); - } - - if (result) { - SDL_SyncIfRequired(window); - } - - return result; -} - -bool SDL_SyncWindow(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false) - - if (_this->SyncWindow) { - return _this->SyncWindow(_this, window); - } else { - return true; - } -} - -static bool ShouldAttemptTextureFramebuffer(void) -{ - const char *hint; - bool attempt_texture_framebuffer = true; - - // The dummy driver never has GPU support, of course. - if (_this->is_dummy) { - return false; - } - - // See if there's a hint override - hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); - if (hint && *hint) { - if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0 || SDL_strcasecmp(hint, SDL_SOFTWARE_RENDERER) == 0) { - attempt_texture_framebuffer = false; - } else { - attempt_texture_framebuffer = true; - } - } else { - // Check for platform specific defaults -#ifdef SDL_PLATFORM_LINUX - // On WSL, direct X11 is faster than using OpenGL for window framebuffers, so try to detect WSL and avoid texture framebuffer. - if ((_this->CreateWindowFramebuffer) && (SDL_strcmp(_this->name, "x11") == 0)) { - struct stat sb; - if ((stat("/proc/sys/fs/binfmt_misc/WSLInterop", &sb) == 0) || (stat("/run/WSL", &sb) == 0)) { // if either of these exist, we're on WSL. - attempt_texture_framebuffer = false; - } - } -#endif -#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) // GDI BitBlt() is way faster than Direct3D dynamic textures right now. (!!! FIXME: is this still true?) - if (_this->CreateWindowFramebuffer && (SDL_strcmp(_this->name, "windows") == 0)) { - attempt_texture_framebuffer = false; - } -#endif -#ifdef SDL_PLATFORM_EMSCRIPTEN - attempt_texture_framebuffer = false; -#endif - } - return attempt_texture_framebuffer; -} - -static SDL_Surface *SDL_CreateWindowFramebuffer(SDL_Window *window) -{ - SDL_PixelFormat format = SDL_PIXELFORMAT_UNKNOWN; - void *pixels = NULL; - int pitch = 0; - bool created_framebuffer = false; - int w, h; - - SDL_GetWindowSizeInPixels(window, &w, &h); - - /* This will switch the video backend from using a software surface to - using a GPU texture through the 2D render API, if we think this would - be more efficient. This only checks once, on demand. */ - if (!_this->checked_texture_framebuffer) { - if (ShouldAttemptTextureFramebuffer()) { - if (!SDL_CreateWindowTexture(_this, window, &format, &pixels, &pitch)) { - /* !!! FIXME: if this failed halfway (made renderer, failed to make texture, etc), - !!! FIXME: we probably need to clean this up so it doesn't interfere with - !!! FIXME: a software fallback at the system level (can we blit to an - !!! FIXME: OpenGL window? etc). */ - } else { - // future attempts will just try to use a texture framebuffer. - /* !!! FIXME: maybe we shouldn't override these but check if we used a texture - !!! FIXME: framebuffer at the right places; is it feasible we could have an - !!! FIXME: accelerated OpenGL window and a second ends up in software? */ - _this->CreateWindowFramebuffer = SDL_CreateWindowTexture; - _this->SetWindowFramebufferVSync = SDL_SetWindowTextureVSync; - _this->GetWindowFramebufferVSync = SDL_GetWindowTextureVSync; - _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture; - _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture; - created_framebuffer = true; - } - } - - _this->checked_texture_framebuffer = true; // don't check this again. - } - - if (!created_framebuffer) { - if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) { - SDL_SetError("Window framebuffer support not available"); - return NULL; - } - - if (!_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch)) { - return NULL; - } - } - - if (window->surface) { - // We may have gone recursive and already created the surface - return window->surface; - } - - return SDL_CreateSurfaceFrom(w, h, format, pixels, pitch); -} - -bool SDL_WindowHasSurface(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - return window->surface ? true : false; -} - -SDL_Surface *SDL_GetWindowSurface(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, NULL); - - if (!window->surface_valid) { - if (window->surface) { - window->surface->internal_flags &= ~SDL_INTERNAL_SURFACE_DONTFREE; - SDL_DestroySurface(window->surface); - window->surface = NULL; - } - - window->surface = SDL_CreateWindowFramebuffer(window); - if (window->surface) { - window->surface_valid = true; - window->surface->internal_flags |= SDL_INTERNAL_SURFACE_DONTFREE; - } - } - return window->surface; -} - -bool SDL_SetWindowSurfaceVSync(SDL_Window *window, int vsync) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (!_this->SetWindowFramebufferVSync) { - return SDL_Unsupported(); - } - return _this->SetWindowFramebufferVSync(_this, window, vsync); -} - -bool SDL_GetWindowSurfaceVSync(SDL_Window *window, int *vsync) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (!_this->GetWindowFramebufferVSync) { - return SDL_Unsupported(); - } - return _this->GetWindowFramebufferVSync(_this, window, vsync); -} - -bool SDL_UpdateWindowSurface(SDL_Window *window) -{ - SDL_Rect full_rect; - - CHECK_WINDOW_MAGIC(window, false); - - full_rect.x = 0; - full_rect.y = 0; - SDL_GetWindowSizeInPixels(window, &full_rect.w, &full_rect.h); - - return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1); -} - -bool SDL_UpdateWindowSurfaceRects(SDL_Window *window, const SDL_Rect *rects, - int numrects) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (!window->surface_valid) { - return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface"); - } - - SDL_assert(_this->checked_texture_framebuffer); // we should have done this before we had a valid surface. - - return _this->UpdateWindowFramebuffer(_this, window, rects, numrects); -} - -bool SDL_DestroyWindowSurface(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (window->surface) { - window->surface->internal_flags &= ~SDL_INTERNAL_SURFACE_DONTFREE; - SDL_DestroySurface(window->surface); - window->surface = NULL; - window->surface_valid = false; - } - - if (_this->checked_texture_framebuffer) { // never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. - if (_this->DestroyWindowFramebuffer) { - _this->DestroyWindowFramebuffer(_this, window); - } - } - return true; -} - -bool SDL_SetWindowOpacity(SDL_Window *window, float opacity) -{ - bool result; - - CHECK_WINDOW_MAGIC(window, false); - - if (!_this->SetWindowOpacity) { - return SDL_Unsupported(); - } - - if (opacity < 0.0f) { - opacity = 0.0f; - } else if (opacity > 1.0f) { - opacity = 1.0f; - } - - result = _this->SetWindowOpacity(_this, window, opacity); - if (result) { - window->opacity = opacity; - } - - return result; -} - -float SDL_GetWindowOpacity(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, -1.0f); - - return window->opacity; -} - -bool SDL_SetWindowParent(SDL_Window *window, SDL_Window *parent) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (parent) { - CHECK_WINDOW_MAGIC(parent, false); - CHECK_WINDOW_NOT_POPUP(parent, false); - } - - if (!_this->SetWindowParent) { - return SDL_Unsupported(); - } - - if (window->flags & SDL_WINDOW_MODAL) { - return SDL_SetError("Modal windows cannot change parents; call SDL_SetWindowModal() to clear modal status first."); - } - - if (window->parent == parent) { - return true; - } - - const bool ret = _this->SetWindowParent(_this, window, parent); - SDL_UpdateWindowHierarchy(window, ret ? parent : NULL); - - return ret; -} - -bool SDL_SetWindowModal(SDL_Window *window, bool modal) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (!_this->SetWindowModal) { - return SDL_Unsupported(); - } - - if (modal) { - if (!window->parent) { - return SDL_SetError("Window must have a parent to enable the modal state; use SDL_SetWindowParent() to set the parent first."); - } - window->flags |= SDL_WINDOW_MODAL; - } else if (window->flags & SDL_WINDOW_MODAL) { - window->flags &= ~SDL_WINDOW_MODAL; - } else { - return true; // Already not modal, so nothing to do. - } - - if (window->flags & SDL_WINDOW_HIDDEN) { - return true; - } - - return _this->SetWindowModal(_this, window, modal); -} - -bool SDL_SetWindowFocusable(SDL_Window *window, bool focusable) -{ - CHECK_WINDOW_MAGIC(window, false); - - const bool want = (focusable != false); // normalize the flag. - const bool have = !(window->flags & SDL_WINDOW_NOT_FOCUSABLE); - if ((want != have) && (_this->SetWindowFocusable)) { - if (want) { - window->flags &= ~SDL_WINDOW_NOT_FOCUSABLE; - } else { - window->flags |= SDL_WINDOW_NOT_FOCUSABLE; - } - if (!_this->SetWindowFocusable(_this, window, want)) { - return false; - } - } - - return true; -} - -void SDL_UpdateWindowGrab(SDL_Window *window) -{ - bool keyboard_grabbed, mouse_grabbed; - - if (window->flags & SDL_WINDOW_INPUT_FOCUS) { - if (SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) { - mouse_grabbed = true; - } else { - mouse_grabbed = false; - } - - if (window->flags & SDL_WINDOW_KEYBOARD_GRABBED) { - keyboard_grabbed = true; - } else { - keyboard_grabbed = false; - } - } else { - mouse_grabbed = false; - keyboard_grabbed = false; - } - - if (mouse_grabbed || keyboard_grabbed) { - if (_this->grabbed_window && (_this->grabbed_window != window)) { - // stealing a grab from another window! - _this->grabbed_window->flags &= ~(SDL_WINDOW_MOUSE_GRABBED | SDL_WINDOW_KEYBOARD_GRABBED); - if (_this->SetWindowMouseGrab) { - _this->SetWindowMouseGrab(_this, _this->grabbed_window, false); - } - if (_this->SetWindowKeyboardGrab) { - _this->SetWindowKeyboardGrab(_this, _this->grabbed_window, false); - } - } - _this->grabbed_window = window; - } else if (_this->grabbed_window == window) { - _this->grabbed_window = NULL; // ungrabbing input. - } - - if (_this->SetWindowMouseGrab) { - if (!_this->SetWindowMouseGrab(_this, window, mouse_grabbed)) { - window->flags &= ~SDL_WINDOW_MOUSE_GRABBED; - } - } - if (_this->SetWindowKeyboardGrab) { - if (!_this->SetWindowKeyboardGrab(_this, window, keyboard_grabbed)) { - window->flags &= ~SDL_WINDOW_KEYBOARD_GRABBED; - } - } - - if (_this->grabbed_window && !(_this->grabbed_window->flags & (SDL_WINDOW_MOUSE_GRABBED | SDL_WINDOW_KEYBOARD_GRABBED))) { - _this->grabbed_window = NULL; - } -} - -bool SDL_SetWindowKeyboardGrab(SDL_Window *window, bool grabbed) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (window->flags & SDL_WINDOW_HIDDEN) { - if (grabbed) { - window->pending_flags |= SDL_WINDOW_KEYBOARD_GRABBED; - } else { - window->pending_flags &= ~SDL_WINDOW_KEYBOARD_GRABBED; - } - return true; - } - - if (!!grabbed == !!(window->flags & SDL_WINDOW_KEYBOARD_GRABBED)) { - return true; - } - if (grabbed) { - window->flags |= SDL_WINDOW_KEYBOARD_GRABBED; - } else { - window->flags &= ~SDL_WINDOW_KEYBOARD_GRABBED; - } - SDL_UpdateWindowGrab(window); - - if (grabbed && !(window->flags & SDL_WINDOW_KEYBOARD_GRABBED)) { - return false; - } - return true; -} - -bool SDL_SetWindowMouseGrab(SDL_Window *window, bool grabbed) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (window->flags & SDL_WINDOW_HIDDEN) { - if (grabbed) { - window->pending_flags |= SDL_WINDOW_MOUSE_GRABBED; - } else { - window->pending_flags &= ~SDL_WINDOW_MOUSE_GRABBED; - } - return true; - } - - if (!!grabbed == !!(window->flags & SDL_WINDOW_MOUSE_GRABBED)) { - return true; - } - if (grabbed) { - window->flags |= SDL_WINDOW_MOUSE_GRABBED; - } else { - window->flags &= ~SDL_WINDOW_MOUSE_GRABBED; - } - SDL_UpdateWindowGrab(window); - - if (grabbed && !(window->flags & SDL_WINDOW_MOUSE_GRABBED)) { - return false; - } - return true; -} - -bool SDL_GetWindowKeyboardGrab(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - return window == _this->grabbed_window && (_this->grabbed_window->flags & SDL_WINDOW_KEYBOARD_GRABBED); -} - -bool SDL_GetWindowMouseGrab(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - return window == _this->grabbed_window && (_this->grabbed_window->flags & SDL_WINDOW_MOUSE_GRABBED); -} - -SDL_Window *SDL_GetGrabbedWindow(void) -{ - if (_this->grabbed_window && - (_this->grabbed_window->flags & (SDL_WINDOW_MOUSE_GRABBED | SDL_WINDOW_KEYBOARD_GRABBED)) != 0) { - return _this->grabbed_window; - } else { - return NULL; - } -} - -bool SDL_SetWindowMouseRect(SDL_Window *window, const SDL_Rect *rect) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (rect) { - SDL_memcpy(&window->mouse_rect, rect, sizeof(*rect)); - } else { - SDL_zero(window->mouse_rect); - } - - if (_this->SetWindowMouseRect) { - return _this->SetWindowMouseRect(_this, window); - } - return true; -} - -const SDL_Rect *SDL_GetWindowMouseRect(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, NULL); - - if (SDL_RectEmpty(&window->mouse_rect)) { - return NULL; - } else { - return &window->mouse_rect; - } -} - -bool SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled) -{ - CHECK_WINDOW_MAGIC(window, false); - - /* If the app toggles relative mode directly, it probably shouldn't - * also be emulating it using repeated mouse warps, so disable - * mouse warp emulation by default. - */ - SDL_DisableMouseWarpEmulation(); - - if (enabled == SDL_GetWindowRelativeMouseMode(window)) { - return true; - } - - if (enabled) { - window->flags |= SDL_WINDOW_MOUSE_RELATIVE_MODE; - } else { - window->flags &= ~SDL_WINDOW_MOUSE_RELATIVE_MODE; - } - SDL_UpdateRelativeMouseMode(); - - return true; -} - -bool SDL_GetWindowRelativeMouseMode(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (window->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE) { - return true; - } else { - return false; - } -} - -bool SDL_FlashWindow(SDL_Window *window, SDL_FlashOperation operation) -{ - CHECK_WINDOW_MAGIC(window, false); - CHECK_WINDOW_NOT_POPUP(window, false); - - if (_this->FlashWindow) { - return _this->FlashWindow(_this, window, operation); - } - - return SDL_Unsupported(); -} - -void SDL_OnWindowShown(SDL_Window *window) -{ - // Set window state if we have pending window flags cached - ApplyWindowFlags(window, window->pending_flags); - window->pending_flags = 0; -} - -void SDL_OnWindowHidden(SDL_Window *window) -{ - /* Store the maximized and fullscreen flags for restoration later, in case - * this was initiated by the window manager due to the window being unmapped - * when minimized. - */ - window->pending_flags |= (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)); - - // The window is already hidden at this point, so just change the mode back if necessary. - SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_LEAVE, false); -} - -void SDL_OnWindowDisplayChanged(SDL_Window *window) -{ - if (window->flags & SDL_WINDOW_FULLSCREEN) { - SDL_DisplayID displayID = SDL_GetDisplayForWindowPosition(window); - - if (window->requested_fullscreen_mode.w != 0 || window->requested_fullscreen_mode.h != 0) { - bool include_high_density_modes = false; - - if (window->requested_fullscreen_mode.pixel_density > 1.0f) { - include_high_density_modes = true; - } - SDL_GetClosestFullscreenDisplayMode(displayID, window->requested_fullscreen_mode.w, window->requested_fullscreen_mode.h, window->requested_fullscreen_mode.refresh_rate, include_high_density_modes, &window->current_fullscreen_mode); - } else { - SDL_zero(window->current_fullscreen_mode); - } - - if (SDL_WINDOW_FULLSCREEN_VISIBLE(window)) { - SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_UPDATE, true); - } - } - - SDL_CheckWindowPixelSizeChanged(window); -} - -void SDL_OnWindowMoved(SDL_Window *window) -{ - SDL_CheckWindowDisplayChanged(window); -} - -void SDL_OnWindowResized(SDL_Window *window) -{ - SDL_CheckWindowDisplayChanged(window); - SDL_CheckWindowPixelSizeChanged(window); - SDL_CheckWindowSafeAreaChanged(window); - - if ((window->flags & SDL_WINDOW_TRANSPARENT) && _this->UpdateWindowShape) { - SDL_Surface *surface = (SDL_Surface *)SDL_GetPointerProperty(window->props, SDL_PROP_WINDOW_SHAPE_POINTER, NULL); - if (surface) { - _this->UpdateWindowShape(_this, window, surface); - } - } -} - -void SDL_CheckWindowPixelSizeChanged(SDL_Window *window) -{ - int pixel_w = 0, pixel_h = 0; - - SDL_GetWindowSizeInPixels(window, &pixel_w, &pixel_h); - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED, pixel_w, pixel_h); - - SDL_CheckWindowDisplayScaleChanged(window); -} - -void SDL_OnWindowPixelSizeChanged(SDL_Window *window) -{ - window->surface_valid = false; -} - -void SDL_OnWindowLiveResizeUpdate(SDL_Window *window) -{ - if (SDL_HasMainCallbacks()) { - SDL_IterateMainCallbacks(false); - } else { - // Send an expose event so the application can redraw - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); - } - - SDL_PumpEventMaintenance(); -} - -static void SDL_CheckWindowSafeAreaChanged(SDL_Window *window) -{ - SDL_Rect rect; - - rect.x = window->safe_inset_left; - rect.y = window->safe_inset_top; - rect.w = window->w - (window->safe_inset_right + window->safe_inset_left); - rect.h = window->h - (window->safe_inset_top + window->safe_inset_bottom); - if (SDL_memcmp(&rect, &window->safe_rect, sizeof(rect)) != 0) { - SDL_copyp(&window->safe_rect, &rect); - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_SAFE_AREA_CHANGED, 0, 0); - } -} - -void SDL_SetWindowSafeAreaInsets(SDL_Window *window, int left, int right, int top, int bottom) -{ - window->safe_inset_left = left; - window->safe_inset_right = right; - window->safe_inset_top = top; - window->safe_inset_bottom = bottom; - SDL_CheckWindowSafeAreaChanged(window); -} - -bool SDL_GetWindowSafeArea(SDL_Window *window, SDL_Rect *rect) -{ - if (rect) { - SDL_zerop(rect); - } - - CHECK_WINDOW_MAGIC(window, false); - - if (rect) { - if (SDL_RectEmpty(&window->safe_rect)) { - rect->w = window->w; - rect->h = window->h; - } else { - SDL_copyp(rect, &window->safe_rect); - } - } - return true; -} - -void SDL_OnWindowMinimized(SDL_Window *window) -{ - if (window->flags & SDL_WINDOW_FULLSCREEN) { - SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_LEAVE, false); - } -} - -void SDL_OnWindowMaximized(SDL_Window *window) -{ -} - -void SDL_OnWindowRestored(SDL_Window *window) -{ - /* - * FIXME: Is this fine to just remove this, or should it be preserved just - * for the fullscreen case? In principle it seems like just hiding/showing - * windows shouldn't affect the stacking order; maybe the right fix is to - * re-decouple OnWindowShown and OnWindowRestored. - */ - // SDL_RaiseWindow(window); - - if (window->flags & SDL_WINDOW_FULLSCREEN) { - SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_ENTER, false); - } -} - -void SDL_OnWindowEnter(SDL_Window *window) -{ - if (_this->OnWindowEnter) { - _this->OnWindowEnter(_this, window); - } -} - -void SDL_OnWindowLeave(SDL_Window *window) -{ -} - -void SDL_OnWindowFocusGained(SDL_Window *window) -{ - SDL_Mouse *mouse = SDL_GetMouse(); - - if (mouse && mouse->relative_mode) { - SDL_SetMouseFocus(window); - } - - SDL_UpdateWindowGrab(window); -} - -static bool SDL_ShouldMinimizeOnFocusLoss(SDL_Window *window) -{ - const char *hint; - - if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) { - return false; - } - -#if defined(SDL_PLATFORM_MACOS) && defined(SDL_VIDEO_DRIVER_COCOA) - if (SDL_strcmp(_this->name, "cocoa") == 0) { // don't do this for X11, etc - if (Cocoa_IsWindowInFullscreenSpace(window)) { - return false; - } - } -#endif - -#ifdef SDL_PLATFORM_ANDROID - { - extern bool Android_JNI_ShouldMinimizeOnFocusLoss(void); - if (!Android_JNI_ShouldMinimizeOnFocusLoss()) { - return false; - } - } -#endif - - // Real fullscreen windows should minimize on focus loss so the desktop video mode is restored - hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS); - if (!hint || !*hint || SDL_strcasecmp(hint, "auto") == 0) { - if (window->fullscreen_exclusive && !SDL_ModeSwitchingEmulated(_this)) { - return true; - } else { - return false; - } - } - return SDL_GetHintBoolean(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, false); -} - -void SDL_OnWindowFocusLost(SDL_Window *window) -{ - SDL_UpdateWindowGrab(window); - - if (SDL_ShouldMinimizeOnFocusLoss(window)) { - SDL_MinimizeWindow(window); - } -} - -SDL_Window *SDL_GetToplevelForKeyboardFocus(void) -{ - SDL_Window *focus = SDL_GetKeyboardFocus(); - - if (focus) { - // Get the toplevel parent window. - while (focus->parent) { - focus = focus->parent; - } - } - - return focus; -} - -bool SDL_AddWindowRenderer(SDL_Window *window, SDL_Renderer *renderer) -{ - SDL_Renderer **renderers = (SDL_Renderer **)SDL_realloc(window->renderers, (window->num_renderers + 1) * sizeof(*renderers)); - if (!renderers) { - return false; - } - - window->renderers = renderers; - window->renderers[window->num_renderers++] = renderer; - return true; -} - -void SDL_RemoveWindowRenderer(SDL_Window *window, SDL_Renderer *renderer) -{ - for (int i = 0; i < window->num_renderers; ++i) { - if (window->renderers[i] == renderer) { - if (i < (window->num_renderers - 1)) { - SDL_memmove(&window->renderers[i], &window->renderers[i + 1], (window->num_renderers - i - 1) * sizeof(window->renderers[i])); - } - --window->num_renderers; - break; - } - } -} - -void SDL_DestroyWindow(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window,); - - window->is_destroying = true; - - // Destroy any child windows of this window - while (window->first_child) { - SDL_DestroyWindow(window->first_child); - } - - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DESTROYED, 0, 0); - - SDL_Renderer *renderer = SDL_GetRenderer(window); - if (renderer) { - SDL_DestroyRendererWithoutFreeing(renderer); - } - - // Restore video mode, etc. - SDL_UpdateFullscreenMode(window, SDL_FULLSCREEN_OP_LEAVE, true); - if (!(window->flags & SDL_WINDOW_EXTERNAL)) { - SDL_HideWindow(window); - } - - SDL_DestroyProperties(window->text_input_props); - SDL_DestroyProperties(window->props); - - /* Clear the modal status, but don't unset the parent just yet, as it - * may be needed later in the destruction process if a backend needs - * to update the input focus. - */ - if (_this->SetWindowModal && (window->flags & SDL_WINDOW_MODAL)) { - _this->SetWindowModal(_this, window, false); - } - - // Make sure the destroyed window isn't referenced by any display as a fullscreen window. - for (int i = 0; i < _this->num_displays; ++i) { - if (_this->displays[i]->fullscreen_window == window) { - _this->displays[i]->fullscreen_window = NULL; - } - } - - // Make sure this window no longer has focus - if (SDL_GetKeyboardFocus() == window) { - SDL_SetKeyboardFocus(NULL); - } - if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE)) { - SDL_UpdateMouseCapture(true); - } - if (SDL_GetMouseFocus() == window) { - SDL_SetMouseFocus(NULL); - } - - SDL_DestroyWindowSurface(window); - - // Make no context current if this is the current context window - if (window->flags & SDL_WINDOW_OPENGL) { - if (_this->current_glwin == window) { - SDL_GL_MakeCurrent(window, NULL); - } - } - - if (_this->DestroyWindow) { - _this->DestroyWindow(_this, window); - } - - // Unload the graphics libraries after the window is destroyed, which may clean up EGL surfaces - if (window->flags & SDL_WINDOW_OPENGL) { - SDL_GL_UnloadLibrary(); - } - if (window->flags & SDL_WINDOW_VULKAN) { - SDL_Vulkan_UnloadLibrary(); - } - - if (_this->grabbed_window == window) { - _this->grabbed_window = NULL; // ungrabbing input. - } - - if (_this->current_glwin == window) { - _this->current_glwin = NULL; - } - - if (_this->wakeup_window == window) { - _this->wakeup_window = NULL; - } - - // Now invalidate magic - SDL_SetObjectValid(window, SDL_OBJECT_TYPE_WINDOW, false); - - // Free memory associated with the window - SDL_free(window->title); - SDL_DestroySurface(window->icon); - - // Unlink the window from its siblings. - SDL_UpdateWindowHierarchy(window, NULL); - - // Unlink the window from the global window list - if (window->next) { - window->next->prev = window->prev; - } - if (window->prev) { - window->prev->next = window->next; - } else { - _this->windows = window->next; - } - - SDL_free(window->renderers); - SDL_free(window); - -#ifdef SDL_VIDEO_DRIVER_UIKIT - SDL_UpdateLifecycleObserver(); -#endif -} - -bool SDL_ScreenSaverEnabled(void) -{ - if (!_this) { - return true; - } - return !_this->suspend_screensaver; -} - -bool SDL_EnableScreenSaver(void) -{ - if (!_this) { - return SDL_UninitializedVideo(); - } - if (!_this->suspend_screensaver) { - return true; - } - _this->suspend_screensaver = false; - if (_this->SuspendScreenSaver) { - return _this->SuspendScreenSaver(_this); - } - - return SDL_Unsupported(); -} - -bool SDL_DisableScreenSaver(void) -{ - if (!_this) { - return SDL_UninitializedVideo(); - } - if (_this->suspend_screensaver) { - return true; - } - _this->suspend_screensaver = true; - if (_this->SuspendScreenSaver) { - return _this->SuspendScreenSaver(_this); - } - - return SDL_Unsupported(); -} - -void SDL_VideoQuit(void) -{ - int i; - - if (!_this) { - return; - } - - // Halt event processing before doing anything else -#if 0 // This was moved to the end to fix a memory leak - SDL_QuitPen(); -#endif - SDL_QuitTouch(); - SDL_QuitMouse(); - SDL_QuitKeyboard(); - SDL_QuitSubSystem(SDL_INIT_EVENTS); - - SDL_EnableScreenSaver(); - - // Clean up the system video - while (_this->windows) { - SDL_DestroyWindow(_this->windows); - } - _this->VideoQuit(_this); - - for (i = _this->num_displays; i--; ) { - SDL_VideoDisplay *display = _this->displays[i]; - SDL_DelVideoDisplay(display->id, false); - } - - SDL_assert(_this->num_displays == 0); - SDL_free(_this->displays); - _this->displays = NULL; - - SDL_CancelClipboardData(0); - - if (_this->primary_selection_text) { - SDL_free(_this->primary_selection_text); - _this->primary_selection_text = NULL; - } - _this->free(_this); - _this = NULL; - - // This needs to happen after the video subsystem has removed pen data - SDL_QuitPen(); -} - -bool SDL_GL_LoadLibrary(const char *path) -{ - bool result; - - if (!_this) { - return SDL_UninitializedVideo(); - } - if (_this->gl_config.driver_loaded) { - if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) { - return SDL_SetError("OpenGL library already loaded"); - } - result = true; - } else { - if (!_this->GL_LoadLibrary) { - return SDL_DllNotSupported("OpenGL"); - } - result = _this->GL_LoadLibrary(_this, path); - } - if (result) { - ++_this->gl_config.driver_loaded; - } else { - if (_this->GL_UnloadLibrary) { - _this->GL_UnloadLibrary(_this); - } - } - return result; -} - -SDL_FunctionPointer SDL_GL_GetProcAddress(const char *proc) -{ - SDL_FunctionPointer func; - - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - func = NULL; - if (_this->GL_GetProcAddress) { - if (_this->gl_config.driver_loaded) { - func = _this->GL_GetProcAddress(_this, proc); - } else { - SDL_SetError("No GL driver has been loaded"); - } - } else { - SDL_SetError("No dynamic GL support in current SDL video driver (%s)", _this->name); - } - return func; -} - -SDL_FunctionPointer SDL_EGL_GetProcAddress(const char *proc) -{ -#ifdef SDL_VIDEO_OPENGL_EGL - SDL_FunctionPointer func; - - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - func = NULL; - - if (_this->egl_data) { - func = SDL_EGL_GetProcAddressInternal(_this, proc); - } else { - SDL_SetError("No EGL library has been loaded"); - } - - return func; -#else - SDL_SetError("SDL was not built with EGL support"); - return NULL; -#endif -} - -void SDL_GL_UnloadLibrary(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return; - } - if (_this->gl_config.driver_loaded > 0) { - if (--_this->gl_config.driver_loaded > 0) { - return; - } - if (_this->GL_UnloadLibrary) { - _this->GL_UnloadLibrary(_this); - } - } -} - -#if defined(SDL_VIDEO_OPENGL) || defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2) -typedef GLenum (APIENTRY* PFNGLGETERRORPROC) (void); -typedef void (APIENTRY* PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params); -typedef const GLubyte *(APIENTRY* PFNGLGETSTRINGPROC) (GLenum name); -#ifndef SDL_VIDEO_OPENGL -typedef const GLubyte *(APIENTRY* PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); -#endif - -static SDL_INLINE bool isAtLeastGL3(const char *verstr) -{ - return verstr && (SDL_atoi(verstr) >= 3); -} -#endif // SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - -bool SDL_GL_ExtensionSupported(const char *extension) -{ -#if defined(SDL_VIDEO_OPENGL) || defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2) - PFNGLGETSTRINGPROC glGetStringFunc; - const char *extensions; - const char *start; - const char *where, *terminator; - - // Extension names should not have spaces. - where = SDL_strchr(extension, ' '); - if (where || *extension == '\0') { - return false; - } - // See if there's a hint or environment variable override - start = SDL_GetHint(extension); - if (start && *start == '0') { - return false; - } - - // Lookup the available extensions - - glGetStringFunc = (PFNGLGETSTRINGPROC)SDL_GL_GetProcAddress("glGetString"); - if (!glGetStringFunc) { - return false; - } - - if (isAtLeastGL3((const char *)glGetStringFunc(GL_VERSION))) { - PFNGLGETSTRINGIPROC glGetStringiFunc; - PFNGLGETINTEGERVPROC glGetIntegervFunc; - GLint num_exts = 0; - GLint i; - - glGetStringiFunc = (PFNGLGETSTRINGIPROC)SDL_GL_GetProcAddress("glGetStringi"); - glGetIntegervFunc = (PFNGLGETINTEGERVPROC)SDL_GL_GetProcAddress("glGetIntegerv"); - if ((!glGetStringiFunc) || (!glGetIntegervFunc)) { - return false; - } - -#ifndef GL_NUM_EXTENSIONS -#define GL_NUM_EXTENSIONS 0x821D -#endif - glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts); - for (i = 0; i < num_exts; i++) { - const char *thisext = (const char *)glGetStringiFunc(GL_EXTENSIONS, i); - if (SDL_strcmp(thisext, extension) == 0) { - return true; - } - } - - return false; - } - - // Try the old way with glGetString(GL_EXTENSIONS) ... - - extensions = (const char *)glGetStringFunc(GL_EXTENSIONS); - if (!extensions) { - return false; - } - /* - * It takes a bit of care to be fool-proof about parsing the OpenGL - * extensions string. Don't be fooled by sub-strings, etc. - */ - - start = extensions; - - for (;;) { - where = SDL_strstr(start, extension); - if (!where) { - break; - } - - terminator = where + SDL_strlen(extension); - if (where == extensions || *(where - 1) == ' ') { - if (*terminator == ' ' || *terminator == '\0') { - return true; - } - } - - start = terminator; - } - return false; -#else - return false; -#endif -} - -/* Deduce supported ES profile versions from the supported - ARB_ES*_compatibility extensions. There is no direct query. - - This is normally only called when the OpenGL driver supports - {GLX,WGL}_EXT_create_context_es2_profile. - */ -void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor) -{ -// THIS REQUIRES AN EXISTING GL CONTEXT THAT HAS BEEN MADE CURRENT. -// Please refer to https://bugzilla.libsdl.org/show_bug.cgi?id=3725 for discussion. -#if defined(SDL_VIDEO_OPENGL) || defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2) - /* XXX This is fragile; it will break in the event of release of - * new versions of OpenGL ES. - */ - if (SDL_GL_ExtensionSupported("GL_ARB_ES3_2_compatibility")) { - *major = 3; - *minor = 2; - } else if (SDL_GL_ExtensionSupported("GL_ARB_ES3_1_compatibility")) { - *major = 3; - *minor = 1; - } else if (SDL_GL_ExtensionSupported("GL_ARB_ES3_compatibility")) { - *major = 3; - *minor = 0; - } else { - *major = 2; - *minor = 0; - } -#endif -} - -void SDL_EGL_SetAttributeCallbacks(SDL_EGLAttribArrayCallback platformAttribCallback, - SDL_EGLIntArrayCallback surfaceAttribCallback, - SDL_EGLIntArrayCallback contextAttribCallback, - void *userdata) -{ - if (!_this) { - return; - } - _this->egl_platformattrib_callback = platformAttribCallback; - _this->egl_surfaceattrib_callback = surfaceAttribCallback; - _this->egl_contextattrib_callback = contextAttribCallback; - _this->egl_attrib_callback_userdata = userdata; -} - -void SDL_GL_ResetAttributes(void) -{ - if (!_this) { - return; - } - - _this->egl_platformattrib_callback = NULL; - _this->egl_surfaceattrib_callback = NULL; - _this->egl_contextattrib_callback = NULL; - _this->egl_attrib_callback_userdata = NULL; - - _this->gl_config.red_size = 8; - _this->gl_config.green_size = 8; - _this->gl_config.blue_size = 8; - _this->gl_config.alpha_size = 8; - _this->gl_config.buffer_size = 0; - _this->gl_config.depth_size = 16; - _this->gl_config.stencil_size = 0; - _this->gl_config.double_buffer = 1; - _this->gl_config.accum_red_size = 0; - _this->gl_config.accum_green_size = 0; - _this->gl_config.accum_blue_size = 0; - _this->gl_config.accum_alpha_size = 0; - _this->gl_config.stereo = 0; - _this->gl_config.multisamplebuffers = 0; - _this->gl_config.multisamplesamples = 0; - _this->gl_config.floatbuffers = 0; - _this->gl_config.retained_backing = 1; - _this->gl_config.accelerated = -1; // accelerated or not, both are fine - -#ifdef SDL_VIDEO_OPENGL - _this->gl_config.major_version = 2; - _this->gl_config.minor_version = 1; - _this->gl_config.profile_mask = 0; -#elif defined(SDL_VIDEO_OPENGL_ES2) - _this->gl_config.major_version = 2; - _this->gl_config.minor_version = 0; - _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; -#elif defined(SDL_VIDEO_OPENGL_ES) - _this->gl_config.major_version = 1; - _this->gl_config.minor_version = 1; - _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; -#endif - - if (_this->GL_DefaultProfileConfig) { - _this->GL_DefaultProfileConfig(_this, &_this->gl_config.profile_mask, - &_this->gl_config.major_version, - &_this->gl_config.minor_version); - } - - _this->gl_config.flags = 0; - _this->gl_config.framebuffer_srgb_capable = 0; - _this->gl_config.no_error = 0; - _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH; - _this->gl_config.reset_notification = SDL_GL_CONTEXT_RESET_NO_NOTIFICATION; - - _this->gl_config.share_with_current_context = 0; - - _this->gl_config.egl_platform = 0; -} - -bool SDL_GL_SetAttribute(SDL_GLAttr attr, int value) -{ -#if defined(SDL_VIDEO_OPENGL) || defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2) - bool result; - - if (!_this) { - return SDL_UninitializedVideo(); - } - result = true; - switch (attr) { - case SDL_GL_RED_SIZE: - _this->gl_config.red_size = value; - break; - case SDL_GL_GREEN_SIZE: - _this->gl_config.green_size = value; - break; - case SDL_GL_BLUE_SIZE: - _this->gl_config.blue_size = value; - break; - case SDL_GL_ALPHA_SIZE: - _this->gl_config.alpha_size = value; - break; - case SDL_GL_DOUBLEBUFFER: - _this->gl_config.double_buffer = value; - break; - case SDL_GL_BUFFER_SIZE: - _this->gl_config.buffer_size = value; - break; - case SDL_GL_DEPTH_SIZE: - _this->gl_config.depth_size = value; - break; - case SDL_GL_STENCIL_SIZE: - _this->gl_config.stencil_size = value; - break; - case SDL_GL_ACCUM_RED_SIZE: - _this->gl_config.accum_red_size = value; - break; - case SDL_GL_ACCUM_GREEN_SIZE: - _this->gl_config.accum_green_size = value; - break; - case SDL_GL_ACCUM_BLUE_SIZE: - _this->gl_config.accum_blue_size = value; - break; - case SDL_GL_ACCUM_ALPHA_SIZE: - _this->gl_config.accum_alpha_size = value; - break; - case SDL_GL_STEREO: - _this->gl_config.stereo = value; - break; - case SDL_GL_MULTISAMPLEBUFFERS: - _this->gl_config.multisamplebuffers = value; - break; - case SDL_GL_MULTISAMPLESAMPLES: - _this->gl_config.multisamplesamples = value; - break; - case SDL_GL_FLOATBUFFERS: - _this->gl_config.floatbuffers = value; - break; - case SDL_GL_ACCELERATED_VISUAL: - _this->gl_config.accelerated = value; - break; - case SDL_GL_RETAINED_BACKING: - _this->gl_config.retained_backing = value; - break; - case SDL_GL_CONTEXT_MAJOR_VERSION: - _this->gl_config.major_version = value; - break; - case SDL_GL_CONTEXT_MINOR_VERSION: - _this->gl_config.minor_version = value; - break; - case SDL_GL_CONTEXT_FLAGS: - if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG | - SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG | - SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG | - SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) { - result = SDL_SetError("Unknown OpenGL context flag %d", value); - break; - } - _this->gl_config.flags = value; - break; - case SDL_GL_CONTEXT_PROFILE_MASK: - if (value != 0 && - value != SDL_GL_CONTEXT_PROFILE_CORE && - value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY && - value != SDL_GL_CONTEXT_PROFILE_ES) { - result = SDL_SetError("Unknown OpenGL context profile %d", value); - break; - } - _this->gl_config.profile_mask = value; - break; - case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: - _this->gl_config.share_with_current_context = value; - break; - case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: - _this->gl_config.framebuffer_srgb_capable = value; - break; - case SDL_GL_CONTEXT_RELEASE_BEHAVIOR: - _this->gl_config.release_behavior = value; - break; - case SDL_GL_CONTEXT_RESET_NOTIFICATION: - _this->gl_config.reset_notification = value; - break; - case SDL_GL_CONTEXT_NO_ERROR: - _this->gl_config.no_error = value; - break; - case SDL_GL_EGL_PLATFORM: - _this->gl_config.egl_platform = value; - break; - default: - result = SDL_SetError("Unknown OpenGL attribute"); - break; - } - return result; -#else - return SDL_Unsupported(); -#endif // SDL_VIDEO_OPENGL -} - -bool SDL_GL_GetAttribute(SDL_GLAttr attr, int *value) -{ -#if defined(SDL_VIDEO_OPENGL) || defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2) - PFNGLGETERRORPROC glGetErrorFunc; - GLenum attrib = 0; - GLenum error = 0; - - /* - * Some queries in Core Profile desktop OpenGL 3+ contexts require - * glGetFramebufferAttachmentParameteriv instead of glGetIntegerv. Note that - * the enums we use for the former function don't exist in OpenGL ES 2, and - * the function itself doesn't exist prior to OpenGL 3 and OpenGL ES 2. - */ -#ifdef SDL_VIDEO_OPENGL - PFNGLGETSTRINGPROC glGetStringFunc; - PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameterivFunc; - GLenum attachment = GL_BACK_LEFT; - GLenum attachmentattrib = 0; -#endif - - if (!value) { - return SDL_InvalidParamError("value"); - } - - // Clear value in any case - *value = 0; - - if (!_this) { - return SDL_UninitializedVideo(); - } - - switch (attr) { - case SDL_GL_RED_SIZE: -#ifdef SDL_VIDEO_OPENGL - attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE; -#endif - attrib = GL_RED_BITS; - break; - case SDL_GL_BLUE_SIZE: -#ifdef SDL_VIDEO_OPENGL - attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE; -#endif - attrib = GL_BLUE_BITS; - break; - case SDL_GL_GREEN_SIZE: -#ifdef SDL_VIDEO_OPENGL - attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE; -#endif - attrib = GL_GREEN_BITS; - break; - case SDL_GL_ALPHA_SIZE: -#ifdef SDL_VIDEO_OPENGL - attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE; -#endif - attrib = GL_ALPHA_BITS; - break; - case SDL_GL_DOUBLEBUFFER: -#ifdef SDL_VIDEO_OPENGL - attrib = GL_DOUBLEBUFFER; - break; -#else - // OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER - // parameter which switches double buffer to single buffer. OpenGL ES - // SDL driver must set proper value after initialization - *value = _this->gl_config.double_buffer; - return true; -#endif - case SDL_GL_DEPTH_SIZE: -#ifdef SDL_VIDEO_OPENGL - attachment = GL_DEPTH; - attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE; -#endif - attrib = GL_DEPTH_BITS; - break; - case SDL_GL_STENCIL_SIZE: -#ifdef SDL_VIDEO_OPENGL - attachment = GL_STENCIL; - attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE; -#endif - attrib = GL_STENCIL_BITS; - break; -#ifdef SDL_VIDEO_OPENGL - case SDL_GL_ACCUM_RED_SIZE: - attrib = GL_ACCUM_RED_BITS; - break; - case SDL_GL_ACCUM_GREEN_SIZE: - attrib = GL_ACCUM_GREEN_BITS; - break; - case SDL_GL_ACCUM_BLUE_SIZE: - attrib = GL_ACCUM_BLUE_BITS; - break; - case SDL_GL_ACCUM_ALPHA_SIZE: - attrib = GL_ACCUM_ALPHA_BITS; - break; - case SDL_GL_STEREO: - attrib = GL_STEREO; - break; -#else - case SDL_GL_ACCUM_RED_SIZE: - case SDL_GL_ACCUM_GREEN_SIZE: - case SDL_GL_ACCUM_BLUE_SIZE: - case SDL_GL_ACCUM_ALPHA_SIZE: - case SDL_GL_STEREO: - // none of these are supported in OpenGL ES - *value = 0; - return true; -#endif - case SDL_GL_MULTISAMPLEBUFFERS: - attrib = GL_SAMPLE_BUFFERS; - break; - case SDL_GL_MULTISAMPLESAMPLES: - attrib = GL_SAMPLES; - break; - case SDL_GL_CONTEXT_RELEASE_BEHAVIOR: - attrib = GL_CONTEXT_RELEASE_BEHAVIOR; - break; - case SDL_GL_BUFFER_SIZE: - { - int rsize = 0, gsize = 0, bsize = 0, asize = 0; - - // There doesn't seem to be a single flag in OpenGL for this! - if (!SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &rsize)) { - return false; - } - if (!SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gsize)) { - return false; - } - if (!SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &bsize)) { - return false; - } - if (!SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &asize)) { - return false; - } - - *value = rsize + gsize + bsize + asize; - return true; - } - case SDL_GL_ACCELERATED_VISUAL: - { - // FIXME: How do we get this information? - *value = (_this->gl_config.accelerated != 0); - return true; - } - case SDL_GL_RETAINED_BACKING: - { - *value = _this->gl_config.retained_backing; - return true; - } - case SDL_GL_CONTEXT_MAJOR_VERSION: - { - *value = _this->gl_config.major_version; - return true; - } - case SDL_GL_CONTEXT_MINOR_VERSION: - { - *value = _this->gl_config.minor_version; - return true; - } - case SDL_GL_CONTEXT_FLAGS: - { - *value = _this->gl_config.flags; - return true; - } - case SDL_GL_CONTEXT_PROFILE_MASK: - { - *value = _this->gl_config.profile_mask; - return true; - } - case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: - { - *value = _this->gl_config.share_with_current_context; - return true; - } - case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: - { - *value = _this->gl_config.framebuffer_srgb_capable; - return true; - } - case SDL_GL_CONTEXT_NO_ERROR: - { - *value = _this->gl_config.no_error; - return true; - } - case SDL_GL_EGL_PLATFORM: - { - *value = _this->gl_config.egl_platform; - return true; - } - default: - return SDL_SetError("Unknown OpenGL attribute"); - } - -#ifdef SDL_VIDEO_OPENGL - glGetStringFunc = (PFNGLGETSTRINGPROC)SDL_GL_GetProcAddress("glGetString"); - if (!glGetStringFunc) { - return false; - } - - if (attachmentattrib && isAtLeastGL3((const char *)glGetStringFunc(GL_VERSION))) { - // glGetFramebufferAttachmentParameteriv needs to operate on the window framebuffer for this, so bind FBO 0 if necessary. - GLint current_fbo = 0; - PFNGLGETINTEGERVPROC glGetIntegervFunc = (PFNGLGETINTEGERVPROC) SDL_GL_GetProcAddress("glGetIntegerv"); - PFNGLBINDFRAMEBUFFERPROC glBindFramebufferFunc = (PFNGLBINDFRAMEBUFFERPROC)SDL_GL_GetProcAddress("glBindFramebuffer"); - if (glGetIntegervFunc && glBindFramebufferFunc) { - glGetIntegervFunc(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo); - } - - glGetFramebufferAttachmentParameterivFunc = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameteriv"); - if (glGetFramebufferAttachmentParameterivFunc) { - if (glBindFramebufferFunc && (current_fbo != 0)) { - glBindFramebufferFunc(GL_DRAW_FRAMEBUFFER, 0); - } - // glGetFramebufferAttachmentParameterivFunc may cause GL_INVALID_OPERATION when querying depth/stencil size if the - // bits is 0. From the GL docs: - // If the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE, then either no framebuffer is bound to target; - // or a default framebuffer is queried, attachment is GL_DEPTH or GL_STENCIL, and the number of depth or stencil bits, - // respectively, is zero. In this case querying pname GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero, and all - // other queries will generate an error. - GLint fbo_type = GL_FRAMEBUFFER_DEFAULT; - if (attachment == GL_DEPTH || attachment == GL_STENCIL) { - glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &fbo_type); - } - if (fbo_type != GL_NONE) { - glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *)value); - } - else { - *value = 0; - } - if (glBindFramebufferFunc && (current_fbo != 0)) { - glBindFramebufferFunc(GL_DRAW_FRAMEBUFFER, current_fbo); - } - } else { - return false; - } - } else -#endif - { - PFNGLGETINTEGERVPROC glGetIntegervFunc = (PFNGLGETINTEGERVPROC)SDL_GL_GetProcAddress("glGetIntegerv"); - if (glGetIntegervFunc) { - glGetIntegervFunc(attrib, (GLint *)value); - } else { - return false; - } - } - - glGetErrorFunc = (PFNGLGETERRORPROC)SDL_GL_GetProcAddress("glGetError"); - if (!glGetErrorFunc) { - return false; - } - - error = glGetErrorFunc(); - if (error != GL_NO_ERROR) { - if (error == GL_INVALID_ENUM) { - return SDL_SetError("OpenGL error: GL_INVALID_ENUM"); - } else if (error == GL_INVALID_VALUE) { - return SDL_SetError("OpenGL error: GL_INVALID_VALUE"); - } - return SDL_SetError("OpenGL error: %08X", error); - } - - // convert GL_CONTEXT_RELEASE_BEHAVIOR values back to SDL_GL_CONTEXT_RELEASE_BEHAVIOR values - if (attr == SDL_GL_CONTEXT_RELEASE_BEHAVIOR) { - *value = (*value == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) ? SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH : SDL_GL_CONTEXT_RELEASE_BEHAVIOR_NONE; - } - - return true; -#else - return SDL_Unsupported(); -#endif // SDL_VIDEO_OPENGL -} - -#define NOT_AN_OPENGL_WINDOW "The specified window isn't an OpenGL window" - -SDL_GLContext SDL_GL_CreateContext(SDL_Window *window) -{ - SDL_GLContext ctx = NULL; - CHECK_WINDOW_MAGIC(window, NULL); - - if (!(window->flags & SDL_WINDOW_OPENGL)) { - SDL_SetError(NOT_AN_OPENGL_WINDOW); - return NULL; - } - - ctx = _this->GL_CreateContext(_this, window); - - // Creating a context is assumed to make it current in the SDL driver. - if (ctx) { - _this->current_glwin = window; - _this->current_glctx = ctx; - SDL_SetTLS(&_this->current_glwin_tls, window, NULL); - SDL_SetTLS(&_this->current_glctx_tls, ctx, NULL); - } - return ctx; -} - -bool SDL_GL_MakeCurrent(SDL_Window *window, SDL_GLContext context) -{ - bool result; - - if (!_this) { - return SDL_UninitializedVideo(); - } - - if (window == SDL_GL_GetCurrentWindow() && - context == SDL_GL_GetCurrentContext()) { - // We're already current. - return true; - } - - if (!context) { - window = NULL; - } else if (window) { - CHECK_WINDOW_MAGIC(window, false); - - if (!(window->flags & SDL_WINDOW_OPENGL)) { - return SDL_SetError(NOT_AN_OPENGL_WINDOW); - } - } else if (!_this->gl_allow_no_surface) { - return SDL_SetError("Use of OpenGL without a window is not supported on this platform"); - } - - result = _this->GL_MakeCurrent(_this, window, context); - if (result) { - _this->current_glwin = window; - _this->current_glctx = context; - SDL_SetTLS(&_this->current_glwin_tls, window, NULL); - SDL_SetTLS(&_this->current_glctx_tls, context, NULL); - } - return result; -} - -SDL_Window *SDL_GL_GetCurrentWindow(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - return (SDL_Window *)SDL_GetTLS(&_this->current_glwin_tls); -} - -SDL_GLContext SDL_GL_GetCurrentContext(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - return (SDL_GLContext)SDL_GetTLS(&_this->current_glctx_tls); -} - -SDL_EGLDisplay SDL_EGL_GetCurrentDisplay(void) -{ -#ifdef SDL_VIDEO_OPENGL_EGL - if (!_this) { - SDL_UninitializedVideo(); - return EGL_NO_DISPLAY; - } - if (!_this->egl_data) { - SDL_SetError("There is no current EGL display"); - return EGL_NO_DISPLAY; - } - return _this->egl_data->egl_display; -#else - SDL_SetError("SDL was not built with EGL support"); - return NULL; -#endif -} - -SDL_EGLConfig SDL_EGL_GetCurrentConfig(void) -{ -#ifdef SDL_VIDEO_OPENGL_EGL - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - if (!_this->egl_data) { - SDL_SetError("There is no current EGL display"); - return NULL; - } - return _this->egl_data->egl_config; -#else - SDL_SetError("SDL was not built with EGL support"); - return NULL; -#endif -} - -SDL_EGLConfig SDL_EGL_GetWindowSurface(SDL_Window *window) -{ -#ifdef SDL_VIDEO_OPENGL_EGL - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - if (!_this->egl_data) { - SDL_SetError("There is no current EGL display"); - return NULL; - } - if (_this->GL_GetEGLSurface) { - return _this->GL_GetEGLSurface(_this, window); - } - return NULL; -#else - SDL_SetError("SDL was not built with EGL support"); - return NULL; -#endif -} - -bool SDL_GL_SetSwapInterval(int interval) -{ - if (!_this) { - return SDL_UninitializedVideo(); - } else if (SDL_GL_GetCurrentContext() == NULL) { - return SDL_SetError("No OpenGL context has been made current"); - } else if (_this->GL_SetSwapInterval) { - return _this->GL_SetSwapInterval(_this, interval); - } else { - return SDL_SetError("Setting the swap interval is not supported"); - } -} - -bool SDL_GL_GetSwapInterval(int *interval) -{ - if (!interval) { - return SDL_InvalidParamError("interval"); - } - - *interval = 0; - - if (!_this) { - return SDL_SetError("no video driver"); - } else if (SDL_GL_GetCurrentContext() == NULL) { - return SDL_SetError("no current context"); - } else if (_this->GL_GetSwapInterval) { - return _this->GL_GetSwapInterval(_this, interval); - } else { - return SDL_SetError("not implemented"); - } -} - -bool SDL_GL_SwapWindow(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (!(window->flags & SDL_WINDOW_OPENGL)) { - return SDL_SetError(NOT_AN_OPENGL_WINDOW); - } - - if (SDL_GL_GetCurrentWindow() != window) { - return SDL_SetError("The specified window has not been made current"); - } - - return _this->GL_SwapWindow(_this, window); -} - -bool SDL_GL_DestroyContext(SDL_GLContext context) -{ - if (!_this) { - return SDL_UninitializedVideo(); \ - } - if (!context) { - return SDL_InvalidParamError("context"); - } - - if (SDL_GL_GetCurrentContext() == context) { - SDL_GL_MakeCurrent(NULL, NULL); - } - - return _this->GL_DestroyContext(_this, context); -} - -#if 0 // FIXME -/* - * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags - * & 2 for alpha channel. - */ -static void CreateMaskFromColorKeyOrAlpha(SDL_Surface *icon, Uint8 *mask, int flags) -{ - int x, y; - Uint32 colorkey; -#define SET_MASKBIT(icon, x, y, mask) \ - mask[(y * ((icon->w + 7) / 8)) + (x / 8)] &= ~(0x01 << (7 - (x % 8))) - - colorkey = icon->format->colorkey; - switch (SDL_BYTESPERPIXEL(icon->format)) { - case 1: - { - Uint8 *pixels; - for (y = 0; y < icon->h; ++y) { - pixels = (Uint8 *) icon->pixels + y * icon->pitch; - for (x = 0; x < icon->w; ++x) { - if (*pixels++ == colorkey) { - SET_MASKBIT(icon, x, y, mask); - } - } - } - } - break; - - case 2: - { - Uint16 *pixels; - for (y = 0; y < icon->h; ++y) { - pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2; - for (x = 0; x < icon->w; ++x) { - if ((flags & 1) && *pixels == colorkey) { - SET_MASKBIT(icon, x, y, mask); - } else if ((flags & 2) - && (*pixels & icon->format->Amask) == 0) { - SET_MASKBIT(icon, x, y, mask); - } - pixels++; - } - } - } - break; - - case 4: - { - Uint32 *pixels; - for (y = 0; y < icon->h; ++y) { - pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4; - for (x = 0; x < icon->w; ++x) { - if ((flags & 1) && *pixels == colorkey) { - SET_MASKBIT(icon, x, y, mask); - } else if ((flags & 2) - && (*pixels & icon->format->Amask) == 0) { - SET_MASKBIT(icon, x, y, mask); - } - pixels++; - } - } - } - break; - } -} - -/* - * Sets the window manager icon for the display window. - */ -void SDL_WM_SetIcon(SDL_Surface *icon, Uint8 *mask) -{ - if (icon && _this->SetIcon) { - // Generate a mask if necessary, and create the icon! - if (mask == NULL) { - int mask_len = icon->h * (icon->w + 7) / 8; - int flags = 0; - mask = (Uint8 *) SDL_malloc(mask_len); - if (mask == NULL) { - return; - } - SDL_memset(mask, ~0, mask_len); - if (icon->flags & SDL_SRCCOLORKEY) - flags |= 1; - if (icon->flags & SDL_SRCALPHA) - flags |= 2; - if (flags) { - CreateMaskFromColorKeyOrAlpha(icon, mask, flags); - } - _this->SetIcon(_this, icon, mask); - SDL_free(mask); - } else { - _this->SetIcon(_this, icon, mask); - } - } -} -#endif - -SDL_TextInputType SDL_GetTextInputType(SDL_PropertiesID props) -{ - return (SDL_TextInputType)SDL_GetNumberProperty(props, SDL_PROP_TEXTINPUT_TYPE_NUMBER, SDL_TEXTINPUT_TYPE_TEXT); -} - -SDL_Capitalization SDL_GetTextInputCapitalization(SDL_PropertiesID props) -{ - if (SDL_HasProperty(props, SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER)) { - return (SDL_Capitalization)SDL_GetNumberProperty(props, SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER, SDL_CAPITALIZE_NONE); - } - - switch (SDL_GetTextInputType(props)) { - case SDL_TEXTINPUT_TYPE_TEXT: - return SDL_CAPITALIZE_SENTENCES; - case SDL_TEXTINPUT_TYPE_TEXT_NAME: - return SDL_CAPITALIZE_WORDS; - default: - return SDL_CAPITALIZE_NONE; - } -} - -bool SDL_GetTextInputAutocorrect(SDL_PropertiesID props) -{ - return SDL_GetBooleanProperty(props, SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN, true); -} - -bool SDL_GetTextInputMultiline(SDL_PropertiesID props) -{ - if (SDL_HasProperty(props, SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN)) { - return SDL_GetBooleanProperty(props, SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN, false); - } - - if (SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, false)) { - return false; - } else { - return true; - } -} - -static bool AutoShowingScreenKeyboard(void) -{ - const char *hint = SDL_GetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD); - if (((!hint || SDL_strcasecmp(hint, "auto") == 0) && !SDL_HasKeyboard()) || - SDL_GetStringBoolean(hint, false)) { - return true; - } else { - return false; - } -} - -bool SDL_StartTextInput(SDL_Window *window) -{ - return SDL_StartTextInputWithProperties(window, 0); -} - -bool SDL_StartTextInputWithProperties(SDL_Window *window, SDL_PropertiesID props) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (window->text_input_props) { - SDL_DestroyProperties(window->text_input_props); - window->text_input_props = 0; - } - - if (props) { - window->text_input_props = SDL_CreateProperties(); - if (!window->text_input_props) { - return false; - } - if (!SDL_CopyProperties(props, window->text_input_props)) { - return false; - } - } - - if (_this->SetTextInputProperties) { - _this->SetTextInputProperties(_this, window, props); - } - - // Show the on-screen keyboard, if desired - if (AutoShowingScreenKeyboard() && !SDL_ScreenKeyboardShown(window)) { - if (_this->ShowScreenKeyboard) { - _this->ShowScreenKeyboard(_this, window, props); - } - } - - if (!window->text_input_active) { - // Finally start the text input system - if (_this->StartTextInput) { - if (!_this->StartTextInput(_this, window, props)) { - return false; - } - } - window->text_input_active = true; - } - return true; -} - -bool SDL_TextInputActive(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - return window->text_input_active; -} - -bool SDL_StopTextInput(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (window->text_input_active) { - // Stop the text input system - if (_this->StopTextInput) { - _this->StopTextInput(_this, window); - } - window->text_input_active = false; - } - - // Hide the on-screen keyboard, if desired - if (AutoShowingScreenKeyboard() && SDL_ScreenKeyboardShown(window)) { - if (_this->HideScreenKeyboard) { - _this->HideScreenKeyboard(_this, window); - } - } - return true; -} - -bool SDL_SetTextInputArea(SDL_Window *window, const SDL_Rect *rect, int cursor) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (rect) { - SDL_copyp(&window->text_input_rect, rect); - window->text_input_cursor = cursor; - } else { - SDL_zero(window->text_input_rect); - window->text_input_cursor = 0; - } - - if (_this && _this->UpdateTextInputArea) { - if (!_this->UpdateTextInputArea(_this, window)) { - return false; - } - } - return true; -} - -bool SDL_GetTextInputArea(SDL_Window *window, SDL_Rect *rect, int *cursor) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (rect) { - SDL_copyp(rect, &window->text_input_rect); - } - if (cursor) { - *cursor = window->text_input_cursor; - } - return true; -} - -bool SDL_ClearComposition(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (_this->ClearComposition) { - return _this->ClearComposition(_this, window); - } - return true; -} - -bool SDL_HasScreenKeyboardSupport(void) -{ - if (_this && _this->HasScreenKeyboardSupport) { - return _this->HasScreenKeyboardSupport(_this); - } - return false; -} - -bool SDL_ScreenKeyboardShown(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (_this->IsScreenKeyboardShown) { - return _this->IsScreenKeyboardShown(_this, window); - } - return false; -} - -int SDL_GetMessageBoxCount(void) -{ - return SDL_GetAtomicInt(&SDL_messagebox_count); -} - -#ifdef SDL_VIDEO_DRIVER_ANDROID -#include "android/SDL_androidmessagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_WINDOWS -#include "windows/SDL_windowsmessagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_COCOA -#include "cocoa/SDL_cocoamessagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_UIKIT -#include "uikit/SDL_uikitmessagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_WAYLAND -#include "wayland/SDL_waylandmessagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_X11 -#include "x11/SDL_x11messagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_HAIKU -#include "haiku/SDL_bmessagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_RISCOS -#include "riscos/SDL_riscosmessagebox.h" -#endif -#ifdef SDL_VIDEO_DRIVER_VITA -#include "vita/SDL_vitamessagebox.h" -#endif - -bool SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID) -{ - int dummybutton; - bool result = false; - bool show_cursor_prev; - SDL_Window *current_window; - SDL_MessageBoxData mbdata; - - if (!messageboxdata) { - return SDL_InvalidParamError("messageboxdata"); - } else if (messageboxdata->numbuttons < 0) { - return SDL_SetError("Invalid number of buttons"); - } - - // in case either the title or message was a pointer from SDL_GetError(), make a copy - // now, as we'll likely overwrite error state in here. - bool titleisstack = false, msgisstack = false; - char *titlecpy = NULL; - char *msgcpy = NULL; - if (messageboxdata->title) { - const size_t slen = SDL_strlen(messageboxdata->title) + 1; - titlecpy = SDL_small_alloc(char, slen, &titleisstack); - if (!titlecpy) { - return false; - } - SDL_memcpy(titlecpy, messageboxdata->title, slen); - } - - if (messageboxdata->message) { - const size_t slen = SDL_strlen(messageboxdata->message) + 1; - msgcpy = SDL_small_alloc(char, slen, &msgisstack); - if (!msgcpy) { - SDL_small_free(titlecpy, titleisstack); - return false; - } - SDL_memcpy(msgcpy, messageboxdata->message, slen); - } - - (void)SDL_AtomicIncRef(&SDL_messagebox_count); - - current_window = SDL_GetKeyboardFocus(); - SDL_UpdateMouseCapture(false); - SDL_SetRelativeMouseMode(false); - show_cursor_prev = SDL_CursorVisible(); - SDL_ShowCursor(); - SDL_ResetKeyboard(); - - if (!buttonID) { - buttonID = &dummybutton; - } - - SDL_memcpy(&mbdata, messageboxdata, sizeof(*messageboxdata)); - mbdata.title = titlecpy; - if (!mbdata.title) { - mbdata.title = ""; - } - mbdata.message = msgcpy; - if (!mbdata.message) { - mbdata.message = ""; - } - messageboxdata = &mbdata; - - SDL_ClearError(); - - if (_this && _this->ShowMessageBox) { - result = _this->ShowMessageBox(_this, messageboxdata, buttonID); - } else { - // It's completely fine to call this function before video is initialized - const char *driver_name = SDL_GetHint(SDL_HINT_VIDEO_DRIVER); - if (driver_name && *driver_name != 0) { - const char *driver_attempt = driver_name; - while (driver_attempt && (*driver_attempt != 0) && !result) { - const char *driver_attempt_end = SDL_strchr(driver_attempt, ','); - size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt) - : SDL_strlen(driver_attempt); - for (int i = 0; bootstrap[i]; ++i) { - if (bootstrap[i]->ShowMessageBox && (driver_attempt_len == SDL_strlen(bootstrap[i]->name)) && - (SDL_strncasecmp(bootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) { - if (bootstrap[i]->ShowMessageBox(messageboxdata, buttonID)) { - result = true; - } - break; - } - } - - driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL; - } - } else { - for (int i = 0; bootstrap[i]; ++i) { - if (bootstrap[i]->ShowMessageBox && bootstrap[i]->ShowMessageBox(messageboxdata, buttonID)) { - result = true; - break; - } - } - } - } - - if (!result) { - const char *error = SDL_GetError(); - - if (!*error) { - SDL_SetError("No message system available"); - } - } else { - SDL_ClearError(); - } - - (void)SDL_AtomicDecRef(&SDL_messagebox_count); - - if (current_window) { - SDL_RaiseWindow(current_window); - } - - if (!show_cursor_prev) { - SDL_HideCursor(); - } - SDL_UpdateRelativeMouseMode(); - SDL_UpdateMouseCapture(false); - - SDL_small_free(msgcpy, msgisstack); - SDL_small_free(titlecpy, titleisstack); - - return result; -} - -bool SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags flags, const char *title, const char *message, SDL_Window *window) -{ -#ifdef SDL_PLATFORM_EMSCRIPTEN - // !!! FIXME: propose a browser API for this, get this #ifdef out of here? - /* Web browsers don't (currently) have an API for a custom message box - that can block, but for the most common case (SDL_ShowSimpleMessageBox), - we can use the standard Javascript alert() function. */ - if (!title) { - title = ""; - } - if (!message) { - message = ""; - } - EM_ASM({ - alert(UTF8ToString($0) + "\n\n" + UTF8ToString($1)); - }, - title, message); - return true; -#elif defined(SDL_PLATFORM_3DS) - errorConf errCnf; - bool hasGpuRight; - - // If the video subsystem has not been initialised, set up graphics temporarily - hasGpuRight = gspHasGpuRight(); - if (!hasGpuRight) - gfxInitDefault(); - - errorInit(&errCnf, ERROR_TEXT_WORD_WRAP, CFG_LANGUAGE_EN); - errorText(&errCnf, message); - errorDisp(&errCnf); - - if (!hasGpuRight) - gfxExit(); - - return true; -#else - SDL_MessageBoxData data; - SDL_MessageBoxButtonData button; - - SDL_zero(data); - data.flags = flags; - data.title = title; - data.message = message; - data.numbuttons = 1; - data.buttons = &button; - data.window = window; - - SDL_zero(button); - button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; - button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT; - button.text = "OK"; - - return SDL_ShowMessageBox(&data, NULL); -#endif -} - -bool SDL_ShouldAllowTopmost(void) -{ - return SDL_GetHintBoolean(SDL_HINT_WINDOW_ALLOW_TOPMOST, true); -} - -bool SDL_ShowWindowSystemMenu(SDL_Window *window, int x, int y) -{ - CHECK_WINDOW_MAGIC(window, false) - CHECK_WINDOW_NOT_POPUP(window, false) - - if (_this->ShowWindowSystemMenu) { - _this->ShowWindowSystemMenu(window, x, y); - return true; - } - - return SDL_Unsupported(); -} - -bool SDL_SetWindowHitTest(SDL_Window *window, SDL_HitTest callback, void *callback_data) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (!_this->SetWindowHitTest) { - return SDL_Unsupported(); - } - - window->hit_test = callback; - window->hit_test_data = callback_data; - - return _this->SetWindowHitTest(window, callback != NULL); -} - -bool SDL_SetWindowShape(SDL_Window *window, SDL_Surface *shape) -{ - SDL_PropertiesID props; - SDL_Surface *surface; - - CHECK_WINDOW_MAGIC(window, false); - - if (!(window->flags & SDL_WINDOW_TRANSPARENT)) { - return SDL_SetError("Window must be created with SDL_WINDOW_TRANSPARENT"); - } - - props = SDL_GetWindowProperties(window); - if (!props) { - return false; - } - - surface = SDL_ConvertSurface(shape, SDL_PIXELFORMAT_ARGB32); - if (!surface) { - return false; - } - - if (!SDL_SetSurfaceProperty(props, SDL_PROP_WINDOW_SHAPE_POINTER, surface)) { - return false; - } - - if (_this->UpdateWindowShape) { - if (!_this->UpdateWindowShape(_this, window, surface)) { - return false; - } - } - return true; -} - -/* - * Functions used by iOS application delegates - */ -void SDL_OnApplicationWillTerminate(void) -{ - SDL_SendAppEvent(SDL_EVENT_TERMINATING); -} - -void SDL_OnApplicationDidReceiveMemoryWarning(void) -{ - SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY); -} - -void SDL_OnApplicationWillEnterBackground(void) -{ - if (_this) { - SDL_Window *window; - for (window = _this->windows; window; window = window->next) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0); - } - SDL_SetKeyboardFocus(NULL); - } - SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_BACKGROUND); -} - -void SDL_OnApplicationDidEnterBackground(void) -{ - SDL_SendAppEvent(SDL_EVENT_DID_ENTER_BACKGROUND); -} - -void SDL_OnApplicationWillEnterForeground(void) -{ - SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_FOREGROUND); -} - -void SDL_OnApplicationDidEnterForeground(void) -{ - SDL_SendAppEvent(SDL_EVENT_DID_ENTER_FOREGROUND); - - if (_this) { - SDL_Window *window; - for (window = _this->windows; window; window = window->next) { - SDL_SetKeyboardFocus(window); - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0); - } - } -} - -#define NOT_A_VULKAN_WINDOW "The specified window isn't a Vulkan window" - -bool SDL_Vulkan_LoadLibrary(const char *path) -{ - bool result; - - if (!_this) { - return SDL_UninitializedVideo(); - } - if (_this->vulkan_config.loader_loaded) { - if (path && SDL_strcmp(path, _this->vulkan_config.loader_path) != 0) { - return SDL_SetError("Vulkan loader library already loaded"); - } - result = true; - } else { - if (!_this->Vulkan_LoadLibrary) { - return SDL_DllNotSupported("Vulkan"); - } - result = _this->Vulkan_LoadLibrary(_this, path); - } - if (result) { - _this->vulkan_config.loader_loaded++; - } - return result; -} - -SDL_FunctionPointer SDL_Vulkan_GetVkGetInstanceProcAddr(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - if (!_this->vulkan_config.loader_loaded) { - SDL_SetError("No Vulkan loader has been loaded"); - return NULL; - } - return (SDL_FunctionPointer)_this->vulkan_config.vkGetInstanceProcAddr; -} - -void SDL_Vulkan_UnloadLibrary(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return; - } - if (_this->vulkan_config.loader_loaded > 0) { - if (--_this->vulkan_config.loader_loaded > 0) { - return; - } - if (_this->Vulkan_UnloadLibrary) { - _this->Vulkan_UnloadLibrary(_this); - } - } -} - -char const* const* SDL_Vulkan_GetInstanceExtensions(Uint32 *count) -{ - return _this->Vulkan_GetInstanceExtensions(_this, count); -} - -bool SDL_Vulkan_CreateSurface(SDL_Window *window, - VkInstance instance, - const struct VkAllocationCallbacks *allocator, - VkSurfaceKHR *surface) -{ - CHECK_WINDOW_MAGIC(window, false); - - if (!(window->flags & SDL_WINDOW_VULKAN)) { - return SDL_SetError(NOT_A_VULKAN_WINDOW); - } - - if (!instance) { - return SDL_InvalidParamError("instance"); - } - - if (!surface) { - return SDL_InvalidParamError("surface"); - } - - return _this->Vulkan_CreateSurface(_this, window, instance, allocator, surface); -} - -void SDL_Vulkan_DestroySurface(VkInstance instance, - VkSurfaceKHR surface, - const struct VkAllocationCallbacks *allocator) -{ - if (_this && instance && surface && _this->Vulkan_DestroySurface) { - _this->Vulkan_DestroySurface(_this, instance, surface, allocator); - } -} - -bool SDL_Vulkan_GetPresentationSupport(VkInstance instance, - VkPhysicalDevice physicalDevice, - Uint32 queueFamilyIndex) -{ - if (!_this) { - SDL_UninitializedVideo(); - return false; - } - - if (!instance) { - SDL_InvalidParamError("instance"); - return false; - } - - if (!physicalDevice) { - SDL_InvalidParamError("physicalDevice"); - return false; - } - - if (_this->Vulkan_GetPresentationSupport) { - return _this->Vulkan_GetPresentationSupport(_this, instance, physicalDevice, queueFamilyIndex); - } - - /* If the backend does not have this function then it does not have a - * WSI function to query it; in other words it's not necessary to check - * as it is always supported. - */ - return true; -} - -SDL_MetalView SDL_Metal_CreateView(SDL_Window *window) -{ - CHECK_WINDOW_MAGIC(window, NULL); - - if (!_this->Metal_CreateView) { - SDL_Unsupported(); - return NULL; - } - - if (!(window->flags & SDL_WINDOW_METAL)) { - // No problem, we can convert to Metal - if (window->flags & SDL_WINDOW_OPENGL) { - window->flags &= ~SDL_WINDOW_OPENGL; - SDL_GL_UnloadLibrary(); - } - if (window->flags & SDL_WINDOW_VULKAN) { - window->flags &= ~SDL_WINDOW_VULKAN; - SDL_Vulkan_UnloadLibrary(); - } - window->flags |= SDL_WINDOW_METAL; - } - - return _this->Metal_CreateView(_this, window); -} - -void SDL_Metal_DestroyView(SDL_MetalView view) -{ - if (_this && view && _this->Metal_DestroyView) { - _this->Metal_DestroyView(_this, view); - } -} - -void *SDL_Metal_GetLayer(SDL_MetalView view) -{ - if (_this && _this->Metal_GetLayer) { - if (view) { - return _this->Metal_GetLayer(_this, view); - } else { - SDL_InvalidParamError("view"); - return NULL; - } - } else { - SDL_SetError("Metal is not supported."); - return NULL; - } -} - -#if defined(SDL_VIDEO_DRIVER_X11) || defined(SDL_VIDEO_DRIVER_WAYLAND) || defined(SDL_VIDEO_DRIVER_EMSCRIPTEN) -const char *SDL_GetCSSCursorName(SDL_SystemCursor id, const char **fallback_name) -{ - // Reference: https://www.w3.org/TR/css-ui-4/#cursor - // Also in: https://www.freedesktop.org/wiki/Specifications/cursor-spec/ - switch (id) { - case SDL_SYSTEM_CURSOR_DEFAULT: - return "default"; - - case SDL_SYSTEM_CURSOR_TEXT: - return "text"; - - case SDL_SYSTEM_CURSOR_WAIT: - return "wait"; - - case SDL_SYSTEM_CURSOR_CROSSHAIR: - return "crosshair"; - - case SDL_SYSTEM_CURSOR_PROGRESS: - return "progress"; - - case SDL_SYSTEM_CURSOR_NWSE_RESIZE: - if (fallback_name) { - // only a single arrow - *fallback_name = "nw-resize"; - } - return "nwse-resize"; - - case SDL_SYSTEM_CURSOR_NESW_RESIZE: - if (fallback_name) { - // only a single arrow - *fallback_name = "ne-resize"; - } - return "nesw-resize"; - - case SDL_SYSTEM_CURSOR_EW_RESIZE: - if (fallback_name) { - *fallback_name = "col-resize"; - } - return "ew-resize"; - - case SDL_SYSTEM_CURSOR_NS_RESIZE: - if (fallback_name) { - *fallback_name = "row-resize"; - } - return "ns-resize"; - - case SDL_SYSTEM_CURSOR_MOVE: - return "all-scroll"; - - case SDL_SYSTEM_CURSOR_NOT_ALLOWED: - return "not-allowed"; - - case SDL_SYSTEM_CURSOR_POINTER: - return "pointer"; - - case SDL_SYSTEM_CURSOR_NW_RESIZE: - return "nw-resize"; - - case SDL_SYSTEM_CURSOR_N_RESIZE: - return "n-resize"; - - case SDL_SYSTEM_CURSOR_NE_RESIZE: - return "ne-resize"; - - case SDL_SYSTEM_CURSOR_E_RESIZE: - return "e-resize"; - - case SDL_SYSTEM_CURSOR_SE_RESIZE: - return "se-resize"; - - case SDL_SYSTEM_CURSOR_S_RESIZE: - return "s-resize"; - - case SDL_SYSTEM_CURSOR_SW_RESIZE: - return "sw-resize"; - - case SDL_SYSTEM_CURSOR_W_RESIZE: - return "w-resize"; - - default: - return "default"; - } -} -#endif -- cgit v1.2.3