511b4c087d54ad31cad43006b0927f31c6cb35e8
[platform/upstream/SDL.git] / src / video / SDL_video.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
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.
8
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:
12
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.
20 */
21 #include "../SDL_internal.h"
22
23 /* The high-level video driver subsystem */
24
25 #include "SDL.h"
26 #include "SDL_video.h"
27 #include "SDL_sysvideo.h"
28 #include "SDL_blit.h"
29 #include "SDL_pixels_c.h"
30 #include "SDL_rect_c.h"
31 #include "../events/SDL_events_c.h"
32 #include "../timer/SDL_timer_c.h"
33
34 #include "SDL_syswm.h"
35
36 #if SDL_VIDEO_OPENGL
37 #include "SDL_opengl.h"
38 #endif /* SDL_VIDEO_OPENGL */
39
40 #if SDL_VIDEO_OPENGL_ES
41 #include "SDL_opengles.h"
42 #endif /* SDL_VIDEO_OPENGL_ES */
43
44 /* GL and GLES2 headers conflict on Linux 32 bits */
45 #if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL
46 #include "SDL_opengles2.h"
47 #endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */
48
49 #ifndef GL_CONTEXT_RELEASE_BEHAVIOR_KHR
50 #define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB
51 #endif
52
53 /* On Windows, windows.h defines CreateWindow */
54 #ifdef CreateWindow
55 #undef CreateWindow
56 #endif
57
58 /* Available video drivers */
59 static VideoBootStrap *bootstrap[] = {
60 #if SDL_VIDEO_DRIVER_COCOA
61     &COCOA_bootstrap,
62 #endif
63 #if SDL_VIDEO_DRIVER_X11
64     &X11_bootstrap,
65 #endif
66 #if SDL_VIDEO_DRIVER_MIR
67     &MIR_bootstrap,
68 #endif
69 #if SDL_VIDEO_DRIVER_WAYLAND
70     &Wayland_bootstrap,
71 #endif
72 #if SDL_VIDEO_DRIVER_VIVANTE
73     &VIVANTE_bootstrap,
74 #endif
75 #if SDL_VIDEO_DRIVER_DIRECTFB
76     &DirectFB_bootstrap,
77 #endif
78 #if SDL_VIDEO_DRIVER_WINDOWS
79     &WINDOWS_bootstrap,
80 #endif
81 #if SDL_VIDEO_DRIVER_WINRT
82     &WINRT_bootstrap,
83 #endif
84 #if SDL_VIDEO_DRIVER_HAIKU
85     &HAIKU_bootstrap,
86 #endif
87 #if SDL_VIDEO_DRIVER_PANDORA
88     &PND_bootstrap,
89 #endif
90 #if SDL_VIDEO_DRIVER_UIKIT
91     &UIKIT_bootstrap,
92 #endif
93 #if SDL_VIDEO_DRIVER_ANDROID
94     &Android_bootstrap,
95 #endif
96 #if SDL_VIDEO_DRIVER_PSP
97     &PSP_bootstrap,
98 #endif
99 #if SDL_VIDEO_DRIVER_RPI
100     &RPI_bootstrap,
101 #endif 
102 #if SDL_VIDEO_DRIVER_NACL
103     &NACL_bootstrap,
104 #endif
105 #if SDL_VIDEO_DRIVER_EMSCRIPTEN
106     &Emscripten_bootstrap,
107 #endif
108 #if SDL_VIDEO_DRIVER_DUMMY
109     &DUMMY_bootstrap,
110 #endif
111     NULL
112 };
113
114 static SDL_VideoDevice *_this = NULL;
115
116 #define CHECK_WINDOW_MAGIC(window, retval) \
117     if (!_this) { \
118         SDL_UninitializedVideo(); \
119         return retval; \
120     } \
121     if (!window || window->magic != &_this->window_magic) { \
122         SDL_SetError("Invalid window"); \
123         return retval; \
124     }
125
126 #define CHECK_DISPLAY_INDEX(displayIndex, retval) \
127     if (!_this) { \
128         SDL_UninitializedVideo(); \
129         return retval; \
130     } \
131     SDL_assert(_this->displays != NULL); \
132     if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
133         SDL_SetError("displayIndex must be in the range 0 - %d", \
134                      _this->num_displays - 1); \
135         return retval; \
136     }
137
138 #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
139
140 #ifdef __MACOSX__
141 /* Support for Mac OS X fullscreen spaces */
142 extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window);
143 extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state);
144 #endif
145
146
147 /* Support for framebuffer emulation using an accelerated renderer */
148
149 #define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
150
151 typedef struct {
152     SDL_Renderer *renderer;
153     SDL_Texture *texture;
154     void *pixels;
155     int pitch;
156     int bytes_per_pixel;
157 } SDL_WindowTextureData;
158
159 static SDL_bool
160 ShouldUseTextureFramebuffer()
161 {
162     const char *hint;
163
164     /* If there's no native framebuffer support then there's no option */
165     if (!_this->CreateWindowFramebuffer) {
166         return SDL_TRUE;
167     }
168
169     /* If the user has specified a software renderer we can't use a
170        texture framebuffer, or renderer creation will go recursive.
171      */
172     hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
173     if (hint && SDL_strcasecmp(hint, "software") == 0) {
174         return SDL_FALSE;
175     }
176
177     /* See if the user or application wants a specific behavior */
178     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
179     if (hint) {
180         if (*hint == '0') {
181             return SDL_FALSE;
182         } else {
183             return SDL_TRUE;
184         }
185     }
186
187     /* Each platform has different performance characteristics */
188 #if defined(__WIN32__)
189     /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
190      */
191     return SDL_FALSE;
192
193 #elif defined(__MACOSX__)
194     /* Mac OS X uses OpenGL as the native fast path */
195     return SDL_TRUE;
196
197 #elif defined(__LINUX__)
198     /* Properly configured OpenGL drivers are faster than MIT-SHM */
199 #if SDL_VIDEO_OPENGL
200     /* Ugh, find a way to cache this value! */
201     {
202         SDL_Window *window;
203         SDL_GLContext context;
204         SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
205
206         window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
207         if (window) {
208             context = SDL_GL_CreateContext(window);
209             if (context) {
210                 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
211                 const char *vendor = NULL;
212
213                 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
214                 if (glGetStringFunc) {
215                     vendor = (const char *) glGetStringFunc(GL_VENDOR);
216                 }
217                 /* Add more vendors here at will... */
218                 if (vendor &&
219                     (SDL_strstr(vendor, "ATI Technologies") ||
220                      SDL_strstr(vendor, "NVIDIA"))) {
221                     hasAcceleratedOpenGL = SDL_TRUE;
222                 }
223                 SDL_GL_DeleteContext(context);
224             }
225             SDL_DestroyWindow(window);
226         }
227         return hasAcceleratedOpenGL;
228     }
229 #elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
230     /* Let's be optimistic about this! */
231     return SDL_TRUE;
232 #else
233     return SDL_FALSE;
234 #endif
235
236 #else
237     /* Play it safe, assume that if there is a framebuffer driver that it's
238        optimized for the current platform.
239     */
240     return SDL_FALSE;
241 #endif
242 }
243
244 static int
245 SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
246 {
247     SDL_WindowTextureData *data;
248
249     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
250     if (!data) {
251         SDL_Renderer *renderer = NULL;
252         int i;
253         const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
254
255         /* Check to see if there's a specific driver requested */
256         if (hint && *hint != '0' && *hint != '1' &&
257             SDL_strcasecmp(hint, "software") != 0) {
258             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
259                 SDL_RendererInfo info;
260                 SDL_GetRenderDriverInfo(i, &info);
261                 if (SDL_strcasecmp(info.name, hint) == 0) {
262                     renderer = SDL_CreateRenderer(window, i, 0);
263                     break;
264                 }
265             }
266         }
267         
268         if (!renderer) {
269             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
270                 SDL_RendererInfo info;
271                 SDL_GetRenderDriverInfo(i, &info);
272                 if (SDL_strcmp(info.name, "software") != 0) {
273                     renderer = SDL_CreateRenderer(window, i, 0);
274                     if (renderer) {
275                         break;
276                     }
277                 }
278             }
279         }
280         if (!renderer) {
281             return SDL_SetError("No hardware accelerated renderers available");
282         }
283
284         /* Create the data after we successfully create the renderer (bug #1116) */
285         data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
286         if (!data) {
287             SDL_DestroyRenderer(renderer);
288             return SDL_OutOfMemory();
289         }
290         SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data);
291
292         data->renderer = renderer;
293     }
294
295     /* Free any old texture and pixel data */
296     if (data->texture) {
297         SDL_DestroyTexture(data->texture);
298         data->texture = NULL;
299     }
300     SDL_free(data->pixels);
301     data->pixels = NULL;
302
303     {
304         SDL_RendererInfo info;
305         Uint32 i;
306
307         if (SDL_GetRendererInfo(data->renderer, &info) < 0) {
308             return -1;
309         }
310
311         /* Find the first format without an alpha channel */
312         *format = info.texture_formats[0];
313
314         for (i = 0; i < info.num_texture_formats; ++i) {
315             if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) &&
316                     !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) {
317                 *format = info.texture_formats[i];
318                 break;
319             }
320         }
321     }
322
323     data->texture = SDL_CreateTexture(data->renderer, *format,
324                                       SDL_TEXTUREACCESS_STREAMING,
325                                       window->w, window->h);
326     if (!data->texture) {
327         return -1;
328     }
329
330     /* Create framebuffer data */
331     data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
332     data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
333     data->pixels = SDL_malloc(window->h * data->pitch);
334     if (!data->pixels) {
335         return SDL_OutOfMemory();
336     }
337
338     *pixels = data->pixels;
339     *pitch = data->pitch;
340
341     /* Make sure we're not double-scaling the viewport */
342     SDL_RenderSetViewport(data->renderer, NULL);
343
344     return 0;
345 }
346
347 static int
348 SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, const SDL_Rect * rects, int numrects)
349 {
350     SDL_WindowTextureData *data;
351     SDL_Rect rect;
352     void *src;
353
354     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
355     if (!data || !data->texture) {
356         return SDL_SetError("No window texture data");
357     }
358
359     /* Update a single rect that contains subrects for best DMA performance */
360     if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
361         src = (void *)((Uint8 *)data->pixels +
362                         rect.y * data->pitch +
363                         rect.x * data->bytes_per_pixel);
364         if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) {
365             return -1;
366         }
367
368         if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) {
369             return -1;
370         }
371
372         SDL_RenderPresent(data->renderer);
373     }
374     return 0;
375 }
376
377 static void
378 SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window)
379 {
380     SDL_WindowTextureData *data;
381
382     data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL);
383     if (!data) {
384         return;
385     }
386     if (data->texture) {
387         SDL_DestroyTexture(data->texture);
388     }
389     if (data->renderer) {
390         SDL_DestroyRenderer(data->renderer);
391     }
392     SDL_free(data->pixels);
393     SDL_free(data);
394 }
395
396
397 static int
398 cmpmodes(const void *A, const void *B)
399 {
400     const SDL_DisplayMode *a = (const SDL_DisplayMode *) A;
401     const SDL_DisplayMode *b = (const SDL_DisplayMode *) B;
402     if (a == b) {
403         return 0;
404     } else if (a->w != b->w) {
405         return b->w - a->w;
406     } else if (a->h != b->h) {
407         return b->h - a->h;
408     } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) {
409         return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format);
410     } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) {
411         return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format);
412     } else if (a->refresh_rate != b->refresh_rate) {
413         return b->refresh_rate - a->refresh_rate;
414     }
415     return 0;
416 }
417
418 static int
419 SDL_UninitializedVideo()
420 {
421     return SDL_SetError("Video subsystem has not been initialized");
422 }
423
424 int
425 SDL_GetNumVideoDrivers(void)
426 {
427     return SDL_arraysize(bootstrap) - 1;
428 }
429
430 const char *
431 SDL_GetVideoDriver(int index)
432 {
433     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
434         return bootstrap[index]->name;
435     }
436     return NULL;
437 }
438
439 /*
440  * Initialize the video and event subsystems -- determine native pixel format
441  */
442 int
443 SDL_VideoInit(const char *driver_name)
444 {
445     SDL_VideoDevice *video;
446     const char *hint;
447     int index;
448     int i;
449     SDL_bool allow_screensaver;
450
451     /* Check to make sure we don't overwrite '_this' */
452     if (_this != NULL) {
453         SDL_VideoQuit();
454     }
455
456 #if !SDL_TIMERS_DISABLED
457     SDL_TicksInit();
458 #endif
459
460     /* Start the event loop */
461     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 ||
462         SDL_KeyboardInit() < 0 ||
463         SDL_MouseInit() < 0 ||
464         SDL_TouchInit() < 0) {
465         return -1;
466     }
467
468     /* Select the proper video driver */
469     index = 0;
470     video = NULL;
471     if (driver_name == NULL) {
472         driver_name = SDL_getenv("SDL_VIDEODRIVER");
473     }
474     if (driver_name != NULL) {
475         for (i = 0; bootstrap[i]; ++i) {
476             if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) {
477                 if (bootstrap[i]->available()) {
478                     video = bootstrap[i]->create(index);
479                     break;
480                 }
481             }
482         }
483     } else {
484         for (i = 0; bootstrap[i]; ++i) {
485             if (bootstrap[i]->available()) {
486                 video = bootstrap[i]->create(index);
487                 if (video != NULL) {
488                     break;
489                 }
490             }
491         }
492     }
493     if (video == NULL) {
494         if (driver_name) {
495             return SDL_SetError("%s not available", driver_name);
496         }
497         return SDL_SetError("No available video device");
498     }
499     _this = video;
500     _this->name = bootstrap[i]->name;
501     _this->next_object_id = 1;
502
503
504     /* Set some very sane GL defaults */
505     _this->gl_config.driver_loaded = 0;
506     _this->gl_config.dll_handle = NULL;
507     SDL_GL_ResetAttributes();
508
509     _this->current_glwin_tls = SDL_TLSCreate();
510     _this->current_glctx_tls = SDL_TLSCreate();
511
512     /* Initialize the video subsystem */
513     if (_this->VideoInit(_this) < 0) {
514         SDL_VideoQuit();
515         return -1;
516     }
517
518     /* Make sure some displays were added */
519     if (_this->num_displays == 0) {
520         SDL_VideoQuit();
521         return SDL_SetError("The video driver did not add any displays");
522     }
523
524     /* Add the renderer framebuffer emulation if desired */
525     if (ShouldUseTextureFramebuffer()) {
526         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
527         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
528         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
529     }
530
531     /* Disable the screen saver by default. This is a change from <= 2.0.1,
532        but most things using SDL are games or media players; you wouldn't
533        want a screensaver to trigger if you're playing exclusively with a
534        joystick, or passively watching a movie. Things that use SDL but
535        function more like a normal desktop app should explicitly reenable the
536        screensaver. */
537     hint = SDL_GetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER);
538     if (hint) {
539         allow_screensaver = SDL_atoi(hint) ? SDL_TRUE : SDL_FALSE;
540     } else {
541         allow_screensaver = SDL_FALSE;
542     }
543     if (!allow_screensaver) {
544         SDL_DisableScreenSaver();
545     }
546
547     /* If we don't use a screen keyboard, turn on text input by default,
548        otherwise programs that expect to get text events without enabling
549        UNICODE input won't get any events.
550
551        Actually, come to think of it, you needed to call SDL_EnableUNICODE(1)
552        in SDL 1.2 before you got text input events.  Hmm...
553      */
554     if (!SDL_HasScreenKeyboardSupport()) {
555         SDL_StartTextInput();
556     }
557
558     /* We're ready to go! */
559     return 0;
560 }
561
562 const char *
563 SDL_GetCurrentVideoDriver()
564 {
565     if (!_this) {
566         SDL_UninitializedVideo();
567         return NULL;
568     }
569     return _this->name;
570 }
571
572 SDL_VideoDevice *
573 SDL_GetVideoDevice(void)
574 {
575     return _this;
576 }
577
578 int
579 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
580 {
581     SDL_VideoDisplay display;
582
583     SDL_zero(display);
584     if (desktop_mode) {
585         display.desktop_mode = *desktop_mode;
586     }
587     display.current_mode = display.desktop_mode;
588
589     return SDL_AddVideoDisplay(&display);
590 }
591
592 int
593 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
594 {
595     SDL_VideoDisplay *displays;
596     int index = -1;
597
598     displays =
599         SDL_realloc(_this->displays,
600                     (_this->num_displays + 1) * sizeof(*displays));
601     if (displays) {
602         index = _this->num_displays++;
603         displays[index] = *display;
604         displays[index].device = _this;
605         _this->displays = displays;
606
607         if (display->name) {
608             displays[index].name = SDL_strdup(display->name);
609         } else {
610             char name[32];
611
612             SDL_itoa(index, name, 10);
613             displays[index].name = SDL_strdup(name);
614         }
615     } else {
616         SDL_OutOfMemory();
617     }
618     return index;
619 }
620
621 int
622 SDL_GetNumVideoDisplays(void)
623 {
624     if (!_this) {
625         SDL_UninitializedVideo();
626         return 0;
627     }
628     return _this->num_displays;
629 }
630
631 static int
632 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
633 {
634     int displayIndex;
635
636     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
637         if (display == &_this->displays[displayIndex]) {
638             return displayIndex;
639         }
640     }
641
642     /* Couldn't find the display, just use index 0 */
643     return 0;
644 }
645
646 void *
647 SDL_GetDisplayDriverData(int displayIndex)
648 {
649     CHECK_DISPLAY_INDEX(displayIndex, NULL);
650
651     return _this->displays[displayIndex].driverdata;
652 }
653
654 const char *
655 SDL_GetDisplayName(int displayIndex)
656 {
657     CHECK_DISPLAY_INDEX(displayIndex, NULL);
658
659     return _this->displays[displayIndex].name;
660 }
661
662 int
663 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
664 {
665     CHECK_DISPLAY_INDEX(displayIndex, -1);
666
667     if (rect) {
668         SDL_VideoDisplay *display = &_this->displays[displayIndex];
669
670         if (_this->GetDisplayBounds) {
671             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
672                 return 0;
673             }
674         }
675
676         /* Assume that the displays are left to right */
677         if (displayIndex == 0) {
678             rect->x = 0;
679             rect->y = 0;
680         } else {
681             SDL_GetDisplayBounds(displayIndex-1, rect);
682             rect->x += rect->w;
683         }
684         rect->w = display->current_mode.w;
685         rect->h = display->current_mode.h;
686     }
687     return 0;
688 }
689
690 int
691 SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi)
692 {
693         SDL_VideoDisplay *display;
694
695     CHECK_DISPLAY_INDEX(displayIndex, -1);
696
697     display = &_this->displays[displayIndex];
698
699         if (_this->GetDisplayDPI) {
700                 if (_this->GetDisplayDPI(_this, display, ddpi, hdpi, vdpi) == 0) {
701                         return 0;
702                 }
703         }
704
705         return -1;
706 }
707
708 SDL_bool
709 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
710 {
711     SDL_DisplayMode *modes;
712     int i, nmodes;
713
714     /* Make sure we don't already have the mode in the list */
715     modes = display->display_modes;
716     nmodes = display->num_display_modes;
717     for (i = 0; i < nmodes; ++i) {
718         if (cmpmodes(mode, &modes[i]) == 0) {
719             return SDL_FALSE;
720         }
721     }
722
723     /* Go ahead and add the new mode */
724     if (nmodes == display->max_display_modes) {
725         modes =
726             SDL_realloc(modes,
727                         (display->max_display_modes + 32) * sizeof(*modes));
728         if (!modes) {
729             return SDL_FALSE;
730         }
731         display->display_modes = modes;
732         display->max_display_modes += 32;
733     }
734     modes[nmodes] = *mode;
735     display->num_display_modes++;
736
737     /* Re-sort video modes */
738     SDL_qsort(display->display_modes, display->num_display_modes,
739               sizeof(SDL_DisplayMode), cmpmodes);
740
741     return SDL_TRUE;
742 }
743
744 static int
745 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
746 {
747     if (!display->num_display_modes && _this->GetDisplayModes) {
748         _this->GetDisplayModes(_this, display);
749         SDL_qsort(display->display_modes, display->num_display_modes,
750                   sizeof(SDL_DisplayMode), cmpmodes);
751     }
752     return display->num_display_modes;
753 }
754
755 int
756 SDL_GetNumDisplayModes(int displayIndex)
757 {
758     CHECK_DISPLAY_INDEX(displayIndex, -1);
759
760     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
761 }
762
763 int
764 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
765 {
766     SDL_VideoDisplay *display;
767
768     CHECK_DISPLAY_INDEX(displayIndex, -1);
769
770     display = &_this->displays[displayIndex];
771     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
772         return SDL_SetError("index must be in the range of 0 - %d",
773                             SDL_GetNumDisplayModesForDisplay(display) - 1);
774     }
775     if (mode) {
776         *mode = display->display_modes[index];
777     }
778     return 0;
779 }
780
781 int
782 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
783 {
784     SDL_VideoDisplay *display;
785
786     CHECK_DISPLAY_INDEX(displayIndex, -1);
787
788     display = &_this->displays[displayIndex];
789     if (mode) {
790         *mode = display->desktop_mode;
791     }
792     return 0;
793 }
794
795 int
796 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
797 {
798     SDL_VideoDisplay *display;
799
800     CHECK_DISPLAY_INDEX(displayIndex, -1);
801
802     display = &_this->displays[displayIndex];
803     if (mode) {
804         *mode = display->current_mode;
805     }
806     return 0;
807 }
808
809 static SDL_DisplayMode *
810 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
811                                     const SDL_DisplayMode * mode,
812                                     SDL_DisplayMode * closest)
813 {
814     Uint32 target_format;
815     int target_refresh_rate;
816     int i;
817     SDL_DisplayMode *current, *match;
818
819     if (!mode || !closest) {
820         SDL_SetError("Missing desired mode or closest mode parameter");
821         return NULL;
822     }
823
824     /* Default to the desktop format */
825     if (mode->format) {
826         target_format = mode->format;
827     } else {
828         target_format = display->desktop_mode.format;
829     }
830
831     /* Default to the desktop refresh rate */
832     if (mode->refresh_rate) {
833         target_refresh_rate = mode->refresh_rate;
834     } else {
835         target_refresh_rate = display->desktop_mode.refresh_rate;
836     }
837
838     match = NULL;
839     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
840         current = &display->display_modes[i];
841
842         if (current->w && (current->w < mode->w)) {
843             /* Out of sorted modes large enough here */
844             break;
845         }
846         if (current->h && (current->h < mode->h)) {
847             if (current->w && (current->w == mode->w)) {
848                 /* Out of sorted modes large enough here */
849                 break;
850             }
851             /* Wider, but not tall enough, due to a different
852                aspect ratio. This mode must be skipped, but closer
853                modes may still follow. */
854             continue;
855         }
856         if (!match || current->w < match->w || current->h < match->h) {
857             match = current;
858             continue;
859         }
860         if (current->format != match->format) {
861             /* Sorted highest depth to lowest */
862             if (current->format == target_format ||
863                 (SDL_BITSPERPIXEL(current->format) >=
864                  SDL_BITSPERPIXEL(target_format)
865                  && SDL_PIXELTYPE(current->format) ==
866                  SDL_PIXELTYPE(target_format))) {
867                 match = current;
868             }
869             continue;
870         }
871         if (current->refresh_rate != match->refresh_rate) {
872             /* Sorted highest refresh to lowest */
873             if (current->refresh_rate >= target_refresh_rate) {
874                 match = current;
875             }
876         }
877     }
878     if (match) {
879         if (match->format) {
880             closest->format = match->format;
881         } else {
882             closest->format = mode->format;
883         }
884         if (match->w && match->h) {
885             closest->w = match->w;
886             closest->h = match->h;
887         } else {
888             closest->w = mode->w;
889             closest->h = mode->h;
890         }
891         if (match->refresh_rate) {
892             closest->refresh_rate = match->refresh_rate;
893         } else {
894             closest->refresh_rate = mode->refresh_rate;
895         }
896         closest->driverdata = match->driverdata;
897
898         /*
899          * Pick some reasonable defaults if the app and driver don't
900          * care
901          */
902         if (!closest->format) {
903             closest->format = SDL_PIXELFORMAT_RGB888;
904         }
905         if (!closest->w) {
906             closest->w = 640;
907         }
908         if (!closest->h) {
909             closest->h = 480;
910         }
911         return closest;
912     }
913     return NULL;
914 }
915
916 SDL_DisplayMode *
917 SDL_GetClosestDisplayMode(int displayIndex,
918                           const SDL_DisplayMode * mode,
919                           SDL_DisplayMode * closest)
920 {
921     SDL_VideoDisplay *display;
922
923     CHECK_DISPLAY_INDEX(displayIndex, NULL);
924
925     display = &_this->displays[displayIndex];
926     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
927 }
928
929 static int
930 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
931 {
932     SDL_DisplayMode display_mode;
933     SDL_DisplayMode current_mode;
934
935     if (mode) {
936         display_mode = *mode;
937
938         /* Default to the current mode */
939         if (!display_mode.format) {
940             display_mode.format = display->current_mode.format;
941         }
942         if (!display_mode.w) {
943             display_mode.w = display->current_mode.w;
944         }
945         if (!display_mode.h) {
946             display_mode.h = display->current_mode.h;
947         }
948         if (!display_mode.refresh_rate) {
949             display_mode.refresh_rate = display->current_mode.refresh_rate;
950         }
951
952         /* Get a good video mode, the closest one possible */
953         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
954             return SDL_SetError("No video mode large enough for %dx%d",
955                                 display_mode.w, display_mode.h);
956         }
957     } else {
958         display_mode = display->desktop_mode;
959     }
960
961     /* See if there's anything left to do */
962     current_mode = display->current_mode;
963     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
964         return 0;
965     }
966
967     /* Actually change the display mode */
968     if (!_this->SetDisplayMode) {
969         return SDL_SetError("Video driver doesn't support changing display mode");
970     }
971     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
972         return -1;
973     }
974     display->current_mode = display_mode;
975     return 0;
976 }
977
978 int
979 SDL_GetWindowDisplayIndex(SDL_Window * window)
980 {
981     int displayIndex;
982     int i, dist;
983     int closest = -1;
984     int closest_dist = 0x7FFFFFFF;
985     SDL_Point center;
986     SDL_Point delta;
987     SDL_Rect rect;
988
989     CHECK_WINDOW_MAGIC(window, -1);
990
991     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
992         SDL_WINDOWPOS_ISCENTERED(window->x)) {
993         displayIndex = (window->x & 0xFFFF);
994         if (displayIndex >= _this->num_displays) {
995             displayIndex = 0;
996         }
997         return displayIndex;
998     }
999     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
1000         SDL_WINDOWPOS_ISCENTERED(window->y)) {
1001         displayIndex = (window->y & 0xFFFF);
1002         if (displayIndex >= _this->num_displays) {
1003             displayIndex = 0;
1004         }
1005         return displayIndex;
1006     }
1007
1008     /* Find the display containing the window */
1009     for (i = 0; i < _this->num_displays; ++i) {
1010         SDL_VideoDisplay *display = &_this->displays[i];
1011
1012         if (display->fullscreen_window == window) {
1013             return i;
1014         }
1015     }
1016     center.x = window->x + window->w / 2;
1017     center.y = window->y + window->h / 2;
1018     for (i = 0; i < _this->num_displays; ++i) {
1019         SDL_GetDisplayBounds(i, &rect);
1020         if (SDL_EnclosePoints(&center, 1, &rect, NULL)) {
1021             return i;
1022         }
1023
1024         delta.x = center.x - (rect.x + rect.w / 2);
1025         delta.y = center.y - (rect.y + rect.h / 2);
1026         dist = (delta.x*delta.x + delta.y*delta.y);
1027         if (dist < closest_dist) {
1028             closest = i;
1029             closest_dist = dist;
1030         }
1031     }
1032     if (closest < 0) {
1033         SDL_SetError("Couldn't find any displays");
1034     }
1035     return closest;
1036 }
1037
1038 SDL_VideoDisplay *
1039 SDL_GetDisplayForWindow(SDL_Window *window)
1040 {
1041     int displayIndex = SDL_GetWindowDisplayIndex(window);
1042     if (displayIndex >= 0) {
1043         return &_this->displays[displayIndex];
1044     } else {
1045         return NULL;
1046     }
1047 }
1048
1049 int
1050 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
1051 {
1052     CHECK_WINDOW_MAGIC(window, -1);
1053
1054     if (mode) {
1055         window->fullscreen_mode = *mode;
1056     } else {
1057         SDL_zero(window->fullscreen_mode);
1058     }
1059
1060     if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
1061         SDL_DisplayMode fullscreen_mode;
1062         if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
1063             SDL_SetDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode);
1064         }
1065     }
1066     return 0;
1067 }
1068
1069 int
1070 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
1071 {
1072     SDL_DisplayMode fullscreen_mode;
1073     SDL_VideoDisplay *display;
1074
1075     CHECK_WINDOW_MAGIC(window, -1);
1076
1077     if (!mode) {
1078         return SDL_InvalidParamError("mode");
1079     }
1080
1081     fullscreen_mode = window->fullscreen_mode;
1082     if (!fullscreen_mode.w) {
1083         fullscreen_mode.w = window->windowed.w;
1084     }
1085     if (!fullscreen_mode.h) {
1086         fullscreen_mode.h = window->windowed.h;
1087     }
1088
1089     display = SDL_GetDisplayForWindow(window);
1090
1091     /* if in desktop size mode, just return the size of the desktop */
1092     if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
1093         fullscreen_mode = display->desktop_mode;
1094     } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
1095                                              &fullscreen_mode,
1096                                              &fullscreen_mode)) {
1097         return SDL_SetError("Couldn't find display mode match");
1098     }
1099
1100     if (mode) {
1101         *mode = fullscreen_mode;
1102     }
1103     return 0;
1104 }
1105
1106 Uint32
1107 SDL_GetWindowPixelFormat(SDL_Window * window)
1108 {
1109     SDL_VideoDisplay *display;
1110
1111     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
1112
1113     display = SDL_GetDisplayForWindow(window);
1114     return display->current_mode.format;
1115 }
1116
1117 static void
1118 SDL_RestoreMousePosition(SDL_Window *window)
1119 {
1120     int x, y;
1121
1122     if (window == SDL_GetMouseFocus()) {
1123         SDL_GetMouseState(&x, &y);
1124         SDL_WarpMouseInWindow(window, x, y);
1125     }
1126 }
1127
1128 #if __WINRT__
1129 extern Uint32 WINRT_DetectWindowFlags(SDL_Window * window);
1130 #endif
1131
1132 static int
1133 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
1134 {
1135     SDL_VideoDisplay *display;
1136     SDL_Window *other;
1137
1138     CHECK_WINDOW_MAGIC(window,-1);
1139
1140     /* if we are in the process of hiding don't go back to fullscreen */
1141     if ( window->is_hiding && fullscreen )
1142         return 0;
1143
1144 #ifdef __MACOSX__
1145     /* if the window is going away and no resolution change is necessary,
1146      do nothing, or else we may trigger an ugly double-transition
1147      */
1148     if (window->is_destroying && (window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP)
1149         return 0;
1150     
1151     /* If we're switching between a fullscreen Space and "normal" fullscreen, we need to get back to normal first. */
1152     if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN)) {
1153         if (!Cocoa_SetWindowFullscreenSpace(window, SDL_FALSE)) {
1154             return -1;
1155         }
1156     } else if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP)) {
1157         display = SDL_GetDisplayForWindow(window);
1158         SDL_SetDisplayModeForDisplay(display, NULL);
1159         if (_this->SetWindowFullscreen) {
1160             _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
1161         }
1162     }
1163
1164     if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
1165         if (Cocoa_IsWindowInFullscreenSpace(window) != fullscreen) {
1166             return -1;
1167         }
1168         window->last_fullscreen_flags = window->flags;
1169         return 0;
1170     }
1171 #elif __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
1172     /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
1173        or not.  The user can choose this, via OS-provided UI, but this can't
1174        be set programmatically.
1175
1176        Just look at what SDL's WinRT video backend code detected with regards
1177        to fullscreen (being active, or not), and figure out a return/error code
1178        from that.
1179     */
1180     if (fullscreen == !(WINRT_DetectWindowFlags(window) & FULLSCREEN_MASK)) {
1181         /* Uh oh, either:
1182             1. fullscreen was requested, and we're already windowed
1183             2. windowed-mode was requested, and we're already fullscreen
1184
1185             WinRT 8.x can't resolve either programmatically, so we're
1186             giving up.
1187         */
1188         return -1;
1189     } else {
1190         /* Whatever was requested, fullscreen or windowed mode, is already
1191             in-place.
1192         */
1193         return 0;
1194     }
1195 #endif
1196
1197     display = SDL_GetDisplayForWindow(window);
1198
1199     if (fullscreen) {
1200         /* Hide any other fullscreen windows */
1201         if (display->fullscreen_window &&
1202             display->fullscreen_window != window) {
1203             SDL_MinimizeWindow(display->fullscreen_window);
1204         }
1205     }
1206
1207     /* See if anything needs to be done now */
1208     if ((display->fullscreen_window == window) == fullscreen) {
1209         if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
1210             return 0;
1211         }
1212     }
1213
1214     /* See if there are any fullscreen windows */
1215     for (other = _this->windows; other; other = other->next) {
1216         SDL_bool setDisplayMode = SDL_FALSE;
1217
1218         if (other == window) {
1219             setDisplayMode = fullscreen;
1220         } else if (FULLSCREEN_VISIBLE(other) &&
1221                    SDL_GetDisplayForWindow(other) == display) {
1222             setDisplayMode = SDL_TRUE;
1223         }
1224
1225         if (setDisplayMode) {
1226             SDL_DisplayMode fullscreen_mode;
1227
1228             SDL_zero(fullscreen_mode);
1229
1230             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
1231                 SDL_bool resized = SDL_TRUE;
1232
1233                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
1234                     resized = SDL_FALSE;
1235                 }
1236
1237                 /* only do the mode change if we want exclusive fullscreen */
1238                 if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
1239                     if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
1240                         return -1;
1241                     }
1242                 } else {
1243                     if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
1244                         return -1;
1245                     }
1246                 }
1247
1248                 if (_this->SetWindowFullscreen) {
1249                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
1250                 }
1251                 display->fullscreen_window = other;
1252
1253                 /* Generate a mode change event here */
1254                 if (resized) {
1255                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
1256                                         fullscreen_mode.w, fullscreen_mode.h);
1257                 } else {
1258                     SDL_OnWindowResized(other);
1259                 }
1260
1261                 SDL_RestoreMousePosition(other);
1262
1263                 window->last_fullscreen_flags = window->flags;
1264                 return 0;
1265             }
1266         }
1267     }
1268
1269     /* Nope, restore the desktop mode */
1270     SDL_SetDisplayModeForDisplay(display, NULL);
1271
1272     if (_this->SetWindowFullscreen) {
1273         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
1274     }
1275     display->fullscreen_window = NULL;
1276
1277     /* Generate a mode change event here */
1278     SDL_OnWindowResized(window);
1279
1280     /* Restore the cursor position */
1281     SDL_RestoreMousePosition(window);
1282
1283     window->last_fullscreen_flags = window->flags;
1284     return 0;
1285 }
1286
1287 #define CREATE_FLAGS \
1288     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI)
1289
1290 static void
1291 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
1292 {
1293     window->windowed.x = window->x;
1294     window->windowed.y = window->y;
1295     window->windowed.w = window->w;
1296     window->windowed.h = window->h;
1297
1298     if (flags & SDL_WINDOW_MAXIMIZED) {
1299         SDL_MaximizeWindow(window);
1300     }
1301     if (flags & SDL_WINDOW_MINIMIZED) {
1302         SDL_MinimizeWindow(window);
1303     }
1304     if (flags & SDL_WINDOW_FULLSCREEN) {
1305         SDL_SetWindowFullscreen(window, flags);
1306     }
1307     if (flags & SDL_WINDOW_INPUT_GRABBED) {
1308         SDL_SetWindowGrab(window, SDL_TRUE);
1309     }
1310     if (!(flags & SDL_WINDOW_HIDDEN)) {
1311         SDL_ShowWindow(window);
1312     }
1313 }
1314
1315 SDL_Window *
1316 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
1317 {
1318     SDL_Window *window;
1319     const char *hint;
1320
1321     if (!_this) {
1322         /* Initialize the video system if needed */
1323         if (SDL_VideoInit(NULL) < 0) {
1324             return NULL;
1325         }
1326     }
1327
1328     /* Some platforms can't create zero-sized windows */
1329     if (w < 1) {
1330         w = 1;
1331     }
1332     if (h < 1) {
1333         h = 1;
1334     }
1335
1336     /* Some platforms blow up if the windows are too large. Raise it later? */
1337     if ((w > 16384) || (h > 16384)) {
1338         SDL_SetError("Window is too large.");
1339         return NULL;
1340     }
1341
1342     /* Some platforms have OpenGL enabled by default */
1343 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
1344     flags |= SDL_WINDOW_OPENGL;
1345 #endif
1346     if (flags & SDL_WINDOW_OPENGL) {
1347         if (!_this->GL_CreateContext) {
1348             SDL_SetError("No OpenGL support in video driver");
1349             return NULL;
1350         }
1351         if (SDL_GL_LoadLibrary(NULL) < 0) {
1352             return NULL;
1353         }
1354     }
1355
1356     /* Unless the user has specified the high-DPI disabling hint, respect the
1357      * SDL_WINDOW_ALLOW_HIGHDPI flag.
1358      */
1359     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
1360         hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
1361         if (hint && SDL_atoi(hint) > 0) {
1362             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
1363         }
1364     }
1365
1366     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
1367     if (!window) {
1368         SDL_OutOfMemory();
1369         return NULL;
1370     }
1371     window->magic = &_this->window_magic;
1372     window->id = _this->next_object_id++;
1373     window->x = x;
1374     window->y = y;
1375     window->w = w;
1376     window->h = h;
1377     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
1378         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
1379         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1380         int displayIndex;
1381         SDL_Rect bounds;
1382
1383         displayIndex = SDL_GetIndexOfDisplay(display);
1384         SDL_GetDisplayBounds(displayIndex, &bounds);
1385         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
1386             window->x = bounds.x + (bounds.w - w) / 2;
1387         }
1388         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
1389             window->y = bounds.y + (bounds.h - h) / 2;
1390         }
1391     }
1392     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
1393     window->last_fullscreen_flags = window->flags;
1394     window->brightness = 1.0f;
1395     window->next = _this->windows;
1396     window->is_destroying = SDL_FALSE;
1397
1398     if (_this->windows) {
1399         _this->windows->prev = window;
1400     }
1401     _this->windows = window;
1402
1403     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
1404         SDL_DestroyWindow(window);
1405         return NULL;
1406     }
1407
1408 #if __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
1409     /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
1410        or not.  The user can choose this, via OS-provided UI, but this can't
1411        be set programmatically.
1412
1413        Just look at what SDL's WinRT video backend code detected with regards
1414        to fullscreen (being active, or not), and figure out a return/error code
1415        from that.
1416     */
1417     flags = window->flags;
1418 #endif
1419
1420     if (title) {
1421         SDL_SetWindowTitle(window, title);
1422     }
1423     SDL_FinishWindowCreation(window, flags);
1424
1425     /* If the window was created fullscreen, make sure the mode code matches */
1426     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
1427
1428     return window;
1429 }
1430
1431 SDL_Window *
1432 SDL_CreateWindowFrom(const void *data)
1433 {
1434     SDL_Window *window;
1435
1436     if (!_this) {
1437         SDL_UninitializedVideo();
1438         return NULL;
1439     }
1440     if (!_this->CreateWindowFrom) {
1441         SDL_Unsupported();
1442         return NULL;
1443     }
1444     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
1445     if (!window) {
1446         SDL_OutOfMemory();
1447         return NULL;
1448     }
1449     window->magic = &_this->window_magic;
1450     window->id = _this->next_object_id++;
1451     window->flags = SDL_WINDOW_FOREIGN;
1452     window->last_fullscreen_flags = window->flags;
1453     window->is_destroying = SDL_FALSE;
1454     window->brightness = 1.0f;
1455     window->next = _this->windows;
1456     if (_this->windows) {
1457         _this->windows->prev = window;
1458     }
1459     _this->windows = window;
1460
1461     if (_this->CreateWindowFrom(_this, window, data) < 0) {
1462         SDL_DestroyWindow(window);
1463         return NULL;
1464     }
1465     return window;
1466 }
1467
1468 int
1469 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
1470 {
1471     SDL_bool loaded_opengl = SDL_FALSE;
1472
1473     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
1474         return SDL_SetError("No OpenGL support in video driver");
1475     }
1476
1477     if (window->flags & SDL_WINDOW_FOREIGN) {
1478         /* Can't destroy and re-create foreign windows, hrm */
1479         flags |= SDL_WINDOW_FOREIGN;
1480     } else {
1481         flags &= ~SDL_WINDOW_FOREIGN;
1482     }
1483
1484     /* Restore video mode, etc. */
1485     SDL_HideWindow(window);
1486
1487     /* Tear down the old native window */
1488     if (window->surface) {
1489         window->surface->flags &= ~SDL_DONTFREE;
1490         SDL_FreeSurface(window->surface);
1491         window->surface = NULL;
1492     }
1493     if (_this->DestroyWindowFramebuffer) {
1494         _this->DestroyWindowFramebuffer(_this, window);
1495     }
1496     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
1497         _this->DestroyWindow(_this, window);
1498     }
1499
1500     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
1501         if (flags & SDL_WINDOW_OPENGL) {
1502             if (SDL_GL_LoadLibrary(NULL) < 0) {
1503                 return -1;
1504             }
1505             loaded_opengl = SDL_TRUE;
1506         } else {
1507             SDL_GL_UnloadLibrary();
1508         }
1509     }
1510
1511     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
1512     window->last_fullscreen_flags = window->flags;
1513     window->is_destroying = SDL_FALSE;
1514
1515     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
1516         if (_this->CreateWindow(_this, window) < 0) {
1517             if (loaded_opengl) {
1518                 SDL_GL_UnloadLibrary();
1519                 window->flags &= ~SDL_WINDOW_OPENGL;
1520             }
1521             return -1;
1522         }
1523     }
1524
1525     if (flags & SDL_WINDOW_FOREIGN) {
1526         window->flags |= SDL_WINDOW_FOREIGN;
1527     }
1528
1529     if (_this->SetWindowTitle && window->title) {
1530         _this->SetWindowTitle(_this, window);
1531     }
1532
1533     if (_this->SetWindowIcon && window->icon) {
1534         _this->SetWindowIcon(_this, window, window->icon);
1535     }
1536
1537     if (window->hit_test) {
1538         _this->SetWindowHitTest(window, SDL_TRUE);
1539     }
1540
1541     SDL_FinishWindowCreation(window, flags);
1542
1543     return 0;
1544 }
1545
1546 Uint32
1547 SDL_GetWindowID(SDL_Window * window)
1548 {
1549     CHECK_WINDOW_MAGIC(window, 0);
1550
1551     return window->id;
1552 }
1553
1554 SDL_Window *
1555 SDL_GetWindowFromID(Uint32 id)
1556 {
1557     SDL_Window *window;
1558
1559     if (!_this) {
1560         return NULL;
1561     }
1562     for (window = _this->windows; window; window = window->next) {
1563         if (window->id == id) {
1564             return window;
1565         }
1566     }
1567     return NULL;
1568 }
1569
1570 Uint32
1571 SDL_GetWindowFlags(SDL_Window * window)
1572 {
1573     CHECK_WINDOW_MAGIC(window, 0);
1574
1575     return window->flags;
1576 }
1577
1578 void
1579 SDL_SetWindowTitle(SDL_Window * window, const char *title)
1580 {
1581     CHECK_WINDOW_MAGIC(window,);
1582
1583     if (title == window->title) {
1584         return;
1585     }
1586     SDL_free(window->title);
1587
1588     window->title = SDL_strdup(title ? title : "");
1589
1590     if (_this->SetWindowTitle) {
1591         _this->SetWindowTitle(_this, window);
1592     }
1593 }
1594
1595 const char *
1596 SDL_GetWindowTitle(SDL_Window * window)
1597 {
1598     CHECK_WINDOW_MAGIC(window, "");
1599
1600     return window->title ? window->title : "";
1601 }
1602
1603 void
1604 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
1605 {
1606     CHECK_WINDOW_MAGIC(window,);
1607
1608     if (!icon) {
1609         return;
1610     }
1611
1612     SDL_FreeSurface(window->icon);
1613
1614     /* Convert the icon into ARGB8888 */
1615     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
1616     if (!window->icon) {
1617         return;
1618     }
1619
1620     if (_this->SetWindowIcon) {
1621         _this->SetWindowIcon(_this, window, window->icon);
1622     }
1623 }
1624
1625 void*
1626 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
1627 {
1628     SDL_WindowUserData *prev, *data;
1629
1630     CHECK_WINDOW_MAGIC(window, NULL);
1631
1632     /* Input validation */
1633     if (name == NULL || name[0] == '\0') {
1634       SDL_InvalidParamError("name");
1635       return NULL;
1636     }
1637
1638     /* See if the named data already exists */
1639     prev = NULL;
1640     for (data = window->data; data; prev = data, data = data->next) {
1641         if (data->name && SDL_strcmp(data->name, name) == 0) {
1642             void *last_value = data->data;
1643
1644             if (userdata) {
1645                 /* Set the new value */
1646                 data->data = userdata;
1647             } else {
1648                 /* Delete this value */
1649                 if (prev) {
1650                     prev->next = data->next;
1651                 } else {
1652                     window->data = data->next;
1653                 }
1654                 SDL_free(data->name);
1655                 SDL_free(data);
1656             }
1657             return last_value;
1658         }
1659     }
1660
1661     /* Add new data to the window */
1662     if (userdata) {
1663         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
1664         data->name = SDL_strdup(name);
1665         data->data = userdata;
1666         data->next = window->data;
1667         window->data = data;
1668     }
1669     return NULL;
1670 }
1671
1672 void *
1673 SDL_GetWindowData(SDL_Window * window, const char *name)
1674 {
1675     SDL_WindowUserData *data;
1676
1677     CHECK_WINDOW_MAGIC(window, NULL);
1678
1679     /* Input validation */
1680     if (name == NULL || name[0] == '\0') {
1681       SDL_InvalidParamError("name");
1682       return NULL;
1683     }
1684
1685     for (data = window->data; data; data = data->next) {
1686         if (data->name && SDL_strcmp(data->name, name) == 0) {
1687             return data->data;
1688         }
1689     }
1690     return NULL;
1691 }
1692
1693 void
1694 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
1695 {
1696     CHECK_WINDOW_MAGIC(window,);
1697
1698     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
1699         int displayIndex = (x & 0xFFFF);
1700         SDL_Rect bounds;
1701         if (displayIndex > _this->num_displays) {
1702             displayIndex = 0;
1703         }
1704
1705         SDL_zero(bounds);
1706
1707         SDL_GetDisplayBounds(displayIndex, &bounds);
1708         if (SDL_WINDOWPOS_ISCENTERED(x)) {
1709             x = bounds.x + (bounds.w - window->w) / 2;
1710         }
1711         if (SDL_WINDOWPOS_ISCENTERED(y)) {
1712             y = bounds.y + (bounds.h - window->h) / 2;
1713         }
1714     }
1715
1716     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
1717         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
1718             window->windowed.x = x;
1719         }
1720         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
1721             window->windowed.y = y;
1722         }
1723     } else {
1724         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
1725             window->x = x;
1726         }
1727         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
1728             window->y = y;
1729         }
1730
1731         if (_this->SetWindowPosition) {
1732             _this->SetWindowPosition(_this, window);
1733         }
1734         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
1735     }
1736 }
1737
1738 void
1739 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
1740 {
1741     CHECK_WINDOW_MAGIC(window,);
1742
1743     /* Fullscreen windows are always at their display's origin */
1744     if (window->flags & SDL_WINDOW_FULLSCREEN) {
1745         int displayIndex;
1746         
1747         if (x) {
1748             *x = 0;
1749         }
1750         if (y) {
1751             *y = 0;
1752         }
1753
1754         /* Find the window's monitor and update to the
1755            monitor offset. */
1756         displayIndex = SDL_GetWindowDisplayIndex(window);
1757         if (displayIndex >= 0) {
1758             SDL_Rect bounds;
1759
1760             SDL_zero(bounds);
1761
1762             SDL_GetDisplayBounds(displayIndex, &bounds);
1763             if (x) {
1764                 *x = bounds.x;
1765             }
1766             if (y) {
1767                 *y = bounds.y;
1768             }
1769         }
1770     } else {
1771         if (x) {
1772             *x = window->x;
1773         }
1774         if (y) {
1775             *y = window->y;
1776         }
1777     }
1778 }
1779
1780 void
1781 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
1782 {
1783     CHECK_WINDOW_MAGIC(window,);
1784     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1785         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
1786         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
1787         if ((want != have) && (_this->SetWindowBordered)) {
1788             if (want) {
1789                 window->flags &= ~SDL_WINDOW_BORDERLESS;
1790             } else {
1791                 window->flags |= SDL_WINDOW_BORDERLESS;
1792             }
1793             _this->SetWindowBordered(_this, window, (SDL_bool) want);
1794         }
1795     }
1796 }
1797
1798 void
1799 SDL_SetWindowSize(SDL_Window * window, int w, int h)
1800 {
1801     CHECK_WINDOW_MAGIC(window,);
1802     if (w <= 0) {
1803         SDL_InvalidParamError("w");
1804         return;
1805     }
1806     if (h <= 0) {
1807         SDL_InvalidParamError("h");
1808         return;
1809     }
1810
1811     /* Make sure we don't exceed any window size limits */
1812     if (window->min_w && w < window->min_w)
1813     {
1814         w = window->min_w;
1815     }
1816     if (window->max_w && w > window->max_w)
1817     {
1818         w = window->max_w;
1819     }
1820     if (window->min_h && h < window->min_h)
1821     {
1822         h = window->min_h;
1823     }
1824     if (window->max_h && h > window->max_h)
1825     {
1826         h = window->max_h;
1827     }
1828
1829     window->windowed.w = w;
1830     window->windowed.h = h;
1831
1832     if (window->flags & SDL_WINDOW_FULLSCREEN) {
1833         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
1834             window->last_fullscreen_flags = 0;
1835             SDL_UpdateFullscreenMode(window, SDL_TRUE);
1836         }
1837     } else {
1838         window->w = w;
1839         window->h = h;
1840         if (_this->SetWindowSize) {
1841             _this->SetWindowSize(_this, window);
1842         }
1843         if (window->w == w && window->h == h) {
1844             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
1845             SDL_OnWindowResized(window);
1846         }
1847     }
1848 }
1849
1850 void
1851 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
1852 {
1853     CHECK_WINDOW_MAGIC(window,);
1854     if (w) {
1855         *w = window->w;
1856     }
1857     if (h) {
1858         *h = window->h;
1859     }
1860 }
1861
1862 void
1863 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
1864 {
1865     CHECK_WINDOW_MAGIC(window,);
1866     if (min_w <= 0) {
1867         SDL_InvalidParamError("min_w");
1868         return;
1869     }
1870     if (min_h <= 0) {
1871         SDL_InvalidParamError("min_h");
1872         return;
1873     }
1874
1875     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1876         window->min_w = min_w;
1877         window->min_h = min_h;
1878         if (_this->SetWindowMinimumSize) {
1879             _this->SetWindowMinimumSize(_this, window);
1880         }
1881         /* Ensure that window is not smaller than minimal size */
1882         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
1883     }
1884 }
1885
1886 void
1887 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
1888 {
1889     CHECK_WINDOW_MAGIC(window,);
1890     if (min_w) {
1891         *min_w = window->min_w;
1892     }
1893     if (min_h) {
1894         *min_h = window->min_h;
1895     }
1896 }
1897
1898 void
1899 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
1900 {
1901     CHECK_WINDOW_MAGIC(window,);
1902     if (max_w <= 0) {
1903         SDL_InvalidParamError("max_w");
1904         return;
1905     }
1906     if (max_h <= 0) {
1907         SDL_InvalidParamError("max_h");
1908         return;
1909     }
1910
1911     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
1912         window->max_w = max_w;
1913         window->max_h = max_h;
1914         if (_this->SetWindowMaximumSize) {
1915             _this->SetWindowMaximumSize(_this, window);
1916         }
1917         /* Ensure that window is not larger than maximal size */
1918         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
1919     }
1920 }
1921
1922 void
1923 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
1924 {
1925     CHECK_WINDOW_MAGIC(window,);
1926     if (max_w) {
1927         *max_w = window->max_w;
1928     }
1929     if (max_h) {
1930         *max_h = window->max_h;
1931     }
1932 }
1933
1934 void
1935 SDL_ShowWindow(SDL_Window * window)
1936 {
1937     CHECK_WINDOW_MAGIC(window,);
1938
1939     if (window->flags & SDL_WINDOW_SHOWN) {
1940         return;
1941     }
1942
1943     if (_this->ShowWindow) {
1944         _this->ShowWindow(_this, window);
1945     }
1946     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
1947 }
1948
1949 void
1950 SDL_HideWindow(SDL_Window * window)
1951 {
1952     CHECK_WINDOW_MAGIC(window,);
1953
1954     if (!(window->flags & SDL_WINDOW_SHOWN)) {
1955         return;
1956     }
1957
1958         window->is_hiding = SDL_TRUE;
1959     SDL_UpdateFullscreenMode(window, SDL_FALSE);
1960
1961     if (_this->HideWindow) {
1962         _this->HideWindow(_this, window);
1963     }
1964         window->is_hiding = SDL_FALSE;
1965     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
1966 }
1967
1968 void
1969 SDL_RaiseWindow(SDL_Window * window)
1970 {
1971     CHECK_WINDOW_MAGIC(window,);
1972
1973     if (!(window->flags & SDL_WINDOW_SHOWN)) {
1974         return;
1975     }
1976     if (_this->RaiseWindow) {
1977         _this->RaiseWindow(_this, window);
1978     }
1979 }
1980
1981 void
1982 SDL_MaximizeWindow(SDL_Window * window)
1983 {
1984     CHECK_WINDOW_MAGIC(window,);
1985
1986     if (window->flags & SDL_WINDOW_MAXIMIZED) {
1987         return;
1988     }
1989
1990     /* !!! FIXME: should this check if the window is resizable? */
1991
1992     if (_this->MaximizeWindow) {
1993         _this->MaximizeWindow(_this, window);
1994     }
1995 }
1996
1997 void
1998 SDL_MinimizeWindow(SDL_Window * window)
1999 {
2000     CHECK_WINDOW_MAGIC(window,);
2001
2002     if (window->flags & SDL_WINDOW_MINIMIZED) {
2003         return;
2004     }
2005
2006     SDL_UpdateFullscreenMode(window, SDL_FALSE);
2007
2008     if (_this->MinimizeWindow) {
2009         _this->MinimizeWindow(_this, window);
2010     }
2011 }
2012
2013 void
2014 SDL_RestoreWindow(SDL_Window * window)
2015 {
2016     CHECK_WINDOW_MAGIC(window,);
2017
2018     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
2019         return;
2020     }
2021
2022     if (_this->RestoreWindow) {
2023         _this->RestoreWindow(_this, window);
2024     }
2025 }
2026
2027 int
2028 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
2029 {
2030     Uint32 oldflags;
2031     CHECK_WINDOW_MAGIC(window, -1);
2032
2033     flags &= FULLSCREEN_MASK;
2034
2035     if (flags == (window->flags & FULLSCREEN_MASK)) {
2036         return 0;
2037     }
2038
2039     /* clear the previous flags and OR in the new ones */
2040     oldflags = window->flags & FULLSCREEN_MASK;
2041     window->flags &= ~FULLSCREEN_MASK;
2042     window->flags |= flags;
2043
2044     if (SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)) == 0) {
2045         return 0;
2046     }
2047     
2048     window->flags &= ~FULLSCREEN_MASK;
2049     window->flags |= oldflags;
2050     return -1;
2051 }
2052
2053 static SDL_Surface *
2054 SDL_CreateWindowFramebuffer(SDL_Window * window)
2055 {
2056     Uint32 format;
2057     void *pixels;
2058     int pitch;
2059     int bpp;
2060     Uint32 Rmask, Gmask, Bmask, Amask;
2061
2062     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
2063         return NULL;
2064     }
2065
2066     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
2067         return NULL;
2068     }
2069
2070     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
2071         return NULL;
2072     }
2073
2074     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
2075 }
2076
2077 SDL_Surface *
2078 SDL_GetWindowSurface(SDL_Window * window)
2079 {
2080     CHECK_WINDOW_MAGIC(window, NULL);
2081
2082     if (!window->surface_valid) {
2083         if (window->surface) {
2084             window->surface->flags &= ~SDL_DONTFREE;
2085             SDL_FreeSurface(window->surface);
2086         }
2087         window->surface = SDL_CreateWindowFramebuffer(window);
2088         if (window->surface) {
2089             window->surface_valid = SDL_TRUE;
2090             window->surface->flags |= SDL_DONTFREE;
2091         }
2092     }
2093     return window->surface;
2094 }
2095
2096 int
2097 SDL_UpdateWindowSurface(SDL_Window * window)
2098 {
2099     SDL_Rect full_rect;
2100
2101     CHECK_WINDOW_MAGIC(window, -1);
2102
2103     full_rect.x = 0;
2104     full_rect.y = 0;
2105     full_rect.w = window->w;
2106     full_rect.h = window->h;
2107     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
2108 }
2109
2110 int
2111 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
2112                              int numrects)
2113 {
2114     CHECK_WINDOW_MAGIC(window, -1);
2115
2116     if (!window->surface_valid) {
2117         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
2118     }
2119
2120     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
2121 }
2122
2123 int
2124 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
2125 {
2126     Uint16 ramp[256];
2127     int status;
2128
2129     CHECK_WINDOW_MAGIC(window, -1);
2130
2131     SDL_CalculateGammaRamp(brightness, ramp);
2132     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
2133     if (status == 0) {
2134         window->brightness = brightness;
2135     }
2136     return status;
2137 }
2138
2139 float
2140 SDL_GetWindowBrightness(SDL_Window * window)
2141 {
2142     CHECK_WINDOW_MAGIC(window, 1.0f);
2143
2144     return window->brightness;
2145 }
2146
2147 int
2148 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
2149                                             const Uint16 * green,
2150                                             const Uint16 * blue)
2151 {
2152     CHECK_WINDOW_MAGIC(window, -1);
2153
2154     if (!_this->SetWindowGammaRamp) {
2155         return SDL_Unsupported();
2156     }
2157
2158     if (!window->gamma) {
2159         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
2160             return -1;
2161         }
2162         SDL_assert(window->gamma != NULL);
2163     }
2164
2165     if (red) {
2166         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
2167     }
2168     if (green) {
2169         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
2170     }
2171     if (blue) {
2172         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
2173     }
2174     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
2175         return _this->SetWindowGammaRamp(_this, window, window->gamma);
2176     } else {
2177         return 0;
2178     }
2179 }
2180
2181 int
2182 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
2183                                             Uint16 * green,
2184                                             Uint16 * blue)
2185 {
2186     CHECK_WINDOW_MAGIC(window, -1);
2187
2188     if (!window->gamma) {
2189         int i;
2190
2191         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
2192         if (!window->gamma) {
2193             return SDL_OutOfMemory();
2194         }
2195         window->saved_gamma = window->gamma + 3*256;
2196
2197         if (_this->GetWindowGammaRamp) {
2198             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
2199                 return -1;
2200             }
2201         } else {
2202             /* Create an identity gamma ramp */
2203             for (i = 0; i < 256; ++i) {
2204                 Uint16 value = (Uint16)((i << 8) | i);
2205
2206                 window->gamma[0*256+i] = value;
2207                 window->gamma[1*256+i] = value;
2208                 window->gamma[2*256+i] = value;
2209             }
2210         }
2211         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
2212     }
2213
2214     if (red) {
2215         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
2216     }
2217     if (green) {
2218         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
2219     }
2220     if (blue) {
2221         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
2222     }
2223     return 0;
2224 }
2225
2226 void
2227 SDL_UpdateWindowGrab(SDL_Window * window)
2228 {
2229     SDL_Window *grabbed_window;
2230     SDL_bool grabbed;
2231     if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
2232          (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
2233         grabbed = SDL_TRUE;
2234     } else {
2235         grabbed = SDL_FALSE;
2236     }
2237
2238     grabbed_window = _this->grabbed_window;
2239     if (grabbed) {
2240         if (grabbed_window && (grabbed_window != window)) {
2241             /* stealing a grab from another window! */
2242             grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
2243             if (_this->SetWindowGrab) {
2244                 _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE);
2245             }
2246         }
2247         _this->grabbed_window = window;
2248     } else if (grabbed_window == window) {
2249         _this->grabbed_window = NULL;  /* ungrabbing. */
2250     }
2251
2252     if (_this->SetWindowGrab) {
2253         _this->SetWindowGrab(_this, window, grabbed);
2254     }
2255 }
2256
2257 void
2258 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
2259 {
2260     CHECK_WINDOW_MAGIC(window,);
2261
2262     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
2263         return;
2264     }
2265     if (grabbed) {
2266         window->flags |= SDL_WINDOW_INPUT_GRABBED;
2267     } else {
2268         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
2269     }
2270     SDL_UpdateWindowGrab(window);
2271 }
2272
2273 SDL_bool
2274 SDL_GetWindowGrab(SDL_Window * window)
2275 {
2276     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
2277     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
2278     return window == _this->grabbed_window;
2279 }
2280
2281 SDL_Window *
2282 SDL_GetGrabbedWindow(void)
2283 {
2284     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
2285     return _this->grabbed_window;
2286 }
2287
2288 void
2289 SDL_OnWindowShown(SDL_Window * window)
2290 {
2291     SDL_OnWindowRestored(window);
2292 }
2293
2294 void
2295 SDL_OnWindowHidden(SDL_Window * window)
2296 {
2297     SDL_UpdateFullscreenMode(window, SDL_FALSE);
2298 }
2299
2300 void
2301 SDL_OnWindowResized(SDL_Window * window)
2302 {
2303     window->surface_valid = SDL_FALSE;
2304     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
2305 }
2306
2307 void
2308 SDL_OnWindowMinimized(SDL_Window * window)
2309 {
2310     SDL_UpdateFullscreenMode(window, SDL_FALSE);
2311 }
2312
2313 void
2314 SDL_OnWindowRestored(SDL_Window * window)
2315 {
2316     /*
2317      * FIXME: Is this fine to just remove this, or should it be preserved just
2318      * for the fullscreen case? In principle it seems like just hiding/showing
2319      * windows shouldn't affect the stacking order; maybe the right fix is to
2320      * re-decouple OnWindowShown and OnWindowRestored.
2321      */
2322     /*SDL_RaiseWindow(window);*/
2323
2324     if (FULLSCREEN_VISIBLE(window)) {
2325         SDL_UpdateFullscreenMode(window, SDL_TRUE);
2326     }
2327 }
2328
2329 void
2330 SDL_OnWindowEnter(SDL_Window * window)
2331 {
2332     if (_this->OnWindowEnter) {
2333         _this->OnWindowEnter(_this, window);
2334     }
2335 }
2336
2337 void
2338 SDL_OnWindowLeave(SDL_Window * window)
2339 {
2340 }
2341
2342 void
2343 SDL_OnWindowFocusGained(SDL_Window * window)
2344 {
2345     SDL_Mouse *mouse = SDL_GetMouse();
2346
2347     if (window->gamma && _this->SetWindowGammaRamp) {
2348         _this->SetWindowGammaRamp(_this, window, window->gamma);
2349     }
2350
2351     if (mouse && mouse->relative_mode) {
2352         SDL_SetMouseFocus(window);
2353         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
2354     }
2355
2356     SDL_UpdateWindowGrab(window);
2357 }
2358
2359 static SDL_bool
2360 ShouldMinimizeOnFocusLoss(SDL_Window * window)
2361 {
2362     const char *hint;
2363
2364     if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
2365         return SDL_FALSE;
2366     }
2367
2368 #ifdef __MACOSX__
2369     if (Cocoa_IsWindowInFullscreenSpace(window)) {
2370         return SDL_FALSE;
2371     }
2372 #endif
2373
2374     hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
2375     if (hint) {
2376         if (*hint == '0') {
2377             return SDL_FALSE;
2378         } else {
2379             return SDL_TRUE;
2380         }
2381     }
2382
2383     return SDL_TRUE;
2384 }
2385
2386 void
2387 SDL_OnWindowFocusLost(SDL_Window * window)
2388 {
2389     if (window->gamma && _this->SetWindowGammaRamp) {
2390         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
2391     }
2392
2393     SDL_UpdateWindowGrab(window);
2394
2395     if (ShouldMinimizeOnFocusLoss(window)) {
2396         SDL_MinimizeWindow(window);
2397     }
2398 }
2399
2400 /* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
2401    !!! FIXME:  Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
2402 SDL_Window *
2403 SDL_GetFocusWindow(void)
2404 {
2405     SDL_Window *window;
2406
2407     if (!_this) {
2408         return NULL;
2409     }
2410     for (window = _this->windows; window; window = window->next) {
2411         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
2412             return window;
2413         }
2414     }
2415     return NULL;
2416 }
2417
2418 void
2419 SDL_DestroyWindow(SDL_Window * window)
2420 {
2421     SDL_VideoDisplay *display;
2422
2423     CHECK_WINDOW_MAGIC(window,);
2424
2425     window->is_destroying = SDL_TRUE;
2426
2427     /* Restore video mode, etc. */
2428     SDL_HideWindow(window);
2429
2430     /* Make sure this window no longer has focus */
2431     if (SDL_GetKeyboardFocus() == window) {
2432         SDL_SetKeyboardFocus(NULL);
2433     }
2434     if (SDL_GetMouseFocus() == window) {
2435         SDL_SetMouseFocus(NULL);
2436     }
2437
2438     /* make no context current if this is the current context window. */
2439     if (window->flags & SDL_WINDOW_OPENGL) {
2440         if (_this->current_glwin == window) {
2441             SDL_GL_MakeCurrent(window, NULL);
2442         }
2443     }
2444
2445     if (window->surface) {
2446         window->surface->flags &= ~SDL_DONTFREE;
2447         SDL_FreeSurface(window->surface);
2448     }
2449     if (_this->DestroyWindowFramebuffer) {
2450         _this->DestroyWindowFramebuffer(_this, window);
2451     }
2452     if (_this->DestroyWindow) {
2453         _this->DestroyWindow(_this, window);
2454     }
2455     if (window->flags & SDL_WINDOW_OPENGL) {
2456         SDL_GL_UnloadLibrary();
2457     }
2458
2459     display = SDL_GetDisplayForWindow(window);
2460     if (display->fullscreen_window == window) {
2461         display->fullscreen_window = NULL;
2462     }
2463
2464     /* Now invalidate magic */
2465     window->magic = NULL;
2466
2467     /* Free memory associated with the window */
2468     SDL_free(window->title);
2469     SDL_FreeSurface(window->icon);
2470     SDL_free(window->gamma);
2471     while (window->data) {
2472         SDL_WindowUserData *data = window->data;
2473
2474         window->data = data->next;
2475         SDL_free(data->name);
2476         SDL_free(data);
2477     }
2478
2479     /* Unlink the window from the list */
2480     if (window->next) {
2481         window->next->prev = window->prev;
2482     }
2483     if (window->prev) {
2484         window->prev->next = window->next;
2485     } else {
2486         _this->windows = window->next;
2487     }
2488
2489     SDL_free(window);
2490 }
2491
2492 SDL_bool
2493 SDL_IsScreenSaverEnabled()
2494 {
2495     if (!_this) {
2496         return SDL_TRUE;
2497     }
2498     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
2499 }
2500
2501 void
2502 SDL_EnableScreenSaver()
2503 {
2504     if (!_this) {
2505         return;
2506     }
2507     if (!_this->suspend_screensaver) {
2508         return;
2509     }
2510     _this->suspend_screensaver = SDL_FALSE;
2511     if (_this->SuspendScreenSaver) {
2512         _this->SuspendScreenSaver(_this);
2513     }
2514 }
2515
2516 void
2517 SDL_DisableScreenSaver()
2518 {
2519     if (!_this) {
2520         return;
2521     }
2522     if (_this->suspend_screensaver) {
2523         return;
2524     }
2525     _this->suspend_screensaver = SDL_TRUE;
2526     if (_this->SuspendScreenSaver) {
2527         _this->SuspendScreenSaver(_this);
2528     }
2529 }
2530
2531 void
2532 SDL_VideoQuit(void)
2533 {
2534     int i, j;
2535
2536     if (!_this) {
2537         return;
2538     }
2539
2540     /* Halt event processing before doing anything else */
2541     SDL_TouchQuit();
2542     SDL_MouseQuit();
2543     SDL_KeyboardQuit();
2544     SDL_QuitSubSystem(SDL_INIT_EVENTS);
2545
2546     SDL_EnableScreenSaver();
2547
2548     /* Clean up the system video */
2549     while (_this->windows) {
2550         SDL_DestroyWindow(_this->windows);
2551     }
2552     _this->VideoQuit(_this);
2553
2554     for (i = 0; i < _this->num_displays; ++i) {
2555         SDL_VideoDisplay *display = &_this->displays[i];
2556         for (j = display->num_display_modes; j--;) {
2557             SDL_free(display->display_modes[j].driverdata);
2558             display->display_modes[j].driverdata = NULL;
2559         }
2560         SDL_free(display->display_modes);
2561         display->display_modes = NULL;
2562         SDL_free(display->desktop_mode.driverdata);
2563         display->desktop_mode.driverdata = NULL;
2564         SDL_free(display->driverdata);
2565         display->driverdata = NULL;
2566     }
2567     if (_this->displays) {
2568         for (i = 0; i < _this->num_displays; ++i) {
2569             SDL_free(_this->displays[i].name);
2570         }
2571         SDL_free(_this->displays);
2572         _this->displays = NULL;
2573         _this->num_displays = 0;
2574     }
2575     SDL_free(_this->clipboard_text);
2576     _this->clipboard_text = NULL;
2577     _this->free(_this);
2578     _this = NULL;
2579 }
2580
2581 int
2582 SDL_GL_LoadLibrary(const char *path)
2583 {
2584     int retval;
2585
2586     if (!_this) {
2587         return SDL_UninitializedVideo();
2588     }
2589     if (_this->gl_config.driver_loaded) {
2590         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
2591             return SDL_SetError("OpenGL library already loaded");
2592         }
2593         retval = 0;
2594     } else {
2595         if (!_this->GL_LoadLibrary) {
2596             return SDL_SetError("No dynamic GL support in video driver");
2597         }
2598         retval = _this->GL_LoadLibrary(_this, path);
2599     }
2600     if (retval == 0) {
2601         ++_this->gl_config.driver_loaded;
2602     } else {
2603         if (_this->GL_UnloadLibrary) {
2604             _this->GL_UnloadLibrary(_this);
2605         }
2606     }
2607     return (retval);
2608 }
2609
2610 void *
2611 SDL_GL_GetProcAddress(const char *proc)
2612 {
2613     void *func;
2614
2615     if (!_this) {
2616         SDL_UninitializedVideo();
2617         return NULL;
2618     }
2619     func = NULL;
2620     if (_this->GL_GetProcAddress) {
2621         if (_this->gl_config.driver_loaded) {
2622             func = _this->GL_GetProcAddress(_this, proc);
2623         } else {
2624             SDL_SetError("No GL driver has been loaded");
2625         }
2626     } else {
2627         SDL_SetError("No dynamic GL support in video driver");
2628     }
2629     return func;
2630 }
2631
2632 void
2633 SDL_GL_UnloadLibrary(void)
2634 {
2635     if (!_this) {
2636         SDL_UninitializedVideo();
2637         return;
2638     }
2639     if (_this->gl_config.driver_loaded > 0) {
2640         if (--_this->gl_config.driver_loaded > 0) {
2641             return;
2642         }
2643         if (_this->GL_UnloadLibrary) {
2644             _this->GL_UnloadLibrary(_this);
2645         }
2646     }
2647 }
2648
2649 static SDL_INLINE SDL_bool
2650 isAtLeastGL3(const char *verstr)
2651 {
2652     return (verstr && (SDL_atoi(verstr) >= 3));
2653 }
2654
2655 SDL_bool
2656 SDL_GL_ExtensionSupported(const char *extension)
2657 {
2658 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2659     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
2660     const char *extensions;
2661     const char *start;
2662     const char *where, *terminator;
2663
2664     /* Extension names should not have spaces. */
2665     where = SDL_strchr(extension, ' ');
2666     if (where || *extension == '\0') {
2667         return SDL_FALSE;
2668     }
2669     /* See if there's an environment variable override */
2670     start = SDL_getenv(extension);
2671     if (start && *start == '0') {
2672         return SDL_FALSE;
2673     }
2674
2675     /* Lookup the available extensions */
2676
2677     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
2678     if (!glGetStringFunc) {
2679         return SDL_FALSE;
2680     }
2681
2682     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
2683         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
2684         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
2685         GLint num_exts = 0;
2686         GLint i;
2687
2688         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
2689         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
2690         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
2691             return SDL_FALSE;
2692         }
2693
2694         #ifndef GL_NUM_EXTENSIONS
2695         #define GL_NUM_EXTENSIONS 0x821D
2696         #endif
2697         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
2698         for (i = 0; i < num_exts; i++) {
2699             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
2700             if (SDL_strcmp(thisext, extension) == 0) {
2701                 return SDL_TRUE;
2702             }
2703         }
2704
2705         return SDL_FALSE;
2706     }
2707
2708     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
2709
2710     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
2711     if (!extensions) {
2712         return SDL_FALSE;
2713     }
2714     /*
2715      * It takes a bit of care to be fool-proof about parsing the OpenGL
2716      * extensions string. Don't be fooled by sub-strings, etc.
2717      */
2718
2719     start = extensions;
2720
2721     for (;;) {
2722         where = SDL_strstr(start, extension);
2723         if (!where)
2724             break;
2725
2726         terminator = where + SDL_strlen(extension);
2727         if (where == start || *(where - 1) == ' ')
2728             if (*terminator == ' ' || *terminator == '\0')
2729                 return SDL_TRUE;
2730
2731         start = terminator;
2732     }
2733     return SDL_FALSE;
2734 #else
2735     return SDL_FALSE;
2736 #endif
2737 }
2738
2739 void
2740 SDL_GL_ResetAttributes()
2741 {
2742     if (!_this) {
2743         return;
2744     }
2745
2746     _this->gl_config.red_size = 3;
2747     _this->gl_config.green_size = 3;
2748     _this->gl_config.blue_size = 2;
2749     _this->gl_config.alpha_size = 0;
2750     _this->gl_config.buffer_size = 0;
2751     _this->gl_config.depth_size = 16;
2752     _this->gl_config.stencil_size = 0;
2753     _this->gl_config.double_buffer = 1;
2754     _this->gl_config.accum_red_size = 0;
2755     _this->gl_config.accum_green_size = 0;
2756     _this->gl_config.accum_blue_size = 0;
2757     _this->gl_config.accum_alpha_size = 0;
2758     _this->gl_config.stereo = 0;
2759     _this->gl_config.multisamplebuffers = 0;
2760     _this->gl_config.multisamplesamples = 0;
2761     _this->gl_config.retained_backing = 1;
2762     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
2763     _this->gl_config.profile_mask = 0;
2764 #if SDL_VIDEO_OPENGL
2765     _this->gl_config.major_version = 2;
2766     _this->gl_config.minor_version = 1;
2767 #elif SDL_VIDEO_OPENGL_ES2
2768     _this->gl_config.major_version = 2;
2769     _this->gl_config.minor_version = 0;
2770     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
2771 #elif SDL_VIDEO_OPENGL_ES
2772     _this->gl_config.major_version = 1;
2773     _this->gl_config.minor_version = 1;
2774     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
2775 #endif
2776     _this->gl_config.flags = 0;
2777     _this->gl_config.framebuffer_srgb_capable = 0;
2778     _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH;
2779
2780     _this->gl_config.share_with_current_context = 0;
2781 }
2782
2783 int
2784 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
2785 {
2786 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2787     int retval;
2788
2789     if (!_this) {
2790         return SDL_UninitializedVideo();
2791     }
2792     retval = 0;
2793     switch (attr) {
2794     case SDL_GL_RED_SIZE:
2795         _this->gl_config.red_size = value;
2796         break;
2797     case SDL_GL_GREEN_SIZE:
2798         _this->gl_config.green_size = value;
2799         break;
2800     case SDL_GL_BLUE_SIZE:
2801         _this->gl_config.blue_size = value;
2802         break;
2803     case SDL_GL_ALPHA_SIZE:
2804         _this->gl_config.alpha_size = value;
2805         break;
2806     case SDL_GL_DOUBLEBUFFER:
2807         _this->gl_config.double_buffer = value;
2808         break;
2809     case SDL_GL_BUFFER_SIZE:
2810         _this->gl_config.buffer_size = value;
2811         break;
2812     case SDL_GL_DEPTH_SIZE:
2813         _this->gl_config.depth_size = value;
2814         break;
2815     case SDL_GL_STENCIL_SIZE:
2816         _this->gl_config.stencil_size = value;
2817         break;
2818     case SDL_GL_ACCUM_RED_SIZE:
2819         _this->gl_config.accum_red_size = value;
2820         break;
2821     case SDL_GL_ACCUM_GREEN_SIZE:
2822         _this->gl_config.accum_green_size = value;
2823         break;
2824     case SDL_GL_ACCUM_BLUE_SIZE:
2825         _this->gl_config.accum_blue_size = value;
2826         break;
2827     case SDL_GL_ACCUM_ALPHA_SIZE:
2828         _this->gl_config.accum_alpha_size = value;
2829         break;
2830     case SDL_GL_STEREO:
2831         _this->gl_config.stereo = value;
2832         break;
2833     case SDL_GL_MULTISAMPLEBUFFERS:
2834         _this->gl_config.multisamplebuffers = value;
2835         break;
2836     case SDL_GL_MULTISAMPLESAMPLES:
2837         _this->gl_config.multisamplesamples = value;
2838         break;
2839     case SDL_GL_ACCELERATED_VISUAL:
2840         _this->gl_config.accelerated = value;
2841         break;
2842     case SDL_GL_RETAINED_BACKING:
2843         _this->gl_config.retained_backing = value;
2844         break;
2845     case SDL_GL_CONTEXT_MAJOR_VERSION:
2846         _this->gl_config.major_version = value;
2847         break;
2848     case SDL_GL_CONTEXT_MINOR_VERSION:
2849         _this->gl_config.minor_version = value;
2850         break;
2851     case SDL_GL_CONTEXT_EGL:
2852         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
2853         if (value != 0) {
2854             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
2855         } else {
2856             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
2857         };
2858         break;
2859     case SDL_GL_CONTEXT_FLAGS:
2860         if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
2861                       SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
2862                       SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
2863                       SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
2864             retval = SDL_SetError("Unknown OpenGL context flag %d", value);
2865             break;
2866         }
2867         _this->gl_config.flags = value;
2868         break;
2869     case SDL_GL_CONTEXT_PROFILE_MASK:
2870         if (value != 0 &&
2871             value != SDL_GL_CONTEXT_PROFILE_CORE &&
2872             value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
2873             value != SDL_GL_CONTEXT_PROFILE_ES) {
2874             retval = SDL_SetError("Unknown OpenGL context profile %d", value);
2875             break;
2876         }
2877         _this->gl_config.profile_mask = value;
2878         break;
2879     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
2880         _this->gl_config.share_with_current_context = value;
2881         break;
2882     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
2883         _this->gl_config.framebuffer_srgb_capable = value;
2884         break;
2885     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
2886         _this->gl_config.release_behavior = value;
2887         break;
2888     default:
2889         retval = SDL_SetError("Unknown OpenGL attribute");
2890         break;
2891     }
2892     return retval;
2893 #else
2894     return SDL_Unsupported();
2895 #endif /* SDL_VIDEO_OPENGL */
2896 }
2897
2898 int
2899 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
2900 {
2901 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
2902     GLenum (APIENTRY *glGetErrorFunc) (void);
2903     GLenum attrib = 0;
2904     GLenum error = 0;
2905
2906     /*
2907      * Some queries in Core Profile desktop OpenGL 3+ contexts require
2908      * glGetFramebufferAttachmentParameteriv instead of glGetIntegerv. Note that
2909      * the enums we use for the former function don't exist in OpenGL ES 2, and
2910      * the function itself doesn't exist prior to OpenGL 3 and OpenGL ES 2.
2911      */
2912 #if SDL_VIDEO_OPENGL
2913     const GLubyte *(APIENTRY *glGetStringFunc) (GLenum name);
2914     void (APIENTRY *glGetFramebufferAttachmentParameterivFunc) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
2915     GLenum attachment = GL_BACK_LEFT;
2916     GLenum attachmentattrib = 0;
2917 #endif
2918
2919     /* Clear value in any case */
2920     *value = 0;
2921
2922     switch (attr) {
2923     case SDL_GL_RED_SIZE:
2924 #if SDL_VIDEO_OPENGL
2925         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE;
2926 #endif
2927         attrib = GL_RED_BITS;
2928         break;
2929     case SDL_GL_BLUE_SIZE:
2930 #if SDL_VIDEO_OPENGL
2931         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE;
2932 #endif
2933         attrib = GL_BLUE_BITS;
2934         break;
2935     case SDL_GL_GREEN_SIZE:
2936 #if SDL_VIDEO_OPENGL
2937         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE;
2938 #endif
2939         attrib = GL_GREEN_BITS;
2940         break;
2941     case SDL_GL_ALPHA_SIZE:
2942 #if SDL_VIDEO_OPENGL
2943         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE;
2944 #endif
2945         attrib = GL_ALPHA_BITS;
2946         break;
2947     case SDL_GL_DOUBLEBUFFER:
2948 #if SDL_VIDEO_OPENGL
2949         attrib = GL_DOUBLEBUFFER;
2950         break;
2951 #else
2952         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
2953         /* parameter which switches double buffer to single buffer. OpenGL ES */
2954         /* SDL driver must set proper value after initialization              */
2955         *value = _this->gl_config.double_buffer;
2956         return 0;
2957 #endif
2958     case SDL_GL_DEPTH_SIZE:
2959 #if SDL_VIDEO_OPENGL
2960         attachment = GL_DEPTH;
2961         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE;
2962 #endif
2963         attrib = GL_DEPTH_BITS;
2964         break;
2965     case SDL_GL_STENCIL_SIZE:
2966 #if SDL_VIDEO_OPENGL
2967         attachment = GL_STENCIL;
2968         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE;
2969 #endif
2970         attrib = GL_STENCIL_BITS;
2971         break;
2972 #if SDL_VIDEO_OPENGL
2973     case SDL_GL_ACCUM_RED_SIZE:
2974         attrib = GL_ACCUM_RED_BITS;
2975         break;
2976     case SDL_GL_ACCUM_GREEN_SIZE:
2977         attrib = GL_ACCUM_GREEN_BITS;
2978         break;
2979     case SDL_GL_ACCUM_BLUE_SIZE:
2980         attrib = GL_ACCUM_BLUE_BITS;
2981         break;
2982     case SDL_GL_ACCUM_ALPHA_SIZE:
2983         attrib = GL_ACCUM_ALPHA_BITS;
2984         break;
2985     case SDL_GL_STEREO:
2986         attrib = GL_STEREO;
2987         break;
2988 #else
2989     case SDL_GL_ACCUM_RED_SIZE:
2990     case SDL_GL_ACCUM_GREEN_SIZE:
2991     case SDL_GL_ACCUM_BLUE_SIZE:
2992     case SDL_GL_ACCUM_ALPHA_SIZE:
2993     case SDL_GL_STEREO:
2994         /* none of these are supported in OpenGL ES */
2995         *value = 0;
2996         return 0;
2997 #endif
2998     case SDL_GL_MULTISAMPLEBUFFERS:
2999         attrib = GL_SAMPLE_BUFFERS;
3000         break;
3001     case SDL_GL_MULTISAMPLESAMPLES:
3002         attrib = GL_SAMPLES;
3003         break;
3004     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
3005 #if SDL_VIDEO_OPENGL
3006         attrib = GL_CONTEXT_RELEASE_BEHAVIOR;
3007 #else
3008         attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR;
3009 #endif
3010         break;
3011     case SDL_GL_BUFFER_SIZE:
3012         {
3013             int rsize = 0, gsize = 0, bsize = 0, asize = 0;
3014
3015             /* There doesn't seem to be a single flag in OpenGL for this! */
3016             if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &rsize) < 0) {
3017                 return -1;
3018             }
3019             if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gsize) < 0) {
3020                 return -1;
3021             }
3022             if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &bsize) < 0) {
3023                 return -1;
3024             }
3025             if (SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &asize) < 0) {
3026                 return -1;
3027             }
3028
3029             *value = rsize + gsize + bsize + asize;
3030             return 0;
3031         }
3032     case SDL_GL_ACCELERATED_VISUAL:
3033         {
3034             /* FIXME: How do we get this information? */
3035             *value = (_this->gl_config.accelerated != 0);
3036             return 0;
3037         }
3038     case SDL_GL_RETAINED_BACKING:
3039         {
3040             *value = _this->gl_config.retained_backing;
3041             return 0;
3042         }
3043     case SDL_GL_CONTEXT_MAJOR_VERSION:
3044         {
3045             *value = _this->gl_config.major_version;
3046             return 0;
3047         }
3048     case SDL_GL_CONTEXT_MINOR_VERSION:
3049         {
3050             *value = _this->gl_config.minor_version;
3051             return 0;
3052         }
3053     case SDL_GL_CONTEXT_EGL:
3054         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
3055         {
3056             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
3057                 *value = 1;
3058             }
3059             else {
3060                 *value = 0;
3061             }
3062             return 0;
3063         }
3064     case SDL_GL_CONTEXT_FLAGS:
3065         {
3066             *value = _this->gl_config.flags;
3067             return 0;
3068         }
3069     case SDL_GL_CONTEXT_PROFILE_MASK:
3070         {
3071             *value = _this->gl_config.profile_mask;
3072             return 0;
3073         }
3074     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
3075         {
3076             *value = _this->gl_config.share_with_current_context;
3077             return 0;
3078         }
3079     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
3080         {
3081             *value = _this->gl_config.framebuffer_srgb_capable;
3082             return 0;
3083         }
3084     default:
3085         return SDL_SetError("Unknown OpenGL attribute");
3086     }
3087
3088 #if SDL_VIDEO_OPENGL
3089     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
3090     if (!glGetStringFunc) {
3091         return SDL_SetError("Failed getting OpenGL glGetString entry point");
3092     }
3093
3094     if (attachmentattrib && isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
3095         glGetFramebufferAttachmentParameterivFunc = SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameteriv");
3096
3097         if (glGetFramebufferAttachmentParameterivFunc) {
3098             glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *) value);
3099         } else {
3100             return SDL_SetError("Failed getting OpenGL glGetFramebufferAttachmentParameteriv entry point");
3101         }
3102     } else
3103 #endif
3104     {
3105         void (APIENTRY *glGetIntegervFunc) (GLenum pname, GLint * params);
3106         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
3107         if (glGetIntegervFunc) {
3108             glGetIntegervFunc(attrib, (GLint *) value);
3109         } else {
3110             return SDL_SetError("Failed getting OpenGL glGetIntegerv entry point");
3111         }
3112     }
3113
3114     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
3115     if (!glGetErrorFunc) {
3116         return SDL_SetError("Failed getting OpenGL glGetError entry point");
3117     }
3118
3119     error = glGetErrorFunc();
3120     if (error != GL_NO_ERROR) {
3121         if (error == GL_INVALID_ENUM) {
3122             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
3123         } else if (error == GL_INVALID_VALUE) {
3124             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
3125         }
3126         return SDL_SetError("OpenGL error: %08X", error);
3127     }
3128     return 0;
3129 #else
3130     return SDL_Unsupported();
3131 #endif /* SDL_VIDEO_OPENGL */
3132 }
3133
3134 SDL_GLContext
3135 SDL_GL_CreateContext(SDL_Window * window)
3136 {
3137     SDL_GLContext ctx = NULL;
3138     CHECK_WINDOW_MAGIC(window, NULL);
3139
3140     if (!(window->flags & SDL_WINDOW_OPENGL)) {
3141         SDL_SetError("The specified window isn't an OpenGL window");
3142         return NULL;
3143     }
3144
3145     ctx = _this->GL_CreateContext(_this, window);
3146
3147     /* Creating a context is assumed to make it current in the SDL driver. */
3148     if (ctx) {
3149         _this->current_glwin = window;
3150         _this->current_glctx = ctx;
3151         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
3152         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
3153     }
3154     return ctx;
3155 }
3156
3157 int
3158 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
3159 {
3160     int retval;
3161
3162     if (window == SDL_GL_GetCurrentWindow() &&
3163         ctx == SDL_GL_GetCurrentContext()) {
3164         /* We're already current. */
3165         return 0;
3166     }
3167
3168     if (!ctx) {
3169         window = NULL;
3170     } else {
3171         CHECK_WINDOW_MAGIC(window, -1);
3172
3173         if (!(window->flags & SDL_WINDOW_OPENGL)) {
3174             return SDL_SetError("The specified window isn't an OpenGL window");
3175         }
3176     }
3177
3178     retval = _this->GL_MakeCurrent(_this, window, ctx);
3179     if (retval == 0) {
3180         _this->current_glwin = window;
3181         _this->current_glctx = ctx;
3182         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
3183         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
3184     }
3185     return retval;
3186 }
3187
3188 SDL_Window *
3189 SDL_GL_GetCurrentWindow(void)
3190 {
3191     if (!_this) {
3192         SDL_UninitializedVideo();
3193         return NULL;
3194     }
3195     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
3196 }
3197
3198 SDL_GLContext
3199 SDL_GL_GetCurrentContext(void)
3200 {
3201     if (!_this) {
3202         SDL_UninitializedVideo();
3203         return NULL;
3204     }
3205     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
3206 }
3207
3208 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
3209 {
3210     CHECK_WINDOW_MAGIC(window,);
3211
3212     if (_this->GL_GetDrawableSize) {
3213         _this->GL_GetDrawableSize(_this, window, w, h);
3214     } else {
3215         SDL_GetWindowSize(window, w, h);
3216     }
3217 }
3218
3219 int
3220 SDL_GL_SetSwapInterval(int interval)
3221 {
3222     if (!_this) {
3223         return SDL_UninitializedVideo();
3224     } else if (SDL_GL_GetCurrentContext() == NULL) {
3225         return SDL_SetError("No OpenGL context has been made current");
3226     } else if (_this->GL_SetSwapInterval) {
3227         return _this->GL_SetSwapInterval(_this, interval);
3228     } else {
3229         return SDL_SetError("Setting the swap interval is not supported");
3230     }
3231 }
3232
3233 int
3234 SDL_GL_GetSwapInterval(void)
3235 {
3236     if (!_this) {
3237         return 0;
3238     } else if (SDL_GL_GetCurrentContext() == NULL) {
3239         return 0;
3240     } else if (_this->GL_GetSwapInterval) {
3241         return _this->GL_GetSwapInterval(_this);
3242     } else {
3243         return 0;
3244     }
3245 }
3246
3247 void
3248 SDL_GL_SwapWindow(SDL_Window * window)
3249 {
3250     CHECK_WINDOW_MAGIC(window,);
3251
3252     if (!(window->flags & SDL_WINDOW_OPENGL)) {
3253         SDL_SetError("The specified window isn't an OpenGL window");
3254         return;
3255     }
3256
3257     if (SDL_GL_GetCurrentWindow() != window) {
3258         SDL_SetError("The specified window has not been made current");
3259         return;
3260     }
3261
3262     _this->GL_SwapWindow(_this, window);
3263 }
3264
3265 void
3266 SDL_GL_DeleteContext(SDL_GLContext context)
3267 {
3268     if (!_this || !context) {
3269         return;
3270     }
3271
3272     if (SDL_GL_GetCurrentContext() == context) {
3273         SDL_GL_MakeCurrent(NULL, NULL);
3274     }
3275
3276     _this->GL_DeleteContext(_this, context);
3277 }
3278
3279 #if 0                           /* FIXME */
3280 /*
3281  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
3282  * & 2 for alpha channel.
3283  */
3284 static void
3285 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
3286 {
3287     int x, y;
3288     Uint32 colorkey;
3289 #define SET_MASKBIT(icon, x, y, mask) \
3290     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
3291
3292     colorkey = icon->format->colorkey;
3293     switch (icon->format->BytesPerPixel) {
3294     case 1:
3295         {
3296             Uint8 *pixels;
3297             for (y = 0; y < icon->h; ++y) {
3298                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
3299                 for (x = 0; x < icon->w; ++x) {
3300                     if (*pixels++ == colorkey) {
3301                         SET_MASKBIT(icon, x, y, mask);
3302                     }
3303                 }
3304             }
3305         }
3306         break;
3307
3308     case 2:
3309         {
3310             Uint16 *pixels;
3311             for (y = 0; y < icon->h; ++y) {
3312                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
3313                 for (x = 0; x < icon->w; ++x) {
3314                     if ((flags & 1) && *pixels == colorkey) {
3315                         SET_MASKBIT(icon, x, y, mask);
3316                     } else if ((flags & 2)
3317                                && (*pixels & icon->format->Amask) == 0) {
3318                         SET_MASKBIT(icon, x, y, mask);
3319                     }
3320                     pixels++;
3321                 }
3322             }
3323         }
3324         break;
3325
3326     case 4:
3327         {
3328             Uint32 *pixels;
3329             for (y = 0; y < icon->h; ++y) {
3330                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
3331                 for (x = 0; x < icon->w; ++x) {
3332                     if ((flags & 1) && *pixels == colorkey) {
3333                         SET_MASKBIT(icon, x, y, mask);
3334                     } else if ((flags & 2)
3335                                && (*pixels & icon->format->Amask) == 0) {
3336                         SET_MASKBIT(icon, x, y, mask);
3337                     }
3338                     pixels++;
3339                 }
3340             }
3341         }
3342         break;
3343     }
3344 }
3345
3346 /*
3347  * Sets the window manager icon for the display window.
3348  */
3349 void
3350 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
3351 {
3352     if (icon && _this->SetIcon) {
3353         /* Generate a mask if necessary, and create the icon! */
3354         if (mask == NULL) {
3355             int mask_len = icon->h * (icon->w + 7) / 8;
3356             int flags = 0;
3357             mask = (Uint8 *) SDL_malloc(mask_len);
3358             if (mask == NULL) {
3359                 return;
3360             }
3361             SDL_memset(mask, ~0, mask_len);
3362             if (icon->flags & SDL_SRCCOLORKEY)
3363                 flags |= 1;
3364             if (icon->flags & SDL_SRCALPHA)
3365                 flags |= 2;
3366             if (flags) {
3367                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
3368             }
3369             _this->SetIcon(_this, icon, mask);
3370             SDL_free(mask);
3371         } else {
3372             _this->SetIcon(_this, icon, mask);
3373         }
3374     }
3375 }
3376 #endif
3377
3378 SDL_bool
3379 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
3380 {
3381     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
3382
3383     if (!info) {
3384         SDL_InvalidParamError("info");
3385         return SDL_FALSE;
3386     }
3387     info->subsystem = SDL_SYSWM_UNKNOWN;
3388
3389     if (!_this->GetWindowWMInfo) {
3390         SDL_Unsupported();
3391         return SDL_FALSE;
3392     }
3393     return (_this->GetWindowWMInfo(_this, window, info));
3394 }
3395
3396 void
3397 SDL_StartTextInput(void)
3398 {
3399     SDL_Window *window;
3400
3401     /* First, enable text events */
3402     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
3403     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
3404
3405     /* Then show the on-screen keyboard, if any */
3406     window = SDL_GetFocusWindow();
3407     if (window && _this && _this->ShowScreenKeyboard) {
3408         _this->ShowScreenKeyboard(_this, window);
3409     }
3410
3411     /* Finally start the text input system */
3412     if (_this && _this->StartTextInput) {
3413         _this->StartTextInput(_this);
3414     }
3415 }
3416
3417 SDL_bool
3418 SDL_IsTextInputActive(void)
3419 {
3420     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
3421 }
3422
3423 void
3424 SDL_StopTextInput(void)
3425 {
3426     SDL_Window *window;
3427
3428     /* Stop the text input system */
3429     if (_this && _this->StopTextInput) {
3430         _this->StopTextInput(_this);
3431     }
3432
3433     /* Hide the on-screen keyboard, if any */
3434     window = SDL_GetFocusWindow();
3435     if (window && _this && _this->HideScreenKeyboard) {
3436         _this->HideScreenKeyboard(_this, window);
3437     }
3438
3439     /* Finally disable text events */
3440     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
3441     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
3442 }
3443
3444 void
3445 SDL_SetTextInputRect(SDL_Rect *rect)
3446 {
3447     if (_this && _this->SetTextInputRect) {
3448         _this->SetTextInputRect(_this, rect);
3449     }
3450 }
3451
3452 SDL_bool
3453 SDL_HasScreenKeyboardSupport(void)
3454 {
3455     if (_this && _this->HasScreenKeyboardSupport) {
3456         return _this->HasScreenKeyboardSupport(_this);
3457     }
3458     return SDL_FALSE;
3459 }
3460
3461 SDL_bool
3462 SDL_IsScreenKeyboardShown(SDL_Window *window)
3463 {
3464     if (window && _this && _this->IsScreenKeyboardShown) {
3465         return _this->IsScreenKeyboardShown(_this, window);
3466     }
3467     return SDL_FALSE;
3468 }
3469
3470 #if SDL_VIDEO_DRIVER_ANDROID
3471 #include "android/SDL_androidmessagebox.h"
3472 #endif
3473 #if SDL_VIDEO_DRIVER_WINDOWS
3474 #include "windows/SDL_windowsmessagebox.h"
3475 #endif
3476 #if SDL_VIDEO_DRIVER_WINRT
3477 #include "winrt/SDL_winrtmessagebox.h"
3478 #endif
3479 #if SDL_VIDEO_DRIVER_COCOA
3480 #include "cocoa/SDL_cocoamessagebox.h"
3481 #endif
3482 #if SDL_VIDEO_DRIVER_UIKIT
3483 #include "uikit/SDL_uikitmessagebox.h"
3484 #endif
3485 #if SDL_VIDEO_DRIVER_X11
3486 #include "x11/SDL_x11messagebox.h"
3487 #endif
3488
3489 // This function will be unused if none of the above video drivers are present.
3490 SDL_UNUSED static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
3491 {
3492     SDL_SysWMinfo info;
3493     SDL_Window *window = messageboxdata->window;
3494
3495     if (!window) {
3496         return SDL_TRUE;
3497     }
3498
3499     SDL_VERSION(&info.version);
3500     if (!SDL_GetWindowWMInfo(window, &info)) {
3501         return SDL_TRUE;
3502     } else {
3503         return (info.subsystem == drivertype);
3504     }
3505 }
3506
3507 int
3508 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
3509 {
3510     int dummybutton;
3511     int retval = -1;
3512     SDL_bool relative_mode;
3513     int show_cursor_prev;
3514     SDL_bool mouse_captured;
3515     SDL_Window *current_window;
3516
3517     if (!messageboxdata) {
3518         return SDL_InvalidParamError("messageboxdata");
3519     }
3520
3521     current_window = SDL_GetKeyboardFocus();
3522     mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
3523     relative_mode = SDL_GetRelativeMouseMode();
3524     SDL_CaptureMouse(SDL_FALSE);
3525     SDL_SetRelativeMouseMode(SDL_FALSE);
3526     show_cursor_prev = SDL_ShowCursor(1);
3527     SDL_ResetKeyboard();
3528
3529     if (!buttonid) {
3530         buttonid = &dummybutton;
3531     }
3532
3533     if (_this && _this->ShowMessageBox) {
3534         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
3535     }
3536
3537     /* It's completely fine to call this function before video is initialized */
3538 #if SDL_VIDEO_DRIVER_ANDROID
3539     if (retval == -1 &&
3540         Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
3541         retval = 0;
3542     }
3543 #endif
3544 #if SDL_VIDEO_DRIVER_WINDOWS
3545     if (retval == -1 &&
3546         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
3547         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
3548         retval = 0;
3549     }
3550 #endif
3551 #if SDL_VIDEO_DRIVER_WINRT
3552     if (retval == -1 &&
3553         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
3554         WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
3555         retval = 0;
3556     }
3557 #endif
3558 #if SDL_VIDEO_DRIVER_COCOA
3559     if (retval == -1 &&
3560         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
3561         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
3562         retval = 0;
3563     }
3564 #endif
3565 #if SDL_VIDEO_DRIVER_UIKIT
3566     if (retval == -1 &&
3567         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
3568         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
3569         retval = 0;
3570     }
3571 #endif
3572 #if SDL_VIDEO_DRIVER_X11
3573     if (retval == -1 &&
3574         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
3575         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
3576         retval = 0;
3577     }
3578 #endif
3579     if (retval == -1) {
3580         SDL_SetError("No message system available");
3581     }
3582
3583     if (current_window) {
3584         SDL_RaiseWindow(current_window);
3585         if (mouse_captured) {
3586             SDL_CaptureMouse(SDL_TRUE);
3587         }
3588     }
3589
3590     SDL_ShowCursor(show_cursor_prev);
3591     SDL_SetRelativeMouseMode(relative_mode);
3592
3593     return retval;
3594 }
3595
3596 int
3597 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
3598 {
3599     SDL_MessageBoxData data;
3600     SDL_MessageBoxButtonData button;
3601
3602     SDL_zero(data);
3603     data.flags = flags;
3604     data.title = title;
3605     data.message = message;
3606     data.numbuttons = 1;
3607     data.buttons = &button;
3608     data.window = window;
3609
3610     SDL_zero(button);
3611     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
3612     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
3613     button.text = "OK";
3614
3615     return SDL_ShowMessageBox(&data, NULL);
3616 }
3617
3618 SDL_bool
3619 SDL_ShouldAllowTopmost(void)
3620 {
3621     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
3622     if (hint) {
3623         if (*hint == '0') {
3624             return SDL_FALSE;
3625         } else {
3626             return SDL_TRUE;
3627         }
3628     }
3629     return SDL_TRUE;
3630 }
3631
3632 int
3633 SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
3634 {
3635     CHECK_WINDOW_MAGIC(window, -1);
3636
3637     if (!_this->SetWindowHitTest) {
3638         return SDL_Unsupported();
3639     } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
3640         return -1;
3641     }
3642
3643     window->hit_test = callback;
3644     window->hit_test_data = userdata;
3645
3646     return 0;
3647 }
3648
3649 float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
3650 {
3651         float den2 = hinches * hinches + vinches * vinches;
3652         if ( den2 <= 0.0f ) {
3653                 return 0.0f;
3654         }
3655                 
3656         return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) /
3657                                    SDL_sqrt((double)den2));
3658 }
3659
3660 /* vi: set ts=4 sw=4 expandtab: */