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