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