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