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