src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 23 Dec 2013 17:37:22 -0800
changeset 8071 1ac2db4abe11
parent 8062 4fc5f66d63cc
child 8072 9d8865351afd
permissions -rw-r--r--
Added a relative mouse mode that uses mouse warping instead of raw input.
To enable this, set the environment variable SDL_MOUSE_RELATIVE_MODE_WARP to "1"

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