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