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