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