2 Simple DirectMedia Layer
3 Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "../SDL_internal.h"
23 /* The high-level video driver subsystem */
26 #include "SDL_video.h"
27 #include "SDL_sysvideo.h"
29 #include "SDL_pixels_c.h"
30 #include "SDL_rect_c.h"
31 #include "SDL_egl_c.h"
32 #include "../events/SDL_events_c.h"
33 #include "../timer/SDL_timer_c.h"
35 #include "SDL_syswm.h"
38 #include "SDL_opengl.h"
39 #endif /* SDL_VIDEO_OPENGL */
41 #if SDL_VIDEO_OPENGL_ES
42 #include "SDL_opengles.h"
43 #endif /* SDL_VIDEO_OPENGL_ES */
45 /* GL and GLES2 headers conflict on Linux 32 bits */
46 #if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL
47 #include "SDL_opengles2.h"
48 #endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */
51 #ifndef GL_CONTEXT_RELEASE_BEHAVIOR_KHR
52 #define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB
57 #include <emscripten.h>
60 /* Available video drivers */
61 static VideoBootStrap *bootstrap[] = {
62 #if SDL_VIDEO_DRIVER_COCOA
65 #if SDL_VIDEO_DRIVER_X11
68 #if SDL_VIDEO_DRIVER_MIR
71 #if SDL_VIDEO_DRIVER_WAYLAND
74 #if SDL_VIDEO_DRIVER_VIVANTE
77 #if SDL_VIDEO_DRIVER_DIRECTFB
80 #if SDL_VIDEO_DRIVER_WINDOWS
83 #if SDL_VIDEO_DRIVER_WINRT
86 #if SDL_VIDEO_DRIVER_HAIKU
89 #if SDL_VIDEO_DRIVER_PANDORA
92 #if SDL_VIDEO_DRIVER_UIKIT
95 #if SDL_VIDEO_DRIVER_ANDROID
98 #if SDL_VIDEO_DRIVER_PSP
101 #if SDL_VIDEO_DRIVER_KMSDRM
104 #if SDL_VIDEO_DRIVER_RPI
107 #if SDL_VIDEO_DRIVER_NACL
110 #if SDL_VIDEO_DRIVER_EMSCRIPTEN
111 &Emscripten_bootstrap,
113 #if SDL_VIDEO_DRIVER_QNX
116 #if SDL_VIDEO_DRIVER_DUMMY
119 #if SDL_VIDEO_DRIVER_TIZEN
125 static SDL_VideoDevice *_this = NULL;
127 #define CHECK_WINDOW_MAGIC(window, retval) \
129 SDL_UninitializedVideo(); \
132 SDL_assert(window && window->magic == &_this->window_magic); \
133 if (!window || window->magic != &_this->window_magic) { \
134 SDL_SetError("Invalid window"); \
138 #define CHECK_DISPLAY_INDEX(displayIndex, retval) \
140 SDL_UninitializedVideo(); \
143 SDL_assert(_this->displays != NULL); \
144 SDL_assert(displayIndex >= 0 && displayIndex < _this->num_displays); \
145 if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
146 SDL_SetError("displayIndex must be in the range 0 - %d", \
147 _this->num_displays - 1); \
151 #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
154 /* Support for Mac OS X fullscreen spaces */
155 extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window);
156 extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state);
160 /* Support for framebuffer emulation using an accelerated renderer */
162 #define SDL_WINDOWTEXTUREDATA "_SDL_WindowTextureData"
165 SDL_Renderer *renderer;
166 SDL_Texture *texture;
170 } SDL_WindowTextureData;
173 ShouldUseTextureFramebuffer()
177 /* If there's no native framebuffer support then there's no option */
178 if (!_this->CreateWindowFramebuffer) {
182 /* If this is the dummy driver there is no texture support */
183 if (_this->is_dummy) {
187 /* If the user has specified a software renderer we can't use a
188 texture framebuffer, or renderer creation will go recursive.
190 hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
191 if (hint && SDL_strcasecmp(hint, "software") == 0) {
195 /* See if the user or application wants a specific behavior */
196 hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
198 if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) {
205 /* Each platform has different performance characteristics */
206 #if defined(__WIN32__)
207 /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
211 #elif defined(__MACOSX__)
212 /* Mac OS X uses OpenGL as the native fast path (for cocoa and X11) */
215 #elif defined(__LINUX__)
216 /* Properly configured OpenGL drivers are faster than MIT-SHM */
218 /* Ugh, find a way to cache this value! */
221 SDL_GLContext context;
222 SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
224 window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
226 context = SDL_GL_CreateContext(window);
228 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
229 const char *vendor = NULL;
231 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
232 if (glGetStringFunc) {
233 vendor = (const char *) glGetStringFunc(GL_VENDOR);
235 /* Add more vendors here at will... */
237 (SDL_strstr(vendor, "ATI Technologies") ||
238 SDL_strstr(vendor, "NVIDIA"))) {
239 hasAcceleratedOpenGL = SDL_TRUE;
241 SDL_GL_DeleteContext(context);
243 SDL_DestroyWindow(window);
245 return hasAcceleratedOpenGL;
247 #elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
248 /* Let's be optimistic about this! */
255 /* Play it safe, assume that if there is a framebuffer driver that it's
256 optimized for the current platform.
263 SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
265 SDL_WindowTextureData *data;
267 data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
269 SDL_Renderer *renderer = NULL;
271 const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
273 /* Check to see if there's a specific driver requested */
274 if (hint && *hint != '0' && *hint != '1' &&
275 SDL_strcasecmp(hint, "true") != 0 &&
276 SDL_strcasecmp(hint, "false") != 0 &&
277 SDL_strcasecmp(hint, "software") != 0) {
278 for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
279 SDL_RendererInfo info;
280 SDL_GetRenderDriverInfo(i, &info);
281 if (SDL_strcasecmp(info.name, hint) == 0) {
282 renderer = SDL_CreateRenderer(window, i, 0);
289 for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
290 SDL_RendererInfo info;
291 SDL_GetRenderDriverInfo(i, &info);
292 if (SDL_strcmp(info.name, "software") != 0) {
293 renderer = SDL_CreateRenderer(window, i, 0);
301 return SDL_SetError("No hardware accelerated renderers available");
304 /* Create the data after we successfully create the renderer (bug #1116) */
305 data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
307 SDL_DestroyRenderer(renderer);
308 return SDL_OutOfMemory();
310 SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data);
312 data->renderer = renderer;
315 /* Free any old texture and pixel data */
317 SDL_DestroyTexture(data->texture);
318 data->texture = NULL;
320 SDL_free(data->pixels);
324 SDL_RendererInfo info;
327 if (SDL_GetRendererInfo(data->renderer, &info) < 0) {
331 /* Find the first format without an alpha channel */
332 *format = info.texture_formats[0];
334 for (i = 0; i < info.num_texture_formats; ++i) {
335 if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) &&
336 !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) {
337 *format = info.texture_formats[i];
343 data->texture = SDL_CreateTexture(data->renderer, *format,
344 SDL_TEXTUREACCESS_STREAMING,
345 window->w, window->h);
346 if (!data->texture) {
350 /* Create framebuffer data */
351 data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
352 data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
355 /* Make static analysis happy about potential malloc(0) calls. */
356 const size_t allocsize = window->h * data->pitch;
357 data->pixels = SDL_malloc((allocsize > 0) ? allocsize : 1);
359 return SDL_OutOfMemory();
363 *pixels = data->pixels;
364 *pitch = data->pitch;
366 /* Make sure we're not double-scaling the viewport */
367 SDL_RenderSetViewport(data->renderer, NULL);
373 SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, const SDL_Rect * rects, int numrects)
375 SDL_WindowTextureData *data;
379 data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
380 if (!data || !data->texture) {
381 return SDL_SetError("No window texture data");
384 /* Update a single rect that contains subrects for best DMA performance */
385 if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
386 src = (void *)((Uint8 *)data->pixels +
387 rect.y * data->pitch +
388 rect.x * data->bytes_per_pixel);
389 if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) {
393 if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) {
397 SDL_RenderPresent(data->renderer);
403 SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window)
405 SDL_WindowTextureData *data;
407 data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL);
412 SDL_DestroyTexture(data->texture);
414 if (data->renderer) {
415 SDL_DestroyRenderer(data->renderer);
417 SDL_free(data->pixels);
423 cmpmodes(const void *A, const void *B)
425 const SDL_DisplayMode *a = (const SDL_DisplayMode *) A;
426 const SDL_DisplayMode *b = (const SDL_DisplayMode *) B;
429 } else if (a->w != b->w) {
431 } else if (a->h != b->h) {
433 } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) {
434 return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format);
435 } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) {
436 return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format);
437 } else if (a->refresh_rate != b->refresh_rate) {
438 return b->refresh_rate - a->refresh_rate;
444 SDL_UninitializedVideo()
446 return SDL_SetError("Video subsystem has not been initialized");
450 SDL_GetNumVideoDrivers(void)
452 return SDL_arraysize(bootstrap) - 1;
456 SDL_GetVideoDriver(int index)
458 if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
459 return bootstrap[index]->name;
465 * Initialize the video and event subsystems -- determine native pixel format
468 SDL_VideoInit(const char *driver_name)
470 SDL_VideoDevice *video;
474 /* Check to make sure we don't overwrite '_this' */
479 #if !SDL_TIMERS_DISABLED
483 /* Start the event loop */
484 if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 ||
485 SDL_KeyboardInit() < 0 ||
486 SDL_MouseInit() < 0 ||
487 SDL_TouchInit() < 0) {
491 /* Select the proper video driver */
494 if (driver_name == NULL) {
495 driver_name = SDL_getenv("SDL_VIDEODRIVER");
499 if (driver_name == NULL) {
500 driver_name = "tizen";
503 if (driver_name != NULL) {
504 for (i = 0; bootstrap[i]; ++i) {
505 if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) {
506 if (bootstrap[i]->available()) {
507 video = bootstrap[i]->create(index);
513 for (i = 0; bootstrap[i]; ++i) {
514 if (bootstrap[i]->available()) {
515 video = bootstrap[i]->create(index);
524 return SDL_SetError("%s not available", driver_name);
526 return SDL_SetError("No available video device");
529 _this->name = bootstrap[i]->name;
530 _this->next_object_id = 1;
533 /* Set some very sane GL defaults */
534 _this->gl_config.driver_loaded = 0;
535 _this->gl_config.dll_handle = NULL;
536 SDL_GL_ResetAttributes();
538 _this->current_glwin_tls = SDL_TLSCreate();
539 _this->current_glctx_tls = SDL_TLSCreate();
541 /* Set vk_config to default values */
543 /* Initialize the video subsystem */
544 if (_this->VideoInit(_this) < 0) {
549 /* Make sure some displays were added */
550 if (_this->num_displays == 0) {
552 return SDL_SetError("The video driver did not add any displays");
555 /* Add the renderer framebuffer emulation if desired */
556 if (ShouldUseTextureFramebuffer()) {
557 _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
558 _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
559 _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
562 /* Disable the screen saver by default. This is a change from <= 2.0.1,
563 but most things using SDL are games or media players; you wouldn't
564 want a screensaver to trigger if you're playing exclusively with a
565 joystick, or passively watching a movie. Things that use SDL but
566 function more like a normal desktop app should explicitly reenable the
568 if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, SDL_FALSE)) {
569 SDL_DisableScreenSaver();
572 /* If we don't use a screen keyboard, turn on text input by default,
573 otherwise programs that expect to get text events without enabling
574 UNICODE input won't get any events.
576 Actually, come to think of it, you needed to call SDL_EnableUNICODE(1)
577 in SDL 1.2 before you got text input events. Hmm...
579 if (!SDL_HasScreenKeyboardSupport()) {
580 SDL_StartTextInput();
583 /* We're ready to go! */
588 SDL_GetCurrentVideoDriver()
591 SDL_UninitializedVideo();
598 SDL_GetVideoDevice(void)
604 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
606 SDL_VideoDisplay display;
610 display.desktop_mode = *desktop_mode;
612 display.current_mode = display.desktop_mode;
614 return SDL_AddVideoDisplay(&display);
618 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
620 SDL_VideoDisplay *displays;
624 SDL_realloc(_this->displays,
625 (_this->num_displays + 1) * sizeof(*displays));
627 index = _this->num_displays++;
628 displays[index] = *display;
629 displays[index].device = _this;
630 _this->displays = displays;
633 displays[index].name = SDL_strdup(display->name);
637 SDL_itoa(index, name, 10);
638 displays[index].name = SDL_strdup(name);
647 SDL_GetNumVideoDisplays(void)
650 SDL_UninitializedVideo();
653 return _this->num_displays;
657 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
661 for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
662 if (display == &_this->displays[displayIndex]) {
667 /* Couldn't find the display, just use index 0 */
672 SDL_GetDisplayDriverData(int displayIndex)
674 CHECK_DISPLAY_INDEX(displayIndex, NULL);
676 return _this->displays[displayIndex].driverdata;
680 SDL_GetDisplayName(int displayIndex)
682 CHECK_DISPLAY_INDEX(displayIndex, NULL);
684 return _this->displays[displayIndex].name;
688 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
690 CHECK_DISPLAY_INDEX(displayIndex, -1);
693 SDL_VideoDisplay *display = &_this->displays[displayIndex];
695 if (_this->GetDisplayBounds) {
696 if (_this->GetDisplayBounds(_this, display, rect) == 0) {
701 /* Assume that the displays are left to right */
702 if (displayIndex == 0) {
706 SDL_GetDisplayBounds(displayIndex-1, rect);
709 rect->w = display->current_mode.w;
710 rect->h = display->current_mode.h;
712 return 0; /* !!! FIXME: should this be an error if (rect==NULL) ? */
715 int SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect)
717 CHECK_DISPLAY_INDEX(displayIndex, -1);
720 SDL_VideoDisplay *display = &_this->displays[displayIndex];
722 if (_this->GetDisplayUsableBounds) {
723 if (_this->GetDisplayUsableBounds(_this, display, rect) == 0) {
728 /* Oh well, just give the entire display bounds. */
729 return SDL_GetDisplayBounds(displayIndex, rect);
731 return 0; /* !!! FIXME: should this be an error if (rect==NULL) ? */
735 SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi)
737 SDL_VideoDisplay *display;
739 CHECK_DISPLAY_INDEX(displayIndex, -1);
741 display = &_this->displays[displayIndex];
743 if (_this->GetDisplayDPI) {
744 if (_this->GetDisplayDPI(_this, display, ddpi, hdpi, vdpi) == 0) {
748 return SDL_Unsupported();
755 SDL_AddDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
757 SDL_DisplayMode *modes;
760 /* Make sure we don't already have the mode in the list */
761 modes = display->display_modes;
762 nmodes = display->num_display_modes;
763 for (i = 0; i < nmodes; ++i) {
764 if (cmpmodes(mode, &modes[i]) == 0) {
769 /* Go ahead and add the new mode */
770 if (nmodes == display->max_display_modes) {
773 (display->max_display_modes + 32) * sizeof(*modes));
777 display->display_modes = modes;
778 display->max_display_modes += 32;
780 modes[nmodes] = *mode;
781 display->num_display_modes++;
783 /* Re-sort video modes */
784 SDL_qsort(display->display_modes, display->num_display_modes,
785 sizeof(SDL_DisplayMode), cmpmodes);
791 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
793 if (!display->num_display_modes && _this->GetDisplayModes) {
794 _this->GetDisplayModes(_this, display);
795 SDL_qsort(display->display_modes, display->num_display_modes,
796 sizeof(SDL_DisplayMode), cmpmodes);
798 return display->num_display_modes;
802 SDL_GetNumDisplayModes(int displayIndex)
804 CHECK_DISPLAY_INDEX(displayIndex, -1);
806 return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
810 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
812 SDL_VideoDisplay *display;
814 CHECK_DISPLAY_INDEX(displayIndex, -1);
816 display = &_this->displays[displayIndex];
817 if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
818 return SDL_SetError("index must be in the range of 0 - %d",
819 SDL_GetNumDisplayModesForDisplay(display) - 1);
822 *mode = display->display_modes[index];
828 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
830 SDL_VideoDisplay *display;
832 CHECK_DISPLAY_INDEX(displayIndex, -1);
834 display = &_this->displays[displayIndex];
836 *mode = display->desktop_mode;
842 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
844 SDL_VideoDisplay *display;
846 CHECK_DISPLAY_INDEX(displayIndex, -1);
848 display = &_this->displays[displayIndex];
850 *mode = display->current_mode;
855 static SDL_DisplayMode *
856 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
857 const SDL_DisplayMode * mode,
858 SDL_DisplayMode * closest)
860 Uint32 target_format;
861 int target_refresh_rate;
863 SDL_DisplayMode *current, *match;
865 if (!mode || !closest) {
866 SDL_SetError("Missing desired mode or closest mode parameter");
870 /* Default to the desktop format */
872 target_format = mode->format;
874 target_format = display->desktop_mode.format;
877 /* Default to the desktop refresh rate */
878 if (mode->refresh_rate) {
879 target_refresh_rate = mode->refresh_rate;
881 target_refresh_rate = display->desktop_mode.refresh_rate;
885 for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
886 current = &display->display_modes[i];
888 if (current->w && (current->w < mode->w)) {
889 /* Out of sorted modes large enough here */
892 if (current->h && (current->h < mode->h)) {
893 if (current->w && (current->w == mode->w)) {
894 /* Out of sorted modes large enough here */
897 /* Wider, but not tall enough, due to a different
898 aspect ratio. This mode must be skipped, but closer
899 modes may still follow. */
902 if (!match || current->w < match->w || current->h < match->h) {
906 if (current->format != match->format) {
907 /* Sorted highest depth to lowest */
908 if (current->format == target_format ||
909 (SDL_BITSPERPIXEL(current->format) >=
910 SDL_BITSPERPIXEL(target_format)
911 && SDL_PIXELTYPE(current->format) ==
912 SDL_PIXELTYPE(target_format))) {
917 if (current->refresh_rate != match->refresh_rate) {
918 /* Sorted highest refresh to lowest */
919 if (current->refresh_rate >= target_refresh_rate) {
926 closest->format = match->format;
928 closest->format = mode->format;
930 if (match->w && match->h) {
931 closest->w = match->w;
932 closest->h = match->h;
934 closest->w = mode->w;
935 closest->h = mode->h;
937 if (match->refresh_rate) {
938 closest->refresh_rate = match->refresh_rate;
940 closest->refresh_rate = mode->refresh_rate;
942 closest->driverdata = match->driverdata;
945 * Pick some reasonable defaults if the app and driver don't
948 if (!closest->format) {
949 closest->format = SDL_PIXELFORMAT_RGB888;
963 SDL_GetClosestDisplayMode(int displayIndex,
964 const SDL_DisplayMode * mode,
965 SDL_DisplayMode * closest)
967 SDL_VideoDisplay *display;
969 CHECK_DISPLAY_INDEX(displayIndex, NULL);
971 display = &_this->displays[displayIndex];
972 return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
976 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
978 SDL_DisplayMode display_mode;
979 SDL_DisplayMode current_mode;
982 display_mode = *mode;
984 /* Default to the current mode */
985 if (!display_mode.format) {
986 display_mode.format = display->current_mode.format;
988 if (!display_mode.w) {
989 display_mode.w = display->current_mode.w;
991 if (!display_mode.h) {
992 display_mode.h = display->current_mode.h;
994 if (!display_mode.refresh_rate) {
995 display_mode.refresh_rate = display->current_mode.refresh_rate;
998 /* Get a good video mode, the closest one possible */
999 if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
1000 return SDL_SetError("No video mode large enough for %dx%d",
1001 display_mode.w, display_mode.h);
1004 display_mode = display->desktop_mode;
1007 /* See if there's anything left to do */
1008 current_mode = display->current_mode;
1009 if (SDL_memcmp(&display_mode, ¤t_mode, sizeof(display_mode)) == 0) {
1013 /* Actually change the display mode */
1014 if (!_this->SetDisplayMode) {
1015 return SDL_SetError("Video driver doesn't support changing display mode");
1017 if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
1020 display->current_mode = display_mode;
1025 SDL_GetWindowDisplayIndex(SDL_Window * window)
1030 int closest_dist = 0x7FFFFFFF;
1035 CHECK_WINDOW_MAGIC(window, -1);
1037 if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
1038 SDL_WINDOWPOS_ISCENTERED(window->x)) {
1039 displayIndex = (window->x & 0xFFFF);
1040 if (displayIndex >= _this->num_displays) {
1043 return displayIndex;
1045 if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
1046 SDL_WINDOWPOS_ISCENTERED(window->y)) {
1047 displayIndex = (window->y & 0xFFFF);
1048 if (displayIndex >= _this->num_displays) {
1051 return displayIndex;
1054 /* Find the display containing the window */
1055 for (i = 0; i < _this->num_displays; ++i) {
1056 SDL_VideoDisplay *display = &_this->displays[i];
1058 if (display->fullscreen_window == window) {
1062 center.x = window->x + window->w / 2;
1063 center.y = window->y + window->h / 2;
1064 for (i = 0; i < _this->num_displays; ++i) {
1065 SDL_GetDisplayBounds(i, &rect);
1066 if (SDL_EnclosePoints(¢er, 1, &rect, NULL)) {
1070 delta.x = center.x - (rect.x + rect.w / 2);
1071 delta.y = center.y - (rect.y + rect.h / 2);
1072 dist = (delta.x*delta.x + delta.y*delta.y);
1073 if (dist < closest_dist) {
1075 closest_dist = dist;
1079 SDL_SetError("Couldn't find any displays");
1085 SDL_GetDisplayForWindow(SDL_Window *window)
1087 int displayIndex = SDL_GetWindowDisplayIndex(window);
1088 if (displayIndex >= 0) {
1089 return &_this->displays[displayIndex];
1096 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
1098 CHECK_WINDOW_MAGIC(window, -1);
1101 window->fullscreen_mode = *mode;
1103 SDL_zero(window->fullscreen_mode);
1106 if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
1107 SDL_DisplayMode fullscreen_mode;
1108 if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
1109 SDL_SetDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode);
1116 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
1118 SDL_DisplayMode fullscreen_mode;
1119 SDL_VideoDisplay *display;
1121 CHECK_WINDOW_MAGIC(window, -1);
1124 return SDL_InvalidParamError("mode");
1127 fullscreen_mode = window->fullscreen_mode;
1128 if (!fullscreen_mode.w) {
1129 fullscreen_mode.w = window->windowed.w;
1131 if (!fullscreen_mode.h) {
1132 fullscreen_mode.h = window->windowed.h;
1135 display = SDL_GetDisplayForWindow(window);
1137 /* if in desktop size mode, just return the size of the desktop */
1138 if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
1139 fullscreen_mode = display->desktop_mode;
1140 } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
1142 &fullscreen_mode)) {
1143 return SDL_SetError("Couldn't find display mode match");
1147 *mode = fullscreen_mode;
1153 SDL_GetWindowPixelFormat(SDL_Window * window)
1155 SDL_VideoDisplay *display;
1157 CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
1159 display = SDL_GetDisplayForWindow(window);
1160 return display->current_mode.format;
1164 SDL_RestoreMousePosition(SDL_Window *window)
1168 if (window == SDL_GetMouseFocus()) {
1169 SDL_GetMouseState(&x, &y);
1170 SDL_WarpMouseInWindow(window, x, y);
1175 extern Uint32 WINRT_DetectWindowFlags(SDL_Window * window);
1179 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
1181 SDL_VideoDisplay *display;
1184 CHECK_WINDOW_MAGIC(window,-1);
1186 /* if we are in the process of hiding don't go back to fullscreen */
1187 if (window->is_hiding && fullscreen) {
1192 /* if the window is going away and no resolution change is necessary,
1193 do nothing, or else we may trigger an ugly double-transition
1195 if (SDL_strcmp(_this->name, "cocoa") == 0) { /* don't do this for X11, etc */
1196 if (window->is_destroying && (window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP)
1199 /* If we're switching between a fullscreen Space and "normal" fullscreen, we need to get back to normal first. */
1200 if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN)) {
1201 if (!Cocoa_SetWindowFullscreenSpace(window, SDL_FALSE)) {
1204 } else if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP)) {
1205 display = SDL_GetDisplayForWindow(window);
1206 SDL_SetDisplayModeForDisplay(display, NULL);
1207 if (_this->SetWindowFullscreen) {
1208 _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
1212 if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
1213 if (Cocoa_IsWindowInFullscreenSpace(window) != fullscreen) {
1216 window->last_fullscreen_flags = window->flags;
1220 #elif __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
1221 /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
1222 or not. The user can choose this, via OS-provided UI, but this can't
1223 be set programmatically.
1225 Just look at what SDL's WinRT video backend code detected with regards
1226 to fullscreen (being active, or not), and figure out a return/error code
1229 if (fullscreen == !(WINRT_DetectWindowFlags(window) & FULLSCREEN_MASK)) {
1231 1. fullscreen was requested, and we're already windowed
1232 2. windowed-mode was requested, and we're already fullscreen
1234 WinRT 8.x can't resolve either programmatically, so we're
1239 /* Whatever was requested, fullscreen or windowed mode, is already
1246 display = SDL_GetDisplayForWindow(window);
1249 /* Hide any other fullscreen windows */
1250 if (display->fullscreen_window &&
1251 display->fullscreen_window != window) {
1252 SDL_MinimizeWindow(display->fullscreen_window);
1256 /* See if anything needs to be done now */
1257 if ((display->fullscreen_window == window) == fullscreen) {
1258 if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
1263 /* See if there are any fullscreen windows */
1264 for (other = _this->windows; other; other = other->next) {
1265 SDL_bool setDisplayMode = SDL_FALSE;
1267 if (other == window) {
1268 setDisplayMode = fullscreen;
1269 } else if (FULLSCREEN_VISIBLE(other) &&
1270 SDL_GetDisplayForWindow(other) == display) {
1271 setDisplayMode = SDL_TRUE;
1274 if (setDisplayMode) {
1275 SDL_DisplayMode fullscreen_mode;
1277 SDL_zero(fullscreen_mode);
1279 if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
1280 SDL_bool resized = SDL_TRUE;
1282 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
1283 resized = SDL_FALSE;
1286 /* only do the mode change if we want exclusive fullscreen */
1287 if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
1288 if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
1292 if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
1297 if (_this->SetWindowFullscreen) {
1298 _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
1300 display->fullscreen_window = other;
1302 /* Generate a mode change event here */
1304 SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
1305 fullscreen_mode.w, fullscreen_mode.h);
1307 SDL_OnWindowResized(other);
1310 SDL_RestoreMousePosition(other);
1312 window->last_fullscreen_flags = window->flags;
1318 /* Nope, restore the desktop mode */
1319 SDL_SetDisplayModeForDisplay(display, NULL);
1321 if (_this->SetWindowFullscreen) {
1322 _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
1324 display->fullscreen_window = NULL;
1326 /* Generate a mode change event here */
1327 SDL_OnWindowResized(window);
1329 /* Restore the cursor position */
1330 SDL_RestoreMousePosition(window);
1332 window->last_fullscreen_flags = window->flags;
1336 #define CREATE_FLAGS \
1337 (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)
1340 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
1342 if (flags & SDL_WINDOW_MAXIMIZED) {
1343 SDL_MaximizeWindow(window);
1345 if (flags & SDL_WINDOW_MINIMIZED) {
1346 SDL_MinimizeWindow(window);
1348 if (flags & SDL_WINDOW_FULLSCREEN) {
1349 SDL_SetWindowFullscreen(window, flags);
1351 if (flags & SDL_WINDOW_INPUT_GRABBED) {
1352 SDL_SetWindowGrab(window, SDL_TRUE);
1354 if (!(flags & SDL_WINDOW_HIDDEN)) {
1355 SDL_ShowWindow(window);
1360 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
1365 /* Initialize the video system if needed */
1366 if (SDL_VideoInit(NULL) < 0) {
1371 if ((((flags & SDL_WINDOW_UTILITY) != 0) + ((flags & SDL_WINDOW_TOOLTIP) != 0) + ((flags & SDL_WINDOW_POPUP_MENU) != 0)) > 1) {
1372 SDL_SetError("Conflicting window flags specified");
1376 /* Some platforms can't create zero-sized windows */
1384 /* Some platforms blow up if the windows are too large. Raise it later? */
1385 if ((w > 16384) || (h > 16384)) {
1386 SDL_SetError("Window is too large.");
1390 /* Some platforms have OpenGL enabled by default */
1391 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
1392 if (!_this->is_dummy && !(flags & SDL_WINDOW_VULKAN)) {
1393 flags |= SDL_WINDOW_OPENGL;
1396 if (flags & SDL_WINDOW_OPENGL) {
1397 if (!_this->GL_CreateContext) {
1398 SDL_SetError("No OpenGL support in video driver");
1401 if (SDL_GL_LoadLibrary(NULL) < 0) {
1408 if ((flags & SDL_WINDOW_OPENGL) && (flags & SDL_WINDOW_VULKAN)) {
1409 SDL_SetError("Don't use both OPENGL and VULKAN");
1414 if (flags & SDL_WINDOW_VULKAN) {
1415 if (!_this->Vulkan_CreateSurface) {
1416 SDL_SetError("Vulkan support is either not configured in SDL "
1417 "or not available in video driver");
1420 if (flags & SDL_WINDOW_OPENGL) {
1421 SDL_SetError("Vulkan and OpenGL not supported on same window");
1424 if (SDL_Vulkan_LoadLibrary(NULL) < 0) {
1429 /* Unless the user has specified the high-DPI disabling hint, respect the
1430 * SDL_WINDOW_ALLOW_HIGHDPI flag.
1432 if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
1433 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_HIGHDPI_DISABLED, SDL_FALSE)) {
1434 flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
1438 window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
1443 window->magic = &_this->window_magic;
1444 window->id = _this->next_object_id++;
1449 if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
1450 SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
1451 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1455 displayIndex = SDL_GetIndexOfDisplay(display);
1456 SDL_GetDisplayBounds(displayIndex, &bounds);
1457 if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
1458 window->x = bounds.x + (bounds.w - w) / 2;
1460 if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
1461 window->y = bounds.y + (bounds.h - h) / 2;
1464 window->windowed.x = window->x;
1465 window->windowed.y = window->y;
1466 window->windowed.w = window->w;
1467 window->windowed.h = window->h;
1469 if (flags & SDL_WINDOW_FULLSCREEN) {
1470 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1474 displayIndex = SDL_GetIndexOfDisplay(display);
1475 SDL_GetDisplayBounds(displayIndex, &bounds);
1477 window->x = bounds.x;
1478 window->y = bounds.y;
1479 window->w = bounds.w;
1480 window->h = bounds.h;
1483 window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
1484 window->last_fullscreen_flags = window->flags;
1485 window->opacity = 1.0f;
1486 window->brightness = 1.0f;
1487 window->next = _this->windows;
1488 window->is_destroying = SDL_FALSE;
1491 if (_this->windows) {
1492 _this->windows->prev = window;
1494 _this->windows = window;
1496 if (_this->CreateSDLWindow && _this->CreateSDLWindow(_this, window) < 0) {
1497 SDL_DestroyWindow(window);
1501 #if __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
1502 /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
1503 or not. The user can choose this, via OS-provided UI, but this can't
1504 be set programmatically.
1506 Just look at what SDL's WinRT video backend code detected with regards
1507 to fullscreen (being active, or not), and figure out a return/error code
1510 flags = window->flags;
1514 SDL_SetWindowTitle(window, title);
1516 SDL_FinishWindowCreation(window, flags);
1518 /* If the window was created fullscreen, make sure the mode code matches */
1519 SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
1525 SDL_CreateWindowFrom(const void *data)
1530 SDL_UninitializedVideo();
1533 if (!_this->CreateSDLWindowFrom) {
1537 window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
1542 window->magic = &_this->window_magic;
1543 window->id = _this->next_object_id++;
1544 window->flags = SDL_WINDOW_FOREIGN;
1545 window->last_fullscreen_flags = window->flags;
1546 window->is_destroying = SDL_FALSE;
1547 window->opacity = 1.0f;
1548 window->brightness = 1.0f;
1549 window->next = _this->windows;
1550 if (_this->windows) {
1551 _this->windows->prev = window;
1553 _this->windows = window;
1555 if (_this->CreateSDLWindowFrom(_this, window, data) < 0) {
1556 SDL_DestroyWindow(window);
1563 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
1565 SDL_bool loaded_opengl = SDL_FALSE;
1567 if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
1568 return SDL_SetError("No OpenGL support in video driver");
1571 if (window->flags & SDL_WINDOW_FOREIGN) {
1572 /* Can't destroy and re-create foreign windows, hrm */
1573 flags |= SDL_WINDOW_FOREIGN;
1575 flags &= ~SDL_WINDOW_FOREIGN;
1578 /* Restore video mode, etc. */
1579 SDL_HideWindow(window);
1581 /* Tear down the old native window */
1582 if (window->surface) {
1583 window->surface->flags &= ~SDL_DONTFREE;
1584 SDL_FreeSurface(window->surface);
1585 window->surface = NULL;
1587 if (_this->DestroyWindowFramebuffer) {
1588 _this->DestroyWindowFramebuffer(_this, window);
1590 if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
1591 _this->DestroyWindow(_this, window);
1594 if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
1595 if (flags & SDL_WINDOW_OPENGL) {
1596 if (SDL_GL_LoadLibrary(NULL) < 0) {
1599 loaded_opengl = SDL_TRUE;
1601 SDL_GL_UnloadLibrary();
1605 if ((window->flags & SDL_WINDOW_VULKAN) != (flags & SDL_WINDOW_VULKAN)) {
1606 SDL_SetError("Can't change SDL_WINDOW_VULKAN window flag");
1610 if ((window->flags & SDL_WINDOW_VULKAN) && (flags & SDL_WINDOW_OPENGL)) {
1611 SDL_SetError("Vulkan and OpenGL not supported on same window");
1615 window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
1616 window->last_fullscreen_flags = window->flags;
1617 window->is_destroying = SDL_FALSE;
1619 if (_this->CreateSDLWindow && !(flags & SDL_WINDOW_FOREIGN)) {
1620 if (_this->CreateSDLWindow(_this, window) < 0) {
1621 if (loaded_opengl) {
1622 SDL_GL_UnloadLibrary();
1623 window->flags &= ~SDL_WINDOW_OPENGL;
1629 if (flags & SDL_WINDOW_FOREIGN) {
1630 window->flags |= SDL_WINDOW_FOREIGN;
1633 if (_this->SetWindowTitle && window->title) {
1634 _this->SetWindowTitle(_this, window);
1637 if (_this->SetWindowIcon && window->icon) {
1638 _this->SetWindowIcon(_this, window, window->icon);
1641 if (window->hit_test) {
1642 _this->SetWindowHitTest(window, SDL_TRUE);
1645 SDL_FinishWindowCreation(window, flags);
1651 SDL_HasWindows(void)
1653 return (_this && _this->windows != NULL);
1657 SDL_GetWindowID(SDL_Window * window)
1659 CHECK_WINDOW_MAGIC(window, 0);
1665 SDL_GetWindowFromID(Uint32 id)
1672 for (window = _this->windows; window; window = window->next) {
1673 if (window->id == id) {
1681 SDL_GetWindowFlags(SDL_Window * window)
1683 CHECK_WINDOW_MAGIC(window, 0);
1685 return window->flags;
1689 SDL_SetWindowTitle(SDL_Window * window, const char *title)
1691 CHECK_WINDOW_MAGIC(window,);
1693 if (title == window->title) {
1696 SDL_free(window->title);
1698 window->title = SDL_strdup(title ? title : "");
1700 if (_this->SetWindowTitle) {
1701 _this->SetWindowTitle(_this, window);
1706 SDL_GetWindowTitle(SDL_Window * window)
1708 CHECK_WINDOW_MAGIC(window, "");
1710 return window->title ? window->title : "";
1714 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
1716 CHECK_WINDOW_MAGIC(window,);
1722 SDL_FreeSurface(window->icon);
1724 /* Convert the icon into ARGB8888 */
1725 window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
1726 if (!window->icon) {
1730 if (_this->SetWindowIcon) {
1731 _this->SetWindowIcon(_this, window, window->icon);
1736 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
1738 SDL_WindowUserData *prev, *data;
1740 CHECK_WINDOW_MAGIC(window, NULL);
1742 /* Input validation */
1743 if (name == NULL || name[0] == '\0') {
1744 SDL_InvalidParamError("name");
1748 /* See if the named data already exists */
1750 for (data = window->data; data; prev = data, data = data->next) {
1751 if (data->name && SDL_strcmp(data->name, name) == 0) {
1752 void *last_value = data->data;
1755 /* Set the new value */
1756 data->data = userdata;
1758 /* Delete this value */
1760 prev->next = data->next;
1762 window->data = data->next;
1764 SDL_free(data->name);
1771 /* Add new data to the window */
1773 data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
1774 data->name = SDL_strdup(name);
1775 data->data = userdata;
1776 data->next = window->data;
1777 window->data = data;
1783 SDL_GetWindowData(SDL_Window * window, const char *name)
1785 SDL_WindowUserData *data;
1787 CHECK_WINDOW_MAGIC(window, NULL);
1789 /* Input validation */
1790 if (name == NULL || name[0] == '\0') {
1791 SDL_InvalidParamError("name");
1795 for (data = window->data; data; data = data->next) {
1796 if (data->name && SDL_strcmp(data->name, name) == 0) {
1804 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
1806 CHECK_WINDOW_MAGIC(window,);
1808 if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
1809 int displayIndex = (x & 0xFFFF);
1811 if (displayIndex >= _this->num_displays) {
1817 SDL_GetDisplayBounds(displayIndex, &bounds);
1818 if (SDL_WINDOWPOS_ISCENTERED(x)) {
1819 x = bounds.x + (bounds.w - window->w) / 2;
1821 if (SDL_WINDOWPOS_ISCENTERED(y)) {
1822 y = bounds.y + (bounds.h - window->h) / 2;
1826 if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
1827 if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
1828 window->windowed.x = x;
1830 if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
1831 window->windowed.y = y;
1834 if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
1837 if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
1841 if (_this->SetWindowPosition) {
1842 _this->SetWindowPosition(_this, window);
1844 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
1849 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
1851 CHECK_WINDOW_MAGIC(window,);
1853 /* Fullscreen windows are always at their display's origin */
1854 if (window->flags & SDL_WINDOW_FULLSCREEN) {
1864 /* Find the window's monitor and update to the
1866 displayIndex = SDL_GetWindowDisplayIndex(window);
1867 if (displayIndex >= 0) {
1872 SDL_GetDisplayBounds(displayIndex, &bounds);
1891 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
1893 CHECK_WINDOW_MAGIC(window,);
1894 if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1895 const int want = (bordered != SDL_FALSE); /* normalize the flag. */
1896 const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
1897 if ((want != have) && (_this->SetWindowBordered)) {
1899 window->flags &= ~SDL_WINDOW_BORDERLESS;
1901 window->flags |= SDL_WINDOW_BORDERLESS;
1903 _this->SetWindowBordered(_this, window, (SDL_bool) want);
1909 SDL_SetWindowResizable(SDL_Window * window, SDL_bool resizable)
1911 CHECK_WINDOW_MAGIC(window,);
1912 if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1913 const int want = (resizable != SDL_FALSE); /* normalize the flag. */
1914 const int have = ((window->flags & SDL_WINDOW_RESIZABLE) != 0);
1915 if ((want != have) && (_this->SetWindowResizable)) {
1917 window->flags |= SDL_WINDOW_RESIZABLE;
1919 window->flags &= ~SDL_WINDOW_RESIZABLE;
1921 _this->SetWindowResizable(_this, window, (SDL_bool) want);
1927 SDL_SetWindowSize(SDL_Window * window, int w, int h)
1929 CHECK_WINDOW_MAGIC(window,);
1931 SDL_InvalidParamError("w");
1935 SDL_InvalidParamError("h");
1939 /* Make sure we don't exceed any window size limits */
1940 if (window->min_w && w < window->min_w) {
1943 if (window->max_w && w > window->max_w) {
1946 if (window->min_h && h < window->min_h) {
1949 if (window->max_h && h > window->max_h) {
1953 window->windowed.w = w;
1954 window->windowed.h = h;
1956 if (window->flags & SDL_WINDOW_FULLSCREEN) {
1957 if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
1958 window->last_fullscreen_flags = 0;
1959 SDL_UpdateFullscreenMode(window, SDL_TRUE);
1964 if (_this->SetWindowSize) {
1965 _this->SetWindowSize(_this, window);
1967 if (window->w == w && window->h == h) {
1968 /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
1969 SDL_OnWindowResized(window);
1975 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
1977 CHECK_WINDOW_MAGIC(window,);
1979 if (_this->GetWindowSize) {
1980 _this->GetWindowSize(_this, window, w, h);
2001 SDL_GetWindowBordersSize(SDL_Window * window, int *top, int *left, int *bottom, int *right)
2005 if (!top) { top = &dummy; }
2006 if (!left) { left = &dummy; }
2007 if (!right) { right = &dummy; }
2008 if (!bottom) { bottom = &dummy; }
2010 /* Always initialize, so applications don't have to care */
2011 *top = *left = *bottom = *right = 0;
2013 CHECK_WINDOW_MAGIC(window, -1);
2015 if (!_this->GetWindowBordersSize) {
2016 return SDL_Unsupported();
2019 return _this->GetWindowBordersSize(_this, window, top, left, bottom, right);
2023 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
2025 CHECK_WINDOW_MAGIC(window,);
2027 SDL_InvalidParamError("min_w");
2031 SDL_InvalidParamError("min_h");
2035 if ((window->max_w && min_w >= window->max_w) ||
2036 (window->max_h && min_h >= window->max_h)) {
2037 SDL_SetError("SDL_SetWindowMinimumSize(): Tried to set minimum size larger than maximum size");
2041 window->min_w = min_w;
2042 window->min_h = min_h;
2044 if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
2045 if (_this->SetWindowMinimumSize) {
2046 _this->SetWindowMinimumSize(_this, window);
2048 /* Ensure that window is not smaller than minimal size */
2049 SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
2054 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
2056 CHECK_WINDOW_MAGIC(window,);
2058 *min_w = window->min_w;
2061 *min_h = window->min_h;
2066 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
2068 CHECK_WINDOW_MAGIC(window,);
2070 SDL_InvalidParamError("max_w");
2074 SDL_InvalidParamError("max_h");
2078 if (max_w <= window->min_w || max_h <= window->min_h) {
2079 SDL_SetError("SDL_SetWindowMaximumSize(): Tried to set maximum size smaller than minimum size");
2083 window->max_w = max_w;
2084 window->max_h = max_h;
2086 if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
2087 if (_this->SetWindowMaximumSize) {
2088 _this->SetWindowMaximumSize(_this, window);
2090 /* Ensure that window is not larger than maximal size */
2091 SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
2096 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
2098 CHECK_WINDOW_MAGIC(window,);
2100 *max_w = window->max_w;
2103 *max_h = window->max_h;
2108 SDL_ShowWindow(SDL_Window * window)
2110 CHECK_WINDOW_MAGIC(window,);
2112 if (window->flags & SDL_WINDOW_SHOWN) {
2116 if (_this->ShowWindow) {
2117 _this->ShowWindow(_this, window);
2119 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
2123 SDL_HideWindow(SDL_Window * window)
2125 CHECK_WINDOW_MAGIC(window,);
2127 if (!(window->flags & SDL_WINDOW_SHOWN)) {
2131 window->is_hiding = SDL_TRUE;
2132 SDL_UpdateFullscreenMode(window, SDL_FALSE);
2134 if (_this->HideWindow) {
2135 _this->HideWindow(_this, window);
2137 window->is_hiding = SDL_FALSE;
2138 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
2142 SDL_RaiseWindow(SDL_Window * window)
2144 CHECK_WINDOW_MAGIC(window,);
2146 if (!(window->flags & SDL_WINDOW_SHOWN)) {
2149 if (_this->RaiseWindow) {
2150 _this->RaiseWindow(_this, window);
2155 SDL_MaximizeWindow(SDL_Window * window)
2157 CHECK_WINDOW_MAGIC(window,);
2159 if (window->flags & SDL_WINDOW_MAXIMIZED) {
2163 /* !!! FIXME: should this check if the window is resizable? */
2165 if (_this->MaximizeWindow) {
2166 _this->MaximizeWindow(_this, window);
2171 SDL_MinimizeWindow(SDL_Window * window)
2173 CHECK_WINDOW_MAGIC(window,);
2175 if (window->flags & SDL_WINDOW_MINIMIZED) {
2179 SDL_UpdateFullscreenMode(window, SDL_FALSE);
2181 if (_this->MinimizeWindow) {
2182 _this->MinimizeWindow(_this, window);
2187 SDL_RestoreWindow(SDL_Window * window)
2189 CHECK_WINDOW_MAGIC(window,);
2191 if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
2195 if (_this->RestoreWindow) {
2196 _this->RestoreWindow(_this, window);
2201 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
2204 CHECK_WINDOW_MAGIC(window, -1);
2206 flags &= FULLSCREEN_MASK;
2208 if (flags == (window->flags & FULLSCREEN_MASK)) {
2212 /* clear the previous flags and OR in the new ones */
2213 oldflags = window->flags & FULLSCREEN_MASK;
2214 window->flags &= ~FULLSCREEN_MASK;
2215 window->flags |= flags;
2217 if (SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)) == 0) {
2221 window->flags &= ~FULLSCREEN_MASK;
2222 window->flags |= oldflags;
2226 static SDL_Surface *
2227 SDL_CreateWindowFramebuffer(SDL_Window * window)
2233 Uint32 Rmask, Gmask, Bmask, Amask;
2235 if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
2239 if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
2243 if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
2247 return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
2251 SDL_GetWindowSurface(SDL_Window * window)
2253 CHECK_WINDOW_MAGIC(window, NULL);
2255 if (!window->surface_valid) {
2256 if (window->surface) {
2257 window->surface->flags &= ~SDL_DONTFREE;
2258 SDL_FreeSurface(window->surface);
2260 window->surface = SDL_CreateWindowFramebuffer(window);
2261 if (window->surface) {
2262 window->surface_valid = SDL_TRUE;
2263 window->surface->flags |= SDL_DONTFREE;
2266 return window->surface;
2270 SDL_UpdateWindowSurface(SDL_Window * window)
2274 CHECK_WINDOW_MAGIC(window, -1);
2278 full_rect.w = window->w;
2279 full_rect.h = window->h;
2280 return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
2284 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
2287 CHECK_WINDOW_MAGIC(window, -1);
2289 if (!window->surface_valid) {
2290 return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
2293 return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
2297 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
2302 CHECK_WINDOW_MAGIC(window, -1);
2304 SDL_CalculateGammaRamp(brightness, ramp);
2305 status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
2307 window->brightness = brightness;
2313 SDL_GetWindowBrightness(SDL_Window * window)
2315 CHECK_WINDOW_MAGIC(window, 1.0f);
2317 return window->brightness;
2321 SDL_SetWindowOpacity(SDL_Window * window, float opacity)
2324 CHECK_WINDOW_MAGIC(window, -1);
2326 if (!_this->SetWindowOpacity) {
2327 return SDL_Unsupported();
2330 if (opacity < 0.0f) {
2332 } else if (opacity > 1.0f) {
2336 retval = _this->SetWindowOpacity(_this, window, opacity);
2338 window->opacity = opacity;
2345 SDL_GetWindowOpacity(SDL_Window * window, float * out_opacity)
2347 CHECK_WINDOW_MAGIC(window, -1);
2350 *out_opacity = window->opacity;
2357 SDL_SetWindowModalFor(SDL_Window * modal_window, SDL_Window * parent_window)
2359 CHECK_WINDOW_MAGIC(modal_window, -1);
2360 CHECK_WINDOW_MAGIC(parent_window, -1);
2362 if (!_this->SetWindowModalFor) {
2363 return SDL_Unsupported();
2366 return _this->SetWindowModalFor(_this, modal_window, parent_window);
2370 SDL_SetWindowInputFocus(SDL_Window * window)
2372 CHECK_WINDOW_MAGIC(window, -1);
2374 if (!_this->SetWindowInputFocus) {
2375 return SDL_Unsupported();
2378 return _this->SetWindowInputFocus(_this, window);
2383 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
2384 const Uint16 * green,
2385 const Uint16 * blue)
2387 CHECK_WINDOW_MAGIC(window, -1);
2389 if (!_this->SetWindowGammaRamp) {
2390 return SDL_Unsupported();
2393 if (!window->gamma) {
2394 if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
2397 SDL_assert(window->gamma != NULL);
2401 SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
2404 SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
2407 SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
2409 if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
2410 return _this->SetWindowGammaRamp(_this, window, window->gamma);
2417 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
2421 CHECK_WINDOW_MAGIC(window, -1);
2423 if (!window->gamma) {
2426 window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
2427 if (!window->gamma) {
2428 return SDL_OutOfMemory();
2430 window->saved_gamma = window->gamma + 3*256;
2432 if (_this->GetWindowGammaRamp) {
2433 if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
2437 /* Create an identity gamma ramp */
2438 for (i = 0; i < 256; ++i) {
2439 Uint16 value = (Uint16)((i << 8) | i);
2441 window->gamma[0*256+i] = value;
2442 window->gamma[1*256+i] = value;
2443 window->gamma[2*256+i] = value;
2446 SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
2450 SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
2453 SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
2456 SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
2462 SDL_UpdateWindowGrab(SDL_Window * window)
2464 SDL_Window *grabbed_window;
2466 if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
2467 (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
2470 grabbed = SDL_FALSE;
2473 grabbed_window = _this->grabbed_window;
2475 if (grabbed_window && (grabbed_window != window)) {
2476 /* stealing a grab from another window! */
2477 grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
2478 if (_this->SetWindowGrab) {
2479 _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE);
2482 _this->grabbed_window = window;
2483 } else if (grabbed_window == window) {
2484 _this->grabbed_window = NULL; /* ungrabbing. */
2487 if (_this->SetWindowGrab) {
2488 _this->SetWindowGrab(_this, window, grabbed);
2493 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
2495 CHECK_WINDOW_MAGIC(window,);
2497 if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
2501 window->flags |= SDL_WINDOW_INPUT_GRABBED;
2503 window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
2505 SDL_UpdateWindowGrab(window);
2509 SDL_GetWindowGrab(SDL_Window * window)
2511 CHECK_WINDOW_MAGIC(window, SDL_FALSE);
2512 SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
2513 return window == _this->grabbed_window;
2517 SDL_GetGrabbedWindow(void)
2519 SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
2520 return _this->grabbed_window;
2524 SDL_OnWindowShown(SDL_Window * window)
2526 SDL_OnWindowRestored(window);
2530 SDL_OnWindowHidden(SDL_Window * window)
2532 SDL_UpdateFullscreenMode(window, SDL_FALSE);
2536 SDL_OnWindowResized(SDL_Window * window)
2538 window->surface_valid = SDL_FALSE;
2539 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
2543 SDL_OnWindowMinimized(SDL_Window * window)
2545 SDL_UpdateFullscreenMode(window, SDL_FALSE);
2549 SDL_OnWindowRestored(SDL_Window * window)
2552 * FIXME: Is this fine to just remove this, or should it be preserved just
2553 * for the fullscreen case? In principle it seems like just hiding/showing
2554 * windows shouldn't affect the stacking order; maybe the right fix is to
2555 * re-decouple OnWindowShown and OnWindowRestored.
2557 /*SDL_RaiseWindow(window);*/
2559 if (FULLSCREEN_VISIBLE(window)) {
2560 SDL_UpdateFullscreenMode(window, SDL_TRUE);
2565 SDL_OnWindowEnter(SDL_Window * window)
2567 if (_this->OnWindowEnter) {
2568 _this->OnWindowEnter(_this, window);
2573 SDL_OnWindowLeave(SDL_Window * window)
2578 SDL_OnWindowFocusGained(SDL_Window * window)
2580 SDL_Mouse *mouse = SDL_GetMouse();
2582 if (window->gamma && _this->SetWindowGammaRamp) {
2583 _this->SetWindowGammaRamp(_this, window, window->gamma);
2586 if (mouse && mouse->relative_mode) {
2587 SDL_SetMouseFocus(window);
2588 SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
2591 SDL_UpdateWindowGrab(window);
2595 ShouldMinimizeOnFocusLoss(SDL_Window * window)
2597 if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
2602 if (SDL_strcmp(_this->name, "cocoa") == 0) { /* don't do this for X11, etc */
2603 if (Cocoa_IsWindowInFullscreenSpace(window)) {
2609 return SDL_GetHintBoolean(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, SDL_TRUE);
2613 SDL_OnWindowFocusLost(SDL_Window * window)
2615 if (window->gamma && _this->SetWindowGammaRamp) {
2616 _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
2619 SDL_UpdateWindowGrab(window);
2621 if (ShouldMinimizeOnFocusLoss(window)) {
2622 SDL_MinimizeWindow(window);
2626 /* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
2627 !!! FIXME: Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
2629 SDL_GetFocusWindow(void)
2636 for (window = _this->windows; window; window = window->next) {
2637 if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
2645 SDL_DestroyWindow(SDL_Window * window)
2647 SDL_VideoDisplay *display;
2649 CHECK_WINDOW_MAGIC(window,);
2651 window->is_destroying = SDL_TRUE;
2653 /* Restore video mode, etc. */
2654 SDL_HideWindow(window);
2656 /* Make sure this window no longer has focus */
2657 if (SDL_GetKeyboardFocus() == window) {
2658 SDL_SetKeyboardFocus(NULL);
2660 if (SDL_GetMouseFocus() == window) {
2661 SDL_SetMouseFocus(NULL);
2664 /* make no context current if this is the current context window. */
2665 if (window->flags & SDL_WINDOW_OPENGL) {
2666 if (_this->current_glwin == window) {
2667 SDL_GL_MakeCurrent(window, NULL);
2671 if (window->surface) {
2672 window->surface->flags &= ~SDL_DONTFREE;
2673 SDL_FreeSurface(window->surface);
2675 if (_this->DestroyWindowFramebuffer) {
2676 _this->DestroyWindowFramebuffer(_this, window);
2678 if (_this->DestroyWindow) {
2679 _this->DestroyWindow(_this, window);
2681 if (window->flags & SDL_WINDOW_OPENGL) {
2682 SDL_GL_UnloadLibrary();
2684 if (window->flags & SDL_WINDOW_VULKAN) {
2685 SDL_Vulkan_UnloadLibrary();
2688 display = SDL_GetDisplayForWindow(window);
2689 if (display->fullscreen_window == window) {
2690 display->fullscreen_window = NULL;
2693 /* Now invalidate magic */
2694 window->magic = NULL;
2696 /* Free memory associated with the window */
2697 SDL_free(window->title);
2698 SDL_FreeSurface(window->icon);
2699 SDL_free(window->gamma);
2700 while (window->data) {
2701 SDL_WindowUserData *data = window->data;
2703 window->data = data->next;
2704 SDL_free(data->name);
2708 /* Unlink the window from the list */
2710 window->next->prev = window->prev;
2713 window->prev->next = window->next;
2715 _this->windows = window->next;
2722 SDL_IsScreenSaverEnabled()
2727 return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
2731 SDL_EnableScreenSaver()
2736 if (!_this->suspend_screensaver) {
2739 _this->suspend_screensaver = SDL_FALSE;
2740 if (_this->SuspendScreenSaver) {
2741 _this->SuspendScreenSaver(_this);
2746 SDL_DisableScreenSaver()
2751 if (_this->suspend_screensaver) {
2754 _this->suspend_screensaver = SDL_TRUE;
2755 if (_this->SuspendScreenSaver) {
2756 _this->SuspendScreenSaver(_this);
2769 /* Halt event processing before doing anything else */
2773 SDL_QuitSubSystem(SDL_INIT_EVENTS);
2775 SDL_EnableScreenSaver();
2777 /* Clean up the system video */
2778 while (_this->windows) {
2779 SDL_DestroyWindow(_this->windows);
2781 _this->VideoQuit(_this);
2783 for (i = 0; i < _this->num_displays; ++i) {
2784 SDL_VideoDisplay *display = &_this->displays[i];
2785 for (j = display->num_display_modes; j--;) {
2786 SDL_free(display->display_modes[j].driverdata);
2787 display->display_modes[j].driverdata = NULL;
2789 SDL_free(display->display_modes);
2790 display->display_modes = NULL;
2791 SDL_free(display->desktop_mode.driverdata);
2792 display->desktop_mode.driverdata = NULL;
2793 SDL_free(display->driverdata);
2794 display->driverdata = NULL;
2796 if (_this->displays) {
2797 for (i = 0; i < _this->num_displays; ++i) {
2798 SDL_free(_this->displays[i].name);
2800 SDL_free(_this->displays);
2801 _this->displays = NULL;
2802 _this->num_displays = 0;
2804 SDL_free(_this->clipboard_text);
2805 _this->clipboard_text = NULL;
2811 SDL_GL_LoadLibrary(const char *path)
2816 return SDL_UninitializedVideo();
2818 if (_this->gl_config.driver_loaded) {
2819 if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
2820 return SDL_SetError("OpenGL library already loaded");
2824 if (!_this->GL_LoadLibrary) {
2825 return SDL_SetError("No dynamic GL support in video driver");
2827 retval = _this->GL_LoadLibrary(_this, path);
2830 ++_this->gl_config.driver_loaded;
2832 if (_this->GL_UnloadLibrary) {
2833 _this->GL_UnloadLibrary(_this);
2840 SDL_GL_GetProcAddress(const char *proc)
2845 SDL_UninitializedVideo();
2849 if (_this->GL_GetProcAddress) {
2850 if (_this->gl_config.driver_loaded) {
2851 func = _this->GL_GetProcAddress(_this, proc);
2853 SDL_SetError("No GL driver has been loaded");
2856 SDL_SetError("No dynamic GL support in video driver");
2862 SDL_GL_UnloadLibrary(void)
2865 SDL_UninitializedVideo();
2868 if (_this->gl_config.driver_loaded > 0) {
2869 if (--_this->gl_config.driver_loaded > 0) {
2872 if (_this->GL_UnloadLibrary) {
2873 _this->GL_UnloadLibrary(_this);
2878 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2879 static SDL_INLINE SDL_bool
2880 isAtLeastGL3(const char *verstr)
2882 return (verstr && (SDL_atoi(verstr) >= 3));
2887 SDL_GL_ExtensionSupported(const char *extension)
2889 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2890 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
2891 const char *extensions;
2893 const char *where, *terminator;
2895 /* Extension names should not have spaces. */
2896 where = SDL_strchr(extension, ' ');
2897 if (where || *extension == '\0') {
2900 /* See if there's an environment variable override */
2901 start = SDL_getenv(extension);
2902 if (start && *start == '0') {
2906 /* Lookup the available extensions */
2908 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
2909 if (!glGetStringFunc) {
2913 if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
2914 const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
2915 void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
2919 glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
2920 glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
2921 if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
2925 #ifndef GL_NUM_EXTENSIONS
2926 #define GL_NUM_EXTENSIONS 0x821D
2928 glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
2929 for (i = 0; i < num_exts; i++) {
2930 const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
2931 if (SDL_strcmp(thisext, extension) == 0) {
2939 /* Try the old way with glGetString(GL_EXTENSIONS) ... */
2941 extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
2946 * It takes a bit of care to be fool-proof about parsing the OpenGL
2947 * extensions string. Don't be fooled by sub-strings, etc.
2953 where = SDL_strstr(start, extension);
2957 terminator = where + SDL_strlen(extension);
2958 if (where == extensions || *(where - 1) == ' ')
2959 if (*terminator == ' ' || *terminator == '\0')
2965 /* check EGL extensions (copied from SDL_EGL_HasExtension())*/
2970 const char *ext_word;
2972 char *Tizen_Not_Support_API[3] = {
2973 "EGL_EXT_buffer_age",
2974 "EGL_KHR_partial_update",
2975 "EGL_EXT_swap_buffers_with_damage"
2980 if(!SDL_strcmp(extension, Tizen_Not_Support_API[i]))
2984 ext_len = SDL_strlen(extension);
2985 exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
2990 for (i = 0; exts[i] != 0; i++) {
2991 if (exts[i] == ' ') {
2992 if (ext_len == len && !SDL_strncmp(ext_word, extension, len)) {
2997 ext_word = &exts[i + 1];
3011 /* Deduce supported ES profile versions from the supported
3012 ARB_ES*_compatibility extensions. There is no direct query.
3014 This is normally only called when the OpenGL driver supports
3015 {GLX,WGL}_EXT_create_context_es2_profile.
3018 SDL_GL_DeduceMaxSupportedESProfile(int* major, int* minor)
3020 /* THIS REQUIRES AN EXISTING GL CONTEXT THAT HAS BEEN MADE CURRENT. */
3021 /* Please refer to https://bugzilla.libsdl.org/show_bug.cgi?id=3725 for discussion. */
3022 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
3023 /* XXX This is fragile; it will break in the event of release of
3024 * new versions of OpenGL ES.
3026 if (SDL_GL_ExtensionSupported("GL_ARB_ES3_2_compatibility")) {
3029 } else if (SDL_GL_ExtensionSupported("GL_ARB_ES3_1_compatibility")) {
3032 } else if (SDL_GL_ExtensionSupported("GL_ARB_ES3_compatibility")) {
3043 SDL_GL_ResetAttributes()
3049 _this->gl_config.red_size = 3;
3050 _this->gl_config.green_size = 3;
3051 _this->gl_config.blue_size = 2;
3052 _this->gl_config.alpha_size = 0;
3053 _this->gl_config.buffer_size = 0;
3054 _this->gl_config.depth_size = 16;
3055 _this->gl_config.stencil_size = 0;
3056 _this->gl_config.double_buffer = 1;
3057 _this->gl_config.accum_red_size = 0;
3058 _this->gl_config.accum_green_size = 0;
3059 _this->gl_config.accum_blue_size = 0;
3060 _this->gl_config.accum_alpha_size = 0;
3061 _this->gl_config.stereo = 0;
3062 _this->gl_config.multisamplebuffers = 0;
3063 _this->gl_config.multisamplesamples = 0;
3064 _this->gl_config.retained_backing = 1;
3065 _this->gl_config.accelerated = -1; /* accelerated or not, both are fine */
3067 if (_this->GL_DefaultProfileConfig) {
3068 _this->GL_DefaultProfileConfig(_this, &_this->gl_config.profile_mask,
3069 &_this->gl_config.major_version,
3070 &_this->gl_config.minor_version);
3072 #if SDL_VIDEO_OPENGL
3073 _this->gl_config.major_version = 2;
3074 _this->gl_config.minor_version = 1;
3075 _this->gl_config.profile_mask = 0;
3076 #elif SDL_VIDEO_OPENGL_ES2
3077 _this->gl_config.major_version = 2;
3078 _this->gl_config.minor_version = 0;
3079 _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
3080 #elif SDL_VIDEO_OPENGL_ES
3081 _this->gl_config.major_version = 1;
3082 _this->gl_config.minor_version = 1;
3083 _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
3087 _this->gl_config.flags = 0;
3088 _this->gl_config.framebuffer_srgb_capable = 0;
3089 _this->gl_config.no_error = 0;
3090 _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH;
3091 _this->gl_config.reset_notification = SDL_GL_CONTEXT_RESET_NO_NOTIFICATION;
3093 _this->gl_config.share_with_current_context = 0;
3095 _this->gl_config.context_priority_level = SDL_GL_CONTEXT_PRIORITY_NONE;
3100 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
3102 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
3106 return SDL_UninitializedVideo();
3110 case SDL_GL_RED_SIZE:
3111 _this->gl_config.red_size = value;
3113 case SDL_GL_GREEN_SIZE:
3114 _this->gl_config.green_size = value;
3116 case SDL_GL_BLUE_SIZE:
3117 _this->gl_config.blue_size = value;
3119 case SDL_GL_ALPHA_SIZE:
3120 _this->gl_config.alpha_size = value;
3122 case SDL_GL_DOUBLEBUFFER:
3123 _this->gl_config.double_buffer = value;
3125 case SDL_GL_BUFFER_SIZE:
3126 _this->gl_config.buffer_size = value;
3128 case SDL_GL_DEPTH_SIZE:
3129 _this->gl_config.depth_size = value;
3131 case SDL_GL_STENCIL_SIZE:
3132 _this->gl_config.stencil_size = value;
3134 case SDL_GL_ACCUM_RED_SIZE:
3135 _this->gl_config.accum_red_size = value;
3137 case SDL_GL_ACCUM_GREEN_SIZE:
3138 _this->gl_config.accum_green_size = value;
3140 case SDL_GL_ACCUM_BLUE_SIZE:
3141 _this->gl_config.accum_blue_size = value;
3143 case SDL_GL_ACCUM_ALPHA_SIZE:
3144 _this->gl_config.accum_alpha_size = value;
3147 _this->gl_config.stereo = value;
3149 case SDL_GL_MULTISAMPLEBUFFERS:
3150 _this->gl_config.multisamplebuffers = value;
3152 case SDL_GL_MULTISAMPLESAMPLES:
3153 _this->gl_config.multisamplesamples = value;
3155 case SDL_GL_ACCELERATED_VISUAL:
3156 _this->gl_config.accelerated = value;
3158 case SDL_GL_RETAINED_BACKING:
3159 _this->gl_config.retained_backing = value;
3161 case SDL_GL_CONTEXT_MAJOR_VERSION:
3162 _this->gl_config.major_version = value;
3164 case SDL_GL_CONTEXT_MINOR_VERSION:
3165 _this->gl_config.minor_version = value;
3167 case SDL_GL_CONTEXT_EGL:
3168 /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
3170 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
3172 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
3175 case SDL_GL_CONTEXT_FLAGS:
3176 if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
3177 SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
3178 SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
3179 SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
3180 retval = SDL_SetError("Unknown OpenGL context flag %d", value);
3183 _this->gl_config.flags = value;
3185 case SDL_GL_CONTEXT_PROFILE_MASK:
3187 value != SDL_GL_CONTEXT_PROFILE_CORE &&
3188 value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
3189 value != SDL_GL_CONTEXT_PROFILE_ES) {
3190 retval = SDL_SetError("Unknown OpenGL context profile %d", value);
3193 _this->gl_config.profile_mask = value;
3195 case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
3196 _this->gl_config.share_with_current_context = value;
3198 case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
3199 _this->gl_config.framebuffer_srgb_capable = value;
3201 case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
3202 _this->gl_config.release_behavior = value;
3204 case SDL_GL_CONTEXT_RESET_NOTIFICATION:
3205 _this->gl_config.reset_notification = value;
3207 case SDL_GL_CONTEXT_NO_ERROR:
3208 _this->gl_config.no_error = value;
3211 case SDL_GL_CONTEXT_PRIORITY:
3212 _this->gl_config.context_priority_level = value;
3216 retval = SDL_SetError("Unknown OpenGL attribute");
3221 return SDL_Unsupported();
3222 #endif /* SDL_VIDEO_OPENGL */
3226 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
3228 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
3229 GLenum (APIENTRY *glGetErrorFunc) (void);
3234 * Some queries in Core Profile desktop OpenGL 3+ contexts require
3235 * glGetFramebufferAttachmentParameteriv instead of glGetIntegerv. Note that
3236 * the enums we use for the former function don't exist in OpenGL ES 2, and
3237 * the function itself doesn't exist prior to OpenGL 3 and OpenGL ES 2.
3239 #if SDL_VIDEO_OPENGL
3240 const GLubyte *(APIENTRY *glGetStringFunc) (GLenum name);
3241 void (APIENTRY *glGetFramebufferAttachmentParameterivFunc) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
3242 GLenum attachment = GL_BACK_LEFT;
3243 GLenum attachmentattrib = 0;
3247 return SDL_InvalidParamError("value");
3250 /* Clear value in any case */
3254 return SDL_UninitializedVideo();
3258 case SDL_GL_RED_SIZE:
3259 #if SDL_VIDEO_OPENGL
3260 attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE;
3262 attrib = GL_RED_BITS;
3264 case SDL_GL_BLUE_SIZE:
3265 #if SDL_VIDEO_OPENGL
3266 attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE;
3268 attrib = GL_BLUE_BITS;
3270 case SDL_GL_GREEN_SIZE:
3271 #if SDL_VIDEO_OPENGL
3272 attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE;
3274 attrib = GL_GREEN_BITS;
3276 case SDL_GL_ALPHA_SIZE:
3277 #if SDL_VIDEO_OPENGL
3278 attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE;
3280 attrib = GL_ALPHA_BITS;
3282 case SDL_GL_DOUBLEBUFFER:
3283 #if SDL_VIDEO_OPENGL
3284 attrib = GL_DOUBLEBUFFER;
3287 /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER */
3288 /* parameter which switches double buffer to single buffer. OpenGL ES */
3289 /* SDL driver must set proper value after initialization */
3290 *value = _this->gl_config.double_buffer;
3293 case SDL_GL_DEPTH_SIZE:
3294 #if SDL_VIDEO_OPENGL
3295 attachment = GL_DEPTH;
3296 attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE;
3298 attrib = GL_DEPTH_BITS;
3300 case SDL_GL_STENCIL_SIZE:
3301 #if SDL_VIDEO_OPENGL
3302 attachment = GL_STENCIL;
3303 attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE;
3305 attrib = GL_STENCIL_BITS;
3307 #if SDL_VIDEO_OPENGL
3308 case SDL_GL_ACCUM_RED_SIZE:
3309 attrib = GL_ACCUM_RED_BITS;
3311 case SDL_GL_ACCUM_GREEN_SIZE:
3312 attrib = GL_ACCUM_GREEN_BITS;
3314 case SDL_GL_ACCUM_BLUE_SIZE:
3315 attrib = GL_ACCUM_BLUE_BITS;
3317 case SDL_GL_ACCUM_ALPHA_SIZE:
3318 attrib = GL_ACCUM_ALPHA_BITS;
3324 case SDL_GL_ACCUM_RED_SIZE:
3325 case SDL_GL_ACCUM_GREEN_SIZE:
3326 case SDL_GL_ACCUM_BLUE_SIZE:
3327 case SDL_GL_ACCUM_ALPHA_SIZE:
3329 /* none of these are supported in OpenGL ES */
3333 case SDL_GL_MULTISAMPLEBUFFERS:
3334 attrib = GL_SAMPLE_BUFFERS;
3336 case SDL_GL_MULTISAMPLESAMPLES:
3337 attrib = GL_SAMPLES;
3339 case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
3340 #if SDL_VIDEO_OPENGL
3341 attrib = GL_CONTEXT_RELEASE_BEHAVIOR;
3343 attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR;
3346 case SDL_GL_BUFFER_SIZE:
3348 int rsize = 0, gsize = 0, bsize = 0, asize = 0;
3350 /* There doesn't seem to be a single flag in OpenGL for this! */
3351 if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &rsize) < 0) {
3354 if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gsize) < 0) {
3357 if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &bsize) < 0) {
3360 if (SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &asize) < 0) {
3364 *value = rsize + gsize + bsize + asize;
3367 case SDL_GL_ACCELERATED_VISUAL:
3369 /* FIXME: How do we get this information? */
3370 *value = (_this->gl_config.accelerated != 0);
3373 case SDL_GL_RETAINED_BACKING:
3375 *value = _this->gl_config.retained_backing;
3378 case SDL_GL_CONTEXT_MAJOR_VERSION:
3380 *value = _this->gl_config.major_version;
3383 case SDL_GL_CONTEXT_MINOR_VERSION:
3385 *value = _this->gl_config.minor_version;
3388 case SDL_GL_CONTEXT_EGL:
3389 /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
3391 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
3399 case SDL_GL_CONTEXT_FLAGS:
3401 *value = _this->gl_config.flags;
3404 case SDL_GL_CONTEXT_PROFILE_MASK:
3406 *value = _this->gl_config.profile_mask;
3409 case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
3411 *value = _this->gl_config.share_with_current_context;
3414 case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
3416 *value = _this->gl_config.framebuffer_srgb_capable;
3420 case SDL_GL_CONTEXT_PRIORITY:
3422 *value = _this->gl_config.context_priority_level;
3426 case SDL_GL_CONTEXT_NO_ERROR:
3428 *value = _this->gl_config.no_error;
3432 return SDL_SetError("Unknown OpenGL attribute");
3435 #if SDL_VIDEO_OPENGL
3436 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
3437 if (!glGetStringFunc) {
3441 if (attachmentattrib && isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
3442 glGetFramebufferAttachmentParameterivFunc = SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameteriv");
3444 if (glGetFramebufferAttachmentParameterivFunc) {
3445 glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *) value);
3452 void (APIENTRY *glGetIntegervFunc) (GLenum pname, GLint * params);
3453 glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
3454 if (glGetIntegervFunc) {
3455 glGetIntegervFunc(attrib, (GLint *) value);
3461 glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
3462 if (!glGetErrorFunc) {
3466 error = glGetErrorFunc();
3467 if (error != GL_NO_ERROR) {
3468 if (error == GL_INVALID_ENUM) {
3469 return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
3470 } else if (error == GL_INVALID_VALUE) {
3471 return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
3473 return SDL_SetError("OpenGL error: %08X", error);
3477 return SDL_Unsupported();
3478 #endif /* SDL_VIDEO_OPENGL */
3482 SDL_GL_CreateContext(SDL_Window * window)
3484 SDL_GLContext ctx = NULL;
3485 CHECK_WINDOW_MAGIC(window, NULL);
3487 if (!(window->flags & SDL_WINDOW_OPENGL)) {
3488 SDL_SetError("The specified window isn't an OpenGL window");
3492 ctx = _this->GL_CreateContext(_this, window);
3494 /* Creating a context is assumed to make it current in the SDL driver. */
3496 _this->current_glwin = window;
3497 _this->current_glctx = ctx;
3498 SDL_TLSSet(_this->current_glwin_tls, window, NULL);
3499 SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
3505 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
3509 if (window == SDL_GL_GetCurrentWindow() &&
3510 ctx == SDL_GL_GetCurrentContext()) {
3511 /* We're already current. */
3516 if ((SDL_GL_ExtensionSupported("EGL_KHR_surfaceless_context")) && (!window)) {
3517 /* current window checking */
3518 SDL_Window* cur_win = SDL_GL_GetCurrentWindow();
3519 if (!ctx) cur_win = NULL;
3520 CHECK_WINDOW_MAGIC(cur_win, -1);
3522 if (!(cur_win->flags & SDL_WINDOW_OPENGL)) {
3523 return SDL_SetError("The specified window isn't an OpenGL window");
3525 retval = _this->GL_MakeCurrent(_this, NULL, ctx);
3527 _this->current_glwin = cur_win;
3528 _this->current_glctx = ctx;
3529 SDL_TLSSet(_this->current_glwin_tls, cur_win, NULL);
3530 SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
3539 CHECK_WINDOW_MAGIC(window, -1);
3541 if (!(window->flags & SDL_WINDOW_OPENGL)) {
3542 return SDL_SetError("The specified window isn't an OpenGL window");
3546 retval = _this->GL_MakeCurrent(_this, window, ctx);
3548 _this->current_glwin = window;
3549 _this->current_glctx = ctx;
3550 SDL_TLSSet(_this->current_glwin_tls, window, NULL);
3551 SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
3557 SDL_GL_GetCurrentWindow(void)
3560 SDL_UninitializedVideo();
3563 return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
3567 SDL_GL_GetCurrentContext(void)
3570 SDL_UninitializedVideo();
3573 return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
3576 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
3578 CHECK_WINDOW_MAGIC(window,);
3580 if (_this->GL_GetDrawableSize) {
3581 _this->GL_GetDrawableSize(_this, window, w, h);
3583 SDL_GetWindowSize(window, w, h);
3588 SDL_GL_SetSwapInterval(int interval)
3591 return SDL_UninitializedVideo();
3592 } else if (SDL_GL_GetCurrentContext() == NULL) {
3593 return SDL_SetError("No OpenGL context has been made current");
3594 } else if (_this->GL_SetSwapInterval) {
3595 return _this->GL_SetSwapInterval(_this, interval);
3597 return SDL_SetError("Setting the swap interval is not supported");
3602 SDL_GL_GetSwapInterval(void)
3606 } else if (SDL_GL_GetCurrentContext() == NULL) {
3608 } else if (_this->GL_GetSwapInterval) {
3609 return _this->GL_GetSwapInterval(_this);
3616 SDL_GL_SwapWindow(SDL_Window * window)
3618 CHECK_WINDOW_MAGIC(window,);
3620 if (!(window->flags & SDL_WINDOW_OPENGL)) {
3621 SDL_SetError("The specified window isn't an OpenGL window");
3625 if (SDL_GL_GetCurrentWindow() != window) {
3626 SDL_SetError("The specified window has not been made current");
3630 _this->GL_SwapWindow(_this, window);
3634 SDL_GL_DeleteContext(SDL_GLContext context)
3636 if (!_this || !context) {
3640 if (SDL_GL_GetCurrentContext() == context) {
3641 SDL_GL_MakeCurrent(NULL, NULL);
3644 _this->GL_DeleteContext(_this, context);
3649 * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
3650 * & 2 for alpha channel.
3653 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
3657 #define SET_MASKBIT(icon, x, y, mask) \
3658 mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
3660 colorkey = icon->format->colorkey;
3661 switch (icon->format->BytesPerPixel) {
3665 for (y = 0; y < icon->h; ++y) {
3666 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
3667 for (x = 0; x < icon->w; ++x) {
3668 if (*pixels++ == colorkey) {
3669 SET_MASKBIT(icon, x, y, mask);
3679 for (y = 0; y < icon->h; ++y) {
3680 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
3681 for (x = 0; x < icon->w; ++x) {
3682 if ((flags & 1) && *pixels == colorkey) {
3683 SET_MASKBIT(icon, x, y, mask);
3684 } else if ((flags & 2)
3685 && (*pixels & icon->format->Amask) == 0) {
3686 SET_MASKBIT(icon, x, y, mask);
3697 for (y = 0; y < icon->h; ++y) {
3698 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
3699 for (x = 0; x < icon->w; ++x) {
3700 if ((flags & 1) && *pixels == colorkey) {
3701 SET_MASKBIT(icon, x, y, mask);
3702 } else if ((flags & 2)
3703 && (*pixels & icon->format->Amask) == 0) {
3704 SET_MASKBIT(icon, x, y, mask);
3715 * Sets the window manager icon for the display window.
3718 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
3720 if (icon && _this->SetIcon) {
3721 /* Generate a mask if necessary, and create the icon! */
3723 int mask_len = icon->h * (icon->w + 7) / 8;
3725 mask = (Uint8 *) SDL_malloc(mask_len);
3729 SDL_memset(mask, ~0, mask_len);
3730 if (icon->flags & SDL_SRCCOLORKEY)
3732 if (icon->flags & SDL_SRCALPHA)
3735 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
3737 _this->SetIcon(_this, icon, mask);
3740 _this->SetIcon(_this, icon, mask);
3747 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
3749 CHECK_WINDOW_MAGIC(window, SDL_FALSE);
3752 SDL_InvalidParamError("info");
3755 info->subsystem = SDL_SYSWM_UNKNOWN;
3757 if (!_this->GetWindowWMInfo) {
3761 return (_this->GetWindowWMInfo(_this, window, info));
3765 SDL_StartTextInput(void)
3769 /* First, enable text events */
3770 SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
3771 SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
3773 /* Then show the on-screen keyboard, if any */
3774 window = SDL_GetFocusWindow();
3775 if (window && _this && _this->ShowScreenKeyboard) {
3776 _this->ShowScreenKeyboard(_this, window);
3779 /* Finally start the text input system */
3780 if (_this && _this->StartTextInput) {
3781 _this->StartTextInput(_this);
3786 SDL_IsTextInputActive(void)
3788 return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
3792 SDL_StopTextInput(void)
3796 /* Stop the text input system */
3797 if (_this && _this->StopTextInput) {
3798 _this->StopTextInput(_this);
3801 /* Hide the on-screen keyboard, if any */
3802 window = SDL_GetFocusWindow();
3803 if (window && _this && _this->HideScreenKeyboard) {
3804 _this->HideScreenKeyboard(_this, window);
3807 /* Finally disable text events */
3808 SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
3809 SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
3813 SDL_SetTextInputRect(SDL_Rect *rect)
3815 if (_this && _this->SetTextInputRect) {
3816 _this->SetTextInputRect(_this, rect);
3821 SDL_HasScreenKeyboardSupport(void)
3823 if (_this && _this->HasScreenKeyboardSupport) {
3824 return _this->HasScreenKeyboardSupport(_this);
3830 SDL_IsScreenKeyboardShown(SDL_Window *window)
3832 if (window && _this && _this->IsScreenKeyboardShown) {
3833 return _this->IsScreenKeyboardShown(_this, window);
3838 #if SDL_VIDEO_DRIVER_ANDROID
3839 #include "android/SDL_androidmessagebox.h"
3841 #if SDL_VIDEO_DRIVER_WINDOWS
3842 #include "windows/SDL_windowsmessagebox.h"
3844 #if SDL_VIDEO_DRIVER_WINRT
3845 #include "winrt/SDL_winrtmessagebox.h"
3847 #if SDL_VIDEO_DRIVER_COCOA
3848 #include "cocoa/SDL_cocoamessagebox.h"
3850 #if SDL_VIDEO_DRIVER_UIKIT
3851 #include "uikit/SDL_uikitmessagebox.h"
3853 #if SDL_VIDEO_DRIVER_X11
3854 #include "x11/SDL_x11messagebox.h"
3858 #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11
3859 static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
3862 SDL_Window *window = messageboxdata->window;
3868 SDL_VERSION(&info.version);
3869 if (!SDL_GetWindowWMInfo(window, &info)) {
3872 return (info.subsystem == drivertype);
3878 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
3882 SDL_bool relative_mode;
3883 int show_cursor_prev;
3884 SDL_bool mouse_captured;
3885 SDL_Window *current_window;
3887 if (!messageboxdata) {
3888 return SDL_InvalidParamError("messageboxdata");
3891 current_window = SDL_GetKeyboardFocus();
3892 mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
3893 relative_mode = SDL_GetRelativeMouseMode();
3894 SDL_CaptureMouse(SDL_FALSE);
3895 SDL_SetRelativeMouseMode(SDL_FALSE);
3896 show_cursor_prev = SDL_ShowCursor(1);
3897 SDL_ResetKeyboard();
3900 buttonid = &dummybutton;
3903 if (_this && _this->ShowMessageBox) {
3904 retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
3907 /* It's completely fine to call this function before video is initialized */
3908 #if SDL_VIDEO_DRIVER_ANDROID
3910 Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
3914 #if SDL_VIDEO_DRIVER_WINDOWS
3916 SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
3917 WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
3921 #if SDL_VIDEO_DRIVER_WINRT
3923 SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
3924 WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
3928 #if SDL_VIDEO_DRIVER_COCOA
3930 SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
3931 Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
3935 #if SDL_VIDEO_DRIVER_UIKIT
3937 SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
3938 UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
3942 #if SDL_VIDEO_DRIVER_X11
3944 SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
3945 X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
3950 SDL_SetError("No message system available");
3953 if (current_window) {
3954 SDL_RaiseWindow(current_window);
3955 if (mouse_captured) {
3956 SDL_CaptureMouse(SDL_TRUE);
3960 SDL_ShowCursor(show_cursor_prev);
3961 SDL_SetRelativeMouseMode(relative_mode);
3967 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
3969 #ifdef __EMSCRIPTEN__
3970 /* !!! FIXME: propose a browser API for this, get this #ifdef out of here? */
3971 /* Web browsers don't (currently) have an API for a custom message box
3972 that can block, but for the most common case (SDL_ShowSimpleMessageBox),
3973 we can use the standard Javascript alert() function. */
3975 alert(UTF8ToString($0) + "\n\n" + UTF8ToString($1));
3979 SDL_MessageBoxData data;
3980 SDL_MessageBoxButtonData button;
3985 data.message = message;
3986 data.numbuttons = 1;
3987 data.buttons = &button;
3988 data.window = window;
3991 button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
3992 button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
3995 return SDL_ShowMessageBox(&data, NULL);
4000 SDL_ShouldAllowTopmost(void)
4002 return SDL_GetHintBoolean(SDL_HINT_ALLOW_TOPMOST, SDL_TRUE);
4006 SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
4008 CHECK_WINDOW_MAGIC(window, -1);
4010 if (!_this->SetWindowHitTest) {
4011 return SDL_Unsupported();
4012 } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
4016 window->hit_test = callback;
4017 window->hit_test_data = userdata;
4023 SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
4025 float den2 = hinches * hinches + vinches * vinches;
4030 return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) /
4031 SDL_sqrt((double)den2));
4035 * Functions used by iOS application delegates
4037 void SDL_OnApplicationWillTerminate(void)
4039 SDL_SendAppEvent(SDL_APP_TERMINATING);
4042 void SDL_OnApplicationDidReceiveMemoryWarning(void)
4044 SDL_SendAppEvent(SDL_APP_LOWMEMORY);
4047 void SDL_OnApplicationWillResignActive(void)
4051 for (window = _this->windows; window != NULL; window = window->next) {
4052 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
4053 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
4056 SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
4059 void SDL_OnApplicationDidEnterBackground(void)
4061 SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
4064 void SDL_OnApplicationWillEnterForeground(void)
4066 SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
4069 void SDL_OnApplicationDidBecomeActive(void)
4071 SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
4075 for (window = _this->windows; window != NULL; window = window->next) {
4076 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
4077 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
4082 #define NOT_A_VULKAN_WINDOW "The specified window isn't a Vulkan window"
4084 int SDL_Vulkan_LoadLibrary(const char *path)
4088 SDL_UninitializedVideo();
4091 if (_this->vulkan_config.loader_loaded) {
4092 if (path && SDL_strcmp(path, _this->vulkan_config.loader_path) != 0) {
4093 return SDL_SetError("Vulkan loader library already loaded");
4097 if (!_this->Vulkan_LoadLibrary) {
4098 return SDL_SetError("No Vulkan support in video driver");
4100 retval = _this->Vulkan_LoadLibrary(_this, path);
4103 _this->vulkan_config.loader_loaded++;
4108 void *SDL_Vulkan_GetVkGetInstanceProcAddr(void)
4111 SDL_UninitializedVideo();
4114 if (!_this->vulkan_config.loader_loaded) {
4115 SDL_SetError("No Vulkan loader has been loaded");
4118 return _this->vulkan_config.vkGetInstanceProcAddr;
4121 void SDL_Vulkan_UnloadLibrary(void)
4124 SDL_UninitializedVideo();
4127 if (_this->vulkan_config.loader_loaded > 0) {
4128 if (--_this->vulkan_config.loader_loaded > 0) {
4131 if (_this->Vulkan_UnloadLibrary) {
4132 _this->Vulkan_UnloadLibrary(_this);
4137 SDL_bool SDL_Vulkan_GetInstanceExtensions(SDL_Window *window, unsigned *count, const char **names)
4139 CHECK_WINDOW_MAGIC(window, SDL_FALSE);
4141 if (!(window->flags & SDL_WINDOW_VULKAN)) {
4142 SDL_SetError(NOT_A_VULKAN_WINDOW);
4147 SDL_InvalidParamError("count");
4151 return _this->Vulkan_GetInstanceExtensions(_this, window, count, names);
4154 SDL_bool SDL_Vulkan_CreateSurface(SDL_Window *window,
4155 VkInstance instance,
4156 VkSurfaceKHR *surface)
4158 CHECK_WINDOW_MAGIC(window, SDL_FALSE);
4160 if (!(window->flags & SDL_WINDOW_VULKAN)) {
4161 SDL_SetError(NOT_A_VULKAN_WINDOW);
4166 SDL_InvalidParamError("instance");
4171 SDL_InvalidParamError("surface");
4175 return _this->Vulkan_CreateSurface(_this, window, instance, surface);
4178 void SDL_Vulkan_GetDrawableSize(SDL_Window * window, int *w, int *h)
4180 CHECK_WINDOW_MAGIC(window,);
4182 if (_this->Vulkan_GetDrawableSize) {
4183 _this->Vulkan_GetDrawableSize(_this, window, w, h);
4185 SDL_GetWindowSize(window, w, h);
4198 /* vi: set ts=4 sw=4 expandtab: */