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