src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 12 Nov 2013 02:02:12 -0800
changeset 7969 72405c8b7dba
parent 7968 8c0afe77a1b2
child 7971 4151d8c29684
permissions -rwxr-xr-x
We still want to generally minimize on focus loss, but not when we're in a fullscreen space on Mac OS X.
     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)
  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     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1240     if (!window) {
  1241         SDL_OutOfMemory();
  1242         return NULL;
  1243     }
  1244     window->magic = &_this->window_magic;
  1245     window->id = _this->next_object_id++;
  1246     window->x = x;
  1247     window->y = y;
  1248     window->w = w;
  1249     window->h = h;
  1250     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1251         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1252         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1253         int displayIndex;
  1254         SDL_Rect bounds;
  1255 
  1256         displayIndex = SDL_GetIndexOfDisplay(display);
  1257         SDL_GetDisplayBounds(displayIndex, &bounds);
  1258         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1259             window->x = bounds.x + (bounds.w - w) / 2;
  1260         }
  1261         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1262             window->y = bounds.y + (bounds.h - h) / 2;
  1263         }
  1264     }
  1265     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1266     window->brightness = 1.0f;
  1267     window->next = _this->windows;
  1268 
  1269     /* Unless the user has specified the high-DPI disabling hint, respect the
  1270      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1271      */
  1272     hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
  1273     if (!hint || *hint != '1') {
  1274         if ((flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
  1275             window->flags |= SDL_WINDOW_ALLOW_HIGHDPI;
  1276         }
  1277     }
  1278 
  1279     if (_this->windows) {
  1280         _this->windows->prev = window;
  1281     }
  1282     _this->windows = window;
  1283 
  1284     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1285         SDL_DestroyWindow(window);
  1286         return NULL;
  1287     }
  1288 
  1289     if (title) {
  1290         SDL_SetWindowTitle(window, title);
  1291     }
  1292     SDL_FinishWindowCreation(window, flags);
  1293 
  1294     /* If the window was created fullscreen, make sure the mode code matches */
  1295     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1296 
  1297     return window;
  1298 }
  1299 
  1300 SDL_Window *
  1301 SDL_CreateWindowFrom(const void *data)
  1302 {
  1303     SDL_Window *window;
  1304 
  1305     if (!_this) {
  1306         SDL_UninitializedVideo();
  1307         return NULL;
  1308     }
  1309     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1310     if (!window) {
  1311         SDL_OutOfMemory();
  1312         return NULL;
  1313     }
  1314     window->magic = &_this->window_magic;
  1315     window->id = _this->next_object_id++;
  1316     window->flags = SDL_WINDOW_FOREIGN;
  1317     window->brightness = 1.0f;
  1318     window->next = _this->windows;
  1319     if (_this->windows) {
  1320         _this->windows->prev = window;
  1321     }
  1322     _this->windows = window;
  1323 
  1324     if (!_this->CreateWindowFrom ||
  1325         _this->CreateWindowFrom(_this, window, data) < 0) {
  1326         SDL_DestroyWindow(window);
  1327         return NULL;
  1328     }
  1329     return window;
  1330 }
  1331 
  1332 int
  1333 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1334 {
  1335     char *title = window->title;
  1336     SDL_Surface *icon = window->icon;
  1337 
  1338     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1339         return SDL_SetError("No OpenGL support in video driver");
  1340     }
  1341 
  1342     if (window->flags & SDL_WINDOW_FOREIGN) {
  1343         /* Can't destroy and re-create foreign windows, hrm */
  1344         flags |= SDL_WINDOW_FOREIGN;
  1345     } else {
  1346         flags &= ~SDL_WINDOW_FOREIGN;
  1347     }
  1348 
  1349     /* Restore video mode, etc. */
  1350     SDL_HideWindow(window);
  1351 
  1352     /* Tear down the old native window */
  1353     if (window->surface) {
  1354         window->surface->flags &= ~SDL_DONTFREE;
  1355         SDL_FreeSurface(window->surface);
  1356     }
  1357     if (_this->DestroyWindowFramebuffer) {
  1358         _this->DestroyWindowFramebuffer(_this, window);
  1359     }
  1360     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1361         _this->DestroyWindow(_this, window);
  1362     }
  1363 
  1364     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1365         if (flags & SDL_WINDOW_OPENGL) {
  1366             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1367                 return -1;
  1368             }
  1369         } else {
  1370             SDL_GL_UnloadLibrary();
  1371         }
  1372     }
  1373 
  1374     window->title = NULL;
  1375     window->icon = NULL;
  1376     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1377 
  1378     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1379         if (_this->CreateWindow(_this, window) < 0) {
  1380             if (flags & SDL_WINDOW_OPENGL) {
  1381                 SDL_GL_UnloadLibrary();
  1382             }
  1383             return -1;
  1384         }
  1385     }
  1386 
  1387     if (title) {
  1388         SDL_SetWindowTitle(window, title);
  1389         SDL_free(title);
  1390     }
  1391     if (icon) {
  1392         SDL_SetWindowIcon(window, icon);
  1393         SDL_FreeSurface(icon);
  1394     }
  1395     SDL_FinishWindowCreation(window, flags);
  1396 
  1397     return 0;
  1398 }
  1399 
  1400 Uint32
  1401 SDL_GetWindowID(SDL_Window * window)
  1402 {
  1403     CHECK_WINDOW_MAGIC(window, 0);
  1404 
  1405     return window->id;
  1406 }
  1407 
  1408 SDL_Window *
  1409 SDL_GetWindowFromID(Uint32 id)
  1410 {
  1411     SDL_Window *window;
  1412 
  1413     if (!_this) {
  1414         return NULL;
  1415     }
  1416     for (window = _this->windows; window; window = window->next) {
  1417         if (window->id == id) {
  1418             return window;
  1419         }
  1420     }
  1421     return NULL;
  1422 }
  1423 
  1424 Uint32
  1425 SDL_GetWindowFlags(SDL_Window * window)
  1426 {
  1427     CHECK_WINDOW_MAGIC(window, 0);
  1428 
  1429     return window->flags;
  1430 }
  1431 
  1432 void
  1433 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1434 {
  1435     CHECK_WINDOW_MAGIC(window, );
  1436 
  1437     if (title == window->title) {
  1438         return;
  1439     }
  1440     SDL_free(window->title);
  1441     if (title && *title) {
  1442         window->title = SDL_strdup(title);
  1443     } else {
  1444         window->title = NULL;
  1445     }
  1446 
  1447     if (_this->SetWindowTitle) {
  1448         _this->SetWindowTitle(_this, window);
  1449     }
  1450 }
  1451 
  1452 const char *
  1453 SDL_GetWindowTitle(SDL_Window * window)
  1454 {
  1455     CHECK_WINDOW_MAGIC(window, "");
  1456 
  1457     return window->title ? window->title : "";
  1458 }
  1459 
  1460 void
  1461 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1462 {
  1463     CHECK_WINDOW_MAGIC(window, );
  1464 
  1465     if (!icon) {
  1466         return;
  1467     }
  1468 
  1469     SDL_FreeSurface(window->icon);
  1470 
  1471     /* Convert the icon into ARGB8888 */
  1472     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1473     if (!window->icon) {
  1474         return;
  1475     }
  1476 
  1477     if (_this->SetWindowIcon) {
  1478         _this->SetWindowIcon(_this, window, window->icon);
  1479     }
  1480 }
  1481 
  1482 void*
  1483 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1484 {
  1485     SDL_WindowUserData *prev, *data;
  1486 
  1487     CHECK_WINDOW_MAGIC(window, NULL);
  1488 
  1489     /* Input validation */
  1490     if (name == NULL || name[0] == '\0') {
  1491       SDL_InvalidParamError("name");
  1492       return NULL;
  1493     }
  1494 
  1495     /* See if the named data already exists */
  1496     prev = NULL;
  1497     for (data = window->data; data; prev = data, data = data->next) {
  1498         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1499             void *last_value = data->data;
  1500 
  1501             if (userdata) {
  1502                 /* Set the new value */
  1503                 data->data = userdata;
  1504             } else {
  1505                 /* Delete this value */
  1506                 if (prev) {
  1507                     prev->next = data->next;
  1508                 } else {
  1509                     window->data = data->next;
  1510                 }
  1511                 SDL_free(data->name);
  1512                 SDL_free(data);
  1513             }
  1514             return last_value;
  1515         }
  1516     }
  1517 
  1518     /* Add new data to the window */
  1519     if (userdata) {
  1520         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1521         data->name = SDL_strdup(name);
  1522         data->data = userdata;
  1523         data->next = window->data;
  1524         window->data = data;
  1525     }
  1526     return NULL;
  1527 }
  1528 
  1529 void *
  1530 SDL_GetWindowData(SDL_Window * window, const char *name)
  1531 {
  1532     SDL_WindowUserData *data;
  1533 
  1534     CHECK_WINDOW_MAGIC(window, NULL);
  1535 
  1536     /* Input validation */
  1537     if (name == NULL || name[0] == '\0') {
  1538       SDL_InvalidParamError("name");
  1539       return NULL;
  1540     }
  1541 
  1542     for (data = window->data; data; data = data->next) {
  1543         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1544             return data->data;
  1545         }
  1546     }
  1547     return NULL;
  1548 }
  1549 
  1550 void
  1551 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1552 {
  1553     CHECK_WINDOW_MAGIC(window, );
  1554 
  1555     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1556         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1557         int displayIndex;
  1558         SDL_Rect bounds;
  1559 
  1560         displayIndex = SDL_GetIndexOfDisplay(display);
  1561         SDL_GetDisplayBounds(displayIndex, &bounds);
  1562         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1563             x = bounds.x + (bounds.w - window->w) / 2;
  1564         }
  1565         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1566             y = bounds.y + (bounds.h - window->h) / 2;
  1567         }
  1568     }
  1569 
  1570     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1571         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1572             window->windowed.x = x;
  1573         }
  1574         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1575             window->windowed.y = y;
  1576         }
  1577     } else {
  1578         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1579             window->x = x;
  1580         }
  1581         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1582             window->y = y;
  1583         }
  1584 
  1585         if (_this->SetWindowPosition) {
  1586             _this->SetWindowPosition(_this, window);
  1587         }
  1588         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1589     }
  1590 }
  1591 
  1592 void
  1593 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1594 {
  1595     CHECK_WINDOW_MAGIC(window, );
  1596 
  1597     /* Fullscreen windows are always at their display's origin */
  1598     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1599         if (x) {
  1600             *x = 0;
  1601         }
  1602         if (y) {
  1603             *y = 0;
  1604         }
  1605     } else {
  1606         if (x) {
  1607             *x = window->x;
  1608         }
  1609         if (y) {
  1610             *y = window->y;
  1611         }
  1612     }
  1613 }
  1614 
  1615 void
  1616 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1617 {
  1618     CHECK_WINDOW_MAGIC(window, );
  1619     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1620         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1621         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1622         if ((want != have) && (_this->SetWindowBordered)) {
  1623             if (want) {
  1624                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1625             } else {
  1626                 window->flags |= SDL_WINDOW_BORDERLESS;
  1627             }
  1628             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1629         }
  1630     }
  1631 }
  1632 
  1633 void
  1634 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1635 {
  1636     CHECK_WINDOW_MAGIC(window, );
  1637     if (w <= 0) {
  1638         SDL_InvalidParamError("w");
  1639         return;
  1640     }
  1641     if (h <= 0) {
  1642         SDL_InvalidParamError("h");
  1643         return;
  1644     }
  1645 
  1646     /* Make sure we don't exceed any window size limits */
  1647     if (window->min_w && w < window->min_w)
  1648     {
  1649         w = window->min_w;
  1650     }
  1651     if (window->max_w && w > window->max_w)
  1652     {
  1653         w = window->max_w;
  1654     }
  1655     if (window->min_h && h < window->min_h)
  1656     {
  1657         h = window->min_h;
  1658     }
  1659     if (window->max_h && h > window->max_h)
  1660     {
  1661         h = window->max_h;
  1662     }
  1663 
  1664     /* FIXME: Should this change fullscreen modes? */
  1665     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1666         window->windowed.w = w;
  1667         window->windowed.h = h;
  1668     } else {
  1669         window->w = w;
  1670         window->h = h;
  1671         if (_this->SetWindowSize) {
  1672             _this->SetWindowSize(_this, window);
  1673         }
  1674         if (window->w == w && window->h == h) {
  1675             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1676             SDL_OnWindowResized(window);
  1677         }
  1678     }
  1679 }
  1680 
  1681 void
  1682 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1683 {
  1684     CHECK_WINDOW_MAGIC(window, );
  1685     if (w) {
  1686         *w = window->w;
  1687     }
  1688     if (h) {
  1689         *h = window->h;
  1690     }
  1691 }
  1692 
  1693 void
  1694 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1695 {
  1696     CHECK_WINDOW_MAGIC(window, );
  1697     if (min_w <= 0) {
  1698         SDL_InvalidParamError("min_w");
  1699         return;
  1700     }
  1701     if (min_h <= 0) {
  1702         SDL_InvalidParamError("min_h");
  1703         return;
  1704     }
  1705 
  1706     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1707         window->min_w = min_w;
  1708         window->min_h = min_h;
  1709         if (_this->SetWindowMinimumSize) {
  1710             _this->SetWindowMinimumSize(_this, window);
  1711         }
  1712         /* Ensure that window is not smaller than minimal size */
  1713         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1714     }
  1715 }
  1716 
  1717 void
  1718 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1719 {
  1720     CHECK_WINDOW_MAGIC(window, );
  1721     if (min_w) {
  1722         *min_w = window->min_w;
  1723     }
  1724     if (min_h) {
  1725         *min_h = window->min_h;
  1726     }
  1727 }
  1728 
  1729 void
  1730 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1731 {
  1732     CHECK_WINDOW_MAGIC(window, );
  1733     if (max_w <= 0) {
  1734         SDL_InvalidParamError("max_w");
  1735         return;
  1736     }
  1737     if (max_h <= 0) {
  1738         SDL_InvalidParamError("max_h");
  1739         return;
  1740     }
  1741 
  1742     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1743         window->max_w = max_w;
  1744         window->max_h = max_h;
  1745         if (_this->SetWindowMaximumSize) {
  1746             _this->SetWindowMaximumSize(_this, window);
  1747         }
  1748         /* Ensure that window is not larger than maximal size */
  1749         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1750     }
  1751 }
  1752 
  1753 void
  1754 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1755 {
  1756     CHECK_WINDOW_MAGIC(window, );
  1757     if (max_w) {
  1758         *max_w = window->max_w;
  1759     }
  1760     if (max_h) {
  1761         *max_h = window->max_h;
  1762     }
  1763 }
  1764 
  1765 void
  1766 SDL_ShowWindow(SDL_Window * window)
  1767 {
  1768     CHECK_WINDOW_MAGIC(window, );
  1769 
  1770     if (window->flags & SDL_WINDOW_SHOWN) {
  1771         return;
  1772     }
  1773 
  1774     if (_this->ShowWindow) {
  1775         _this->ShowWindow(_this, window);
  1776     }
  1777     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1778 }
  1779 
  1780 void
  1781 SDL_HideWindow(SDL_Window * window)
  1782 {
  1783     CHECK_WINDOW_MAGIC(window, );
  1784 
  1785     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1786         return;
  1787     }
  1788 
  1789     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1790 
  1791     if (_this->HideWindow) {
  1792         _this->HideWindow(_this, window);
  1793     }
  1794     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1795 }
  1796 
  1797 void
  1798 SDL_RaiseWindow(SDL_Window * window)
  1799 {
  1800     CHECK_WINDOW_MAGIC(window, );
  1801 
  1802     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1803         return;
  1804     }
  1805     if (_this->RaiseWindow) {
  1806         _this->RaiseWindow(_this, window);
  1807     }
  1808 }
  1809 
  1810 void
  1811 SDL_MaximizeWindow(SDL_Window * window)
  1812 {
  1813     CHECK_WINDOW_MAGIC(window, );
  1814 
  1815     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1816         return;
  1817     }
  1818 
  1819     /* !!! FIXME: should this check if the window is resizable? */
  1820 
  1821     if (_this->MaximizeWindow) {
  1822         _this->MaximizeWindow(_this, window);
  1823     }
  1824 }
  1825 
  1826 void
  1827 SDL_MinimizeWindow(SDL_Window * window)
  1828 {
  1829     CHECK_WINDOW_MAGIC(window, );
  1830 
  1831     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1832         return;
  1833     }
  1834 
  1835     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1836 
  1837     if (_this->MinimizeWindow) {
  1838         _this->MinimizeWindow(_this, window);
  1839     }
  1840 }
  1841 
  1842 void
  1843 SDL_RestoreWindow(SDL_Window * window)
  1844 {
  1845     CHECK_WINDOW_MAGIC(window, );
  1846 
  1847     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1848         return;
  1849     }
  1850 
  1851     if (_this->RestoreWindow) {
  1852         _this->RestoreWindow(_this, window);
  1853     }
  1854 }
  1855 
  1856 #define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN )
  1857 int
  1858 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1859 {
  1860     CHECK_WINDOW_MAGIC(window, -1);
  1861 
  1862     flags &= FULLSCREEN_MASK;
  1863 
  1864     if ( flags == (window->flags & FULLSCREEN_MASK) ) {
  1865         return 0;
  1866     }
  1867 
  1868     /* clear the previous flags and OR in the new ones */
  1869     window->flags &= ~FULLSCREEN_MASK;
  1870     window->flags |= flags;
  1871 
  1872     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1873 
  1874     return 0;
  1875 }
  1876 
  1877 static SDL_Surface *
  1878 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1879 {
  1880     Uint32 format;
  1881     void *pixels;
  1882     int pitch;
  1883     int bpp;
  1884     Uint32 Rmask, Gmask, Bmask, Amask;
  1885 
  1886     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1887         return NULL;
  1888     }
  1889 
  1890     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1891         return NULL;
  1892     }
  1893 
  1894     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1895         return NULL;
  1896     }
  1897 
  1898     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1899 }
  1900 
  1901 SDL_Surface *
  1902 SDL_GetWindowSurface(SDL_Window * window)
  1903 {
  1904     CHECK_WINDOW_MAGIC(window, NULL);
  1905 
  1906     if (!window->surface_valid) {
  1907         if (window->surface) {
  1908             window->surface->flags &= ~SDL_DONTFREE;
  1909             SDL_FreeSurface(window->surface);
  1910         }
  1911         window->surface = SDL_CreateWindowFramebuffer(window);
  1912         if (window->surface) {
  1913             window->surface_valid = SDL_TRUE;
  1914             window->surface->flags |= SDL_DONTFREE;
  1915         }
  1916     }
  1917     return window->surface;
  1918 }
  1919 
  1920 int
  1921 SDL_UpdateWindowSurface(SDL_Window * window)
  1922 {
  1923     SDL_Rect full_rect;
  1924 
  1925     CHECK_WINDOW_MAGIC(window, -1);
  1926 
  1927     full_rect.x = 0;
  1928     full_rect.y = 0;
  1929     full_rect.w = window->w;
  1930     full_rect.h = window->h;
  1931     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1932 }
  1933 
  1934 int
  1935 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  1936                              int numrects)
  1937 {
  1938     CHECK_WINDOW_MAGIC(window, -1);
  1939 
  1940     if (!window->surface_valid) {
  1941         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1942     }
  1943 
  1944     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1945 }
  1946 
  1947 int
  1948 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  1949 {
  1950     Uint16 ramp[256];
  1951     int status;
  1952 
  1953     CHECK_WINDOW_MAGIC(window, -1);
  1954 
  1955     SDL_CalculateGammaRamp(brightness, ramp);
  1956     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  1957     if (status == 0) {
  1958         window->brightness = brightness;
  1959     }
  1960     return status;
  1961 }
  1962 
  1963 float
  1964 SDL_GetWindowBrightness(SDL_Window * window)
  1965 {
  1966     CHECK_WINDOW_MAGIC(window, 1.0f);
  1967 
  1968     return window->brightness;
  1969 }
  1970 
  1971 int
  1972 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  1973                                             const Uint16 * green,
  1974                                             const Uint16 * blue)
  1975 {
  1976     CHECK_WINDOW_MAGIC(window, -1);
  1977 
  1978     if (!_this->SetWindowGammaRamp) {
  1979         return SDL_Unsupported();
  1980     }
  1981 
  1982     if (!window->gamma) {
  1983         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  1984             return -1;
  1985         }
  1986     }
  1987 
  1988     if (red) {
  1989         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  1990     }
  1991     if (green) {
  1992         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  1993     }
  1994     if (blue) {
  1995         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  1996     }
  1997     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1998         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  1999     } else {
  2000         return 0;
  2001     }
  2002 }
  2003 
  2004 int
  2005 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  2006                                             Uint16 * green,
  2007                                             Uint16 * blue)
  2008 {
  2009     CHECK_WINDOW_MAGIC(window, -1);
  2010 
  2011     if (!window->gamma) {
  2012         int i;
  2013 
  2014         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  2015         if (!window->gamma) {
  2016             return SDL_OutOfMemory();
  2017         }
  2018         window->saved_gamma = window->gamma + 3*256;
  2019 
  2020         if (_this->GetWindowGammaRamp) {
  2021             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  2022                 return -1;
  2023             }
  2024         } else {
  2025             /* Create an identity gamma ramp */
  2026             for (i = 0; i < 256; ++i) {
  2027                 Uint16 value = (Uint16)((i << 8) | i);
  2028 
  2029                 window->gamma[0*256+i] = value;
  2030                 window->gamma[1*256+i] = value;
  2031                 window->gamma[2*256+i] = value;
  2032             }
  2033         }
  2034         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  2035     }
  2036 
  2037     if (red) {
  2038         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  2039     }
  2040     if (green) {
  2041         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  2042     }
  2043     if (blue) {
  2044         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  2045     }
  2046     return 0;
  2047 }
  2048 
  2049 void
  2050 SDL_UpdateWindowGrab(SDL_Window * window)
  2051 {
  2052     if (_this->SetWindowGrab) {
  2053         SDL_bool grabbed;
  2054         if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
  2055             (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  2056             grabbed = SDL_TRUE;
  2057         } else {
  2058             grabbed = SDL_FALSE;
  2059         }
  2060         _this->SetWindowGrab(_this, window, grabbed);
  2061     }
  2062 }
  2063 
  2064 void
  2065 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  2066 {
  2067     CHECK_WINDOW_MAGIC(window, );
  2068 
  2069     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  2070         return;
  2071     }
  2072     if (grabbed) {
  2073         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  2074     } else {
  2075         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2076     }
  2077     SDL_UpdateWindowGrab(window);
  2078 }
  2079 
  2080 SDL_bool
  2081 SDL_GetWindowGrab(SDL_Window * window)
  2082 {
  2083     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2084 
  2085     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  2086 }
  2087 
  2088 void
  2089 SDL_OnWindowShown(SDL_Window * window)
  2090 {
  2091     SDL_OnWindowRestored(window);
  2092 }
  2093 
  2094 void
  2095 SDL_OnWindowHidden(SDL_Window * window)
  2096 {
  2097     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2098 }
  2099 
  2100 void
  2101 SDL_OnWindowResized(SDL_Window * window)
  2102 {
  2103     window->surface_valid = SDL_FALSE;
  2104     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2105 }
  2106 
  2107 void
  2108 SDL_OnWindowMinimized(SDL_Window * window)
  2109 {
  2110     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2111 }
  2112 
  2113 void
  2114 SDL_OnWindowRestored(SDL_Window * window)
  2115 {
  2116     SDL_RaiseWindow(window);
  2117 
  2118     if (FULLSCREEN_VISIBLE(window)) {
  2119         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2120     }
  2121 }
  2122 
  2123 void
  2124 SDL_OnWindowEnter(SDL_Window * window)
  2125 {
  2126     if (_this->OnWindowEnter) {
  2127         _this->OnWindowEnter(_this, window);
  2128     }
  2129 }
  2130 
  2131 void
  2132 SDL_OnWindowLeave(SDL_Window * window)
  2133 {
  2134 }
  2135 
  2136 void
  2137 SDL_OnWindowFocusGained(SDL_Window * window)
  2138 {
  2139     SDL_Mouse *mouse = SDL_GetMouse();
  2140 
  2141     if (window->gamma && _this->SetWindowGammaRamp) {
  2142         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2143     }
  2144 
  2145     if (mouse && mouse->relative_mode) {
  2146         SDL_SetMouseFocus(window);
  2147         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2148     }
  2149 
  2150     SDL_UpdateWindowGrab(window);
  2151 }
  2152 
  2153 static SDL_bool
  2154 ShouldMinimizeOnFocusLoss(SDL_Window * window)
  2155 {
  2156     const char *hint;
  2157 
  2158     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  2159         return SDL_FALSE;
  2160     }
  2161 
  2162 #ifdef __MACOSX__
  2163     if (Cocoa_IsWindowInFullscreenSpace(window)) {
  2164         return SDL_FALSE;
  2165     }
  2166 #endif
  2167 
  2168     hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2169     if (hint) {
  2170         if (*hint == '0') {
  2171             return SDL_FALSE;
  2172         } else {
  2173             return SDL_TRUE;
  2174         }
  2175     }
  2176 
  2177     return SDL_TRUE;
  2178 }
  2179 
  2180 void
  2181 SDL_OnWindowFocusLost(SDL_Window * window)
  2182 {
  2183     if (window->gamma && _this->SetWindowGammaRamp) {
  2184         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2185     }
  2186 
  2187     SDL_UpdateWindowGrab(window);
  2188 
  2189     if (ShouldMinimizeOnFocusLoss(window)) {
  2190         SDL_MinimizeWindow(window);
  2191     }
  2192 }
  2193 
  2194 SDL_Window *
  2195 SDL_GetFocusWindow(void)
  2196 {
  2197     SDL_Window *window;
  2198 
  2199     if (!_this) {
  2200         return NULL;
  2201     }
  2202     for (window = _this->windows; window; window = window->next) {
  2203         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2204             return window;
  2205         }
  2206     }
  2207     return NULL;
  2208 }
  2209 
  2210 void
  2211 SDL_DestroyWindow(SDL_Window * window)
  2212 {
  2213     SDL_VideoDisplay *display;
  2214 
  2215     CHECK_WINDOW_MAGIC(window, );
  2216 
  2217     /* Restore video mode, etc. */
  2218     SDL_HideWindow(window);
  2219 
  2220     /* Make sure this window no longer has focus */
  2221     if (SDL_GetKeyboardFocus() == window) {
  2222         SDL_SetKeyboardFocus(NULL);
  2223     }
  2224     if (SDL_GetMouseFocus() == window) {
  2225         SDL_SetMouseFocus(NULL);
  2226     }
  2227 
  2228     /* make no context current if this is the current context window. */
  2229     if (window->flags & SDL_WINDOW_OPENGL) {
  2230         if (_this->current_glwin == window) {
  2231             SDL_GL_MakeCurrent(window, NULL);
  2232         }
  2233     }
  2234 
  2235     if (window->surface) {
  2236         window->surface->flags &= ~SDL_DONTFREE;
  2237         SDL_FreeSurface(window->surface);
  2238     }
  2239     if (_this->DestroyWindowFramebuffer) {
  2240         _this->DestroyWindowFramebuffer(_this, window);
  2241     }
  2242     if (_this->DestroyWindow) {
  2243         _this->DestroyWindow(_this, window);
  2244     }
  2245     if (window->flags & SDL_WINDOW_OPENGL) {
  2246         SDL_GL_UnloadLibrary();
  2247     }
  2248 
  2249     display = SDL_GetDisplayForWindow(window);
  2250     if (display->fullscreen_window == window) {
  2251         display->fullscreen_window = NULL;
  2252     }
  2253 
  2254     /* Now invalidate magic */
  2255     window->magic = NULL;
  2256 
  2257     /* Free memory associated with the window */
  2258     SDL_free(window->title);
  2259     SDL_FreeSurface(window->icon);
  2260     SDL_free(window->gamma);
  2261     while (window->data) {
  2262         SDL_WindowUserData *data = window->data;
  2263 
  2264         window->data = data->next;
  2265         SDL_free(data->name);
  2266         SDL_free(data);
  2267     }
  2268 
  2269     /* Unlink the window from the list */
  2270     if (window->next) {
  2271         window->next->prev = window->prev;
  2272     }
  2273     if (window->prev) {
  2274         window->prev->next = window->next;
  2275     } else {
  2276         _this->windows = window->next;
  2277     }
  2278 
  2279     SDL_free(window);
  2280 }
  2281 
  2282 SDL_bool
  2283 SDL_IsScreenSaverEnabled()
  2284 {
  2285     if (!_this) {
  2286         return SDL_TRUE;
  2287     }
  2288     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2289 }
  2290 
  2291 void
  2292 SDL_EnableScreenSaver()
  2293 {
  2294     if (!_this) {
  2295         return;
  2296     }
  2297     if (!_this->suspend_screensaver) {
  2298         return;
  2299     }
  2300     _this->suspend_screensaver = SDL_FALSE;
  2301     if (_this->SuspendScreenSaver) {
  2302         _this->SuspendScreenSaver(_this);
  2303     }
  2304 }
  2305 
  2306 void
  2307 SDL_DisableScreenSaver()
  2308 {
  2309     if (!_this) {
  2310         return;
  2311     }
  2312     if (_this->suspend_screensaver) {
  2313         return;
  2314     }
  2315     _this->suspend_screensaver = SDL_TRUE;
  2316     if (_this->SuspendScreenSaver) {
  2317         _this->SuspendScreenSaver(_this);
  2318     }
  2319 }
  2320 
  2321 void
  2322 SDL_VideoQuit(void)
  2323 {
  2324     int i, j;
  2325 
  2326     if (!_this) {
  2327         return;
  2328     }
  2329 
  2330     /* Halt event processing before doing anything else */
  2331     SDL_TouchQuit();
  2332     SDL_MouseQuit();
  2333     SDL_KeyboardQuit();
  2334     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2335 
  2336     SDL_EnableScreenSaver();
  2337 
  2338     /* Clean up the system video */
  2339     while (_this->windows) {
  2340         SDL_DestroyWindow(_this->windows);
  2341     }
  2342     _this->VideoQuit(_this);
  2343 
  2344     for (i = 0; i < _this->num_displays; ++i) {
  2345         SDL_VideoDisplay *display = &_this->displays[i];
  2346         for (j = display->num_display_modes; j--;) {
  2347             SDL_free(display->display_modes[j].driverdata);
  2348             display->display_modes[j].driverdata = NULL;
  2349         }
  2350         SDL_free(display->display_modes);
  2351         display->display_modes = NULL;
  2352         SDL_free(display->desktop_mode.driverdata);
  2353         display->desktop_mode.driverdata = NULL;
  2354         SDL_free(display->driverdata);
  2355         display->driverdata = NULL;
  2356     }
  2357     if (_this->displays) {
  2358         for (i = 0; i < _this->num_displays; ++i) {
  2359             SDL_free(_this->displays[i].name);
  2360         }
  2361         SDL_free(_this->displays);
  2362         _this->displays = NULL;
  2363         _this->num_displays = 0;
  2364     }
  2365     SDL_free(_this->clipboard_text);
  2366     _this->clipboard_text = NULL;
  2367     _this->free(_this);
  2368     _this = NULL;
  2369 }
  2370 
  2371 int
  2372 SDL_GL_LoadLibrary(const char *path)
  2373 {
  2374     int retval;
  2375 
  2376     if (!_this) {
  2377         return SDL_UninitializedVideo();
  2378     }
  2379     if (_this->gl_config.driver_loaded) {
  2380         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2381             return SDL_SetError("OpenGL library already loaded");
  2382         }
  2383         retval = 0;
  2384     } else {
  2385         if (!_this->GL_LoadLibrary) {
  2386             return SDL_SetError("No dynamic GL support in video driver");
  2387         }
  2388         retval = _this->GL_LoadLibrary(_this, path);
  2389     }
  2390     if (retval == 0) {
  2391         ++_this->gl_config.driver_loaded;
  2392     } else {
  2393         if (_this->GL_UnloadLibrary) {
  2394             _this->GL_UnloadLibrary(_this);
  2395         }
  2396     }
  2397     return (retval);
  2398 }
  2399 
  2400 void *
  2401 SDL_GL_GetProcAddress(const char *proc)
  2402 {
  2403     void *func;
  2404 
  2405     if (!_this) {
  2406         SDL_UninitializedVideo();
  2407         return NULL;
  2408     }
  2409     func = NULL;
  2410     if (_this->GL_GetProcAddress) {
  2411         if (_this->gl_config.driver_loaded) {
  2412             func = _this->GL_GetProcAddress(_this, proc);
  2413         } else {
  2414             SDL_SetError("No GL driver has been loaded");
  2415         }
  2416     } else {
  2417         SDL_SetError("No dynamic GL support in video driver");
  2418     }
  2419     return func;
  2420 }
  2421 
  2422 void
  2423 SDL_GL_UnloadLibrary(void)
  2424 {
  2425     if (!_this) {
  2426         SDL_UninitializedVideo();
  2427         return;
  2428     }
  2429     if (_this->gl_config.driver_loaded > 0) {
  2430         if (--_this->gl_config.driver_loaded > 0) {
  2431             return;
  2432         }
  2433         if (_this->GL_UnloadLibrary) {
  2434             _this->GL_UnloadLibrary(_this);
  2435         }
  2436     }
  2437 }
  2438 
  2439 static SDL_INLINE SDL_bool
  2440 isAtLeastGL3(const char *verstr)
  2441 {
  2442     return ( verstr && (SDL_atoi(verstr) >= 3) );
  2443 }
  2444 
  2445 SDL_bool
  2446 SDL_GL_ExtensionSupported(const char *extension)
  2447 {
  2448 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2449     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2450     const char *extensions;
  2451     const char *start;
  2452     const char *where, *terminator;
  2453 
  2454     /* Extension names should not have spaces. */
  2455     where = SDL_strchr(extension, ' ');
  2456     if (where || *extension == '\0') {
  2457         return SDL_FALSE;
  2458     }
  2459     /* See if there's an environment variable override */
  2460     start = SDL_getenv(extension);
  2461     if (start && *start == '0') {
  2462         return SDL_FALSE;
  2463     }
  2464 
  2465     /* Lookup the available extensions */
  2466 
  2467     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2468     if (!glGetStringFunc) {
  2469         return SDL_FALSE;
  2470     }
  2471 
  2472     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2473         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2474         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2475         GLint num_exts = 0;
  2476         GLint i;
  2477 
  2478         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2479         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2480         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2481             return SDL_FALSE;
  2482         }
  2483 
  2484         #ifndef GL_NUM_EXTENSIONS
  2485         #define GL_NUM_EXTENSIONS 0x821D
  2486         #endif
  2487         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2488         for (i = 0; i < num_exts; i++) {
  2489             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2490             if (SDL_strcmp(thisext, extension) == 0) {
  2491                 return SDL_TRUE;
  2492             }
  2493         }
  2494 
  2495         return SDL_FALSE;
  2496     }
  2497 
  2498     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2499 
  2500     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2501     if (!extensions) {
  2502         return SDL_FALSE;
  2503     }
  2504     /*
  2505      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2506      * extensions string. Don't be fooled by sub-strings, etc.
  2507      */
  2508 
  2509     start = extensions;
  2510 
  2511     for (;;) {
  2512         where = SDL_strstr(start, extension);
  2513         if (!where)
  2514             break;
  2515 
  2516         terminator = where + SDL_strlen(extension);
  2517         if (where == start || *(where - 1) == ' ')
  2518             if (*terminator == ' ' || *terminator == '\0')
  2519                 return SDL_TRUE;
  2520 
  2521         start = terminator;
  2522     }
  2523     return SDL_FALSE;
  2524 #else
  2525     return SDL_FALSE;
  2526 #endif
  2527 }
  2528 
  2529 int
  2530 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2531 {
  2532 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2533     int retval;
  2534 
  2535     if (!_this) {
  2536         return SDL_UninitializedVideo();
  2537     }
  2538     retval = 0;
  2539     switch (attr) {
  2540     case SDL_GL_RED_SIZE:
  2541         _this->gl_config.red_size = value;
  2542         break;
  2543     case SDL_GL_GREEN_SIZE:
  2544         _this->gl_config.green_size = value;
  2545         break;
  2546     case SDL_GL_BLUE_SIZE:
  2547         _this->gl_config.blue_size = value;
  2548         break;
  2549     case SDL_GL_ALPHA_SIZE:
  2550         _this->gl_config.alpha_size = value;
  2551         break;
  2552     case SDL_GL_DOUBLEBUFFER:
  2553         _this->gl_config.double_buffer = value;
  2554         break;
  2555     case SDL_GL_BUFFER_SIZE:
  2556         _this->gl_config.buffer_size = value;
  2557         break;
  2558     case SDL_GL_DEPTH_SIZE:
  2559         _this->gl_config.depth_size = value;
  2560         break;
  2561     case SDL_GL_STENCIL_SIZE:
  2562         _this->gl_config.stencil_size = value;
  2563         break;
  2564     case SDL_GL_ACCUM_RED_SIZE:
  2565         _this->gl_config.accum_red_size = value;
  2566         break;
  2567     case SDL_GL_ACCUM_GREEN_SIZE:
  2568         _this->gl_config.accum_green_size = value;
  2569         break;
  2570     case SDL_GL_ACCUM_BLUE_SIZE:
  2571         _this->gl_config.accum_blue_size = value;
  2572         break;
  2573     case SDL_GL_ACCUM_ALPHA_SIZE:
  2574         _this->gl_config.accum_alpha_size = value;
  2575         break;
  2576     case SDL_GL_STEREO:
  2577         _this->gl_config.stereo = value;
  2578         break;
  2579     case SDL_GL_MULTISAMPLEBUFFERS:
  2580         _this->gl_config.multisamplebuffers = value;
  2581         break;
  2582     case SDL_GL_MULTISAMPLESAMPLES:
  2583         _this->gl_config.multisamplesamples = value;
  2584         break;
  2585     case SDL_GL_ACCELERATED_VISUAL:
  2586         _this->gl_config.accelerated = value;
  2587         break;
  2588     case SDL_GL_RETAINED_BACKING:
  2589         _this->gl_config.retained_backing = value;
  2590         break;
  2591     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2592         _this->gl_config.major_version = value;
  2593         break;
  2594     case SDL_GL_CONTEXT_MINOR_VERSION:
  2595         _this->gl_config.minor_version = value;
  2596         break;
  2597     case SDL_GL_CONTEXT_EGL:
  2598         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2599         if (value != 0) {
  2600             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  2601         } else {
  2602             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  2603         };
  2604         break;
  2605     case SDL_GL_CONTEXT_FLAGS:
  2606         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2607               SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2608               SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2609               SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2610         retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2611         break;
  2612     }
  2613         _this->gl_config.flags = value;
  2614         break;
  2615     case SDL_GL_CONTEXT_PROFILE_MASK:
  2616         if( value != 0 &&
  2617         value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2618         value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2619         value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2620         retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2621         break;
  2622     }
  2623         _this->gl_config.profile_mask = value;
  2624         break;
  2625     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2626         _this->gl_config.share_with_current_context = value;
  2627         break;
  2628     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2629         _this->gl_config.framebuffer_srgb_capable = value;
  2630         break;
  2631     default:
  2632         retval = SDL_SetError("Unknown OpenGL attribute");
  2633         break;
  2634     }
  2635     return retval;
  2636 #else
  2637     return SDL_Unsupported();
  2638 #endif /* SDL_VIDEO_OPENGL */
  2639 }
  2640 
  2641 int
  2642 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2643 {
  2644 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2645     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2646     GLenum(APIENTRY * glGetErrorFunc) (void);
  2647     GLenum attrib = 0;
  2648     GLenum error = 0;
  2649 
  2650     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2651     if (!glGetIntegervFunc) {
  2652         return -1;
  2653     }
  2654 
  2655     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2656     if (!glGetErrorFunc) {
  2657         return -1;
  2658     }
  2659 
  2660     /* Clear value in any case */
  2661     *value = 0;
  2662 
  2663     switch (attr) {
  2664     case SDL_GL_RED_SIZE:
  2665         attrib = GL_RED_BITS;
  2666         break;
  2667     case SDL_GL_BLUE_SIZE:
  2668         attrib = GL_BLUE_BITS;
  2669         break;
  2670     case SDL_GL_GREEN_SIZE:
  2671         attrib = GL_GREEN_BITS;
  2672         break;
  2673     case SDL_GL_ALPHA_SIZE:
  2674         attrib = GL_ALPHA_BITS;
  2675         break;
  2676     case SDL_GL_DOUBLEBUFFER:
  2677 #if SDL_VIDEO_OPENGL
  2678         attrib = GL_DOUBLEBUFFER;
  2679         break;
  2680 #else
  2681         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2682         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2683         /* SDL driver must set proper value after initialization              */
  2684         *value = _this->gl_config.double_buffer;
  2685         return 0;
  2686 #endif
  2687     case SDL_GL_DEPTH_SIZE:
  2688         attrib = GL_DEPTH_BITS;
  2689         break;
  2690     case SDL_GL_STENCIL_SIZE:
  2691         attrib = GL_STENCIL_BITS;
  2692         break;
  2693 #if SDL_VIDEO_OPENGL
  2694     case SDL_GL_ACCUM_RED_SIZE:
  2695         attrib = GL_ACCUM_RED_BITS;
  2696         break;
  2697     case SDL_GL_ACCUM_GREEN_SIZE:
  2698         attrib = GL_ACCUM_GREEN_BITS;
  2699         break;
  2700     case SDL_GL_ACCUM_BLUE_SIZE:
  2701         attrib = GL_ACCUM_BLUE_BITS;
  2702         break;
  2703     case SDL_GL_ACCUM_ALPHA_SIZE:
  2704         attrib = GL_ACCUM_ALPHA_BITS;
  2705         break;
  2706     case SDL_GL_STEREO:
  2707         attrib = GL_STEREO;
  2708         break;
  2709 #else
  2710     case SDL_GL_ACCUM_RED_SIZE:
  2711     case SDL_GL_ACCUM_GREEN_SIZE:
  2712     case SDL_GL_ACCUM_BLUE_SIZE:
  2713     case SDL_GL_ACCUM_ALPHA_SIZE:
  2714     case SDL_GL_STEREO:
  2715         /* none of these are supported in OpenGL ES */
  2716         *value = 0;
  2717         return 0;
  2718 #endif
  2719     case SDL_GL_MULTISAMPLEBUFFERS:
  2720 #if SDL_VIDEO_OPENGL
  2721         attrib = GL_SAMPLE_BUFFERS_ARB;
  2722 #else
  2723         attrib = GL_SAMPLE_BUFFERS;
  2724 #endif
  2725         break;
  2726     case SDL_GL_MULTISAMPLESAMPLES:
  2727 #if SDL_VIDEO_OPENGL
  2728         attrib = GL_SAMPLES_ARB;
  2729 #else
  2730         attrib = GL_SAMPLES;
  2731 #endif
  2732         break;
  2733     case SDL_GL_BUFFER_SIZE:
  2734         {
  2735             GLint bits = 0;
  2736             GLint component;
  2737 
  2738             /*
  2739              * there doesn't seem to be a single flag in OpenGL
  2740              * for this!
  2741              */
  2742             glGetIntegervFunc(GL_RED_BITS, &component);
  2743             bits += component;
  2744             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2745             bits += component;
  2746             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2747             bits += component;
  2748             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2749             bits += component;
  2750 
  2751             *value = bits;
  2752             return 0;
  2753         }
  2754     case SDL_GL_ACCELERATED_VISUAL:
  2755         {
  2756             /* FIXME: How do we get this information? */
  2757             *value = (_this->gl_config.accelerated != 0);
  2758             return 0;
  2759         }
  2760     case SDL_GL_RETAINED_BACKING:
  2761         {
  2762             *value = _this->gl_config.retained_backing;
  2763             return 0;
  2764         }
  2765     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2766         {
  2767             *value = _this->gl_config.major_version;
  2768             return 0;
  2769         }
  2770     case SDL_GL_CONTEXT_MINOR_VERSION:
  2771         {
  2772             *value = _this->gl_config.minor_version;
  2773             return 0;
  2774         }
  2775     case SDL_GL_CONTEXT_EGL:
  2776         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2777         {
  2778             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  2779                 *value = 1;
  2780             }
  2781             else {
  2782                 *value = 0;
  2783             }
  2784             return 0;
  2785         }
  2786     case SDL_GL_CONTEXT_FLAGS:
  2787         {
  2788             *value = _this->gl_config.flags;
  2789             return 0;
  2790         }
  2791     case SDL_GL_CONTEXT_PROFILE_MASK:
  2792         {
  2793             *value = _this->gl_config.profile_mask;
  2794             return 0;
  2795         }
  2796     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2797         {
  2798             *value = _this->gl_config.share_with_current_context;
  2799             return 0;
  2800         }
  2801     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2802         {
  2803             *value = _this->gl_config.framebuffer_srgb_capable;
  2804             return 0;
  2805         }
  2806     default:
  2807         return SDL_SetError("Unknown OpenGL attribute");
  2808     }
  2809 
  2810     glGetIntegervFunc(attrib, (GLint *) value);
  2811     error = glGetErrorFunc();
  2812     if (error != GL_NO_ERROR) {
  2813         if (error == GL_INVALID_ENUM) {
  2814             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2815         } else if (error == GL_INVALID_VALUE) {
  2816             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2817         }
  2818         return SDL_SetError("OpenGL error: %08X", error);
  2819     }
  2820     return 0;
  2821 #else
  2822     return SDL_Unsupported();
  2823 #endif /* SDL_VIDEO_OPENGL */
  2824 }
  2825 
  2826 SDL_GLContext
  2827 SDL_GL_CreateContext(SDL_Window * window)
  2828 {
  2829     SDL_GLContext ctx = NULL;
  2830     CHECK_WINDOW_MAGIC(window, NULL);
  2831 
  2832     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2833         SDL_SetError("The specified window isn't an OpenGL window");
  2834         return NULL;
  2835     }
  2836 
  2837     ctx = _this->GL_CreateContext(_this, window);
  2838 
  2839     /* Creating a context is assumed to make it current in the SDL driver. */
  2840     if (ctx) {
  2841         _this->current_glwin = window;
  2842         _this->current_glctx = ctx;
  2843         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2844         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2845     }
  2846     return ctx;
  2847 }
  2848 
  2849 int
  2850 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2851 {
  2852     int retval;
  2853 
  2854     if (window == SDL_GL_GetCurrentWindow() &&
  2855         ctx == SDL_GL_GetCurrentContext()) {
  2856         /* We're already current. */
  2857         return 0;
  2858     }
  2859 
  2860     if (!ctx) {
  2861         window = NULL;
  2862     } else {
  2863         CHECK_WINDOW_MAGIC(window, -1);
  2864 
  2865         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2866             return SDL_SetError("The specified window isn't an OpenGL window");
  2867         }
  2868     }
  2869 
  2870     retval = _this->GL_MakeCurrent(_this, window, ctx);
  2871     if (retval == 0) {
  2872         _this->current_glwin = window;
  2873         _this->current_glctx = ctx;
  2874         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2875         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2876     }
  2877     return retval;
  2878 }
  2879 
  2880 SDL_Window *
  2881 SDL_GL_GetCurrentWindow(void)
  2882 {
  2883     if (!_this) {
  2884         SDL_UninitializedVideo();
  2885         return NULL;
  2886     }
  2887     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
  2888 }
  2889 
  2890 SDL_GLContext
  2891 SDL_GL_GetCurrentContext(void)
  2892 {
  2893     if (!_this) {
  2894         SDL_UninitializedVideo();
  2895         return NULL;
  2896     }
  2897     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
  2898 }
  2899 
  2900 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
  2901 {
  2902     CHECK_WINDOW_MAGIC(window, );
  2903 
  2904     if (_this->GL_GetDrawableSize) {
  2905         _this->GL_GetDrawableSize(_this, window, w, h);
  2906     } else {
  2907         SDL_GetWindowSize(window, w, h);
  2908     }
  2909 }
  2910 
  2911 int
  2912 SDL_GL_SetSwapInterval(int interval)
  2913 {
  2914     if (!_this) {
  2915         return SDL_UninitializedVideo();
  2916     } else if (SDL_GL_GetCurrentContext() == NULL) {
  2917         return SDL_SetError("No OpenGL context has been made current");
  2918     } else if (_this->GL_SetSwapInterval) {
  2919         return _this->GL_SetSwapInterval(_this, interval);
  2920     } else {
  2921         return SDL_SetError("Setting the swap interval is not supported");
  2922     }
  2923 }
  2924 
  2925 int
  2926 SDL_GL_GetSwapInterval(void)
  2927 {
  2928     if (!_this) {
  2929         return 0;
  2930     } else if (SDL_GL_GetCurrentContext() == NULL) {
  2931         return 0;
  2932     } else if (_this->GL_GetSwapInterval) {
  2933         return _this->GL_GetSwapInterval(_this);
  2934     } else {
  2935         return 0;
  2936     }
  2937 }
  2938 
  2939 void
  2940 SDL_GL_SwapWindow(SDL_Window * window)
  2941 {
  2942     CHECK_WINDOW_MAGIC(window, );
  2943 
  2944     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2945         SDL_SetError("The specified window isn't an OpenGL window");
  2946         return;
  2947     }
  2948 
  2949     if (SDL_GL_GetCurrentWindow() != window) {
  2950         SDL_SetError("The specified window has not been made current");
  2951         return;
  2952     }
  2953 
  2954     _this->GL_SwapWindow(_this, window);
  2955 }
  2956 
  2957 void
  2958 SDL_GL_DeleteContext(SDL_GLContext context)
  2959 {
  2960     if (!_this || !context) {
  2961         return;
  2962     }
  2963 
  2964     if (SDL_GL_GetCurrentContext() == context) {
  2965         SDL_GL_MakeCurrent(NULL, NULL);
  2966     }
  2967 
  2968     _this->GL_DeleteContext(_this, context);
  2969 }
  2970 
  2971 #if 0                           /* FIXME */
  2972 /*
  2973  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2974  * & 2 for alpha channel.
  2975  */
  2976 static void
  2977 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2978 {
  2979     int x, y;
  2980     Uint32 colorkey;
  2981 #define SET_MASKBIT(icon, x, y, mask) \
  2982     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2983 
  2984     colorkey = icon->format->colorkey;
  2985     switch (icon->format->BytesPerPixel) {
  2986     case 1:
  2987         {
  2988             Uint8 *pixels;
  2989             for (y = 0; y < icon->h; ++y) {
  2990                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2991                 for (x = 0; x < icon->w; ++x) {
  2992                     if (*pixels++ == colorkey) {
  2993                         SET_MASKBIT(icon, x, y, mask);
  2994                     }
  2995                 }
  2996             }
  2997         }
  2998         break;
  2999 
  3000     case 2:
  3001         {
  3002             Uint16 *pixels;
  3003             for (y = 0; y < icon->h; ++y) {
  3004                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  3005                 for (x = 0; x < icon->w; ++x) {
  3006                     if ((flags & 1) && *pixels == colorkey) {
  3007                         SET_MASKBIT(icon, x, y, mask);
  3008                     } else if ((flags & 2)
  3009                                && (*pixels & icon->format->Amask) == 0) {
  3010                         SET_MASKBIT(icon, x, y, mask);
  3011                     }
  3012                     pixels++;
  3013                 }
  3014             }
  3015         }
  3016         break;
  3017 
  3018     case 4:
  3019         {
  3020             Uint32 *pixels;
  3021             for (y = 0; y < icon->h; ++y) {
  3022                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3023                 for (x = 0; x < icon->w; ++x) {
  3024                     if ((flags & 1) && *pixels == colorkey) {
  3025                         SET_MASKBIT(icon, x, y, mask);
  3026                     } else if ((flags & 2)
  3027                                && (*pixels & icon->format->Amask) == 0) {
  3028                         SET_MASKBIT(icon, x, y, mask);
  3029                     }
  3030                     pixels++;
  3031                 }
  3032             }
  3033         }
  3034         break;
  3035     }
  3036 }
  3037 
  3038 /*
  3039  * Sets the window manager icon for the display window.
  3040  */
  3041 void
  3042 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3043 {
  3044     if (icon && _this->SetIcon) {
  3045         /* Generate a mask if necessary, and create the icon! */
  3046         if (mask == NULL) {
  3047             int mask_len = icon->h * (icon->w + 7) / 8;
  3048             int flags = 0;
  3049             mask = (Uint8 *) SDL_malloc(mask_len);
  3050             if (mask == NULL) {
  3051                 return;
  3052             }
  3053             SDL_memset(mask, ~0, mask_len);
  3054             if (icon->flags & SDL_SRCCOLORKEY)
  3055                 flags |= 1;
  3056             if (icon->flags & SDL_SRCALPHA)
  3057                 flags |= 2;
  3058             if (flags) {
  3059                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3060             }
  3061             _this->SetIcon(_this, icon, mask);
  3062             SDL_free(mask);
  3063         } else {
  3064             _this->SetIcon(_this, icon, mask);
  3065         }
  3066     }
  3067 }
  3068 #endif
  3069 
  3070 SDL_bool
  3071 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3072 {
  3073     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3074 
  3075     if (!info) {
  3076         return SDL_FALSE;
  3077     }
  3078     info->subsystem = SDL_SYSWM_UNKNOWN;
  3079 
  3080     if (!_this->GetWindowWMInfo) {
  3081         return SDL_FALSE;
  3082     }
  3083     return (_this->GetWindowWMInfo(_this, window, info));
  3084 }
  3085 
  3086 void
  3087 SDL_StartTextInput(void)
  3088 {
  3089     SDL_Window *window;
  3090 
  3091     /* First, enable text events */
  3092     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3093     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3094 
  3095     /* Then show the on-screen keyboard, if any */
  3096     window = SDL_GetFocusWindow();
  3097     if (window && _this && _this->ShowScreenKeyboard) {
  3098         _this->ShowScreenKeyboard(_this, window);
  3099     }
  3100 
  3101     /* Finally start the text input system */
  3102     if (_this && _this->StartTextInput) {
  3103         _this->StartTextInput(_this);
  3104     }
  3105 }
  3106 
  3107 SDL_bool
  3108 SDL_IsTextInputActive(void)
  3109 {
  3110     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  3111 }
  3112 
  3113 void
  3114 SDL_StopTextInput(void)
  3115 {
  3116     SDL_Window *window;
  3117 
  3118     /* Stop the text input system */
  3119     if (_this && _this->StopTextInput) {
  3120         _this->StopTextInput(_this);
  3121     }
  3122 
  3123     /* Hide the on-screen keyboard, if any */
  3124     window = SDL_GetFocusWindow();
  3125     if (window && _this && _this->HideScreenKeyboard) {
  3126         _this->HideScreenKeyboard(_this, window);
  3127     }
  3128 
  3129     /* Finally disable text events */
  3130     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3131     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3132 }
  3133 
  3134 void
  3135 SDL_SetTextInputRect(SDL_Rect *rect)
  3136 {
  3137     if (_this && _this->SetTextInputRect) {
  3138         _this->SetTextInputRect(_this, rect);
  3139     }
  3140 }
  3141 
  3142 SDL_bool
  3143 SDL_HasScreenKeyboardSupport(void)
  3144 {
  3145     if (_this && _this->HasScreenKeyboardSupport) {
  3146         return _this->HasScreenKeyboardSupport(_this);
  3147     }
  3148     return SDL_FALSE;
  3149 }
  3150 
  3151 SDL_bool
  3152 SDL_IsScreenKeyboardShown(SDL_Window *window)
  3153 {
  3154     if (window && _this && _this->IsScreenKeyboardShown) {
  3155         return _this->IsScreenKeyboardShown(_this, window);
  3156     }
  3157     return SDL_FALSE;
  3158 }
  3159 
  3160 #if SDL_VIDEO_DRIVER_WINDOWS
  3161 #include "windows/SDL_windowsmessagebox.h"
  3162 #endif
  3163 #if SDL_VIDEO_DRIVER_COCOA
  3164 #include "cocoa/SDL_cocoamessagebox.h"
  3165 #endif
  3166 #if SDL_VIDEO_DRIVER_UIKIT
  3167 #include "uikit/SDL_uikitmessagebox.h"
  3168 #endif
  3169 #if SDL_VIDEO_DRIVER_X11
  3170 #include "x11/SDL_x11messagebox.h"
  3171 #endif
  3172 
  3173 static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
  3174 {
  3175     SDL_SysWMinfo info;
  3176     SDL_Window *window = messageboxdata->window;
  3177 
  3178     if (!window) {
  3179         return SDL_TRUE;
  3180     }
  3181 
  3182     SDL_VERSION(&info.version);
  3183     if (!SDL_GetWindowWMInfo(window, &info)) {
  3184         return SDL_TRUE;
  3185     } else {
  3186         return (info.subsystem == drivertype);
  3187     }
  3188 }
  3189 
  3190 int
  3191 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3192 {
  3193     int dummybutton;
  3194     int retval = -1;
  3195     SDL_bool relative_mode;
  3196     int show_cursor_prev;
  3197 
  3198     if (!messageboxdata) {
  3199         return SDL_InvalidParamError("messageboxdata");
  3200     }
  3201 
  3202     relative_mode = SDL_GetRelativeMouseMode();
  3203     SDL_SetRelativeMouseMode(SDL_FALSE);
  3204     show_cursor_prev = SDL_ShowCursor(1);
  3205 
  3206     if (!buttonid) {
  3207         buttonid = &dummybutton;
  3208     }
  3209 
  3210     if (_this && _this->ShowMessageBox) {
  3211         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
  3212     }
  3213 
  3214     /* It's completely fine to call this function before video is initialized */
  3215 #if SDL_VIDEO_DRIVER_WINDOWS
  3216     if (retval == -1 &&
  3217         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
  3218         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3219         retval = 0;
  3220     }
  3221 #endif
  3222 #if SDL_VIDEO_DRIVER_COCOA
  3223     if (retval == -1 &&
  3224         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
  3225         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3226         retval = 0;
  3227     }
  3228 #endif
  3229 #if SDL_VIDEO_DRIVER_UIKIT
  3230     if (retval == -1 &&
  3231         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
  3232         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3233         retval = 0;
  3234     }
  3235 #endif
  3236 #if SDL_VIDEO_DRIVER_X11
  3237     if (retval == -1 &&
  3238         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
  3239         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3240         retval = 0;
  3241     }
  3242 #endif
  3243     if (retval == -1) {
  3244         SDL_SetError("No message system available");
  3245     }
  3246 
  3247     SDL_ShowCursor(show_cursor_prev);
  3248     SDL_SetRelativeMouseMode(relative_mode);
  3249 
  3250     return retval;
  3251 }
  3252 
  3253 int
  3254 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3255 {
  3256     SDL_MessageBoxData data;
  3257     SDL_MessageBoxButtonData button;
  3258 
  3259     SDL_zero(data);
  3260     data.flags = flags;
  3261     data.title = title;
  3262     data.message = message;
  3263     data.numbuttons = 1;
  3264     data.buttons = &button;
  3265     data.window = window;
  3266 
  3267     SDL_zero(button);
  3268     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3269     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3270     button.text = "OK";
  3271 
  3272     return SDL_ShowMessageBox(&data, NULL);
  3273 }
  3274 
  3275 SDL_bool
  3276 SDL_ShouldAllowTopmost(void)
  3277 {
  3278     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3279     if (hint) {
  3280         if (*hint == '0') {
  3281             return SDL_FALSE;
  3282         } else {
  3283             return SDL_TRUE;
  3284         }
  3285     }
  3286     return SDL_TRUE;
  3287 }
  3288 
  3289 /* vi: set ts=4 sw=4 expandtab: */