| /* |
| Simple DirectMedia Layer |
| Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
| |
| 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.h" |
| #include "SDL_video.h" |
| #include "SDL_sysvideo.h" |
| #include "SDL_blit.h" |
| #include "SDL_pixels_c.h" |
| #include "SDL_rect_c.h" |
| #include "../events/SDL_events_c.h" |
| #include "../timer/SDL_timer_c.h" |
| |
| #include "SDL_syswm.h" |
| |
| #if SDL_VIDEO_OPENGL |
| #include "SDL_opengl.h" |
| #endif /* SDL_VIDEO_OPENGL */ |
| |
| #if SDL_VIDEO_OPENGL_ES && !SDL_VIDEO_OPENGL |
| #include "SDL_opengles.h" |
| #endif /* SDL_VIDEO_OPENGL_ES && !SDL_VIDEO_OPENGL */ |
| |
| /* GL and GLES2 headers conflict on Linux 32 bits */ |
| #if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL |
| #include "SDL_opengles2.h" |
| #endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */ |
| |
| #if !SDL_VIDEO_OPENGL |
| #ifndef GL_CONTEXT_RELEASE_BEHAVIOR_KHR |
| #define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB |
| #endif |
| #endif |
| |
| #ifdef __EMSCRIPTEN__ |
| #include <emscripten.h> |
| #endif |
| |
| /* Available video drivers */ |
| static VideoBootStrap *bootstrap[] = { |
| #if SDL_VIDEO_DRIVER_COCOA |
| &COCOA_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_X11 |
| &X11_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_WAYLAND |
| &Wayland_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_VIVANTE |
| &VIVANTE_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_DIRECTFB |
| &DirectFB_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_WINDOWS |
| &WINDOWS_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_WINRT |
| &WINRT_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_HAIKU |
| &HAIKU_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_PANDORA |
| &PND_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_UIKIT |
| &UIKIT_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_ANDROID |
| &Android_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_PSP |
| &PSP_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_KMSDRM |
| &KMSDRM_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_RPI |
| &RPI_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_NACL |
| &NACL_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_EMSCRIPTEN |
| &Emscripten_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_QNX |
| &QNX_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_OFFSCREEN |
| &OFFSCREEN_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_OS2 |
| &OS2DIVE_bootstrap, |
| &OS2VMAN_bootstrap, |
| #endif |
| #if SDL_VIDEO_DRIVER_DUMMY |
| &DUMMY_bootstrap, |
| #endif |
| NULL |
| }; |
| |
| static SDL_VideoDevice *_this = NULL; |
| |
| #define CHECK_WINDOW_MAGIC(window, retval) \ |
| if (!_this) { \ |
| SDL_UninitializedVideo(); \ |
| return retval; \ |
| } \ |
| SDL_assert(window && window->magic == &_this->window_magic); \ |
| if (!window || window->magic != &_this->window_magic) { \ |
| SDL_SetError("Invalid window"); \ |
| return retval; \ |
| } |
| |
| #define CHECK_DISPLAY_INDEX(displayIndex, retval) \ |
| if (!_this) { \ |
| SDL_UninitializedVideo(); \ |
| return retval; \ |
| } \ |
| SDL_assert(_this->displays != NULL); \ |
| SDL_assert(displayIndex >= 0 && displayIndex < _this->num_displays); \ |
| if (displayIndex < 0 || displayIndex >= _this->num_displays) { \ |
| SDL_SetError("displayIndex must be in the range 0 - %d", \ |
| _this->num_displays - 1); \ |
| return retval; \ |
| } |
| |
| #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN) |
| |
| #ifdef __MACOSX__ |
| /* Support for Mac OS X fullscreen spaces */ |
| extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window); |
| extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state); |
| #endif |
| |
| |
| /* Support for framebuffer emulation using an accelerated renderer */ |
| |
| #define SDL_WINDOWTEXTUREDATA "_SDL_WindowTextureData" |
| |
| typedef struct { |
| SDL_Renderer *renderer; |
| SDL_Texture *texture; |
| void *pixels; |
| int pitch; |
| int bytes_per_pixel; |
| } SDL_WindowTextureData; |
| |
| static SDL_bool |
| ShouldUseTextureFramebuffer() |
| { |
| const char *hint; |
| |
| /* If there's no native framebuffer support then there's no option */ |
| if (!_this->CreateWindowFramebuffer) { |
| return SDL_TRUE; |
| } |
| |
| /* If this is the dummy driver there is no texture support */ |
| if (_this->is_dummy) { |
| return SDL_FALSE; |
| } |
| |
| /* If the user has specified a software renderer we can't use a |
| texture framebuffer, or renderer creation will go recursive. |
| */ |
| hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER); |
| if (hint && SDL_strcasecmp(hint, "software") == 0) { |
| return SDL_FALSE; |
| } |
| |
| /* See if the user or application wants a specific behavior */ |
| hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); |
| if (hint) { |
| if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) { |
| return SDL_FALSE; |
| } else { |
| return SDL_TRUE; |
| } |
| } |
| |
| /* Each platform has different performance characteristics */ |
| #if defined(__WIN32__) |
| /* GDI BitBlt() is way faster than Direct3D dynamic textures right now. |
| */ |
| return SDL_FALSE; |
| |
| #elif defined(__MACOSX__) |
| /* Mac OS X uses OpenGL as the native fast path (for cocoa and X11) */ |
| return SDL_TRUE; |
| |
| #elif defined(__LINUX__) |
| /* Properly configured OpenGL drivers are faster than MIT-SHM */ |
| #if SDL_VIDEO_OPENGL |
| /* Ugh, find a way to cache this value! */ |
| { |
| SDL_Window *window; |
| SDL_GLContext context; |
| SDL_bool hasAcceleratedOpenGL = SDL_FALSE; |
| |
| window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN); |
| if (window) { |
| context = SDL_GL_CreateContext(window); |
| if (context) { |
| const GLubyte *(APIENTRY * glGetStringFunc) (GLenum); |
| const char *vendor = NULL; |
| |
| glGetStringFunc = SDL_GL_GetProcAddress("glGetString"); |
| if (glGetStringFunc) { |
| vendor = (const char *) glGetStringFunc(GL_VENDOR); |
| } |
| /* Add more vendors here at will... */ |
| if (vendor && |
| (SDL_strstr(vendor, "ATI Technologies") || |
| SDL_strstr(vendor, "NVIDIA"))) { |
| hasAcceleratedOpenGL = SDL_TRUE; |
| } |
| SDL_GL_DeleteContext(context); |
| } |
| SDL_DestroyWindow(window); |
| } |
| return hasAcceleratedOpenGL; |
| } |
| #elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 |
| /* Let's be optimistic about this! */ |
| return SDL_TRUE; |
| #else |
| return SDL_FALSE; |
| #endif |
| |
| #else |
| /* Play it safe, assume that if there is a framebuffer driver that it's |
| optimized for the current platform. |
| */ |
| return SDL_FALSE; |
| #endif |
| } |
| |
| static int |
| SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) |
| { |
| SDL_WindowTextureData *data; |
| |
| data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); |
| if (!data) { |
| SDL_Renderer *renderer = NULL; |
| int i; |
| const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); |
| |
| /* Check to see if there's a specific driver requested */ |
| if (hint && *hint != '0' && *hint != '1' && |
| SDL_strcasecmp(hint, "true") != 0 && |
| SDL_strcasecmp(hint, "false") != 0 && |
| SDL_strcasecmp(hint, "software") != 0) { |
| for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { |
| SDL_RendererInfo info; |
| SDL_GetRenderDriverInfo(i, &info); |
| if (SDL_strcasecmp(info.name, hint) == 0) { |
| renderer = SDL_CreateRenderer(window, i, 0); |
| break; |
| } |
| } |
| } |
| |
| if (!renderer) { |
| for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { |
| SDL_RendererInfo info; |
| SDL_GetRenderDriverInfo(i, &info); |
| if (SDL_strcmp(info.name, "software") != 0) { |
| renderer = SDL_CreateRenderer(window, i, 0); |
| if (renderer) { |
| break; |
| } |
| } |
| } |
| } |
| if (!renderer) { |
| return SDL_SetError("No hardware accelerated renderers available"); |
| } |
| |
| /* 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 SDL_OutOfMemory(); |
| } |
| SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data); |
| |
| data->renderer = renderer; |
| } |
| |
| /* Free any old texture and pixel data */ |
| if (data->texture) { |
| SDL_DestroyTexture(data->texture); |
| data->texture = NULL; |
| } |
| SDL_free(data->pixels); |
| data->pixels = NULL; |
| |
| { |
| SDL_RendererInfo info; |
| Uint32 i; |
| |
| if (SDL_GetRendererInfo(data->renderer, &info) < 0) { |
| return -1; |
| } |
| |
| /* Find the first format without an alpha channel */ |
| *format = info.texture_formats[0]; |
| |
| for (i = 0; i < info.num_texture_formats; ++i) { |
| if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) && |
| !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { |
| *format = info.texture_formats[i]; |
| break; |
| } |
| } |
| } |
| |
| data->texture = SDL_CreateTexture(data->renderer, *format, |
| SDL_TEXTUREACCESS_STREAMING, |
| window->w, window->h); |
| if (!data->texture) { |
| return -1; |
| } |
| |
| /* Create framebuffer data */ |
| data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format); |
| data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3); |
| |
| { |
| /* Make static analysis happy about potential malloc(0) calls. */ |
| const size_t allocsize = window->h * data->pitch; |
| data->pixels = SDL_malloc((allocsize > 0) ? allocsize : 1); |
| if (!data->pixels) { |
| return SDL_OutOfMemory(); |
| } |
| } |
| |
| *pixels = data->pixels; |
| *pitch = data->pitch; |
| |
| /* Make sure we're not double-scaling the viewport */ |
| SDL_RenderSetViewport(data->renderer, NULL); |
| |
| return 0; |
| } |
| |
| static int |
| SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, const SDL_Rect * rects, int numrects) |
| { |
| SDL_WindowTextureData *data; |
| SDL_Rect rect; |
| void *src; |
| |
| data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); |
| 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(window->w, window->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) < 0) { |
| return -1; |
| } |
| |
| if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) { |
| return -1; |
| } |
| |
| SDL_RenderPresent(data->renderer); |
| } |
| return 0; |
| } |
| |
| static void |
| SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window) |
| { |
| SDL_WindowTextureData *data; |
| |
| data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL); |
| if (!data) { |
| return; |
| } |
| if (data->texture) { |
| SDL_DestroyTexture(data->texture); |
| } |
| if (data->renderer) { |
| SDL_DestroyRenderer(data->renderer); |
| } |
| SDL_free(data->pixels); |
| SDL_free(data); |
| } |
| |
| |
| static int |
| cmpmodes(const void *A, const void *B) |
| { |
| const SDL_DisplayMode *a = (const SDL_DisplayMode *) A; |
| const SDL_DisplayMode *b = (const SDL_DisplayMode *) B; |
| if (a == b) { |
| return 0; |
| } else 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; |
| } |
| return 0; |
| } |
| |
| static int |
| SDL_UninitializedVideo() |
| { |
| return SDL_SetError("Video subsystem has not been initialized"); |
| } |
| |
| int |
| SDL_GetNumVideoDrivers(void) |
| { |
| return SDL_arraysize(bootstrap) - 1; |
| } |
| |
| const char * |
| SDL_GetVideoDriver(int index) |
| { |
| if (index >= 0 && index < SDL_GetNumVideoDrivers()) { |
| return bootstrap[index]->name; |
| } |
| return NULL; |
| } |
| |
| /* |
| * Initialize the video and event subsystems -- determine native pixel format |
| */ |
| int |
| SDL_VideoInit(const char *driver_name) |
| { |
| SDL_VideoDevice *video; |
| int index; |
| int i; |
| |
| /* Check to make sure we don't overwrite '_this' */ |
| if (_this != NULL) { |
| SDL_VideoQuit(); |
| } |
| |
| #if !SDL_TIMERS_DISABLED |
| SDL_TicksInit(); |
| #endif |
| |
| /* Start the event loop */ |
| if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 || |
| SDL_KeyboardInit() < 0 || |
| SDL_MouseInit() < 0 || |
| SDL_TouchInit() < 0) { |
| return -1; |
| } |
| |
| /* Select the proper video driver */ |
| index = 0; |
| video = NULL; |
| if (driver_name == NULL) { |
| driver_name = SDL_getenv("SDL_VIDEODRIVER"); |
| } |
| if (driver_name != NULL) { |
| for (i = 0; bootstrap[i]; ++i) { |
| if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) { |
| video = bootstrap[i]->create(index); |
| break; |
| } |
| } |
| } else { |
| for (i = 0; bootstrap[i]; ++i) { |
| video = bootstrap[i]->create(index); |
| if (video != NULL) { |
| break; |
| } |
| } |
| } |
| if (video == NULL) { |
| if (driver_name) { |
| return SDL_SetError("%s not available", driver_name); |
| } |
| return SDL_SetError("No available video device"); |
| } |
| _this = video; |
| _this->name = bootstrap[i]->name; |
| _this->next_object_id = 1; |
| |
| |
| /* Set some very sane GL defaults */ |
| _this->gl_config.driver_loaded = 0; |
| _this->gl_config.dll_handle = NULL; |
| SDL_GL_ResetAttributes(); |
| |
| _this->current_glwin_tls = SDL_TLSCreate(); |
| _this->current_glctx_tls = SDL_TLSCreate(); |
| |
| /* Initialize the video subsystem */ |
| if (_this->VideoInit(_this) < 0) { |
| SDL_VideoQuit(); |
| return -1; |
| } |
| |
| /* Make sure some displays were added */ |
| if (_this->num_displays == 0) { |
| SDL_VideoQuit(); |
| return SDL_SetError("The video driver did not add any displays"); |
| } |
| |
| /* Add the renderer framebuffer emulation if desired */ |
| if (ShouldUseTextureFramebuffer()) { |
| _this->CreateWindowFramebuffer = SDL_CreateWindowTexture; |
| _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture; |
| _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture; |
| } |
| |
| /* 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, SDL_FALSE)) { |
| SDL_DisableScreenSaver(); |
| } |
| |
| /* If we don't use a screen keyboard, turn on text input by default, |
| otherwise programs that expect to get text events without enabling |
| UNICODE input won't get any events. |
| |
| Actually, come to think of it, you needed to call SDL_EnableUNICODE(1) |
| in SDL 1.2 before you got text input events. Hmm... |
| */ |
| if (!SDL_HasScreenKeyboardSupport()) { |
| SDL_StartTextInput(); |
| } |
| |
| /* We're ready to go! */ |
| return 0; |
| } |
| |
| const char * |
| SDL_GetCurrentVideoDriver() |
| { |
| if (!_this) { |
| SDL_UninitializedVideo(); |
| return NULL; |
| } |
| return _this->name; |
| } |
| |
| SDL_VideoDevice * |
| SDL_GetVideoDevice(void) |
| { |
| return _this; |
| } |
| |
| int |
| SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode) |
| { |
| SDL_VideoDisplay display; |
| |
| SDL_zero(display); |
| if (desktop_mode) { |
| display.desktop_mode = *desktop_mode; |
| } |
| display.current_mode = display.desktop_mode; |
| |
| return SDL_AddVideoDisplay(&display, SDL_FALSE); |
| } |
| |
| int |
| SDL_AddVideoDisplay(const SDL_VideoDisplay * display, SDL_bool send_event) |
| { |
| SDL_VideoDisplay *displays; |
| int index = -1; |
| |
| displays = |
| SDL_realloc(_this->displays, |
| (_this->num_displays + 1) * sizeof(*displays)); |
| if (displays) { |
| index = _this->num_displays++; |
| displays[index] = *display; |
| displays[index].device = _this; |
| _this->displays = displays; |
| |
| if (display->name) { |
| displays[index].name = SDL_strdup(display->name); |
| } else { |
| char name[32]; |
| |
| SDL_itoa(index, name, 10); |
| displays[index].name = SDL_strdup(name); |
| } |
| |
| if (send_event) { |
| SDL_SendDisplayEvent(&_this->displays[index], SDL_DISPLAYEVENT_CONNECTED, 0); |
| } |
| } else { |
| SDL_OutOfMemory(); |
| } |
| return index; |
| } |
| |
| void |
| SDL_DelVideoDisplay(int index) |
| { |
| if (index < 0 || index >= _this->num_displays) { |
| return; |
| } |
| |
| SDL_SendDisplayEvent(&_this->displays[index], SDL_DISPLAYEVENT_DISCONNECTED, 0); |
| |
| if (index < (_this->num_displays - 1)) { |
| SDL_memmove(&_this->displays[index], &_this->displays[index+1], (_this->num_displays - index - 1)*sizeof(_this->displays[index])); |
| } |
| --_this->num_displays; |
| } |
| |
| int |
| SDL_GetNumVideoDisplays(void) |
| { |
| if (!_this) { |
| SDL_UninitializedVideo(); |
| return 0; |
| } |
| return _this->num_displays; |
| } |
| |
| int |
| SDL_GetIndexOfDisplay(SDL_VideoDisplay *display) |
| { |
| int displayIndex; |
| |
| for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) { |
| if (display == &_this->displays[displayIndex]) { |
| return displayIndex; |
| } |
| } |
| |
| /* Couldn't find the display, just use index 0 */ |
| return 0; |
| } |
| |
| void * |
| SDL_GetDisplayDriverData(int displayIndex) |
| { |
| CHECK_DISPLAY_INDEX(displayIndex, NULL); |
| |
| return _this->displays[displayIndex].driverdata; |
| } |
| |
| SDL_bool |
| SDL_IsVideoContextExternal(void) |
| { |
| return SDL_GetHintBoolean(SDL_HINT_VIDEO_EXTERNAL_CONTEXT, SDL_FALSE); |
| } |
| |
| const char * |
| SDL_GetDisplayName(int displayIndex) |
| { |
| CHECK_DISPLAY_INDEX(displayIndex, NULL); |
| |
| return _this->displays[displayIndex].name; |
| } |
| |
| int |
| SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect) |
| { |
| CHECK_DISPLAY_INDEX(displayIndex, -1); |
| |
| if (rect) { |
| SDL_VideoDisplay *display = &_this->displays[displayIndex]; |
| |
| if (_this->GetDisplayBounds) { |
| if (_this->GetDisplayBounds(_this, display, rect) == 0) { |
| return 0; |
| } |
| } |
| |
| /* Assume that the displays are left to right */ |
| if (displayIndex == 0) { |
| rect->x = 0; |
| rect->y = 0; |
| } else { |
| SDL_GetDisplayBounds(displayIndex-1, rect); |
| rect->x += rect->w; |
| } |
| rect->w = display->current_mode.w; |
| rect->h = display->current_mode.h; |
| } |
| return 0; /* !!! FIXME: should this be an error if (rect==NULL) ? */ |
| } |
| |
| 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); |
| } |
| |
| int |
| SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect) |
| { |
| CHECK_DISPLAY_INDEX(displayIndex, -1); |
| |
| if (rect) { |
| SDL_VideoDisplay *display = &_this->displays[displayIndex]; |
| |
| if ((displayIndex == 0) && ParseDisplayUsableBoundsHint(rect)) { |
| return 0; |
| } |
| |
| if (_this->GetDisplayUsableBounds) { |
| if (_this->GetDisplayUsableBounds(_this, display, rect) == 0) { |
| return 0; |
| } |
| } |
| |
| /* Oh well, just give the entire display bounds. */ |
| return SDL_GetDisplayBounds(displayIndex, rect); |
| } |
| return 0; /* !!! FIXME: should this be an error if (rect==NULL) ? */ |
| } |
| |
| int |
| SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_DISPLAY_INDEX(displayIndex, -1); |
| |
| display = &_this->displays[displayIndex]; |
| |
| if (_this->GetDisplayDPI) { |
| if (_this->GetDisplayDPI(_this, display, ddpi, hdpi, vdpi) == 0) { |
| return 0; |
| } |
| } else { |
| return SDL_Unsupported(); |
| } |
| |
| return -1; |
| } |
| |
| SDL_DisplayOrientation |
| SDL_GetDisplayOrientation(int displayIndex) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_DISPLAY_INDEX(displayIndex, SDL_ORIENTATION_UNKNOWN); |
| |
| display = &_this->displays[displayIndex]; |
| return display->orientation; |
| } |
| |
| SDL_bool |
| SDL_AddDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode) |
| { |
| SDL_DisplayMode *modes; |
| int i, nmodes; |
| |
| /* Make sure we don't already have the mode in the list */ |
| modes = display->display_modes; |
| nmodes = display->num_display_modes; |
| for (i = 0; i < nmodes; ++i) { |
| if (cmpmodes(mode, &modes[i]) == 0) { |
| return SDL_FALSE; |
| } |
| } |
| |
| /* Go ahead and add the new mode */ |
| if (nmodes == display->max_display_modes) { |
| modes = |
| SDL_realloc(modes, |
| (display->max_display_modes + 32) * sizeof(*modes)); |
| if (!modes) { |
| return SDL_FALSE; |
| } |
| display->display_modes = modes; |
| display->max_display_modes += 32; |
| } |
| modes[nmodes] = *mode; |
| display->num_display_modes++; |
| |
| /* Re-sort video modes */ |
| SDL_qsort(display->display_modes, display->num_display_modes, |
| sizeof(SDL_DisplayMode), cmpmodes); |
| |
| return SDL_TRUE; |
| } |
| |
| static int |
| SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display) |
| { |
| if (!display->num_display_modes && _this->GetDisplayModes) { |
| _this->GetDisplayModes(_this, display); |
| SDL_qsort(display->display_modes, display->num_display_modes, |
| sizeof(SDL_DisplayMode), cmpmodes); |
| } |
| return display->num_display_modes; |
| } |
| |
| int |
| SDL_GetNumDisplayModes(int displayIndex) |
| { |
| CHECK_DISPLAY_INDEX(displayIndex, -1); |
| |
| return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]); |
| } |
| |
| int |
| SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_DISPLAY_INDEX(displayIndex, -1); |
| |
| display = &_this->displays[displayIndex]; |
| if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) { |
| return SDL_SetError("index must be in the range of 0 - %d", |
| SDL_GetNumDisplayModesForDisplay(display) - 1); |
| } |
| if (mode) { |
| *mode = display->display_modes[index]; |
| } |
| return 0; |
| } |
| |
| int |
| SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_DISPLAY_INDEX(displayIndex, -1); |
| |
| display = &_this->displays[displayIndex]; |
| if (mode) { |
| *mode = display->desktop_mode; |
| } |
| return 0; |
| } |
| |
| int |
| SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_DISPLAY_INDEX(displayIndex, -1); |
| |
| display = &_this->displays[displayIndex]; |
| if (mode) { |
| *mode = display->current_mode; |
| } |
| return 0; |
| } |
| |
| static SDL_DisplayMode * |
| SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display, |
| const SDL_DisplayMode * mode, |
| SDL_DisplayMode * closest) |
| { |
| Uint32 target_format; |
| int target_refresh_rate; |
| int i; |
| SDL_DisplayMode *current, *match; |
| |
| if (!mode || !closest) { |
| SDL_SetError("Missing desired mode or closest mode parameter"); |
| return NULL; |
| } |
| |
| /* Default to the desktop format */ |
| if (mode->format) { |
| target_format = mode->format; |
| } else { |
| target_format = display->desktop_mode.format; |
| } |
| |
| /* Default to the desktop refresh rate */ |
| if (mode->refresh_rate) { |
| target_refresh_rate = mode->refresh_rate; |
| } else { |
| target_refresh_rate = display->desktop_mode.refresh_rate; |
| } |
| |
| match = NULL; |
| for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) { |
| current = &display->display_modes[i]; |
| |
| if (current->w && (current->w < mode->w)) { |
| /* Out of sorted modes large enough here */ |
| break; |
| } |
| if (current->h && (current->h < mode->h)) { |
| if (current->w && (current->w == mode->w)) { |
| /* Out of sorted modes large enough here */ |
| break; |
| } |
| /* Wider, but not tall enough, due to a different |
| aspect ratio. This mode must be skipped, but closer |
| modes may still follow. */ |
| continue; |
| } |
| if (!match || current->w < match->w || current->h < match->h) { |
| match = current; |
| continue; |
| } |
| if (current->format != match->format) { |
| /* Sorted highest depth to lowest */ |
| if (current->format == target_format || |
| (SDL_BITSPERPIXEL(current->format) >= |
| SDL_BITSPERPIXEL(target_format) |
| && SDL_PIXELTYPE(current->format) == |
| SDL_PIXELTYPE(target_format))) { |
| match = current; |
| } |
| continue; |
| } |
| if (current->refresh_rate != match->refresh_rate) { |
| /* Sorted highest refresh to lowest */ |
| if (current->refresh_rate >= target_refresh_rate) { |
| match = current; |
| } |
| } |
| } |
| if (match) { |
| if (match->format) { |
| closest->format = match->format; |
| } else { |
| closest->format = mode->format; |
| } |
| if (match->w && match->h) { |
| closest->w = match->w; |
| closest->h = match->h; |
| } else { |
| closest->w = mode->w; |
| closest->h = mode->h; |
| } |
| if (match->refresh_rate) { |
| closest->refresh_rate = match->refresh_rate; |
| } else { |
| closest->refresh_rate = mode->refresh_rate; |
| } |
| closest->driverdata = match->driverdata; |
| |
| /* |
| * Pick some reasonable defaults if the app and driver don't |
| * care |
| */ |
| if (!closest->format) { |
| closest->format = SDL_PIXELFORMAT_RGB888; |
| } |
| if (!closest->w) { |
| closest->w = 640; |
| } |
| if (!closest->h) { |
| closest->h = 480; |
| } |
| return closest; |
| } |
| return NULL; |
| } |
| |
| SDL_DisplayMode * |
| SDL_GetClosestDisplayMode(int displayIndex, |
| const SDL_DisplayMode * mode, |
| SDL_DisplayMode * closest) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_DISPLAY_INDEX(displayIndex, NULL); |
| |
| display = &_this->displays[displayIndex]; |
| return SDL_GetClosestDisplayModeForDisplay(display, mode, closest); |
| } |
| |
| static int |
| SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode) |
| { |
| SDL_DisplayMode display_mode; |
| SDL_DisplayMode current_mode; |
| |
| if (mode) { |
| display_mode = *mode; |
| |
| /* Default to the current mode */ |
| if (!display_mode.format) { |
| display_mode.format = display->current_mode.format; |
| } |
| if (!display_mode.w) { |
| display_mode.w = display->current_mode.w; |
| } |
| if (!display_mode.h) { |
| display_mode.h = display->current_mode.h; |
| } |
| if (!display_mode.refresh_rate) { |
| display_mode.refresh_rate = display->current_mode.refresh_rate; |
| } |
| |
| /* Get a good video mode, the closest one possible */ |
| if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) { |
| return SDL_SetError("No video mode large enough for %dx%d", |
| display_mode.w, display_mode.h); |
| } |
| } else { |
| display_mode = display->desktop_mode; |
| } |
| |
| /* See if there's anything left to do */ |
| current_mode = display->current_mode; |
| if (SDL_memcmp(&display_mode, ¤t_mode, sizeof(display_mode)) == 0) { |
| return 0; |
| } |
| |
| /* Actually change the display mode */ |
| if (!_this->SetDisplayMode) { |
| return SDL_SetError("SDL video driver doesn't support changing display mode"); |
| } |
| if (_this->SetDisplayMode(_this, display, &display_mode) < 0) { |
| return -1; |
| } |
| display->current_mode = display_mode; |
| return 0; |
| } |
| |
| SDL_VideoDisplay * |
| SDL_GetDisplay(int displayIndex) |
| { |
| CHECK_DISPLAY_INDEX(displayIndex, NULL); |
| |
| return &_this->displays[displayIndex]; |
| } |
| |
| int |
| SDL_GetWindowDisplayIndex(SDL_Window * window) |
| { |
| int displayIndex; |
| int i, dist; |
| int closest = -1; |
| int closest_dist = 0x7FFFFFFF; |
| SDL_Point center; |
| SDL_Point delta; |
| SDL_Rect rect; |
| |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (SDL_WINDOWPOS_ISUNDEFINED(window->x) || |
| SDL_WINDOWPOS_ISCENTERED(window->x)) { |
| displayIndex = (window->x & 0xFFFF); |
| if (displayIndex >= _this->num_displays) { |
| displayIndex = 0; |
| } |
| return displayIndex; |
| } |
| if (SDL_WINDOWPOS_ISUNDEFINED(window->y) || |
| SDL_WINDOWPOS_ISCENTERED(window->y)) { |
| displayIndex = (window->y & 0xFFFF); |
| if (displayIndex >= _this->num_displays) { |
| displayIndex = 0; |
| } |
| return displayIndex; |
| } |
| |
| /* Find the display containing the window */ |
| for (i = 0; i < _this->num_displays; ++i) { |
| SDL_VideoDisplay *display = &_this->displays[i]; |
| |
| if (display->fullscreen_window == window) { |
| return i; |
| } |
| } |
| center.x = window->x + window->w / 2; |
| center.y = window->y + window->h / 2; |
| for (i = 0; i < _this->num_displays; ++i) { |
| SDL_GetDisplayBounds(i, &rect); |
| if (SDL_EnclosePoints(¢er, 1, &rect, NULL)) { |
| return i; |
| } |
| |
| delta.x = center.x - (rect.x + rect.w / 2); |
| delta.y = center.y - (rect.y + rect.h / 2); |
| dist = (delta.x*delta.x + delta.y*delta.y); |
| if (dist < closest_dist) { |
| closest = i; |
| closest_dist = dist; |
| } |
| } |
| if (closest < 0) { |
| SDL_SetError("Couldn't find any displays"); |
| } |
| return closest; |
| } |
| |
| SDL_VideoDisplay * |
| SDL_GetDisplayForWindow(SDL_Window *window) |
| { |
| int displayIndex = SDL_GetWindowDisplayIndex(window); |
| if (displayIndex >= 0) { |
| return &_this->displays[displayIndex]; |
| } else { |
| return NULL; |
| } |
| } |
| |
| int |
| SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode) |
| { |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (mode) { |
| window->fullscreen_mode = *mode; |
| } else { |
| SDL_zero(window->fullscreen_mode); |
| } |
| |
| if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { |
| SDL_DisplayMode fullscreen_mode; |
| if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) { |
| SDL_SetDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode); |
| } |
| } |
| return 0; |
| } |
| |
| int |
| SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode) |
| { |
| SDL_DisplayMode fullscreen_mode; |
| SDL_VideoDisplay *display; |
| |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (!mode) { |
| return SDL_InvalidParamError("mode"); |
| } |
| |
| fullscreen_mode = window->fullscreen_mode; |
| if (!fullscreen_mode.w) { |
| fullscreen_mode.w = window->windowed.w; |
| } |
| if (!fullscreen_mode.h) { |
| fullscreen_mode.h = window->windowed.h; |
| } |
| |
| display = SDL_GetDisplayForWindow(window); |
| |
| /* if in desktop size mode, just return the size of the desktop */ |
| if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { |
| fullscreen_mode = display->desktop_mode; |
| } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window), |
| &fullscreen_mode, |
| &fullscreen_mode)) { |
| return SDL_SetError("Couldn't find display mode match"); |
| } |
| |
| if (mode) { |
| *mode = fullscreen_mode; |
| } |
| return 0; |
| } |
| |
| Uint32 |
| SDL_GetWindowPixelFormat(SDL_Window * window) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN); |
| |
| display = SDL_GetDisplayForWindow(window); |
| return display->current_mode.format; |
| } |
| |
| static void |
| SDL_RestoreMousePosition(SDL_Window *window) |
| { |
| int x, y; |
| |
| if (window == SDL_GetMouseFocus()) { |
| SDL_GetMouseState(&x, &y); |
| SDL_WarpMouseInWindow(window, x, y); |
| } |
| } |
| |
| #if __WINRT__ |
| extern Uint32 WINRT_DetectWindowFlags(SDL_Window * window); |
| #endif |
| |
| static int |
| SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) |
| { |
| SDL_VideoDisplay *display; |
| SDL_Window *other; |
| |
| CHECK_WINDOW_MAGIC(window,-1); |
| |
| /* if we are in the process of hiding don't go back to fullscreen */ |
| if (window->is_hiding && fullscreen) { |
| return 0; |
| } |
| |
| #ifdef __MACOSX__ |
| /* 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_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP) |
| return 0; |
| |
| /* If we're switching between a fullscreen Space and "normal" fullscreen, we need to get back to normal first. */ |
| if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN)) { |
| if (!Cocoa_SetWindowFullscreenSpace(window, SDL_FALSE)) { |
| return -1; |
| } |
| } else if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP)) { |
| display = SDL_GetDisplayForWindow(window); |
| SDL_SetDisplayModeForDisplay(display, NULL); |
| if (_this->SetWindowFullscreen) { |
| _this->SetWindowFullscreen(_this, window, display, SDL_FALSE); |
| } |
| } |
| |
| if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) { |
| if (Cocoa_IsWindowInFullscreenSpace(window) != fullscreen) { |
| return -1; |
| } |
| window->last_fullscreen_flags = window->flags; |
| return 0; |
| } |
| } |
| #elif __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10) |
| /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen |
| or not. The user can choose this, via OS-provided UI, but this can't |
| be set programmatically. |
| |
| Just look at what SDL's WinRT video backend code detected with regards |
| to fullscreen (being active, or not), and figure out a return/error code |
| from that. |
| */ |
| if (fullscreen == !(WINRT_DetectWindowFlags(window) & FULLSCREEN_MASK)) { |
| /* Uh oh, either: |
| 1. fullscreen was requested, and we're already windowed |
| 2. windowed-mode was requested, and we're already fullscreen |
| |
| WinRT 8.x can't resolve either programmatically, so we're |
| giving up. |
| */ |
| return -1; |
| } else { |
| /* Whatever was requested, fullscreen or windowed mode, is already |
| in-place. |
| */ |
| return 0; |
| } |
| #endif |
| |
| display = SDL_GetDisplayForWindow(window); |
| |
| if (fullscreen) { |
| /* Hide any other fullscreen windows */ |
| if (display->fullscreen_window && |
| display->fullscreen_window != window) { |
| SDL_MinimizeWindow(display->fullscreen_window); |
| } |
| } |
| |
| /* See if anything needs to be done now */ |
| if ((display->fullscreen_window == window) == fullscreen) { |
| if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) { |
| return 0; |
| } |
| } |
| |
| /* See if there are any fullscreen windows */ |
| for (other = _this->windows; other; other = other->next) { |
| SDL_bool setDisplayMode = SDL_FALSE; |
| |
| if (other == window) { |
| setDisplayMode = fullscreen; |
| } else if (FULLSCREEN_VISIBLE(other) && |
| SDL_GetDisplayForWindow(other) == display) { |
| setDisplayMode = SDL_TRUE; |
| } |
| |
| if (setDisplayMode) { |
| SDL_DisplayMode fullscreen_mode; |
| |
| SDL_zero(fullscreen_mode); |
| |
| if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) { |
| SDL_bool resized = SDL_TRUE; |
| |
| if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) { |
| resized = SDL_FALSE; |
| } |
| |
| /* only do the mode change if we want exclusive fullscreen */ |
| if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { |
| if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) { |
| return -1; |
| } |
| } else { |
| if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) { |
| return -1; |
| } |
| } |
| |
| if (_this->SetWindowFullscreen) { |
| _this->SetWindowFullscreen(_this, other, display, SDL_TRUE); |
| } |
| display->fullscreen_window = other; |
| |
| /* Generate a mode change event here */ |
| if (resized) { |
| #ifndef ANDROID |
| // 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 fullscreen_mode.w and fullscreen_mode.h, but rather get our current native size. As such, |
| // Android's SetWindowFullscreen will generate the window event for us with the proper final size. |
| |
| SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED, |
| fullscreen_mode.w, fullscreen_mode.h); |
| #endif |
| } else { |
| SDL_OnWindowResized(other); |
| } |
| |
| SDL_RestoreMousePosition(other); |
| |
| window->last_fullscreen_flags = window->flags; |
| return 0; |
| } |
| } |
| } |
| |
| /* Nope, restore the desktop mode */ |
| SDL_SetDisplayModeForDisplay(display, NULL); |
| |
| if (_this->SetWindowFullscreen) { |
| _this->SetWindowFullscreen(_this, window, display, SDL_FALSE); |
| } |
| display->fullscreen_window = NULL; |
| |
| /* Generate a mode change event here */ |
| SDL_OnWindowResized(window); |
| |
| /* Restore the cursor position */ |
| SDL_RestoreMousePosition(window); |
| |
| window->last_fullscreen_flags = window->flags; |
| return 0; |
| } |
| |
| #define CREATE_FLAGS \ |
| (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL) |
| |
| static SDL_INLINE SDL_bool |
| IsAcceptingDragAndDrop(void) |
| { |
| if ((SDL_GetEventState(SDL_DROPFILE) == SDL_ENABLE) || |
| (SDL_GetEventState(SDL_DROPTEXT) == SDL_ENABLE)) { |
| return SDL_TRUE; |
| } |
| return SDL_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 SDL_bool enable = IsAcceptingDragAndDrop(); |
| SDL_Window *window; |
| for (window = _this->windows; window; window = window->next) { |
| _this->AcceptDragAndDrop(window, enable); |
| } |
| } |
| } |
| |
| static void |
| SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags) |
| { |
| PrepareDragAndDropSupport(window); |
| |
| if (flags & SDL_WINDOW_MAXIMIZED) { |
| SDL_MaximizeWindow(window); |
| } |
| if (flags & SDL_WINDOW_MINIMIZED) { |
| SDL_MinimizeWindow(window); |
| } |
| if (flags & SDL_WINDOW_FULLSCREEN) { |
| SDL_SetWindowFullscreen(window, flags); |
| } |
| if (flags & SDL_WINDOW_MOUSE_GRABBED) { |
| /* We must specifically call SDL_SetWindowGrab() and not |
| SDL_SetWindowMouseGrab() here because older applications may use |
| this flag plus SDL_HINT_GRAB_KEYBOARD to indicate that they want |
| the keyboard grabbed too and SDL_SetWindowMouseGrab() won't do that. |
| */ |
| SDL_SetWindowGrab(window, SDL_TRUE); |
| } |
| if (flags & SDL_WINDOW_KEYBOARD_GRABBED) { |
| SDL_SetWindowKeyboardGrab(window, SDL_TRUE); |
| } |
| if (!(flags & SDL_WINDOW_HIDDEN)) { |
| SDL_ShowWindow(window); |
| } |
| } |
| |
| SDL_Window * |
| SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) |
| { |
| SDL_Window *window; |
| |
| if (!_this) { |
| /* Initialize the video system if needed */ |
| if (SDL_Init(SDL_INIT_VIDEO) < 0) { |
| return NULL; |
| } |
| } |
| |
| if ((((flags & SDL_WINDOW_UTILITY) != 0) + ((flags & SDL_WINDOW_TOOLTIP) != 0) + ((flags & SDL_WINDOW_POPUP_MENU) != 0)) > 1) { |
| SDL_SetError("Conflicting window flags specified"); |
| return NULL; |
| } |
| |
| /* Some platforms can't create zero-sized windows */ |
| if (w < 1) { |
| w = 1; |
| } |
| if (h < 1) { |
| h = 1; |
| } |
| |
| /* Some platforms blow up if the windows are too large. Raise it later? */ |
| if ((w > 16384) || (h > 16384)) { |
| SDL_SetError("Window is too large."); |
| return NULL; |
| } |
| |
| /* Some platforms have OpenGL enabled by default */ |
| #if (SDL_VIDEO_OPENGL && __MACOSX__) || (__IPHONEOS__ && !TARGET_OS_MACCATALYST) || __ANDROID__ || __NACL__ |
| if (!_this->is_dummy && !(flags & SDL_WINDOW_VULKAN) && !(flags & SDL_WINDOW_METAL) && !SDL_IsVideoContextExternal()) { |
| flags |= SDL_WINDOW_OPENGL; |
| } |
| #elif TARGET_OS_MACCATALYST |
| if (!_this->is_dummy && !(flags & SDL_WINDOW_VULKAN) && !(flags & SDL_WINDOW_OPENGL) && !SDL_IsVideoContextExternal()) { |
| flags |= SDL_WINDOW_METAL; |
| } |
| #endif |
| if (flags & SDL_WINDOW_OPENGL) { |
| if (!_this->GL_CreateContext) { |
| SDL_SetError("OpenGL support is either not configured in SDL " |
| "or not available in current SDL video driver " |
| "(%s) or platform", _this->name); |
| return NULL; |
| } |
| if (SDL_GL_LoadLibrary(NULL) < 0) { |
| return NULL; |
| } |
| } |
| |
| if (flags & SDL_WINDOW_VULKAN) { |
| if (!_this->Vulkan_CreateSurface) { |
| SDL_SetError("Vulkan support is either not configured in SDL " |
| "or not available in current SDL video driver " |
| "(%s) or platform", _this->name); |
| return NULL; |
| } |
| if (flags & SDL_WINDOW_OPENGL) { |
| SDL_SetError("Vulkan and OpenGL not supported on same window"); |
| return NULL; |
| } |
| if (SDL_Vulkan_LoadLibrary(NULL) < 0) { |
| return NULL; |
| } |
| } |
| |
| if (flags & SDL_WINDOW_METAL) { |
| if (!_this->Metal_CreateView) { |
| SDL_SetError("Metal support is either not configured in SDL " |
| "or not available in current SDL video driver " |
| "(%s) or platform", _this->name); |
| return NULL; |
| } |
| if (flags & SDL_WINDOW_OPENGL) { |
| SDL_SetError("Metal and OpenGL not supported on same window"); |
| return NULL; |
| } |
| if (flags & SDL_WINDOW_VULKAN) { |
| SDL_SetError("Metal and Vulkan not supported on same window. " |
| "To use MoltenVK, set SDL_WINDOW_VULKAN only."); |
| return NULL; |
| } |
| } |
| |
| /* Unless the user has specified the high-DPI disabling hint, respect the |
| * SDL_WINDOW_ALLOW_HIGHDPI flag. |
| */ |
| if (flags & SDL_WINDOW_ALLOW_HIGHDPI) { |
| if (SDL_GetHintBoolean(SDL_HINT_VIDEO_HIGHDPI_DISABLED, SDL_FALSE)) { |
| flags &= ~SDL_WINDOW_ALLOW_HIGHDPI; |
| } |
| } |
| |
| window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); |
| if (!window) { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| window->magic = &_this->window_magic; |
| window->id = _this->next_object_id++; |
| window->x = x; |
| window->y = y; |
| window->w = w; |
| window->h = h; |
| if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) || |
| SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { |
| SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); |
| int displayIndex; |
| SDL_Rect bounds; |
| |
| displayIndex = SDL_GetIndexOfDisplay(display); |
| SDL_GetDisplayBounds(displayIndex, &bounds); |
| if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) { |
| window->x = bounds.x + (bounds.w - w) / 2; |
| } |
| if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) { |
| window->y = bounds.y + (bounds.h - h) / 2; |
| } |
| } |
| window->windowed.x = window->x; |
| window->windowed.y = window->y; |
| window->windowed.w = window->w; |
| window->windowed.h = window->h; |
| |
| if (flags & SDL_WINDOW_FULLSCREEN) { |
| SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); |
| int displayIndex; |
| SDL_Rect bounds; |
| |
| displayIndex = SDL_GetIndexOfDisplay(display); |
| SDL_GetDisplayBounds(displayIndex, &bounds); |
| |
| window->x = bounds.x; |
| window->y = bounds.y; |
| window->w = bounds.w; |
| window->h = bounds.h; |
| } |
| |
| window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); |
| window->last_fullscreen_flags = window->flags; |
| window->opacity = 1.0f; |
| window->brightness = 1.0f; |
| window->next = _this->windows; |
| window->is_destroying = SDL_FALSE; |
| |
| if (_this->windows) { |
| _this->windows->prev = window; |
| } |
| _this->windows = window; |
| |
| if (_this->CreateSDLWindow && _this->CreateSDLWindow(_this, window) < 0) { |
| 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(__WIN32__) |
| if (window->flags & SDL_WINDOW_MINIMIZED) { |
| window->flags &= ~SDL_WINDOW_MINIMIZED; |
| } |
| #endif |
| |
| #if __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10) |
| /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen |
| or not. The user can choose this, via OS-provided UI, but this can't |
| be set programmatically. |
| |
| Just look at what SDL's WinRT video backend code detected with regards |
| to fullscreen (being active, or not), and figure out a return/error code |
| from that. |
| */ |
| flags = window->flags; |
| #endif |
| |
| if (title) { |
| SDL_SetWindowTitle(window, title); |
| } |
| SDL_FinishWindowCreation(window, flags); |
| |
| /* If the window was created fullscreen, make sure the mode code matches */ |
| SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)); |
| |
| return window; |
| } |
| |
| SDL_Window * |
| SDL_CreateWindowFrom(const void *data) |
| { |
| SDL_Window *window; |
| |
| if (!_this) { |
| SDL_UninitializedVideo(); |
| return NULL; |
| } |
| if (!_this->CreateSDLWindowFrom) { |
| SDL_Unsupported(); |
| return NULL; |
| } |
| window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); |
| if (!window) { |
| SDL_OutOfMemory(); |
| return NULL; |
| } |
| window->magic = &_this->window_magic; |
| window->id = _this->next_object_id++; |
| window->flags = SDL_WINDOW_FOREIGN; |
| window->last_fullscreen_flags = window->flags; |
| window->is_destroying = SDL_FALSE; |
| window->opacity = 1.0f; |
| window->brightness = 1.0f; |
| window->next = _this->windows; |
| if (_this->windows) { |
| _this->windows->prev = window; |
| } |
| _this->windows = window; |
| |
| if (_this->CreateSDLWindowFrom(_this, window, data) < 0) { |
| SDL_DestroyWindow(window); |
| return NULL; |
| } |
| |
| PrepareDragAndDropSupport(window); |
| |
| return window; |
| } |
| |
| int |
| SDL_RecreateWindow(SDL_Window * window, Uint32 flags) |
| { |
| SDL_bool loaded_opengl = SDL_FALSE; |
| SDL_bool need_gl_unload = SDL_FALSE; |
| SDL_bool need_gl_load = SDL_FALSE; |
| SDL_bool loaded_vulkan = SDL_FALSE; |
| SDL_bool need_vulkan_unload = SDL_FALSE; |
| SDL_bool need_vulkan_load = SDL_FALSE; |
| |
| if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) { |
| return SDL_SetError("OpenGL support is either not configured in SDL " |
| "or not available in current SDL video driver " |
| "(%s) or platform", _this->name); |
| } |
| |
| if (window->flags & SDL_WINDOW_FOREIGN) { |
| /* Can't destroy and re-create foreign windows, hrm */ |
| flags |= SDL_WINDOW_FOREIGN; |
| } else { |
| flags &= ~SDL_WINDOW_FOREIGN; |
| } |
| |
| /* Restore video mode, etc. */ |
| SDL_HideWindow(window); |
| |
| /* Tear down the old native window */ |
| if (window->surface) { |
| window->surface->flags &= ~SDL_DONTFREE; |
| SDL_FreeSurface(window->surface); |
| window->surface = NULL; |
| window->surface_valid = SDL_FALSE; |
| } |
| if (_this->DestroyWindowFramebuffer) { |
| _this->DestroyWindowFramebuffer(_this, window); |
| } |
| if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) { |
| _this->DestroyWindow(_this, window); |
| } |
| |
| if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) { |
| if (flags & SDL_WINDOW_OPENGL) { |
| need_gl_load = SDL_TRUE; |
| } else { |
| need_gl_unload = SDL_TRUE; |
| } |
| } else if (window->flags & SDL_WINDOW_OPENGL) { |
| need_gl_unload = SDL_TRUE; |
| need_gl_load = SDL_TRUE; |
| } |
| |
| if ((window->flags & SDL_WINDOW_METAL) != (flags & SDL_WINDOW_METAL)) { |
| if (flags & SDL_WINDOW_METAL) { |
| need_gl_load = SDL_TRUE; |
| } else { |
| need_gl_unload = SDL_TRUE; |
| } |
| } else if (window->flags & SDL_WINDOW_METAL) { |
| need_gl_unload = SDL_TRUE; |
| need_gl_load = SDL_TRUE; |
| } |
| |
| if ((window->flags & SDL_WINDOW_VULKAN) != (flags & SDL_WINDOW_VULKAN)) { |
| if (flags & SDL_WINDOW_VULKAN) { |
| need_vulkan_load = SDL_TRUE; |
| } else { |
| need_vulkan_unload = SDL_TRUE; |
| } |
| } else if (window->flags & SDL_WINDOW_VULKAN) { |
| need_vulkan_unload = SDL_TRUE; |
| need_vulkan_load = SDL_TRUE; |
| } |
| |
| if ((flags & SDL_WINDOW_VULKAN) && (flags & SDL_WINDOW_OPENGL)) { |
| SDL_SetError("Vulkan and OpenGL not supported on same window"); |
| return -1; |
| } |
| |
| if ((flags & SDL_WINDOW_METAL) && (flags & SDL_WINDOW_OPENGL)) { |
| SDL_SetError("Metal and OpenGL not supported on same window"); |
| return -1; |
| } |
| |
| if ((flags & SDL_WINDOW_METAL) && (flags & SDL_WINDOW_VULKAN)) { |
| SDL_SetError("Metal and Vulkan not supported on same window"); |
| return -1; |
| } |
| |
| if (need_gl_unload) { |
| SDL_GL_UnloadLibrary(); |
| } |
| |
| if (need_vulkan_unload) { |
| SDL_Vulkan_UnloadLibrary(); |
| } |
| |
| if (need_gl_load) { |
| if (SDL_GL_LoadLibrary(NULL) < 0) { |
| return -1; |
| } |
| loaded_opengl = SDL_TRUE; |
| } |
| |
| if (need_vulkan_load) { |
| if (SDL_Vulkan_LoadLibrary(NULL) < 0) { |
| return -1; |
| } |
| loaded_vulkan = SDL_TRUE; |
| } |
| |
| window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); |
| window->last_fullscreen_flags = window->flags; |
| window->is_destroying = SDL_FALSE; |
| |
| if (_this->CreateSDLWindow && !(flags & SDL_WINDOW_FOREIGN)) { |
| 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 -1; |
| } |
| } |
| |
| if (flags & SDL_WINDOW_FOREIGN) { |
| window->flags |= SDL_WINDOW_FOREIGN; |
| } |
| |
| if (_this->SetWindowTitle && window->title) { |
| _this->SetWindowTitle(_this, window); |
| } |
| |
| if (_this->SetWindowIcon && window->icon) { |
| _this->SetWindowIcon(_this, window, window->icon); |
| } |
| |
| if (window->hit_test) { |
| _this->SetWindowHitTest(window, SDL_TRUE); |
| } |
| |
| SDL_FinishWindowCreation(window, flags); |
| |
| return 0; |
| } |
| |
| SDL_bool |
| SDL_HasWindows(void) |
| { |
| return (_this && _this->windows != NULL); |
| } |
| |
| Uint32 |
| SDL_GetWindowID(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, 0); |
| |
| return window->id; |
| } |
| |
| SDL_Window * |
| SDL_GetWindowFromID(Uint32 id) |
| { |
| SDL_Window *window; |
| |
| if (!_this) { |
| return NULL; |
| } |
| for (window = _this->windows; window; window = window->next) { |
| if (window->id == id) { |
| return window; |
| } |
| } |
| return NULL; |
| } |
| |
| Uint32 |
| SDL_GetWindowFlags(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, 0); |
| |
| return window->flags; |
| } |
| |
| void |
| SDL_SetWindowTitle(SDL_Window * window, const char *title) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (title == window->title) { |
| return; |
| } |
| SDL_free(window->title); |
| |
| window->title = SDL_strdup(title ? title : ""); |
| |
| if (_this->SetWindowTitle) { |
| _this->SetWindowTitle(_this, window); |
| } |
| } |
| |
| const char * |
| SDL_GetWindowTitle(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, ""); |
| |
| return window->title ? window->title : ""; |
| } |
| |
| void |
| SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (!icon) { |
| return; |
| } |
| |
| SDL_FreeSurface(window->icon); |
| |
| /* Convert the icon into ARGB8888 */ |
| window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0); |
| if (!window->icon) { |
| return; |
| } |
| |
| if (_this->SetWindowIcon) { |
| _this->SetWindowIcon(_this, window, window->icon); |
| } |
| } |
| |
| void* |
| SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata) |
| { |
| SDL_WindowUserData *prev, *data; |
| |
| CHECK_WINDOW_MAGIC(window, NULL); |
| |
| /* Input validation */ |
| if (name == NULL || name[0] == '\0') { |
| SDL_InvalidParamError("name"); |
| return NULL; |
| } |
| |
| /* See if the named data already exists */ |
| prev = NULL; |
| for (data = window->data; data; prev = data, data = data->next) { |
| if (data->name && SDL_strcmp(data->name, name) == 0) { |
| void *last_value = data->data; |
| |
| if (userdata) { |
| /* Set the new value */ |
| data->data = userdata; |
| } else { |
| /* Delete this value */ |
| if (prev) { |
| prev->next = data->next; |
| } else { |
| window->data = data->next; |
| } |
| SDL_free(data->name); |
| SDL_free(data); |
| } |
| return last_value; |
| } |
| } |
| |
| /* Add new data to the window */ |
| if (userdata) { |
| data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data)); |
| data->name = SDL_strdup(name); |
| data->data = userdata; |
| data->next = window->data; |
| window->data = data; |
| } |
| return NULL; |
| } |
| |
| void * |
| SDL_GetWindowData(SDL_Window * window, const char *name) |
| { |
| SDL_WindowUserData *data; |
| |
| CHECK_WINDOW_MAGIC(window, NULL); |
| |
| /* Input validation */ |
| if (name == NULL || name[0] == '\0') { |
| SDL_InvalidParamError("name"); |
| return NULL; |
| } |
| |
| for (data = window->data; data; data = data->next) { |
| if (data->name && SDL_strcmp(data->name, name) == 0) { |
| return data->data; |
| } |
| } |
| return NULL; |
| } |
| |
| void |
| SDL_SetWindowPosition(SDL_Window * window, int x, int y) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { |
| int displayIndex = (x & 0xFFFF); |
| SDL_Rect bounds; |
| if (displayIndex >= _this->num_displays) { |
| displayIndex = 0; |
| } |
| |
| SDL_zero(bounds); |
| |
| SDL_GetDisplayBounds(displayIndex, &bounds); |
| if (SDL_WINDOWPOS_ISCENTERED(x)) { |
| x = bounds.x + (bounds.w - window->w) / 2; |
| } |
| if (SDL_WINDOWPOS_ISCENTERED(y)) { |
| y = bounds.y + (bounds.h - window->h) / 2; |
| } |
| } |
| |
| if ((window->flags & SDL_WINDOW_FULLSCREEN)) { |
| if (!SDL_WINDOWPOS_ISUNDEFINED(x)) { |
| window->windowed.x = x; |
| } |
| if (!SDL_WINDOWPOS_ISUNDEFINED(y)) { |
| window->windowed.y = y; |
| } |
| } else { |
| if (!SDL_WINDOWPOS_ISUNDEFINED(x)) { |
| window->x = x; |
| } |
| if (!SDL_WINDOWPOS_ISUNDEFINED(y)) { |
| window->y = y; |
| } |
| |
| if (_this->SetWindowPosition) { |
| _this->SetWindowPosition(_this, window); |
| } |
| } |
| } |
| |
| void |
| SDL_GetWindowPosition(SDL_Window * window, int *x, int *y) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| /* Fullscreen windows are always at their display's origin */ |
| if (window->flags & SDL_WINDOW_FULLSCREEN) { |
| int displayIndex; |
| |
| if (x) { |
| *x = 0; |
| } |
| if (y) { |
| *y = 0; |
| } |
| |
| /* Find the window's monitor and update to the |
| monitor offset. */ |
| displayIndex = SDL_GetWindowDisplayIndex(window); |
| if (displayIndex >= 0) { |
| SDL_Rect bounds; |
| |
| SDL_zero(bounds); |
| |
| SDL_GetDisplayBounds(displayIndex, &bounds); |
| if (x) { |
| *x = bounds.x; |
| } |
| if (y) { |
| *y = bounds.y; |
| } |
| } |
| } else { |
| if (x) { |
| *x = window->x; |
| } |
| if (y) { |
| *y = window->y; |
| } |
| } |
| } |
| |
| void |
| SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { |
| const int want = (bordered != SDL_FALSE); /* normalize the flag. */ |
| const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0); |
| if ((want != have) && (_this->SetWindowBordered)) { |
| if (want) { |
| window->flags &= ~SDL_WINDOW_BORDERLESS; |
| } else { |
| window->flags |= SDL_WINDOW_BORDERLESS; |
| } |
| _this->SetWindowBordered(_this, window, (SDL_bool) want); |
| } |
| } |
| } |
| |
| void |
| SDL_SetWindowResizable(SDL_Window * window, SDL_bool resizable) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { |
| const int want = (resizable != SDL_FALSE); /* normalize the flag. */ |
| const int 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; |
| } |
| _this->SetWindowResizable(_this, window, (SDL_bool) want); |
| } |
| } |
| } |
| |
| void |
| SDL_SetWindowSize(SDL_Window * window, int w, int h) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (w <= 0) { |
| SDL_InvalidParamError("w"); |
| return; |
| } |
| if (h <= 0) { |
| SDL_InvalidParamError("h"); |
| return; |
| } |
| |
| /* 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->windowed.w = w; |
| window->windowed.h = h; |
| |
| if (window->flags & SDL_WINDOW_FULLSCREEN) { |
| if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { |
| window->last_fullscreen_flags = 0; |
| SDL_UpdateFullscreenMode(window, SDL_TRUE); |
| } |
| } else { |
| window->w = w; |
| window->h = h; |
| if (_this->SetWindowSize) { |
| _this->SetWindowSize(_this, window); |
| } |
| if (window->w == w && window->h == h) { |
| /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */ |
| SDL_OnWindowResized(window); |
| } |
| } |
| } |
| |
| void |
| SDL_GetWindowSize(SDL_Window * window, int *w, int *h) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (w) { |
| *w = window->w; |
| } |
| if (h) { |
| *h = window->h; |
| } |
| } |
| |
| int |
| 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, -1); |
| |
| if (!_this->GetWindowBordersSize) { |
| return SDL_Unsupported(); |
| } |
| |
| return _this->GetWindowBordersSize(_this, window, top, left, bottom, right); |
| } |
| |
| void |
| SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (min_w <= 0) { |
| SDL_InvalidParamError("min_w"); |
| return; |
| } |
| if (min_h <= 0) { |
| SDL_InvalidParamError("min_h"); |
| return; |
| } |
| |
| if ((window->max_w && min_w > window->max_w) || |
| (window->max_h && min_h > window->max_h)) { |
| SDL_SetError("SDL_SetWindowMinimumSize(): Tried to set minimum size larger than maximum size"); |
| return; |
| } |
| |
| window->min_w = min_w; |
| window->min_h = min_h; |
| |
| if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { |
| if (_this->SetWindowMinimumSize) { |
| _this->SetWindowMinimumSize(_this, window); |
| } |
| /* Ensure that window is not smaller than minimal size */ |
| SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h)); |
| } |
| } |
| |
| void |
| SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (min_w) { |
| *min_w = window->min_w; |
| } |
| if (min_h) { |
| *min_h = window->min_h; |
| } |
| } |
| |
| void |
| SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (max_w <= 0) { |
| SDL_InvalidParamError("max_w"); |
| return; |
| } |
| if (max_h <= 0) { |
| SDL_InvalidParamError("max_h"); |
| return; |
| } |
| |
| if (max_w < window->min_w || max_h < window->min_h) { |
| SDL_SetError("SDL_SetWindowMaximumSize(): Tried to set maximum size smaller than minimum size"); |
| return; |
| } |
| |
| window->max_w = max_w; |
| window->max_h = max_h; |
| |
| if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { |
| if (_this->SetWindowMaximumSize) { |
| _this->SetWindowMaximumSize(_this, window); |
| } |
| /* Ensure that window is not larger than maximal size */ |
| SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h)); |
| } |
| } |
| |
| void |
| SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| if (max_w) { |
| *max_w = window->max_w; |
| } |
| if (max_h) { |
| *max_h = window->max_h; |
| } |
| } |
| |
| void |
| SDL_ShowWindow(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (window->flags & SDL_WINDOW_SHOWN) { |
| return; |
| } |
| |
| if (_this->ShowWindow) { |
| _this->ShowWindow(_this, window); |
| } |
| SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0); |
| } |
| |
| void |
| SDL_HideWindow(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (!(window->flags & SDL_WINDOW_SHOWN)) { |
| return; |
| } |
| |
| window->is_hiding = SDL_TRUE; |
| SDL_UpdateFullscreenMode(window, SDL_FALSE); |
| |
| if (_this->HideWindow) { |
| _this->HideWindow(_this, window); |
| } |
| window->is_hiding = SDL_FALSE; |
| SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0); |
| } |
| |
| void |
| SDL_RaiseWindow(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (!(window->flags & SDL_WINDOW_SHOWN)) { |
| return; |
| } |
| if (_this->RaiseWindow) { |
| _this->RaiseWindow(_this, window); |
| } |
| } |
| |
| void |
| SDL_MaximizeWindow(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (window->flags & SDL_WINDOW_MAXIMIZED) { |
| return; |
| } |
| |
| /* !!! FIXME: should this check if the window is resizable? */ |
| |
| if (_this->MaximizeWindow) { |
| _this->MaximizeWindow(_this, window); |
| } |
| } |
| |
| static SDL_bool |
| CanMinimizeWindow(SDL_Window * window) |
| { |
| if (!_this->MinimizeWindow) { |
| return SDL_FALSE; |
| } |
| return SDL_TRUE; |
| } |
| |
| void |
| SDL_MinimizeWindow(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (window->flags & SDL_WINDOW_MINIMIZED) { |
| return; |
| } |
| |
| if (!CanMinimizeWindow(window)) { |
| return; |
| } |
| |
| SDL_UpdateFullscreenMode(window, SDL_FALSE); |
| |
| if (_this->MinimizeWindow) { |
| _this->MinimizeWindow(_this, window); |
| } |
| } |
| |
| void |
| SDL_RestoreWindow(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) { |
| return; |
| } |
| |
| if (_this->RestoreWindow) { |
| _this->RestoreWindow(_this, window); |
| } |
| } |
| |
| int |
| SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags) |
| { |
| Uint32 oldflags; |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| flags &= FULLSCREEN_MASK; |
| |
| if (flags == (window->flags & FULLSCREEN_MASK)) { |
| return 0; |
| } |
| |
| /* clear the previous flags and OR in the new ones */ |
| oldflags = window->flags & FULLSCREEN_MASK; |
| window->flags &= ~FULLSCREEN_MASK; |
| window->flags |= flags; |
| |
| if (SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)) == 0) { |
| return 0; |
| } |
| |
| window->flags &= ~FULLSCREEN_MASK; |
| window->flags |= oldflags; |
| return -1; |
| } |
| |
| static SDL_Surface * |
| SDL_CreateWindowFramebuffer(SDL_Window * window) |
| { |
| Uint32 format; |
| void *pixels; |
| int pitch; |
| int bpp; |
| Uint32 Rmask, Gmask, Bmask, Amask; |
| |
| if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) { |
| return NULL; |
| } |
| |
| if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) { |
| return NULL; |
| } |
| |
| if (window->surface) { |
| return window->surface; |
| } |
| |
| if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { |
| return NULL; |
| } |
| |
| return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask); |
| } |
| |
| SDL_Surface * |
| SDL_GetWindowSurface(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, NULL); |
| |
| if (!window->surface_valid) { |
| if (window->surface) { |
| window->surface->flags &= ~SDL_DONTFREE; |
| SDL_FreeSurface(window->surface); |
| window->surface = NULL; |
| } |
| window->surface = SDL_CreateWindowFramebuffer(window); |
| if (window->surface) { |
| window->surface_valid = SDL_TRUE; |
| window->surface->flags |= SDL_DONTFREE; |
| } |
| } |
| return window->surface; |
| } |
| |
| int |
| SDL_UpdateWindowSurface(SDL_Window * window) |
| { |
| SDL_Rect full_rect; |
| |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| full_rect.x = 0; |
| full_rect.y = 0; |
| full_rect.w = window->w; |
| full_rect.h = window->h; |
| return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1); |
| } |
| |
| int |
| SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects, |
| int numrects) |
| { |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (!window->surface_valid) { |
| return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface"); |
| } |
| |
| return _this->UpdateWindowFramebuffer(_this, window, rects, numrects); |
| } |
| |
| int |
| SDL_SetWindowBrightness(SDL_Window * window, float brightness) |
| { |
| Uint16 ramp[256]; |
| int status; |
| |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| SDL_CalculateGammaRamp(brightness, ramp); |
| status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp); |
| if (status == 0) { |
| window->brightness = brightness; |
| } |
| return status; |
| } |
| |
| float |
| SDL_GetWindowBrightness(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, 1.0f); |
| |
| return window->brightness; |
| } |
| |
| int |
| SDL_SetWindowOpacity(SDL_Window * window, float opacity) |
| { |
| int retval; |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (!_this->SetWindowOpacity) { |
| return SDL_Unsupported(); |
| } |
| |
| if (opacity < 0.0f) { |
| opacity = 0.0f; |
| } else if (opacity > 1.0f) { |
| opacity = 1.0f; |
| } |
| |
| retval = _this->SetWindowOpacity(_this, window, opacity); |
| if (retval == 0) { |
| window->opacity = opacity; |
| } |
| |
| return retval; |
| } |
| |
| int |
| SDL_GetWindowOpacity(SDL_Window * window, float * out_opacity) |
| { |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (out_opacity) { |
| *out_opacity = window->opacity; |
| } |
| |
| return 0; |
| } |
| |
| int |
| SDL_SetWindowModalFor(SDL_Window * modal_window, SDL_Window * parent_window) |
| { |
| CHECK_WINDOW_MAGIC(modal_window, -1); |
| CHECK_WINDOW_MAGIC(parent_window, -1); |
| |
| if (!_this->SetWindowModalFor) { |
| return SDL_Unsupported(); |
| } |
| |
| return _this->SetWindowModalFor(_this, modal_window, parent_window); |
| } |
| |
| int |
| SDL_SetWindowInputFocus(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (!_this->SetWindowInputFocus) { |
| return SDL_Unsupported(); |
| } |
| |
| return _this->SetWindowInputFocus(_this, window); |
| } |
| |
| |
| int |
| SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red, |
| const Uint16 * green, |
| const Uint16 * blue) |
| { |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (!_this->SetWindowGammaRamp) { |
| return SDL_Unsupported(); |
| } |
| |
| if (!window->gamma) { |
| if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) { |
| return -1; |
| } |
| SDL_assert(window->gamma != NULL); |
| } |
| |
| if (red) { |
| SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16)); |
| } |
| if (green) { |
| SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16)); |
| } |
| if (blue) { |
| SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16)); |
| } |
| if (window->flags & SDL_WINDOW_INPUT_FOCUS) { |
| return _this->SetWindowGammaRamp(_this, window, window->gamma); |
| } else { |
| return 0; |
| } |
| } |
| |
| int |
| SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red, |
| Uint16 * green, |
| Uint16 * blue) |
| { |
| CHECK_WINDOW_MAGIC(window, -1); |
| |
| if (!window->gamma) { |
| int i; |
| |
| window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16)); |
| if (!window->gamma) { |
| return SDL_OutOfMemory(); |
| } |
| window->saved_gamma = window->gamma + 3*256; |
| |
| if (_this->GetWindowGammaRamp) { |
| if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) { |
| return -1; |
| } |
| } else { |
| /* Create an identity gamma ramp */ |
| for (i = 0; i < 256; ++i) { |
| Uint16 value = (Uint16)((i << 8) | i); |
| |
| window->gamma[0*256+i] = value; |
| window->gamma[1*256+i] = value; |
| window->gamma[2*256+i] = value; |
| } |
| } |
| SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16)); |
| } |
| |
| if (red) { |
| SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16)); |
| } |
| if (green) { |
| SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16)); |
| } |
| if (blue) { |
| SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16)); |
| } |
| return 0; |
| } |
| |
| void |
| SDL_UpdateWindowGrab(SDL_Window * window) |
| { |
| SDL_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 = SDL_TRUE; |
| } else { |
| mouse_grabbed = SDL_FALSE; |
| } |
| |
| if (window->flags & SDL_WINDOW_KEYBOARD_GRABBED) { |
| keyboard_grabbed = SDL_TRUE; |
| } else { |
| keyboard_grabbed = SDL_FALSE; |
| } |
| } else { |
| mouse_grabbed = SDL_FALSE; |
| keyboard_grabbed = SDL_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, SDL_FALSE); |
| } |
| if (_this->SetWindowKeyboardGrab) { |
| _this->SetWindowKeyboardGrab(_this, _this->grabbed_window, SDL_FALSE); |
| } |
| } |
| _this->grabbed_window = window; |
| } else if (_this->grabbed_window == window) { |
| _this->grabbed_window = NULL; /* ungrabbing input. */ |
| } |
| |
| if (_this->SetWindowMouseGrab) { |
| _this->SetWindowMouseGrab(_this, window, mouse_grabbed); |
| } |
| if (_this->SetWindowKeyboardGrab) { |
| _this->SetWindowKeyboardGrab(_this, window, keyboard_grabbed); |
| } |
| } |
| |
| void |
| SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| SDL_SetWindowMouseGrab(window, grabbed); |
| |
| if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) { |
| SDL_SetWindowKeyboardGrab(window, grabbed); |
| } |
| } |
| |
| void |
| SDL_SetWindowKeyboardGrab(SDL_Window * window, SDL_bool grabbed) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (!!grabbed == !!(window->flags & SDL_WINDOW_KEYBOARD_GRABBED)) { |
| return; |
| } |
| if (grabbed) { |
| window->flags |= SDL_WINDOW_KEYBOARD_GRABBED; |
| } else { |
| window->flags &= ~SDL_WINDOW_KEYBOARD_GRABBED; |
| } |
| SDL_UpdateWindowGrab(window); |
| } |
| |
| void |
| SDL_SetWindowMouseGrab(SDL_Window * window, SDL_bool grabbed) |
| { |
| CHECK_WINDOW_MAGIC(window,); |
| |
| if (!!grabbed == !!(window->flags & SDL_WINDOW_MOUSE_GRABBED)) { |
| return; |
| } |
| if (grabbed) { |
| window->flags |= SDL_WINDOW_MOUSE_GRABBED; |
| } else { |
| window->flags &= ~SDL_WINDOW_MOUSE_GRABBED; |
| } |
| SDL_UpdateWindowGrab(window); |
| } |
| |
| SDL_bool |
| SDL_GetWindowGrab(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, SDL_FALSE); |
| SDL_assert(!_this->grabbed_window || |
| ((_this->grabbed_window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) || |
| ((_this->grabbed_window->flags & SDL_WINDOW_KEYBOARD_GRABBED) != 0)); |
| return window == _this->grabbed_window; |
| } |
| |
| SDL_bool |
| SDL_GetWindowKeyboardGrab(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, SDL_FALSE); |
| return window == _this->grabbed_window && |
| ((_this->grabbed_window->flags & SDL_WINDOW_KEYBOARD_GRABBED) != 0); |
| } |
| |
| SDL_bool |
| SDL_GetWindowMouseGrab(SDL_Window * window) |
| { |
| CHECK_WINDOW_MAGIC(window, SDL_FALSE); |
| return window == _this->grabbed_window && |
| ((_this->grabbed_window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0); |
| } |
| |
| SDL_Window * |
| SDL_GetGrabbedWindow(void) |
| { |
| SDL_assert(!_this->grabbed_window || |
| ((_this->grabbed_window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) || |
| ((_this->grabbed_window->flags & SDL_WINDOW_KEYBOARD_GRABBED) != 0)); |
| return _this->grabbed_window; |
| } |
| |
| void |
| SDL_OnWindowShown(SDL_Window * window) |
| { |
| SDL_OnWindowRestored(window); |
| } |
| |
| void |
| SDL_OnWindowHidden(SDL_Window * window) |
| { |
| SDL_UpdateFullscreenMode(window, SDL_FALSE); |
| } |
| |
| void |
| SDL_OnWindowResized(SDL_Window * window) |
| { |
| window->surface_valid = SDL_FALSE; |
| SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h); |
| } |
| |
| void |
| SDL_OnWindowMinimized(SDL_Window * window) |
| { |
| SDL_UpdateFullscreenMode(window, SDL_FALSE); |
| } |
| |
| 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 (FULLSCREEN_VISIBLE(window)) { |
| SDL_UpdateFullscreenMode(window, SDL_TRUE); |
| } |
| } |
| |
| 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 (window->gamma && _this->SetWindowGammaRamp) { |
| _this->SetWindowGammaRamp(_this, window, window->gamma); |
| } |
| |
| if (mouse && mouse->relative_mode) { |
| SDL_SetMouseFocus(window); |
| SDL_WarpMouseInWindow(window, window->w/2, window->h/2); |
| } |
| |
| SDL_UpdateWindowGrab(window); |
| } |
| |
| static SDL_bool |
| ShouldMinimizeOnFocusLoss(SDL_Window * window) |
| { |
| if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) { |
| return SDL_FALSE; |
| } |
| |
| #ifdef __MACOSX__ |
| if (SDL_strcmp(_this->name, "cocoa") == 0) { /* don't do this for X11, etc */ |
| if (Cocoa_IsWindowInFullscreenSpace(window)) { |
| return SDL_FALSE; |
| } |
| } |
| #endif |
| |
| #ifdef __ANDROID__ |
| { |
| extern SDL_bool Android_JNI_ShouldMinimizeOnFocusLoss(void); |
| if (! Android_JNI_ShouldMinimizeOnFocusLoss()) { |
| return SDL_FALSE; |
| } |
| } |
| #endif |
| |
| return SDL_GetHintBoolean(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, SDL_FALSE); |
| } |
| |
| void |
| SDL_OnWindowFocusLost(SDL_Window * window) |
| { |
| if (window->gamma && _this->SetWindowGammaRamp) { |
| _this->SetWindowGammaRamp(_this, window, window->saved_gamma); |
| } |
| |
| SDL_UpdateWindowGrab(window); |
| |
| if (ShouldMinimizeOnFocusLoss(window)) { |
| SDL_MinimizeWindow(window); |
| } |
| } |
| |
| /* !!! FIXME: is this different than SDL_GetKeyboardFocus()? |
| !!! FIXME: Also, SDL_GetKeyboardFocus() is O(1), this isn't. */ |
| SDL_Window * |
| SDL_GetFocusWindow(void) |
| { |
| SDL_Window *window; |
| |
| if (!_this) { |
| return NULL; |
| } |
| for (window = _this->windows; window; window = window->next) { |
| if (window->flags & SDL_WINDOW_INPUT_FOCUS) { |
| return window; |
| } |
| } |
| return NULL; |
| } |
| |
| void |
| SDL_DestroyWindow(SDL_Window * window) |
| { |
| SDL_VideoDisplay *display; |
| |
| CHECK_WINDOW_MAGIC(window,); |
| |
| window->is_destroying = SDL_TRUE; |
| |
| /* Restore video mode, etc. */ |
| SDL_HideWindow(window); |
| |
| /* Make sure this window no longer has focus */ |
| if (SDL_GetKeyboardFocus() == window) { |
| SDL_SetKeyboardFocus(NULL); |
| } |
| if (SDL_GetMouseFocus() == window) { |
| SDL_SetMouseFocus(NULL); |
| } |
| |
| /* 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 (window->surface) { |
| window->surface->flags &= ~SDL_DONTFREE; |
| SDL_FreeSurface(window->surface); |
| window->surface = NULL; |
| window->surface_valid = SDL_FALSE; |
| } |
| if (_this->DestroyWindowFramebuffer) { |
| _this->DestroyWindowFramebuffer(_this, window); |
| } |
| if (_this->DestroyWindow) { |
| _this->DestroyWindow(_this, window); |
| } |
| if (window->flags & SDL_WINDOW_OPENGL) { |
| SDL_GL_UnloadLibrary(); |
| } |
| if (window->flags & SDL_WINDOW_VULKAN) { |
| SDL_Vulkan_UnloadLibrary(); |
| } |
| |
| display = SDL_GetDisplayForWindow(window); |
| if (display->fullscreen_window == window) { |
| display->fullscreen_window = NULL; |
| } |
| |
| /* Now invalidate magic */ |
| window->magic = NULL; |
| |
| /* Free memory associated with the window */ |
| SDL_free(window->title); |
| SDL_FreeSurface(window->icon); |
| SDL_free(window->gamma); |
| while (window->data) { |
| SDL_WindowUserData *data = window->data; |
| |
| window->data = data->next; |
| SDL_free(data->name); |
| SDL_free(data); |
| } |
| |
| /* Unlink the window from the 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); |
| } |
| |
| SDL_bool |
| SDL_IsScreenSaverEnabled() |
| { |
| if (!_this) { |
| return SDL_TRUE; |
| } |
| return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE; |
| } |
| |
| void |
| SDL_EnableScreenSaver() |
| { |
| if (!_this) { |
| return; |
| } |
| if (!_this->suspend_screensaver) { |
| return; |
| } |
| _this->suspend_screensaver = SDL_FALSE; |
| if (_this->SuspendScreenSaver) { |
| _this->SuspendScreenSaver(_this); |
| } |
| } |
| |
| void |
| SDL_DisableScreenSaver() |
| { |
| if (!_this) { |
| return; |
| } |
| if (_this->suspend_screensaver) { |
| return; |
| } |
| _this->suspend_screensaver = SDL_TRUE; |
| if (_this->SuspendScreenSaver) { |
| _this->SuspendScreenSaver(_this); |
| } |
| } |
| |
| void |
| SDL_VideoQuit(void) |
| { |
| int i, j; |
| |
| if (!_this) { |
| return; |
| } |
| |
| /* Halt event processing before doing anything else */ |
| SDL_TouchQuit(); |
| SDL_MouseQuit(); |
| SDL_KeyboardQuit(); |
| SDL_QuitSubSystem(SDL_INIT_EVENTS); |
| |
| SDL_EnableScreenSaver(); |
| |
| /* Clean up the system video */ |
| while (_this->windows) { |
| SDL_DestroyWindow(_this->windows); |
| } |
| _this->VideoQuit(_this); |
| |
| for (i = 0; i < _this->num_displays; ++i) { |
| SDL_VideoDisplay *display = &_this->displays[i]; |
| for (j = display->num_display_modes; j--;) { |
| SDL_free(display->display_modes[j].driverdata); |
| display->display_modes[j].driverdata = NULL; |
| } |
| SDL_free(display->display_modes); |
| display->display_modes = NULL; |
| SDL_free(display->desktop_mode.driverdata); |
| display->desktop_mode.driverdata = NULL; |
| SDL_free(display->driverdata); |
| display->driverdata = NULL; |
| } |
| if (_this->displays) { |
| for (i = 0; i < _this->num_displays; ++i) { |
| SDL_free(_this->displays[i].name); |
| } |
| SDL_free(_this->displays); |
| _this->displays = NULL; |
| _this->num_displays = 0; |
| } |
| SDL_free(_this->clipboard_text); |
| _this->clipboard_text = NULL; |
| _this->free(_this); |
| _this = NULL; |
| } |
| |
| int |
| SDL_GL_LoadLibrary(const char *path) |
| { |
| int retval; |
| |
| if (!_this) { |
| return SDL_UninitializedVideo(); |
| } |
| if (_this->gl_config.driver_loaded) |