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