src/video/SDL_video.c
author Edward Rudd <urkle@outoforder.cc>
Fri, 20 Sep 2013 13:43:00 -0400
changeset 7746 6a05d7352575
parent 7745 c52d519d104a
child 7753 e4c38f17bfad
permissions -rw-r--r--
add in High DPI support (aka Retina)

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