src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 11 Jul 2013 22:59:20 -0700
changeset 7412 50211a1fd557
parent 7399 f35ff854121a
child 7429 ff7edbf76a73
permissions -rw-r--r--
Fixed bug 1946 - OpenGL contexts in threads

The SDL OpenGL context code is now properly thread aware. There are two new functions which return the current OpenGL window and context for the current thread.

There are still places in the cocoa driver where the OpenGL context needs to be updated when the view changes. These will need a different solution and still use the last globally set context to avoid changing behavior.
     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     SDL_DisplayMode a = *(const SDL_DisplayMode *) A;
   364     SDL_DisplayMode b = *(const SDL_DisplayMode *) B;
   365 
   366     if (a.w != b.w) {
   367         return b.w - a.w;
   368     }
   369     if (a.h != b.h) {
   370         return b.h - a.h;
   371     }
   372     if (SDL_BITSPERPIXEL(a.format) != SDL_BITSPERPIXEL(b.format)) {
   373         return SDL_BITSPERPIXEL(b.format) - SDL_BITSPERPIXEL(a.format);
   374     }
   375     if (SDL_PIXELLAYOUT(a.format) != SDL_PIXELLAYOUT(b.format)) {
   376         return SDL_PIXELLAYOUT(b.format) - SDL_PIXELLAYOUT(a.format);
   377     }
   378     if (a.refresh_rate != b.refresh_rate) {
   379         return b.refresh_rate - a.refresh_rate;
   380     }
   381     return 0;
   382 }
   383 
   384 static int
   385 SDL_UninitializedVideo()
   386 {
   387     return SDL_SetError("Video subsystem has not been initialized");
   388 }
   389 
   390 int
   391 SDL_GetNumVideoDrivers(void)
   392 {
   393     return SDL_arraysize(bootstrap) - 1;
   394 }
   395 
   396 const char *
   397 SDL_GetVideoDriver(int index)
   398 {
   399     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
   400         return bootstrap[index]->name;
   401     }
   402     return NULL;
   403 }
   404 
   405 /*
   406  * Initialize the video and event subsystems -- determine native pixel format
   407  */
   408 int
   409 SDL_VideoInit(const char *driver_name)
   410 {
   411     SDL_VideoDevice *video;
   412     int index;
   413     int i;
   414 
   415     /* Check to make sure we don't overwrite '_this' */
   416     if (_this != NULL) {
   417         SDL_VideoQuit();
   418     }
   419 
   420 #if !SDL_TIMERS_DISABLED
   421     SDL_InitTicks();
   422 #endif
   423 
   424     /* Start the event loop */
   425     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 ||
   426         SDL_KeyboardInit() < 0 ||
   427         SDL_MouseInit() < 0 ||
   428         SDL_TouchInit() < 0) {
   429         return -1;
   430     }
   431 
   432     /* Select the proper video driver */
   433     index = 0;
   434     video = NULL;
   435     if (driver_name == NULL) {
   436         driver_name = SDL_getenv("SDL_VIDEODRIVER");
   437     }
   438     if (driver_name != NULL) {
   439         for (i = 0; bootstrap[i]; ++i) {
   440             if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) {
   441                 video = bootstrap[i]->create(index);
   442                 break;
   443             }
   444         }
   445     } else {
   446         for (i = 0; bootstrap[i]; ++i) {
   447             if (bootstrap[i]->available()) {
   448                 video = bootstrap[i]->create(index);
   449                 if (video != NULL) {
   450                     break;
   451                 }
   452             }
   453         }
   454     }
   455     if (video == NULL) {
   456         if (driver_name) {
   457             return SDL_SetError("%s not available", driver_name);
   458         }
   459         return SDL_SetError("No available video device");
   460     }
   461     _this = video;
   462     _this->name = bootstrap[i]->name;
   463     _this->next_object_id = 1;
   464 
   465 
   466     /* Set some very sane GL defaults */
   467     _this->gl_config.driver_loaded = 0;
   468     _this->gl_config.dll_handle = NULL;
   469     _this->gl_config.red_size = 3;
   470     _this->gl_config.green_size = 3;
   471     _this->gl_config.blue_size = 2;
   472     _this->gl_config.alpha_size = 0;
   473     _this->gl_config.buffer_size = 0;
   474     _this->gl_config.depth_size = 16;
   475     _this->gl_config.stencil_size = 0;
   476     _this->gl_config.double_buffer = 1;
   477     _this->gl_config.accum_red_size = 0;
   478     _this->gl_config.accum_green_size = 0;
   479     _this->gl_config.accum_blue_size = 0;
   480     _this->gl_config.accum_alpha_size = 0;
   481     _this->gl_config.stereo = 0;
   482     _this->gl_config.multisamplebuffers = 0;
   483     _this->gl_config.multisamplesamples = 0;
   484     _this->gl_config.retained_backing = 1;
   485     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
   486 #if SDL_VIDEO_OPENGL
   487     _this->gl_config.major_version = 2;
   488     _this->gl_config.minor_version = 1;
   489     _this->gl_config.use_egl = 0;
   490 #elif SDL_VIDEO_OPENGL_ES
   491     _this->gl_config.major_version = 1;
   492     _this->gl_config.minor_version = 1;
   493     _this->gl_config.use_egl = 1;
   494 #elif SDL_VIDEO_OPENGL_ES2
   495     _this->gl_config.major_version = 2;
   496     _this->gl_config.minor_version = 0;
   497     _this->gl_config.use_egl = 1;
   498 #endif
   499     _this->gl_config.flags = 0;
   500     _this->gl_config.profile_mask = 0;
   501     _this->gl_config.share_with_current_context = 0;
   502 
   503     _this->current_glwin_tls = SDL_TLSCreate();
   504     _this->current_glctx_tls = SDL_TLSCreate();
   505 
   506     /* Initialize the video subsystem */
   507     if (_this->VideoInit(_this) < 0) {
   508         SDL_VideoQuit();
   509         return -1;
   510     }
   511 
   512     /* Make sure some displays were added */
   513     if (_this->num_displays == 0) {
   514         SDL_VideoQuit();
   515         return SDL_SetError("The video driver did not add any displays");
   516     }
   517 
   518     /* Add the renderer framebuffer emulation if desired */
   519     if (ShouldUseTextureFramebuffer()) {
   520         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
   521         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
   522         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
   523     }
   524 
   525     /* If we don't use a screen keyboard, turn on text input by default,
   526        otherwise programs that expect to get text events without enabling
   527        UNICODE input won't get any events.
   528 
   529        Actually, come to think of it, you needed to call SDL_EnableUNICODE(1)
   530        in SDL 1.2 before you got text input events.  Hmm...
   531      */
   532     if (!SDL_HasScreenKeyboardSupport()) {
   533         SDL_StartTextInput();
   534     }
   535 
   536     /* We're ready to go! */
   537     return 0;
   538 }
   539 
   540 const char *
   541 SDL_GetCurrentVideoDriver()
   542 {
   543     if (!_this) {
   544         SDL_UninitializedVideo();
   545         return NULL;
   546     }
   547     return _this->name;
   548 }
   549 
   550 SDL_VideoDevice *
   551 SDL_GetVideoDevice(void)
   552 {
   553     return _this;
   554 }
   555 
   556 int
   557 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   558 {
   559     SDL_VideoDisplay display;
   560 
   561     SDL_zero(display);
   562     if (desktop_mode) {
   563         display.desktop_mode = *desktop_mode;
   564     }
   565     display.current_mode = display.desktop_mode;
   566 
   567     return SDL_AddVideoDisplay(&display);
   568 }
   569 
   570 int
   571 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   572 {
   573     SDL_VideoDisplay *displays;
   574     int index = -1;
   575 
   576     displays =
   577         SDL_realloc(_this->displays,
   578                     (_this->num_displays + 1) * sizeof(*displays));
   579     if (displays) {
   580         index = _this->num_displays++;
   581         displays[index] = *display;
   582         displays[index].device = _this;
   583         _this->displays = displays;
   584 
   585         if (display->name) {
   586             displays[index].name = SDL_strdup(display->name);
   587         } else {
   588             char name[32];
   589 
   590             SDL_itoa(index, name, 10);
   591             displays[index].name = SDL_strdup(name);
   592         }
   593     } else {
   594         SDL_OutOfMemory();
   595     }
   596     return index;
   597 }
   598 
   599 int
   600 SDL_GetNumVideoDisplays(void)
   601 {
   602     if (!_this) {
   603         SDL_UninitializedVideo();
   604         return 0;
   605     }
   606     return _this->num_displays;
   607 }
   608 
   609 static int
   610 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
   611 {
   612     int displayIndex;
   613 
   614     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
   615         if (display == &_this->displays[displayIndex]) {
   616             return displayIndex;
   617         }
   618     }
   619 
   620     /* Couldn't find the display, just use index 0 */
   621     return 0;
   622 }
   623 
   624 const char *
   625 SDL_GetDisplayName(int displayIndex)
   626 {
   627     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   628 
   629     return _this->displays[displayIndex].name;
   630 }
   631 
   632 int
   633 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
   634 {
   635     CHECK_DISPLAY_INDEX(displayIndex, -1);
   636 
   637     if (rect) {
   638         SDL_VideoDisplay *display = &_this->displays[displayIndex];
   639 
   640         if (_this->GetDisplayBounds) {
   641             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
   642                 return 0;
   643             }
   644         }
   645 
   646         /* Assume that the displays are left to right */
   647         if (displayIndex == 0) {
   648             rect->x = 0;
   649             rect->y = 0;
   650         } else {
   651             SDL_GetDisplayBounds(displayIndex-1, rect);
   652             rect->x += rect->w;
   653         }
   654         rect->w = display->current_mode.w;
   655         rect->h = display->current_mode.h;
   656     }
   657     return 0;
   658 }
   659 
   660 SDL_bool
   661 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   662 {
   663     SDL_DisplayMode *modes;
   664     int i, nmodes;
   665 
   666     /* Make sure we don't already have the mode in the list */
   667     modes = display->display_modes;
   668     nmodes = display->num_display_modes;
   669     for (i = nmodes; i--;) {
   670         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   671             return SDL_FALSE;
   672         }
   673     }
   674 
   675     /* Go ahead and add the new mode */
   676     if (nmodes == display->max_display_modes) {
   677         modes =
   678             SDL_realloc(modes,
   679                         (display->max_display_modes + 32) * sizeof(*modes));
   680         if (!modes) {
   681             return SDL_FALSE;
   682         }
   683         display->display_modes = modes;
   684         display->max_display_modes += 32;
   685     }
   686     modes[nmodes] = *mode;
   687     display->num_display_modes++;
   688 
   689     /* Re-sort video modes */
   690     SDL_qsort(display->display_modes, display->num_display_modes,
   691               sizeof(SDL_DisplayMode), cmpmodes);
   692 
   693     return SDL_TRUE;
   694 }
   695 
   696 static int
   697 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   698 {
   699     if (!display->num_display_modes && _this->GetDisplayModes) {
   700         _this->GetDisplayModes(_this, display);
   701         SDL_qsort(display->display_modes, display->num_display_modes,
   702                   sizeof(SDL_DisplayMode), cmpmodes);
   703     }
   704     return display->num_display_modes;
   705 }
   706 
   707 int
   708 SDL_GetNumDisplayModes(int displayIndex)
   709 {
   710     CHECK_DISPLAY_INDEX(displayIndex, -1);
   711 
   712     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
   713 }
   714 
   715 int
   716 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
   717 {
   718     SDL_VideoDisplay *display;
   719 
   720     CHECK_DISPLAY_INDEX(displayIndex, -1);
   721 
   722     display = &_this->displays[displayIndex];
   723     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   724         return SDL_SetError("index must be in the range of 0 - %d",
   725                             SDL_GetNumDisplayModesForDisplay(display) - 1);
   726     }
   727     if (mode) {
   728         *mode = display->display_modes[index];
   729     }
   730     return 0;
   731 }
   732 
   733 int
   734 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   735 {
   736     SDL_VideoDisplay *display;
   737 
   738     CHECK_DISPLAY_INDEX(displayIndex, -1);
   739 
   740     display = &_this->displays[displayIndex];
   741     if (mode) {
   742         *mode = display->desktop_mode;
   743     }
   744     return 0;
   745 }
   746 
   747 int
   748 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   749 {
   750     SDL_VideoDisplay *display;
   751 
   752     CHECK_DISPLAY_INDEX(displayIndex, -1);
   753 
   754     display = &_this->displays[displayIndex];
   755     if (mode) {
   756         *mode = display->current_mode;
   757     }
   758     return 0;
   759 }
   760 
   761 static SDL_DisplayMode *
   762 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   763                                     const SDL_DisplayMode * mode,
   764                                     SDL_DisplayMode * closest)
   765 {
   766     Uint32 target_format;
   767     int target_refresh_rate;
   768     int i;
   769     SDL_DisplayMode *current, *match;
   770 
   771     if (!mode || !closest) {
   772         SDL_SetError("Missing desired mode or closest mode parameter");
   773         return NULL;
   774     }
   775 
   776     /* Default to the desktop format */
   777     if (mode->format) {
   778         target_format = mode->format;
   779     } else {
   780         target_format = display->desktop_mode.format;
   781     }
   782 
   783     /* Default to the desktop refresh rate */
   784     if (mode->refresh_rate) {
   785         target_refresh_rate = mode->refresh_rate;
   786     } else {
   787         target_refresh_rate = display->desktop_mode.refresh_rate;
   788     }
   789 
   790     match = NULL;
   791     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   792         current = &display->display_modes[i];
   793 
   794         if (current->w && (current->w < mode->w)) {
   795             /* Out of sorted modes large enough here */
   796             break;
   797         }
   798         if (current->h && (current->h < mode->h)) {
   799             if (current->w && (current->w == mode->w)) {
   800                 /* Out of sorted modes large enough here */
   801                 break;
   802             }
   803             /* Wider, but not tall enough, due to a different
   804                aspect ratio. This mode must be skipped, but closer
   805                modes may still follow. */
   806             continue;
   807         }
   808         if (!match || current->w < match->w || current->h < match->h) {
   809             match = current;
   810             continue;
   811         }
   812         if (current->format != match->format) {
   813             /* Sorted highest depth to lowest */
   814             if (current->format == target_format ||
   815                 (SDL_BITSPERPIXEL(current->format) >=
   816                  SDL_BITSPERPIXEL(target_format)
   817                  && SDL_PIXELTYPE(current->format) ==
   818                  SDL_PIXELTYPE(target_format))) {
   819                 match = current;
   820             }
   821             continue;
   822         }
   823         if (current->refresh_rate != match->refresh_rate) {
   824             /* Sorted highest refresh to lowest */
   825             if (current->refresh_rate >= target_refresh_rate) {
   826                 match = current;
   827             }
   828         }
   829     }
   830     if (match) {
   831         if (match->format) {
   832             closest->format = match->format;
   833         } else {
   834             closest->format = mode->format;
   835         }
   836         if (match->w && match->h) {
   837             closest->w = match->w;
   838             closest->h = match->h;
   839         } else {
   840             closest->w = mode->w;
   841             closest->h = mode->h;
   842         }
   843         if (match->refresh_rate) {
   844             closest->refresh_rate = match->refresh_rate;
   845         } else {
   846             closest->refresh_rate = mode->refresh_rate;
   847         }
   848         closest->driverdata = match->driverdata;
   849 
   850         /*
   851          * Pick some reasonable defaults if the app and driver don't
   852          * care
   853          */
   854         if (!closest->format) {
   855             closest->format = SDL_PIXELFORMAT_RGB888;
   856         }
   857         if (!closest->w) {
   858             closest->w = 640;
   859         }
   860         if (!closest->h) {
   861             closest->h = 480;
   862         }
   863         return closest;
   864     }
   865     return NULL;
   866 }
   867 
   868 SDL_DisplayMode *
   869 SDL_GetClosestDisplayMode(int displayIndex,
   870                           const SDL_DisplayMode * mode,
   871                           SDL_DisplayMode * closest)
   872 {
   873     SDL_VideoDisplay *display;
   874 
   875     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   876 
   877     display = &_this->displays[displayIndex];
   878     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
   879 }
   880 
   881 static int
   882 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   883 {
   884     SDL_DisplayMode display_mode;
   885     SDL_DisplayMode current_mode;
   886 
   887     if (mode) {
   888         display_mode = *mode;
   889 
   890         /* Default to the current mode */
   891         if (!display_mode.format) {
   892             display_mode.format = display->current_mode.format;
   893         }
   894         if (!display_mode.w) {
   895             display_mode.w = display->current_mode.w;
   896         }
   897         if (!display_mode.h) {
   898             display_mode.h = display->current_mode.h;
   899         }
   900         if (!display_mode.refresh_rate) {
   901             display_mode.refresh_rate = display->current_mode.refresh_rate;
   902         }
   903 
   904         /* Get a good video mode, the closest one possible */
   905         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   906             return SDL_SetError("No video mode large enough for %dx%d",
   907                                 display_mode.w, display_mode.h);
   908         }
   909     } else {
   910         display_mode = display->desktop_mode;
   911     }
   912 
   913     /* See if there's anything left to do */
   914     current_mode = display->current_mode;
   915     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   916         return 0;
   917     }
   918 
   919     /* Actually change the display mode */
   920     if (!_this->SetDisplayMode) {
   921         return SDL_SetError("Video driver doesn't support changing display mode");
   922     }
   923     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   924         return -1;
   925     }
   926     display->current_mode = display_mode;
   927     return 0;
   928 }
   929 
   930 int
   931 SDL_GetWindowDisplayIndex(SDL_Window * window)
   932 {
   933     int displayIndex;
   934     int i, dist;
   935     int closest = -1;
   936     int closest_dist = 0x7FFFFFFF;
   937     SDL_Point center;
   938     SDL_Point delta;
   939     SDL_Rect rect;
   940 
   941     CHECK_WINDOW_MAGIC(window, -1);
   942 
   943     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
   944         SDL_WINDOWPOS_ISCENTERED(window->x)) {
   945         displayIndex = (window->x & 0xFFFF);
   946         if (displayIndex >= _this->num_displays) {
   947             displayIndex = 0;
   948         }
   949         return displayIndex;
   950     }
   951     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
   952         SDL_WINDOWPOS_ISCENTERED(window->y)) {
   953         displayIndex = (window->y & 0xFFFF);
   954         if (displayIndex >= _this->num_displays) {
   955             displayIndex = 0;
   956         }
   957         return displayIndex;
   958     }
   959 
   960     /* Find the display containing the window */
   961     for (i = 0; i < _this->num_displays; ++i) {
   962         SDL_VideoDisplay *display = &_this->displays[i];
   963 
   964         if (display->fullscreen_window == window) {
   965             return i;
   966         }
   967     }
   968     center.x = window->x + window->w / 2;
   969     center.y = window->y + window->h / 2;
   970     for (i = 0; i < _this->num_displays; ++i) {
   971         SDL_GetDisplayBounds(i, &rect);
   972         if (SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   973             return i;
   974         }
   975 
   976         delta.x = center.x - (rect.x + rect.w / 2);
   977         delta.y = center.y - (rect.y + rect.h / 2);
   978         dist = (delta.x*delta.x + delta.y*delta.y);
   979         if (dist < closest_dist) {
   980             closest = i;
   981             closest_dist = dist;
   982         }
   983     }
   984     if (closest < 0) {
   985         SDL_SetError("Couldn't find any displays");
   986     }
   987     return closest;
   988 }
   989 
   990 SDL_VideoDisplay *
   991 SDL_GetDisplayForWindow(SDL_Window *window)
   992 {
   993     int displayIndex = SDL_GetWindowDisplayIndex(window);
   994     if (displayIndex >= 0) {
   995         return &_this->displays[displayIndex];
   996     } else {
   997         return NULL;
   998     }
   999 }
  1000 
  1001 int
  1002 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
  1003 {
  1004     CHECK_WINDOW_MAGIC(window, -1);
  1005 
  1006     if (mode) {
  1007         window->fullscreen_mode = *mode;
  1008     } else {
  1009         SDL_zero(window->fullscreen_mode);
  1010     }
  1011     return 0;
  1012 }
  1013 
  1014 int
  1015 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
  1016 {
  1017     SDL_DisplayMode fullscreen_mode;
  1018     SDL_VideoDisplay *display;
  1019 
  1020     if (!mode) {
  1021       return SDL_InvalidParamError("mode");
  1022     }
  1023 
  1024     CHECK_WINDOW_MAGIC(window, -1);
  1025 
  1026     fullscreen_mode = window->fullscreen_mode;
  1027     if (!fullscreen_mode.w) {
  1028         fullscreen_mode.w = window->w;
  1029     }
  1030     if (!fullscreen_mode.h) {
  1031         fullscreen_mode.h = window->h;
  1032     }
  1033 
  1034     display = SDL_GetDisplayForWindow(window);
  1035 
  1036     /* if in desktop size mode, just return the size of the desktop */
  1037     if ( ( window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) == SDL_WINDOW_FULLSCREEN_DESKTOP )
  1038     {
  1039         fullscreen_mode = display->desktop_mode;
  1040     }
  1041     else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
  1042                                              &fullscreen_mode,
  1043                                              &fullscreen_mode)) {
  1044         return SDL_SetError("Couldn't find display mode match");
  1045     }
  1046 
  1047     if (mode) {
  1048         *mode = fullscreen_mode;
  1049     }
  1050     return 0;
  1051 }
  1052 
  1053 Uint32
  1054 SDL_GetWindowPixelFormat(SDL_Window * window)
  1055 {
  1056     SDL_VideoDisplay *display;
  1057 
  1058     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1059 
  1060     display = SDL_GetDisplayForWindow(window);
  1061     return display->current_mode.format;
  1062 }
  1063 
  1064 static void
  1065 SDL_RestoreMousePosition(SDL_Window *window)
  1066 {
  1067     int x, y;
  1068 
  1069     if (window == SDL_GetMouseFocus()) {
  1070         SDL_GetMouseState(&x, &y);
  1071         SDL_WarpMouseInWindow(window, x, y);
  1072     }
  1073 }
  1074 
  1075 static void
  1076 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1077 {
  1078     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1079     SDL_Window *other;
  1080 
  1081     if (fullscreen) {
  1082         /* Hide any other fullscreen windows */
  1083         if (display->fullscreen_window &&
  1084             display->fullscreen_window != window) {
  1085             SDL_MinimizeWindow(display->fullscreen_window);
  1086         }
  1087     }
  1088 
  1089     /* See if anything needs to be done now */
  1090     if ((display->fullscreen_window == window) == fullscreen) {
  1091         return;
  1092     }
  1093 
  1094     /* See if there are any fullscreen windows */
  1095     for (other = _this->windows; other; other = other->next) {
  1096         SDL_bool setDisplayMode = SDL_FALSE;
  1097 
  1098         if (other == window) {
  1099             setDisplayMode = fullscreen;
  1100         } else if (FULLSCREEN_VISIBLE(other) &&
  1101                    SDL_GetDisplayForWindow(other) == display) {
  1102             setDisplayMode = SDL_TRUE;
  1103         }
  1104 
  1105         if (setDisplayMode) {
  1106             SDL_DisplayMode fullscreen_mode;
  1107 
  1108             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1109                 SDL_bool resized = SDL_TRUE;
  1110 
  1111                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1112                     resized = SDL_FALSE;
  1113                 }
  1114 
  1115                 /* only do the mode change if we want exclusive fullscreen */
  1116                 if ( ( window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) != SDL_WINDOW_FULLSCREEN_DESKTOP )
  1117                     SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1118                 else
  1119                     SDL_SetDisplayModeForDisplay(display, NULL);
  1120 
  1121 
  1122                 if (_this->SetWindowFullscreen) {
  1123                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1124                 }
  1125                 display->fullscreen_window = other;
  1126 
  1127                 /* Generate a mode change event here */
  1128                 if (resized) {
  1129                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1130                                         fullscreen_mode.w, fullscreen_mode.h);
  1131                 } else {
  1132                     SDL_OnWindowResized(other);
  1133                 }
  1134 
  1135                 SDL_RestoreMousePosition(other);
  1136                 return;
  1137             }
  1138         }
  1139     }
  1140 
  1141     /* Nope, restore the desktop mode */
  1142     SDL_SetDisplayModeForDisplay(display, NULL);
  1143 
  1144     if (_this->SetWindowFullscreen) {
  1145         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1146     }
  1147     display->fullscreen_window = NULL;
  1148 
  1149     /* Generate a mode change event here */
  1150     SDL_OnWindowResized(window);
  1151 
  1152     /* Restore the cursor position */
  1153     SDL_RestoreMousePosition(window);
  1154 }
  1155 
  1156 #define CREATE_FLAGS \
  1157     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE)
  1158 
  1159 static void
  1160 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1161 {
  1162     window->windowed.x = window->x;
  1163     window->windowed.y = window->y;
  1164     window->windowed.w = window->w;
  1165     window->windowed.h = window->h;
  1166 
  1167     if (flags & SDL_WINDOW_MAXIMIZED) {
  1168         SDL_MaximizeWindow(window);
  1169     }
  1170     if (flags & SDL_WINDOW_MINIMIZED) {
  1171         SDL_MinimizeWindow(window);
  1172     }
  1173     if (flags & SDL_WINDOW_FULLSCREEN) {
  1174         SDL_SetWindowFullscreen(window, flags);
  1175     }
  1176     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1177         SDL_SetWindowGrab(window, SDL_TRUE);
  1178     }
  1179     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1180         SDL_ShowWindow(window);
  1181     }
  1182 }
  1183 
  1184 SDL_Window *
  1185 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1186 {
  1187     SDL_Window *window;
  1188 
  1189     if (!_this) {
  1190         /* Initialize the video system if needed */
  1191         if (SDL_VideoInit(NULL) < 0) {
  1192             return NULL;
  1193         }
  1194     }
  1195 
  1196     /* Some platforms can't create zero-sized windows */
  1197     if (w < 1) {
  1198         w = 1;
  1199     }
  1200     if (h < 1) {
  1201         h = 1;
  1202     }
  1203 
  1204     /* Some platforms have OpenGL enabled by default */
  1205 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__
  1206     flags |= SDL_WINDOW_OPENGL;
  1207 #endif
  1208     if (flags & SDL_WINDOW_OPENGL) {
  1209         if (!_this->GL_CreateContext) {
  1210             SDL_SetError("No OpenGL support in video driver");
  1211             return NULL;
  1212         }
  1213         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1214             return NULL;
  1215         }
  1216     }
  1217     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1218     if (!window) {
  1219         SDL_OutOfMemory();
  1220         return NULL;
  1221     }
  1222     window->magic = &_this->window_magic;
  1223     window->id = _this->next_object_id++;
  1224     window->x = x;
  1225     window->y = y;
  1226     window->w = w;
  1227     window->h = h;
  1228     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1229         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1230         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1231         int displayIndex;
  1232         SDL_Rect bounds;
  1233 
  1234         displayIndex = SDL_GetIndexOfDisplay(display);
  1235         SDL_GetDisplayBounds(displayIndex, &bounds);
  1236         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1237             window->x = bounds.x + (bounds.w - w) / 2;
  1238         }
  1239         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1240             window->y = bounds.y + (bounds.h - h) / 2;
  1241         }
  1242     }
  1243     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1244     window->brightness = 1.0f;
  1245     window->next = _this->windows;
  1246     if (_this->windows) {
  1247         _this->windows->prev = window;
  1248     }
  1249     _this->windows = window;
  1250 
  1251     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1252         SDL_DestroyWindow(window);
  1253         return NULL;
  1254     }
  1255 
  1256     if (title) {
  1257         SDL_SetWindowTitle(window, title);
  1258     }
  1259     SDL_FinishWindowCreation(window, flags);
  1260 
  1261     /* If the window was created fullscreen, make sure the mode code matches */
  1262     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1263 
  1264     return window;
  1265 }
  1266 
  1267 SDL_Window *
  1268 SDL_CreateWindowFrom(const void *data)
  1269 {
  1270     SDL_Window *window;
  1271 
  1272     if (!_this) {
  1273         SDL_UninitializedVideo();
  1274         return NULL;
  1275     }
  1276     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1277     if (!window) {
  1278         SDL_OutOfMemory();
  1279         return NULL;
  1280     }
  1281     window->magic = &_this->window_magic;
  1282     window->id = _this->next_object_id++;
  1283     window->flags = SDL_WINDOW_FOREIGN;
  1284     window->brightness = 1.0f;
  1285     window->next = _this->windows;
  1286     if (_this->windows) {
  1287         _this->windows->prev = window;
  1288     }
  1289     _this->windows = window;
  1290 
  1291     if (!_this->CreateWindowFrom ||
  1292         _this->CreateWindowFrom(_this, window, data) < 0) {
  1293         SDL_DestroyWindow(window);
  1294         return NULL;
  1295     }
  1296     return window;
  1297 }
  1298 
  1299 int
  1300 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1301 {
  1302     char *title = window->title;
  1303 
  1304     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1305         return SDL_SetError("No OpenGL support in video driver");
  1306     }
  1307 
  1308     if (window->flags & SDL_WINDOW_FOREIGN) {
  1309         /* Can't destroy and re-create foreign windows, hrm */
  1310         flags |= SDL_WINDOW_FOREIGN;
  1311     } else {
  1312         flags &= ~SDL_WINDOW_FOREIGN;
  1313     }
  1314 
  1315     /* Restore video mode, etc. */
  1316     SDL_HideWindow(window);
  1317 
  1318     /* Tear down the old native window */
  1319     if (window->surface) {
  1320         window->surface->flags &= ~SDL_DONTFREE;
  1321         SDL_FreeSurface(window->surface);
  1322     }
  1323     if (_this->DestroyWindowFramebuffer) {
  1324         _this->DestroyWindowFramebuffer(_this, window);
  1325     }
  1326     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1327         _this->DestroyWindow(_this, window);
  1328     }
  1329 
  1330     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1331         if (flags & SDL_WINDOW_OPENGL) {
  1332             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1333                 return -1;
  1334             }
  1335         } else {
  1336             SDL_GL_UnloadLibrary();
  1337         }
  1338     }
  1339 
  1340     window->title = NULL;
  1341     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1342 
  1343     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1344         if (_this->CreateWindow(_this, window) < 0) {
  1345             if (flags & SDL_WINDOW_OPENGL) {
  1346                 SDL_GL_UnloadLibrary();
  1347             }
  1348             return -1;
  1349         }
  1350     }
  1351 
  1352     if (title) {
  1353         SDL_SetWindowTitle(window, title);
  1354         SDL_free(title);
  1355     }
  1356     SDL_FinishWindowCreation(window, flags);
  1357 
  1358     return 0;
  1359 }
  1360 
  1361 Uint32
  1362 SDL_GetWindowID(SDL_Window * window)
  1363 {
  1364     CHECK_WINDOW_MAGIC(window, 0);
  1365 
  1366     return window->id;
  1367 }
  1368 
  1369 SDL_Window *
  1370 SDL_GetWindowFromID(Uint32 id)
  1371 {
  1372     SDL_Window *window;
  1373 
  1374     if (!_this) {
  1375         return NULL;
  1376     }
  1377     for (window = _this->windows; window; window = window->next) {
  1378         if (window->id == id) {
  1379             return window;
  1380         }
  1381     }
  1382     return NULL;
  1383 }
  1384 
  1385 Uint32
  1386 SDL_GetWindowFlags(SDL_Window * window)
  1387 {
  1388     CHECK_WINDOW_MAGIC(window, 0);
  1389 
  1390     return window->flags;
  1391 }
  1392 
  1393 void
  1394 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1395 {
  1396     CHECK_WINDOW_MAGIC(window, );
  1397 
  1398     if (title == window->title) {
  1399         return;
  1400     }
  1401     if (window->title) {
  1402         SDL_free(window->title);
  1403     }
  1404     if (title && *title) {
  1405         window->title = SDL_strdup(title);
  1406     } else {
  1407         window->title = NULL;
  1408     }
  1409 
  1410     if (_this->SetWindowTitle) {
  1411         _this->SetWindowTitle(_this, window);
  1412     }
  1413 }
  1414 
  1415 const char *
  1416 SDL_GetWindowTitle(SDL_Window * window)
  1417 {
  1418     CHECK_WINDOW_MAGIC(window, "");
  1419 
  1420     return window->title ? window->title : "";
  1421 }
  1422 
  1423 void
  1424 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1425 {
  1426     CHECK_WINDOW_MAGIC(window, );
  1427 
  1428     if (!icon) {
  1429         return;
  1430     }
  1431 
  1432     if (_this->SetWindowIcon) {
  1433         _this->SetWindowIcon(_this, window, icon);
  1434     }
  1435 }
  1436 
  1437 void*
  1438 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1439 {
  1440     SDL_WindowUserData *prev, *data;
  1441 
  1442     CHECK_WINDOW_MAGIC(window, NULL);
  1443 
  1444     /* Input validation */
  1445     if (name == NULL || SDL_strlen(name) == 0) {
  1446       SDL_InvalidParamError("name");
  1447       return NULL;
  1448     }
  1449 
  1450     /* See if the named data already exists */
  1451     prev = NULL;
  1452     for (data = window->data; data; prev = data, data = data->next) {
  1453         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1454             void *last_value = data->data;
  1455 
  1456             if (userdata) {
  1457                 /* Set the new value */
  1458                 data->data = userdata;
  1459             } else {
  1460                 /* Delete this value */
  1461                 if (prev) {
  1462                     prev->next = data->next;
  1463                 } else {
  1464                     window->data = data->next;
  1465                 }
  1466                 SDL_free(data->name);
  1467                 SDL_free(data);
  1468             }
  1469             return last_value;
  1470         }
  1471     }
  1472 
  1473     /* Add new data to the window */
  1474     if (userdata) {
  1475         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1476         data->name = SDL_strdup(name);
  1477         data->data = userdata;
  1478         data->next = window->data;
  1479         window->data = data;
  1480     }
  1481     return NULL;
  1482 }
  1483 
  1484 void *
  1485 SDL_GetWindowData(SDL_Window * window, const char *name)
  1486 {
  1487     SDL_WindowUserData *data;
  1488 
  1489     CHECK_WINDOW_MAGIC(window, NULL);
  1490 
  1491     /* Input validation */
  1492     if (name == NULL || SDL_strlen(name) == 0) {
  1493       SDL_InvalidParamError("name");
  1494       return NULL;
  1495     }
  1496 
  1497     for (data = window->data; data; data = data->next) {
  1498         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1499             return data->data;
  1500         }
  1501     }
  1502     return NULL;
  1503 }
  1504 
  1505 void
  1506 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1507 {
  1508     CHECK_WINDOW_MAGIC(window, );
  1509 
  1510     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1511         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1512         int displayIndex;
  1513         SDL_Rect bounds;
  1514 
  1515         displayIndex = SDL_GetIndexOfDisplay(display);
  1516         SDL_GetDisplayBounds(displayIndex, &bounds);
  1517         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1518             x = bounds.x + (bounds.w - window->w) / 2;
  1519         }
  1520         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1521             y = bounds.y + (bounds.h - window->h) / 2;
  1522         }
  1523     }
  1524 
  1525     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1526         window->x = x;
  1527     }
  1528     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1529         window->y = y;
  1530     }
  1531 
  1532     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1533         if (_this->SetWindowPosition) {
  1534             _this->SetWindowPosition(_this, window);
  1535         }
  1536         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1537     }
  1538 }
  1539 
  1540 void
  1541 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1542 {
  1543     CHECK_WINDOW_MAGIC(window, );
  1544 
  1545     /* Fullscreen windows are always at their display's origin */
  1546     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1547         if (x) {
  1548             *x = 0;
  1549         }
  1550         if (y) {
  1551             *y = 0;
  1552         }
  1553     } else {
  1554         if (x) {
  1555             *x = window->x;
  1556         }
  1557         if (y) {
  1558             *y = window->y;
  1559         }
  1560     }
  1561 }
  1562 
  1563 void
  1564 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1565 {
  1566     CHECK_WINDOW_MAGIC(window, );
  1567     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1568         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1569         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1570         if ((want != have) && (_this->SetWindowBordered)) {
  1571             if (want) {
  1572                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1573             } else {
  1574                 window->flags |= SDL_WINDOW_BORDERLESS;
  1575             }
  1576             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1577         }
  1578     }
  1579 }
  1580 
  1581 void
  1582 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1583 {
  1584     CHECK_WINDOW_MAGIC(window, );
  1585     if (w <= 0) {
  1586         SDL_InvalidParamError("w");
  1587         return;
  1588     }
  1589     if (h <= 0) {
  1590         SDL_InvalidParamError("h");
  1591         return;
  1592     }
  1593 
  1594     /* FIXME: Should this change fullscreen modes? */
  1595     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1596         window->w = w;
  1597         window->h = h;
  1598         if (_this->SetWindowSize) {
  1599             _this->SetWindowSize(_this, window);
  1600         }
  1601         if (window->w == w && window->h == h) {
  1602             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1603             SDL_OnWindowResized(window);
  1604         }
  1605     }
  1606 }
  1607 
  1608 void
  1609 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1610 {
  1611     CHECK_WINDOW_MAGIC(window, );
  1612     if (w) {
  1613         *w = window->w;
  1614     }
  1615     if (h) {
  1616         *h = window->h;
  1617     }
  1618 }
  1619 
  1620 void
  1621 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1622 {
  1623     CHECK_WINDOW_MAGIC(window, );
  1624     if (min_w <= 0) {
  1625         SDL_InvalidParamError("min_w");
  1626         return;
  1627     }
  1628     if (min_h <= 0) {
  1629         SDL_InvalidParamError("min_h");
  1630         return;
  1631     }
  1632 
  1633     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1634         window->min_w = min_w;
  1635         window->min_h = min_h;
  1636         if (_this->SetWindowMinimumSize) {
  1637             _this->SetWindowMinimumSize(_this, window);
  1638         }
  1639         /* Ensure that window is not smaller than minimal size */
  1640         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1641     }
  1642 }
  1643 
  1644 void
  1645 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1646 {
  1647     CHECK_WINDOW_MAGIC(window, );
  1648     if (min_w) {
  1649         *min_w = window->min_w;
  1650     }
  1651     if (min_h) {
  1652         *min_h = window->min_h;
  1653     }
  1654 }
  1655 
  1656 void
  1657 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1658 {
  1659     CHECK_WINDOW_MAGIC(window, );
  1660     if (max_w <= 0) {
  1661         SDL_InvalidParamError("max_w");
  1662         return;
  1663     }
  1664     if (max_h <= 0) {
  1665         SDL_InvalidParamError("max_h");
  1666         return;
  1667     }
  1668 
  1669     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1670         window->max_w = max_w;
  1671         window->max_h = max_h;
  1672         if (_this->SetWindowMaximumSize) {
  1673             _this->SetWindowMaximumSize(_this, window);
  1674         }
  1675         /* Ensure that window is not larger than maximal size */
  1676         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1677     }
  1678 }
  1679 
  1680 void
  1681 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1682 {
  1683     CHECK_WINDOW_MAGIC(window, );
  1684     if (max_w) {
  1685         *max_w = window->max_w;
  1686     }
  1687     if (max_h) {
  1688         *max_h = window->max_h;
  1689     }
  1690 }
  1691 
  1692 void
  1693 SDL_ShowWindow(SDL_Window * window)
  1694 {
  1695     CHECK_WINDOW_MAGIC(window, );
  1696 
  1697     if (window->flags & SDL_WINDOW_SHOWN) {
  1698         return;
  1699     }
  1700 
  1701     if (_this->ShowWindow) {
  1702         _this->ShowWindow(_this, window);
  1703     }
  1704     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1705 }
  1706 
  1707 void
  1708 SDL_HideWindow(SDL_Window * window)
  1709 {
  1710     CHECK_WINDOW_MAGIC(window, );
  1711 
  1712     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1713         return;
  1714     }
  1715 
  1716     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1717 
  1718     if (_this->HideWindow) {
  1719         _this->HideWindow(_this, window);
  1720     }
  1721     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1722 }
  1723 
  1724 void
  1725 SDL_RaiseWindow(SDL_Window * window)
  1726 {
  1727     CHECK_WINDOW_MAGIC(window, );
  1728 
  1729     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1730         return;
  1731     }
  1732     if (_this->RaiseWindow) {
  1733         _this->RaiseWindow(_this, window);
  1734     }
  1735 }
  1736 
  1737 void
  1738 SDL_MaximizeWindow(SDL_Window * window)
  1739 {
  1740     CHECK_WINDOW_MAGIC(window, );
  1741 
  1742     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1743         return;
  1744     }
  1745 
  1746     if (_this->MaximizeWindow) {
  1747         _this->MaximizeWindow(_this, window);
  1748     }
  1749 }
  1750 
  1751 void
  1752 SDL_MinimizeWindow(SDL_Window * window)
  1753 {
  1754     CHECK_WINDOW_MAGIC(window, );
  1755 
  1756     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1757         return;
  1758     }
  1759 
  1760     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1761 
  1762     if (_this->MinimizeWindow) {
  1763         _this->MinimizeWindow(_this, window);
  1764     }
  1765 }
  1766 
  1767 void
  1768 SDL_RestoreWindow(SDL_Window * window)
  1769 {
  1770     CHECK_WINDOW_MAGIC(window, );
  1771 
  1772     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1773         return;
  1774     }
  1775 
  1776     if (_this->RestoreWindow) {
  1777         _this->RestoreWindow(_this, window);
  1778     }
  1779 }
  1780 
  1781 #define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN )
  1782 int
  1783 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1784 {
  1785     CHECK_WINDOW_MAGIC(window, -1);
  1786 
  1787     flags &= FULLSCREEN_MASK;
  1788 
  1789     if ( flags == (window->flags & FULLSCREEN_MASK) ) {
  1790         return 0;
  1791     }
  1792 
  1793     /* clear the previous flags and OR in the new ones */
  1794     window->flags &= ~FULLSCREEN_MASK;
  1795     window->flags |= flags;
  1796 
  1797     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1798 
  1799     return 0;
  1800 }
  1801 
  1802 static SDL_Surface *
  1803 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1804 {
  1805     Uint32 format;
  1806     void *pixels;
  1807     int pitch;
  1808     int bpp;
  1809     Uint32 Rmask, Gmask, Bmask, Amask;
  1810 
  1811     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1812         return NULL;
  1813     }
  1814 
  1815     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1816         return NULL;
  1817     }
  1818 
  1819     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1820         return NULL;
  1821     }
  1822 
  1823     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1824 }
  1825 
  1826 SDL_Surface *
  1827 SDL_GetWindowSurface(SDL_Window * window)
  1828 {
  1829     CHECK_WINDOW_MAGIC(window, NULL);
  1830 
  1831     if (!window->surface_valid) {
  1832         if (window->surface) {
  1833             window->surface->flags &= ~SDL_DONTFREE;
  1834             SDL_FreeSurface(window->surface);
  1835         }
  1836         window->surface = SDL_CreateWindowFramebuffer(window);
  1837         if (window->surface) {
  1838             window->surface_valid = SDL_TRUE;
  1839             window->surface->flags |= SDL_DONTFREE;
  1840         }
  1841     }
  1842     return window->surface;
  1843 }
  1844 
  1845 int
  1846 SDL_UpdateWindowSurface(SDL_Window * window)
  1847 {
  1848     SDL_Rect full_rect;
  1849 
  1850     CHECK_WINDOW_MAGIC(window, -1);
  1851 
  1852     full_rect.x = 0;
  1853     full_rect.y = 0;
  1854     full_rect.w = window->w;
  1855     full_rect.h = window->h;
  1856     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1857 }
  1858 
  1859 int
  1860 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  1861                              int numrects)
  1862 {
  1863     CHECK_WINDOW_MAGIC(window, -1);
  1864 
  1865     if (!window->surface_valid) {
  1866         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1867     }
  1868 
  1869     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1870 }
  1871 
  1872 int
  1873 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  1874 {
  1875     Uint16 ramp[256];
  1876     int status;
  1877 
  1878     CHECK_WINDOW_MAGIC(window, -1);
  1879 
  1880     SDL_CalculateGammaRamp(brightness, ramp);
  1881     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  1882     if (status == 0) {
  1883         window->brightness = brightness;
  1884     }
  1885     return status;
  1886 }
  1887 
  1888 float
  1889 SDL_GetWindowBrightness(SDL_Window * window)
  1890 {
  1891     CHECK_WINDOW_MAGIC(window, 1.0f);
  1892 
  1893     return window->brightness;
  1894 }
  1895 
  1896 int
  1897 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  1898                                             const Uint16 * green,
  1899                                             const Uint16 * blue)
  1900 {
  1901     CHECK_WINDOW_MAGIC(window, -1);
  1902 
  1903     if (!_this->SetWindowGammaRamp) {
  1904         return SDL_Unsupported();
  1905     }
  1906 
  1907     if (!window->gamma) {
  1908         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  1909             return -1;
  1910         }
  1911     }
  1912 
  1913     if (red) {
  1914         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  1915     }
  1916     if (green) {
  1917         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  1918     }
  1919     if (blue) {
  1920         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  1921     }
  1922     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1923         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  1924     } else {
  1925         return 0;
  1926     }
  1927 }
  1928 
  1929 int
  1930 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  1931                                             Uint16 * green,
  1932                                             Uint16 * blue)
  1933 {
  1934     CHECK_WINDOW_MAGIC(window, -1);
  1935 
  1936     if (!window->gamma) {
  1937         int i;
  1938 
  1939         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  1940         if (!window->gamma) {
  1941             return SDL_OutOfMemory();
  1942         }
  1943         window->saved_gamma = window->gamma + 3*256;
  1944 
  1945         if (_this->GetWindowGammaRamp) {
  1946             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  1947                 return -1;
  1948             }
  1949         } else {
  1950             /* Create an identity gamma ramp */
  1951             for (i = 0; i < 256; ++i) {
  1952                 Uint16 value = (Uint16)((i << 8) | i);
  1953 
  1954                 window->gamma[0*256+i] = value;
  1955                 window->gamma[1*256+i] = value;
  1956                 window->gamma[2*256+i] = value;
  1957             }
  1958         }
  1959         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  1960     }
  1961 
  1962     if (red) {
  1963         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  1964     }
  1965     if (green) {
  1966         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  1967     }
  1968     if (blue) {
  1969         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  1970     }
  1971     return 0;
  1972 }
  1973 
  1974 void
  1975 SDL_UpdateWindowGrab(SDL_Window * window)
  1976 {
  1977     if (_this->SetWindowGrab) {
  1978         SDL_bool grabbed;
  1979         if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
  1980             (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1981             grabbed = SDL_TRUE;
  1982         } else {
  1983             grabbed = SDL_FALSE;
  1984         }
  1985         _this->SetWindowGrab(_this, window, grabbed);
  1986     }
  1987 }
  1988 
  1989 void
  1990 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  1991 {
  1992     CHECK_WINDOW_MAGIC(window, );
  1993 
  1994     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  1995         return;
  1996     }
  1997     if (grabbed) {
  1998         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1999     } else {
  2000         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2001     }
  2002     SDL_UpdateWindowGrab(window);
  2003 }
  2004 
  2005 SDL_bool
  2006 SDL_GetWindowGrab(SDL_Window * window)
  2007 {
  2008     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2009 
  2010     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  2011 }
  2012 
  2013 void
  2014 SDL_OnWindowShown(SDL_Window * window)
  2015 {
  2016     SDL_OnWindowRestored(window);
  2017 }
  2018 
  2019 void
  2020 SDL_OnWindowHidden(SDL_Window * window)
  2021 {
  2022     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2023 }
  2024 
  2025 void
  2026 SDL_OnWindowResized(SDL_Window * window)
  2027 {
  2028     window->surface_valid = SDL_FALSE;
  2029     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2030 }
  2031 
  2032 void
  2033 SDL_OnWindowMinimized(SDL_Window * window)
  2034 {
  2035     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2036 }
  2037 
  2038 void
  2039 SDL_OnWindowRestored(SDL_Window * window)
  2040 {
  2041     SDL_RaiseWindow(window);
  2042 
  2043     if (FULLSCREEN_VISIBLE(window)) {
  2044         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2045     }
  2046 }
  2047 
  2048 void
  2049 SDL_OnWindowEnter(SDL_Window * window)
  2050 {
  2051     if (_this->OnWindowEnter) {
  2052         _this->OnWindowEnter(_this, window);
  2053     }
  2054 }
  2055 
  2056 void
  2057 SDL_OnWindowLeave(SDL_Window * window)
  2058 {
  2059 }
  2060 
  2061 void
  2062 SDL_OnWindowFocusGained(SDL_Window * window)
  2063 {
  2064     SDL_Mouse *mouse = SDL_GetMouse();
  2065 
  2066     if (window->gamma && _this->SetWindowGammaRamp) {
  2067         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2068     }
  2069 
  2070     if (mouse && mouse->relative_mode) {
  2071         SDL_SetMouseFocus(window);
  2072         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2073     }
  2074 
  2075     SDL_UpdateWindowGrab(window);
  2076 }
  2077 
  2078 static SDL_bool ShouldMinimizeOnFocusLoss()
  2079 {
  2080     const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2081     if (hint) {
  2082         if (*hint == '0') {
  2083             return SDL_FALSE;
  2084         } else {
  2085             return SDL_TRUE;
  2086         }
  2087     }
  2088     return SDL_TRUE;
  2089 }
  2090 
  2091 void
  2092 SDL_OnWindowFocusLost(SDL_Window * window)
  2093 {
  2094     if (window->gamma && _this->SetWindowGammaRamp) {
  2095         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2096     }
  2097 
  2098     SDL_UpdateWindowGrab(window);
  2099 
  2100     /* If we're fullscreen and lose focus, minimize unless the hint tells us otherwise */
  2101      if ((window->flags & SDL_WINDOW_FULLSCREEN) && ShouldMinimizeOnFocusLoss() ) {
  2102             SDL_MinimizeWindow(window);
  2103     }
  2104 }
  2105 
  2106 SDL_Window *
  2107 SDL_GetFocusWindow(void)
  2108 {
  2109     SDL_Window *window;
  2110 
  2111     if (!_this) {
  2112         return NULL;
  2113     }
  2114     for (window = _this->windows; window; window = window->next) {
  2115         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2116             return window;
  2117         }
  2118     }
  2119     return NULL;
  2120 }
  2121 
  2122 void
  2123 SDL_DestroyWindow(SDL_Window * window)
  2124 {
  2125     SDL_VideoDisplay *display;
  2126 
  2127     CHECK_WINDOW_MAGIC(window, );
  2128 
  2129     /* Restore video mode, etc. */
  2130     SDL_HideWindow(window);
  2131 
  2132     /* Make sure this window no longer has focus */
  2133     if (SDL_GetKeyboardFocus() == window) {
  2134         SDL_SetKeyboardFocus(NULL);
  2135     }
  2136     if (SDL_GetMouseFocus() == window) {
  2137         SDL_SetMouseFocus(NULL);
  2138     }
  2139 
  2140     /* make no context current if this is the current context window. */
  2141     if (window->flags & SDL_WINDOW_OPENGL) {
  2142         if (_this->current_glwin == window) {
  2143             SDL_GL_MakeCurrent(window, NULL);
  2144         }
  2145     }
  2146 
  2147     if (window->surface) {
  2148         window->surface->flags &= ~SDL_DONTFREE;
  2149         SDL_FreeSurface(window->surface);
  2150     }
  2151     if (_this->DestroyWindowFramebuffer) {
  2152         _this->DestroyWindowFramebuffer(_this, window);
  2153     }
  2154     if (_this->DestroyWindow) {
  2155         _this->DestroyWindow(_this, window);
  2156     }
  2157     if (window->flags & SDL_WINDOW_OPENGL) {
  2158         SDL_GL_UnloadLibrary();
  2159     }
  2160 
  2161     display = SDL_GetDisplayForWindow(window);
  2162     if (display->fullscreen_window == window) {
  2163         display->fullscreen_window = NULL;
  2164     }
  2165 
  2166     /* Now invalidate magic */
  2167     window->magic = NULL;
  2168 
  2169     /* Free memory associated with the window */
  2170     if (window->title) {
  2171         SDL_free(window->title);
  2172     }
  2173     if (window->gamma) {
  2174         SDL_free(window->gamma);
  2175     }
  2176     while (window->data) {
  2177         SDL_WindowUserData *data = window->data;
  2178 
  2179         window->data = data->next;
  2180         SDL_free(data->name);
  2181         SDL_free(data);
  2182     }
  2183 
  2184     /* Unlink the window from the list */
  2185     if (window->next) {
  2186         window->next->prev = window->prev;
  2187     }
  2188     if (window->prev) {
  2189         window->prev->next = window->next;
  2190     } else {
  2191         _this->windows = window->next;
  2192     }
  2193 
  2194     SDL_free(window);
  2195 }
  2196 
  2197 SDL_bool
  2198 SDL_IsScreenSaverEnabled()
  2199 {
  2200     if (!_this) {
  2201         return SDL_TRUE;
  2202     }
  2203     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2204 }
  2205 
  2206 void
  2207 SDL_EnableScreenSaver()
  2208 {
  2209     if (!_this) {
  2210         return;
  2211     }
  2212     if (!_this->suspend_screensaver) {
  2213         return;
  2214     }
  2215     _this->suspend_screensaver = SDL_FALSE;
  2216     if (_this->SuspendScreenSaver) {
  2217         _this->SuspendScreenSaver(_this);
  2218     }
  2219 }
  2220 
  2221 void
  2222 SDL_DisableScreenSaver()
  2223 {
  2224     if (!_this) {
  2225         return;
  2226     }
  2227     if (_this->suspend_screensaver) {
  2228         return;
  2229     }
  2230     _this->suspend_screensaver = SDL_TRUE;
  2231     if (_this->SuspendScreenSaver) {
  2232         _this->SuspendScreenSaver(_this);
  2233     }
  2234 }
  2235 
  2236 void
  2237 SDL_VideoQuit(void)
  2238 {
  2239     int i, j;
  2240 
  2241     if (!_this) {
  2242         return;
  2243     }
  2244 
  2245     /* Halt event processing before doing anything else */
  2246     SDL_TouchQuit();
  2247     SDL_MouseQuit();
  2248     SDL_KeyboardQuit();
  2249     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2250 
  2251     SDL_EnableScreenSaver();
  2252 
  2253     /* Clean up the system video */
  2254     while (_this->windows) {
  2255         SDL_DestroyWindow(_this->windows);
  2256     }
  2257     _this->VideoQuit(_this);
  2258 
  2259     for (i = _this->num_displays; i--;) {
  2260         SDL_VideoDisplay *display = &_this->displays[i];
  2261         for (j = display->num_display_modes; j--;) {
  2262             if (display->display_modes[j].driverdata) {
  2263                 SDL_free(display->display_modes[j].driverdata);
  2264                 display->display_modes[j].driverdata = NULL;
  2265             }
  2266         }
  2267         if (display->display_modes) {
  2268             SDL_free(display->display_modes);
  2269             display->display_modes = NULL;
  2270         }
  2271         if (display->desktop_mode.driverdata) {
  2272             SDL_free(display->desktop_mode.driverdata);
  2273             display->desktop_mode.driverdata = NULL;
  2274         }
  2275         if (display->driverdata) {
  2276             SDL_free(display->driverdata);
  2277             display->driverdata = NULL;
  2278         }
  2279     }
  2280     if (_this->displays) {
  2281         for (i = 0; i < _this->num_displays; ++i) {
  2282             SDL_free(_this->displays[i].name);
  2283         }
  2284         SDL_free(_this->displays);
  2285         _this->displays = NULL;
  2286         _this->num_displays = 0;
  2287     }
  2288     if (_this->clipboard_text) {
  2289         SDL_free(_this->clipboard_text);
  2290         _this->clipboard_text = NULL;
  2291     }
  2292     _this->free(_this);
  2293     _this = NULL;
  2294 }
  2295 
  2296 int
  2297 SDL_GL_LoadLibrary(const char *path)
  2298 {
  2299     int retval;
  2300 
  2301     if (!_this) {
  2302         return SDL_UninitializedVideo();
  2303     }
  2304     if (_this->gl_config.driver_loaded) {
  2305         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2306             return SDL_SetError("OpenGL library already loaded");
  2307         }
  2308         retval = 0;
  2309     } else {
  2310         if (!_this->GL_LoadLibrary) {
  2311             return  SDL_SetError("No dynamic GL support in video driver");
  2312         }
  2313         retval = _this->GL_LoadLibrary(_this, path);
  2314     }
  2315     if (retval == 0) {
  2316         ++_this->gl_config.driver_loaded;
  2317     }
  2318     return (retval);
  2319 }
  2320 
  2321 void *
  2322 SDL_GL_GetProcAddress(const char *proc)
  2323 {
  2324     void *func;
  2325 
  2326     if (!_this) {
  2327         SDL_UninitializedVideo();
  2328         return NULL;
  2329     }
  2330     func = NULL;
  2331     if (_this->GL_GetProcAddress) {
  2332         if (_this->gl_config.driver_loaded) {
  2333             func = _this->GL_GetProcAddress(_this, proc);
  2334         } else {
  2335             SDL_SetError("No GL driver has been loaded");
  2336         }
  2337     } else {
  2338         SDL_SetError("No dynamic GL support in video driver");
  2339     }
  2340     return func;
  2341 }
  2342 
  2343 void
  2344 SDL_GL_UnloadLibrary(void)
  2345 {
  2346     if (!_this) {
  2347         SDL_UninitializedVideo();
  2348         return;
  2349     }
  2350     if (_this->gl_config.driver_loaded > 0) {
  2351         if (--_this->gl_config.driver_loaded > 0) {
  2352             return;
  2353         }
  2354         if (_this->GL_UnloadLibrary) {
  2355             _this->GL_UnloadLibrary(_this);
  2356         }
  2357     }
  2358 }
  2359 
  2360 static __inline__ SDL_bool
  2361 isAtLeastGL3(const char *verstr)
  2362 {
  2363     return ( verstr && (SDL_atoi(verstr) >= 3) );
  2364 }
  2365 
  2366 SDL_bool
  2367 SDL_GL_ExtensionSupported(const char *extension)
  2368 {
  2369 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2370     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2371     const char *extensions;
  2372     const char *start;
  2373     const char *where, *terminator;
  2374 
  2375     /* Extension names should not have spaces. */
  2376     where = SDL_strchr(extension, ' ');
  2377     if (where || *extension == '\0') {
  2378         return SDL_FALSE;
  2379     }
  2380     /* See if there's an environment variable override */
  2381     start = SDL_getenv(extension);
  2382     if (start && *start == '0') {
  2383         return SDL_FALSE;
  2384     }
  2385 
  2386     /* Lookup the available extensions */
  2387 
  2388     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2389     if (!glGetStringFunc) {
  2390         return SDL_FALSE;
  2391     }
  2392 
  2393     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2394         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2395         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2396         GLint num_exts = 0;
  2397         GLint i;
  2398 
  2399         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2400         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2401         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2402             return SDL_FALSE;
  2403         }
  2404 
  2405         #ifndef GL_NUM_EXTENSIONS
  2406         #define GL_NUM_EXTENSIONS 0x821D
  2407         #endif
  2408         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2409         for (i = 0; i < num_exts; i++) {
  2410             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2411             if (SDL_strcmp(thisext, extension) == 0) {
  2412                 return SDL_TRUE;
  2413             }
  2414         }
  2415 
  2416         return SDL_FALSE;
  2417     }
  2418 
  2419     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2420 
  2421     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2422     if (!extensions) {
  2423         return SDL_FALSE;
  2424     }
  2425     /*
  2426      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2427      * extensions string. Don't be fooled by sub-strings, etc.
  2428      */
  2429 
  2430     start = extensions;
  2431 
  2432     for (;;) {
  2433         where = SDL_strstr(start, extension);
  2434         if (!where)
  2435             break;
  2436 
  2437         terminator = where + SDL_strlen(extension);
  2438         if (where == start || *(where - 1) == ' ')
  2439             if (*terminator == ' ' || *terminator == '\0')
  2440                 return SDL_TRUE;
  2441 
  2442         start = terminator;
  2443     }
  2444     return SDL_FALSE;
  2445 #else
  2446     return SDL_FALSE;
  2447 #endif
  2448 }
  2449 
  2450 int
  2451 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2452 {
  2453 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2454     int retval;
  2455 
  2456     if (!_this) {
  2457         return SDL_UninitializedVideo();
  2458     }
  2459     retval = 0;
  2460     switch (attr) {
  2461     case SDL_GL_RED_SIZE:
  2462         _this->gl_config.red_size = value;
  2463         break;
  2464     case SDL_GL_GREEN_SIZE:
  2465         _this->gl_config.green_size = value;
  2466         break;
  2467     case SDL_GL_BLUE_SIZE:
  2468         _this->gl_config.blue_size = value;
  2469         break;
  2470     case SDL_GL_ALPHA_SIZE:
  2471         _this->gl_config.alpha_size = value;
  2472         break;
  2473     case SDL_GL_DOUBLEBUFFER:
  2474         _this->gl_config.double_buffer = value;
  2475         break;
  2476     case SDL_GL_BUFFER_SIZE:
  2477         _this->gl_config.buffer_size = value;
  2478         break;
  2479     case SDL_GL_DEPTH_SIZE:
  2480         _this->gl_config.depth_size = value;
  2481         break;
  2482     case SDL_GL_STENCIL_SIZE:
  2483         _this->gl_config.stencil_size = value;
  2484         break;
  2485     case SDL_GL_ACCUM_RED_SIZE:
  2486         _this->gl_config.accum_red_size = value;
  2487         break;
  2488     case SDL_GL_ACCUM_GREEN_SIZE:
  2489         _this->gl_config.accum_green_size = value;
  2490         break;
  2491     case SDL_GL_ACCUM_BLUE_SIZE:
  2492         _this->gl_config.accum_blue_size = value;
  2493         break;
  2494     case SDL_GL_ACCUM_ALPHA_SIZE:
  2495         _this->gl_config.accum_alpha_size = value;
  2496         break;
  2497     case SDL_GL_STEREO:
  2498         _this->gl_config.stereo = value;
  2499         break;
  2500     case SDL_GL_MULTISAMPLEBUFFERS:
  2501         _this->gl_config.multisamplebuffers = value;
  2502         break;
  2503     case SDL_GL_MULTISAMPLESAMPLES:
  2504         _this->gl_config.multisamplesamples = value;
  2505         break;
  2506     case SDL_GL_ACCELERATED_VISUAL:
  2507         _this->gl_config.accelerated = value;
  2508         break;
  2509     case SDL_GL_RETAINED_BACKING:
  2510         _this->gl_config.retained_backing = value;
  2511         break;
  2512     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2513         _this->gl_config.major_version = value;
  2514         break;
  2515     case SDL_GL_CONTEXT_MINOR_VERSION:
  2516         _this->gl_config.minor_version = value;
  2517         break;
  2518     case SDL_GL_CONTEXT_EGL:
  2519         _this->gl_config.use_egl = value;
  2520         break;
  2521     case SDL_GL_CONTEXT_FLAGS:
  2522         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2523               SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2524               SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2525               SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2526         retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2527         break;
  2528     }
  2529         _this->gl_config.flags = value;
  2530         break;
  2531     case SDL_GL_CONTEXT_PROFILE_MASK:
  2532         if( value != 0 &&
  2533         value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2534         value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2535         value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2536         retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2537         break;
  2538     }
  2539         _this->gl_config.profile_mask = value;
  2540         break;
  2541     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2542         _this->gl_config.share_with_current_context = value;
  2543     break;
  2544     default:
  2545         retval = SDL_SetError("Unknown OpenGL attribute");
  2546         break;
  2547     }
  2548     return retval;
  2549 #else
  2550     return SDL_Unsupported();
  2551 #endif /* SDL_VIDEO_OPENGL */
  2552 }
  2553 
  2554 int
  2555 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2556 {
  2557 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2558     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2559     GLenum(APIENTRY * glGetErrorFunc) (void);
  2560     GLenum attrib = 0;
  2561     GLenum error = 0;
  2562 
  2563     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2564     if (!glGetIntegervFunc) {
  2565         return -1;
  2566     }
  2567 
  2568     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2569     if (!glGetErrorFunc) {
  2570         return -1;
  2571     }
  2572 
  2573     /* Clear value in any case */
  2574     *value = 0;
  2575 
  2576     switch (attr) {
  2577     case SDL_GL_RED_SIZE:
  2578         attrib = GL_RED_BITS;
  2579         break;
  2580     case SDL_GL_BLUE_SIZE:
  2581         attrib = GL_BLUE_BITS;
  2582         break;
  2583     case SDL_GL_GREEN_SIZE:
  2584         attrib = GL_GREEN_BITS;
  2585         break;
  2586     case SDL_GL_ALPHA_SIZE:
  2587         attrib = GL_ALPHA_BITS;
  2588         break;
  2589     case SDL_GL_DOUBLEBUFFER:
  2590 #if SDL_VIDEO_OPENGL
  2591         attrib = GL_DOUBLEBUFFER;
  2592         break;
  2593 #else
  2594         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2595         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2596         /* SDL driver must set proper value after initialization              */
  2597         *value = _this->gl_config.double_buffer;
  2598         return 0;
  2599 #endif
  2600     case SDL_GL_DEPTH_SIZE:
  2601         attrib = GL_DEPTH_BITS;
  2602         break;
  2603     case SDL_GL_STENCIL_SIZE:
  2604         attrib = GL_STENCIL_BITS;
  2605         break;
  2606 #if SDL_VIDEO_OPENGL
  2607     case SDL_GL_ACCUM_RED_SIZE:
  2608         attrib = GL_ACCUM_RED_BITS;
  2609         break;
  2610     case SDL_GL_ACCUM_GREEN_SIZE:
  2611         attrib = GL_ACCUM_GREEN_BITS;
  2612         break;
  2613     case SDL_GL_ACCUM_BLUE_SIZE:
  2614         attrib = GL_ACCUM_BLUE_BITS;
  2615         break;
  2616     case SDL_GL_ACCUM_ALPHA_SIZE:
  2617         attrib = GL_ACCUM_ALPHA_BITS;
  2618         break;
  2619     case SDL_GL_STEREO:
  2620         attrib = GL_STEREO;
  2621         break;
  2622 #else
  2623     case SDL_GL_ACCUM_RED_SIZE:
  2624     case SDL_GL_ACCUM_GREEN_SIZE:
  2625     case SDL_GL_ACCUM_BLUE_SIZE:
  2626     case SDL_GL_ACCUM_ALPHA_SIZE:
  2627     case SDL_GL_STEREO:
  2628         /* none of these are supported in OpenGL ES */
  2629         *value = 0;
  2630         return 0;
  2631 #endif
  2632     case SDL_GL_MULTISAMPLEBUFFERS:
  2633 #if SDL_VIDEO_OPENGL
  2634         attrib = GL_SAMPLE_BUFFERS_ARB;
  2635 #else
  2636         attrib = GL_SAMPLE_BUFFERS;
  2637 #endif
  2638         break;
  2639     case SDL_GL_MULTISAMPLESAMPLES:
  2640 #if SDL_VIDEO_OPENGL
  2641         attrib = GL_SAMPLES_ARB;
  2642 #else
  2643         attrib = GL_SAMPLES;
  2644 #endif
  2645         break;
  2646     case SDL_GL_BUFFER_SIZE:
  2647         {
  2648             GLint bits = 0;
  2649             GLint component;
  2650 
  2651             /*
  2652              * there doesn't seem to be a single flag in OpenGL
  2653              * for this!
  2654              */
  2655             glGetIntegervFunc(GL_RED_BITS, &component);
  2656             bits += component;
  2657             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2658             bits += component;
  2659             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2660             bits += component;
  2661             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2662             bits += component;
  2663 
  2664             *value = bits;
  2665             return 0;
  2666         }
  2667     case SDL_GL_ACCELERATED_VISUAL:
  2668         {
  2669             /* FIXME: How do we get this information? */
  2670             *value = (_this->gl_config.accelerated != 0);
  2671             return 0;
  2672         }
  2673     case SDL_GL_RETAINED_BACKING:
  2674         {
  2675             *value = _this->gl_config.retained_backing;
  2676             return 0;
  2677         }
  2678     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2679         {
  2680             *value = _this->gl_config.major_version;
  2681             return 0;
  2682         }
  2683     case SDL_GL_CONTEXT_MINOR_VERSION:
  2684         {
  2685             *value = _this->gl_config.minor_version;
  2686             return 0;
  2687         }
  2688     case SDL_GL_CONTEXT_EGL:
  2689         {
  2690             *value = _this->gl_config.use_egl;
  2691             return 0;
  2692         }
  2693     case SDL_GL_CONTEXT_FLAGS:
  2694         {
  2695             *value = _this->gl_config.flags;
  2696             return 0;
  2697         }
  2698     case SDL_GL_CONTEXT_PROFILE_MASK:
  2699         {
  2700             *value = _this->gl_config.profile_mask;
  2701             return 0;
  2702         }
  2703     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2704         {
  2705             *value = _this->gl_config.share_with_current_context;
  2706             return 0;
  2707         }
  2708     default:
  2709         return SDL_SetError("Unknown OpenGL attribute");
  2710     }
  2711 
  2712     glGetIntegervFunc(attrib, (GLint *) value);
  2713     error = glGetErrorFunc();
  2714     if (error != GL_NO_ERROR) {
  2715         if (error == GL_INVALID_ENUM) {
  2716             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2717         } else if (error == GL_INVALID_VALUE) {
  2718             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2719         }
  2720         return SDL_SetError("OpenGL error: %08X", error);
  2721     }
  2722     return 0;
  2723 #else
  2724     return SDL_Unsupported();
  2725 #endif /* SDL_VIDEO_OPENGL */
  2726 }
  2727 
  2728 SDL_GLContext
  2729 SDL_GL_CreateContext(SDL_Window * window)
  2730 {
  2731     SDL_GLContext ctx = NULL;
  2732     CHECK_WINDOW_MAGIC(window, NULL);
  2733 
  2734     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2735         SDL_SetError("The specified window isn't an OpenGL window");
  2736         return NULL;
  2737     }
  2738 
  2739     ctx = _this->GL_CreateContext(_this, window);
  2740 
  2741     /* Creating a context is assumed to make it current in the SDL driver. */
  2742     _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 int
  3058 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3059 {
  3060     int dummybutton;
  3061     int retval = -1;
  3062     SDL_bool relative_mode = SDL_GetRelativeMouseMode();
  3063     int show_cursor_prev = SDL_ShowCursor( 1 );
  3064 
  3065     SDL_SetRelativeMouseMode( SDL_FALSE );
  3066 
  3067     if (!buttonid) {
  3068         buttonid = &dummybutton;
  3069     }
  3070     if (_this && _this->ShowMessageBox) {
  3071         if (_this->ShowMessageBox(_this, messageboxdata, buttonid) == 0) {
  3072             retval = 0;
  3073         }
  3074     }
  3075 
  3076     /* It's completely fine to call this function before video is initialized */
  3077 #if SDL_VIDEO_DRIVER_WINDOWS
  3078     if ((retval == -1) && (WIN_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3079         retval = 0;
  3080     }
  3081 #endif
  3082 #if SDL_VIDEO_DRIVER_COCOA
  3083     if ((retval == -1) && (Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3084         retval = 0;
  3085     }
  3086 #endif
  3087 #if SDL_VIDEO_DRIVER_UIKIT
  3088     if ((retval == -1) && (UIKit_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3089         retval = 0;
  3090     }
  3091 #endif
  3092 #if SDL_VIDEO_DRIVER_X11
  3093     if ((retval == -1) && (X11_ShowMessageBox(messageboxdata, buttonid) == 0)) {
  3094         retval = 0;
  3095     }
  3096 #endif
  3097 
  3098     SDL_ShowCursor( show_cursor_prev );
  3099     SDL_SetRelativeMouseMode( relative_mode );
  3100 
  3101     if(retval == -1) {
  3102         SDL_SetError("No message system available");
  3103     }
  3104     return retval;
  3105 }
  3106 
  3107 int
  3108 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3109 {
  3110     SDL_MessageBoxData data;
  3111     SDL_MessageBoxButtonData button;
  3112 
  3113     SDL_zero(data);
  3114     data.flags = flags;
  3115     data.title = title;
  3116     data.message = message;
  3117     data.numbuttons = 1;
  3118     data.buttons = &button;
  3119     data.window = window;
  3120 
  3121     SDL_zero(button);
  3122     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3123     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3124     button.text = "OK";
  3125 
  3126     return SDL_ShowMessageBox(&data, NULL);
  3127 }
  3128 
  3129 SDL_bool
  3130 SDL_ShouldAllowTopmost(void)
  3131 {
  3132     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3133     if (hint) {
  3134         if (*hint == '0') {
  3135             return SDL_FALSE;
  3136         } else {
  3137             return SDL_TRUE;
  3138         }
  3139     }
  3140     return SDL_TRUE;
  3141 }
  3142 
  3143 /* vi: set ts=4 sw=4 expandtab: */