src/video/SDL_video.c
author Gabriel Jacobo <gabomdq@gmail.com>
Thu, 29 Aug 2013 15:02:32 -0300
changeset 7723 aea98cc3e696
parent 7721 bdf8c2c84e14
child 7742 84e32c3d415c
permissions -rw-r--r--
Fixes bug #2040, prepare SDL_GL_CONTEXT_EGL for deprecation on v2.1

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