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