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