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