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