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