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