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