src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 27 May 2014 01:27:42 -0400
changeset 8931 44d8a2f4b431
parent 8927 be64f5daf64b
child 8935 9d2f0236322b
permissions -rw-r--r--
First shot at SDL_SetWindowDragAreas().

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