src/video/SDL_video.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Tue, 29 Dec 2015 19:13:56 +0100
changeset 9988 08d023f75d78
parent 9958 687e118144c7
child 9998 f67cf37e9cd4
permissions -rw-r--r--
Fixed a crash if creating accelerated renderer after accessing window surface.

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