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