src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Sep 2013 17:42:46 -0700
changeset 7742 84e32c3d415c
parent 7723 aea98cc3e696
child 7745 c52d519d104a
permissions -rw-r--r--
Added SDL_Direct3D9GetAdapterIndex(), which returns the adapter index you would pass into CreateDevice to get your device on the right monitor in full screen mode. This fixes the default adapter in SDL_render_d3d.c, which means that tests will work fullscreen off the main monitor now.

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