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