src/video/SDL_video.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 15 Jul 2013 14:38:19 -0400
changeset 7463 f2f794cf85c0
parent 7453 91c3bb321036
child 7493 7bfda8f0bfdf
permissions -rw-r--r--
Turn the system mouse cursor back on before VideoQuit().

This is good policy, so it doesn't have a chance to leave it hidden on targets
that wouldn't necessarily reset it by default, but it also fixes a crash if
you try to use a message box after SDL_Quit() is called.

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