src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 11 Nov 2013 03:02:42 -0800
changeset 7953 255ca6c77e58
parent 7950 85dc78d922db
child 7954 712d8544f8a1
permissions -rwxr-xr-x
Don't minimize by default when in fullscreen desktop mode.
This fixes behavior with the new Mac OS X fullscreen space code, as well as improve behavior on Linux desktops.
The default for normal fullscreen mode is still to minimize because we're likely doing a mode switch and don't want to stick around as a borderless window in the background.
     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
  2138 ShouldMinimizeOnFocusLoss(SDL_Window * window)
  2139 {
  2140     SDL_bool default_minimize;
  2141 
  2142     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  2143         return SDL_FALSE;
  2144     }
  2145 
  2146     if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
  2147         /* We're not doing a mode switch, so it's okay to stay around */
  2148         default_minimize = SDL_FALSE;
  2149     } else {
  2150         default_minimize = SDL_TRUE;
  2151     }
  2152 
  2153     const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2154     if (hint) {
  2155         if (*hint == '0') {
  2156             return SDL_FALSE;
  2157         } else {
  2158             return SDL_TRUE;
  2159         }
  2160     }
  2161 
  2162     return default_minimize;
  2163 }
  2164 
  2165 void
  2166 SDL_OnWindowFocusLost(SDL_Window * window)
  2167 {
  2168     if (window->gamma && _this->SetWindowGammaRamp) {
  2169         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2170     }
  2171 
  2172     SDL_UpdateWindowGrab(window);
  2173 
  2174     if (ShouldMinimizeOnFocusLoss(window)) {
  2175         SDL_MinimizeWindow(window);
  2176     }
  2177 }
  2178 
  2179 SDL_Window *
  2180 SDL_GetFocusWindow(void)
  2181 {
  2182     SDL_Window *window;
  2183 
  2184     if (!_this) {
  2185         return NULL;
  2186     }
  2187     for (window = _this->windows; window; window = window->next) {
  2188         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2189             return window;
  2190         }
  2191     }
  2192     return NULL;
  2193 }
  2194 
  2195 void
  2196 SDL_DestroyWindow(SDL_Window * window)
  2197 {
  2198     SDL_VideoDisplay *display;
  2199 
  2200     CHECK_WINDOW_MAGIC(window, );
  2201 
  2202     /* Restore video mode, etc. */
  2203     SDL_HideWindow(window);
  2204 
  2205     /* Make sure this window no longer has focus */
  2206     if (SDL_GetKeyboardFocus() == window) {
  2207         SDL_SetKeyboardFocus(NULL);
  2208     }
  2209     if (SDL_GetMouseFocus() == window) {
  2210         SDL_SetMouseFocus(NULL);
  2211     }
  2212 
  2213     /* make no context current if this is the current context window. */
  2214     if (window->flags & SDL_WINDOW_OPENGL) {
  2215         if (_this->current_glwin == window) {
  2216             SDL_GL_MakeCurrent(window, NULL);
  2217         }
  2218     }
  2219 
  2220     if (window->surface) {
  2221         window->surface->flags &= ~SDL_DONTFREE;
  2222         SDL_FreeSurface(window->surface);
  2223     }
  2224     if (_this->DestroyWindowFramebuffer) {
  2225         _this->DestroyWindowFramebuffer(_this, window);
  2226     }
  2227     if (_this->DestroyWindow) {
  2228         _this->DestroyWindow(_this, window);
  2229     }
  2230     if (window->flags & SDL_WINDOW_OPENGL) {
  2231         SDL_GL_UnloadLibrary();
  2232     }
  2233 
  2234     display = SDL_GetDisplayForWindow(window);
  2235     if (display->fullscreen_window == window) {
  2236         display->fullscreen_window = NULL;
  2237     }
  2238 
  2239     /* Now invalidate magic */
  2240     window->magic = NULL;
  2241 
  2242     /* Free memory associated with the window */
  2243     SDL_free(window->title);
  2244     SDL_FreeSurface(window->icon);
  2245     SDL_free(window->gamma);
  2246     while (window->data) {
  2247         SDL_WindowUserData *data = window->data;
  2248 
  2249         window->data = data->next;
  2250         SDL_free(data->name);
  2251         SDL_free(data);
  2252     }
  2253 
  2254     /* Unlink the window from the list */
  2255     if (window->next) {
  2256         window->next->prev = window->prev;
  2257     }
  2258     if (window->prev) {
  2259         window->prev->next = window->next;
  2260     } else {
  2261         _this->windows = window->next;
  2262     }
  2263 
  2264     SDL_free(window);
  2265 }
  2266 
  2267 SDL_bool
  2268 SDL_IsScreenSaverEnabled()
  2269 {
  2270     if (!_this) {
  2271         return SDL_TRUE;
  2272     }
  2273     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2274 }
  2275 
  2276 void
  2277 SDL_EnableScreenSaver()
  2278 {
  2279     if (!_this) {
  2280         return;
  2281     }
  2282     if (!_this->suspend_screensaver) {
  2283         return;
  2284     }
  2285     _this->suspend_screensaver = SDL_FALSE;
  2286     if (_this->SuspendScreenSaver) {
  2287         _this->SuspendScreenSaver(_this);
  2288     }
  2289 }
  2290 
  2291 void
  2292 SDL_DisableScreenSaver()
  2293 {
  2294     if (!_this) {
  2295         return;
  2296     }
  2297     if (_this->suspend_screensaver) {
  2298         return;
  2299     }
  2300     _this->suspend_screensaver = SDL_TRUE;
  2301     if (_this->SuspendScreenSaver) {
  2302         _this->SuspendScreenSaver(_this);
  2303     }
  2304 }
  2305 
  2306 void
  2307 SDL_VideoQuit(void)
  2308 {
  2309     int i, j;
  2310 
  2311     if (!_this) {
  2312         return;
  2313     }
  2314 
  2315     /* Halt event processing before doing anything else */
  2316     SDL_TouchQuit();
  2317     SDL_MouseQuit();
  2318     SDL_KeyboardQuit();
  2319     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2320 
  2321     SDL_EnableScreenSaver();
  2322 
  2323     /* Clean up the system video */
  2324     while (_this->windows) {
  2325         SDL_DestroyWindow(_this->windows);
  2326     }
  2327     _this->VideoQuit(_this);
  2328 
  2329     for (i = 0; i < _this->num_displays; ++i) {
  2330         SDL_VideoDisplay *display = &_this->displays[i];
  2331         for (j = display->num_display_modes; j--;) {
  2332             SDL_free(display->display_modes[j].driverdata);
  2333             display->display_modes[j].driverdata = NULL;
  2334         }
  2335         SDL_free(display->display_modes);
  2336         display->display_modes = NULL;
  2337         SDL_free(display->desktop_mode.driverdata);
  2338         display->desktop_mode.driverdata = NULL;
  2339         SDL_free(display->driverdata);
  2340         display->driverdata = NULL;
  2341     }
  2342     if (_this->displays) {
  2343         for (i = 0; i < _this->num_displays; ++i) {
  2344             SDL_free(_this->displays[i].name);
  2345         }
  2346         SDL_free(_this->displays);
  2347         _this->displays = NULL;
  2348         _this->num_displays = 0;
  2349     }
  2350     SDL_free(_this->clipboard_text);
  2351     _this->clipboard_text = NULL;
  2352     _this->free(_this);
  2353     _this = NULL;
  2354 }
  2355 
  2356 int
  2357 SDL_GL_LoadLibrary(const char *path)
  2358 {
  2359     int retval;
  2360 
  2361     if (!_this) {
  2362         return SDL_UninitializedVideo();
  2363     }
  2364     if (_this->gl_config.driver_loaded) {
  2365         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2366             return SDL_SetError("OpenGL library already loaded");
  2367         }
  2368         retval = 0;
  2369     } else {
  2370         if (!_this->GL_LoadLibrary) {
  2371             return SDL_SetError("No dynamic GL support in video driver");
  2372         }
  2373         retval = _this->GL_LoadLibrary(_this, path);
  2374     }
  2375     if (retval == 0) {
  2376         ++_this->gl_config.driver_loaded;
  2377     } else {
  2378         if (_this->GL_UnloadLibrary) {
  2379             _this->GL_UnloadLibrary(_this);
  2380         }
  2381     }
  2382     return (retval);
  2383 }
  2384 
  2385 void *
  2386 SDL_GL_GetProcAddress(const char *proc)
  2387 {
  2388     void *func;
  2389 
  2390     if (!_this) {
  2391         SDL_UninitializedVideo();
  2392         return NULL;
  2393     }
  2394     func = NULL;
  2395     if (_this->GL_GetProcAddress) {
  2396         if (_this->gl_config.driver_loaded) {
  2397             func = _this->GL_GetProcAddress(_this, proc);
  2398         } else {
  2399             SDL_SetError("No GL driver has been loaded");
  2400         }
  2401     } else {
  2402         SDL_SetError("No dynamic GL support in video driver");
  2403     }
  2404     return func;
  2405 }
  2406 
  2407 void
  2408 SDL_GL_UnloadLibrary(void)
  2409 {
  2410     if (!_this) {
  2411         SDL_UninitializedVideo();
  2412         return;
  2413     }
  2414     if (_this->gl_config.driver_loaded > 0) {
  2415         if (--_this->gl_config.driver_loaded > 0) {
  2416             return;
  2417         }
  2418         if (_this->GL_UnloadLibrary) {
  2419             _this->GL_UnloadLibrary(_this);
  2420         }
  2421     }
  2422 }
  2423 
  2424 static SDL_INLINE SDL_bool
  2425 isAtLeastGL3(const char *verstr)
  2426 {
  2427     return ( verstr && (SDL_atoi(verstr) >= 3) );
  2428 }
  2429 
  2430 SDL_bool
  2431 SDL_GL_ExtensionSupported(const char *extension)
  2432 {
  2433 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2434     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2435     const char *extensions;
  2436     const char *start;
  2437     const char *where, *terminator;
  2438 
  2439     /* Extension names should not have spaces. */
  2440     where = SDL_strchr(extension, ' ');
  2441     if (where || *extension == '\0') {
  2442         return SDL_FALSE;
  2443     }
  2444     /* See if there's an environment variable override */
  2445     start = SDL_getenv(extension);
  2446     if (start && *start == '0') {
  2447         return SDL_FALSE;
  2448     }
  2449 
  2450     /* Lookup the available extensions */
  2451 
  2452     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2453     if (!glGetStringFunc) {
  2454         return SDL_FALSE;
  2455     }
  2456 
  2457     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2458         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2459         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2460         GLint num_exts = 0;
  2461         GLint i;
  2462 
  2463         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2464         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2465         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2466             return SDL_FALSE;
  2467         }
  2468 
  2469         #ifndef GL_NUM_EXTENSIONS
  2470         #define GL_NUM_EXTENSIONS 0x821D
  2471         #endif
  2472         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2473         for (i = 0; i < num_exts; i++) {
  2474             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2475             if (SDL_strcmp(thisext, extension) == 0) {
  2476                 return SDL_TRUE;
  2477             }
  2478         }
  2479 
  2480         return SDL_FALSE;
  2481     }
  2482 
  2483     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2484 
  2485     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2486     if (!extensions) {
  2487         return SDL_FALSE;
  2488     }
  2489     /*
  2490      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2491      * extensions string. Don't be fooled by sub-strings, etc.
  2492      */
  2493 
  2494     start = extensions;
  2495 
  2496     for (;;) {
  2497         where = SDL_strstr(start, extension);
  2498         if (!where)
  2499             break;
  2500 
  2501         terminator = where + SDL_strlen(extension);
  2502         if (where == start || *(where - 1) == ' ')
  2503             if (*terminator == ' ' || *terminator == '\0')
  2504                 return SDL_TRUE;
  2505 
  2506         start = terminator;
  2507     }
  2508     return SDL_FALSE;
  2509 #else
  2510     return SDL_FALSE;
  2511 #endif
  2512 }
  2513 
  2514 int
  2515 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2516 {
  2517 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2518     int retval;
  2519 
  2520     if (!_this) {
  2521         return SDL_UninitializedVideo();
  2522     }
  2523     retval = 0;
  2524     switch (attr) {
  2525     case SDL_GL_RED_SIZE:
  2526         _this->gl_config.red_size = value;
  2527         break;
  2528     case SDL_GL_GREEN_SIZE:
  2529         _this->gl_config.green_size = value;
  2530         break;
  2531     case SDL_GL_BLUE_SIZE:
  2532         _this->gl_config.blue_size = value;
  2533         break;
  2534     case SDL_GL_ALPHA_SIZE:
  2535         _this->gl_config.alpha_size = value;
  2536         break;
  2537     case SDL_GL_DOUBLEBUFFER:
  2538         _this->gl_config.double_buffer = value;
  2539         break;
  2540     case SDL_GL_BUFFER_SIZE:
  2541         _this->gl_config.buffer_size = value;
  2542         break;
  2543     case SDL_GL_DEPTH_SIZE:
  2544         _this->gl_config.depth_size = value;
  2545         break;
  2546     case SDL_GL_STENCIL_SIZE:
  2547         _this->gl_config.stencil_size = value;
  2548         break;
  2549     case SDL_GL_ACCUM_RED_SIZE:
  2550         _this->gl_config.accum_red_size = value;
  2551         break;
  2552     case SDL_GL_ACCUM_GREEN_SIZE:
  2553         _this->gl_config.accum_green_size = value;
  2554         break;
  2555     case SDL_GL_ACCUM_BLUE_SIZE:
  2556         _this->gl_config.accum_blue_size = value;
  2557         break;
  2558     case SDL_GL_ACCUM_ALPHA_SIZE:
  2559         _this->gl_config.accum_alpha_size = value;
  2560         break;
  2561     case SDL_GL_STEREO:
  2562         _this->gl_config.stereo = value;
  2563         break;
  2564     case SDL_GL_MULTISAMPLEBUFFERS:
  2565         _this->gl_config.multisamplebuffers = value;
  2566         break;
  2567     case SDL_GL_MULTISAMPLESAMPLES:
  2568         _this->gl_config.multisamplesamples = value;
  2569         break;
  2570     case SDL_GL_ACCELERATED_VISUAL:
  2571         _this->gl_config.accelerated = value;
  2572         break;
  2573     case SDL_GL_RETAINED_BACKING:
  2574         _this->gl_config.retained_backing = value;
  2575         break;
  2576     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2577         _this->gl_config.major_version = value;
  2578         break;
  2579     case SDL_GL_CONTEXT_MINOR_VERSION:
  2580         _this->gl_config.minor_version = value;
  2581         break;
  2582     case SDL_GL_CONTEXT_EGL:
  2583         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2584         if (value != 0) {
  2585             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  2586         } else {
  2587             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  2588         };
  2589         break;
  2590     case SDL_GL_CONTEXT_FLAGS:
  2591         if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2592               SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2593               SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2594               SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) {
  2595         retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2596         break;
  2597     }
  2598         _this->gl_config.flags = value;
  2599         break;
  2600     case SDL_GL_CONTEXT_PROFILE_MASK:
  2601         if( value != 0 &&
  2602         value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2603         value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2604         value != SDL_GL_CONTEXT_PROFILE_ES ) {
  2605         retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2606         break;
  2607     }
  2608         _this->gl_config.profile_mask = value;
  2609         break;
  2610     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2611         _this->gl_config.share_with_current_context = value;
  2612         break;
  2613     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2614         _this->gl_config.framebuffer_srgb_capable = value;
  2615         break;
  2616     default:
  2617         retval = SDL_SetError("Unknown OpenGL attribute");
  2618         break;
  2619     }
  2620     return retval;
  2621 #else
  2622     return SDL_Unsupported();
  2623 #endif /* SDL_VIDEO_OPENGL */
  2624 }
  2625 
  2626 int
  2627 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2628 {
  2629 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2630     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2631     GLenum(APIENTRY * glGetErrorFunc) (void);
  2632     GLenum attrib = 0;
  2633     GLenum error = 0;
  2634 
  2635     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2636     if (!glGetIntegervFunc) {
  2637         return -1;
  2638     }
  2639 
  2640     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2641     if (!glGetErrorFunc) {
  2642         return -1;
  2643     }
  2644 
  2645     /* Clear value in any case */
  2646     *value = 0;
  2647 
  2648     switch (attr) {
  2649     case SDL_GL_RED_SIZE:
  2650         attrib = GL_RED_BITS;
  2651         break;
  2652     case SDL_GL_BLUE_SIZE:
  2653         attrib = GL_BLUE_BITS;
  2654         break;
  2655     case SDL_GL_GREEN_SIZE:
  2656         attrib = GL_GREEN_BITS;
  2657         break;
  2658     case SDL_GL_ALPHA_SIZE:
  2659         attrib = GL_ALPHA_BITS;
  2660         break;
  2661     case SDL_GL_DOUBLEBUFFER:
  2662 #if SDL_VIDEO_OPENGL
  2663         attrib = GL_DOUBLEBUFFER;
  2664         break;
  2665 #else
  2666         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2667         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2668         /* SDL driver must set proper value after initialization              */
  2669         *value = _this->gl_config.double_buffer;
  2670         return 0;
  2671 #endif
  2672     case SDL_GL_DEPTH_SIZE:
  2673         attrib = GL_DEPTH_BITS;
  2674         break;
  2675     case SDL_GL_STENCIL_SIZE:
  2676         attrib = GL_STENCIL_BITS;
  2677         break;
  2678 #if SDL_VIDEO_OPENGL
  2679     case SDL_GL_ACCUM_RED_SIZE:
  2680         attrib = GL_ACCUM_RED_BITS;
  2681         break;
  2682     case SDL_GL_ACCUM_GREEN_SIZE:
  2683         attrib = GL_ACCUM_GREEN_BITS;
  2684         break;
  2685     case SDL_GL_ACCUM_BLUE_SIZE:
  2686         attrib = GL_ACCUM_BLUE_BITS;
  2687         break;
  2688     case SDL_GL_ACCUM_ALPHA_SIZE:
  2689         attrib = GL_ACCUM_ALPHA_BITS;
  2690         break;
  2691     case SDL_GL_STEREO:
  2692         attrib = GL_STEREO;
  2693         break;
  2694 #else
  2695     case SDL_GL_ACCUM_RED_SIZE:
  2696     case SDL_GL_ACCUM_GREEN_SIZE:
  2697     case SDL_GL_ACCUM_BLUE_SIZE:
  2698     case SDL_GL_ACCUM_ALPHA_SIZE:
  2699     case SDL_GL_STEREO:
  2700         /* none of these are supported in OpenGL ES */
  2701         *value = 0;
  2702         return 0;
  2703 #endif
  2704     case SDL_GL_MULTISAMPLEBUFFERS:
  2705 #if SDL_VIDEO_OPENGL
  2706         attrib = GL_SAMPLE_BUFFERS_ARB;
  2707 #else
  2708         attrib = GL_SAMPLE_BUFFERS;
  2709 #endif
  2710         break;
  2711     case SDL_GL_MULTISAMPLESAMPLES:
  2712 #if SDL_VIDEO_OPENGL
  2713         attrib = GL_SAMPLES_ARB;
  2714 #else
  2715         attrib = GL_SAMPLES;
  2716 #endif
  2717         break;
  2718     case SDL_GL_BUFFER_SIZE:
  2719         {
  2720             GLint bits = 0;
  2721             GLint component;
  2722 
  2723             /*
  2724              * there doesn't seem to be a single flag in OpenGL
  2725              * for this!
  2726              */
  2727             glGetIntegervFunc(GL_RED_BITS, &component);
  2728             bits += component;
  2729             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2730             bits += component;
  2731             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2732             bits += component;
  2733             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2734             bits += component;
  2735 
  2736             *value = bits;
  2737             return 0;
  2738         }
  2739     case SDL_GL_ACCELERATED_VISUAL:
  2740         {
  2741             /* FIXME: How do we get this information? */
  2742             *value = (_this->gl_config.accelerated != 0);
  2743             return 0;
  2744         }
  2745     case SDL_GL_RETAINED_BACKING:
  2746         {
  2747             *value = _this->gl_config.retained_backing;
  2748             return 0;
  2749         }
  2750     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2751         {
  2752             *value = _this->gl_config.major_version;
  2753             return 0;
  2754         }
  2755     case SDL_GL_CONTEXT_MINOR_VERSION:
  2756         {
  2757             *value = _this->gl_config.minor_version;
  2758             return 0;
  2759         }
  2760     case SDL_GL_CONTEXT_EGL:
  2761         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2762         {
  2763             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  2764                 *value = 1;
  2765             }
  2766             else {
  2767                 *value = 0;
  2768             }
  2769             return 0;
  2770         }
  2771     case SDL_GL_CONTEXT_FLAGS:
  2772         {
  2773             *value = _this->gl_config.flags;
  2774             return 0;
  2775         }
  2776     case SDL_GL_CONTEXT_PROFILE_MASK:
  2777         {
  2778             *value = _this->gl_config.profile_mask;
  2779             return 0;
  2780         }
  2781     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2782         {
  2783             *value = _this->gl_config.share_with_current_context;
  2784             return 0;
  2785         }
  2786     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2787         {
  2788             *value = _this->gl_config.framebuffer_srgb_capable;
  2789             return 0;
  2790         }
  2791     default:
  2792         return SDL_SetError("Unknown OpenGL attribute");
  2793     }
  2794 
  2795     glGetIntegervFunc(attrib, (GLint *) value);
  2796     error = glGetErrorFunc();
  2797     if (error != GL_NO_ERROR) {
  2798         if (error == GL_INVALID_ENUM) {
  2799             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2800         } else if (error == GL_INVALID_VALUE) {
  2801             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2802         }
  2803         return SDL_SetError("OpenGL error: %08X", error);
  2804     }
  2805     return 0;
  2806 #else
  2807     return SDL_Unsupported();
  2808 #endif /* SDL_VIDEO_OPENGL */
  2809 }
  2810 
  2811 SDL_GLContext
  2812 SDL_GL_CreateContext(SDL_Window * window)
  2813 {
  2814     SDL_GLContext ctx = NULL;
  2815     CHECK_WINDOW_MAGIC(window, NULL);
  2816 
  2817     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2818         SDL_SetError("The specified window isn't an OpenGL window");
  2819         return NULL;
  2820     }
  2821 
  2822     ctx = _this->GL_CreateContext(_this, window);
  2823 
  2824     /* Creating a context is assumed to make it current in the SDL driver. */
  2825     if (ctx) {
  2826         _this->current_glwin = window;
  2827         _this->current_glctx = ctx;
  2828         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2829         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2830     }
  2831     return ctx;
  2832 }
  2833 
  2834 int
  2835 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2836 {
  2837     int retval;
  2838 
  2839     if (window == SDL_GL_GetCurrentWindow() &&
  2840         ctx == SDL_GL_GetCurrentContext()) {
  2841         /* We're already current. */
  2842         return 0;
  2843     }
  2844 
  2845     if (!ctx) {
  2846         window = NULL;
  2847     } else {
  2848         CHECK_WINDOW_MAGIC(window, -1);
  2849 
  2850         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2851             return SDL_SetError("The specified window isn't an OpenGL window");
  2852         }
  2853     }
  2854 
  2855     retval = _this->GL_MakeCurrent(_this, window, ctx);
  2856     if (retval == 0) {
  2857         _this->current_glwin = window;
  2858         _this->current_glctx = ctx;
  2859         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  2860         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  2861     }
  2862     return retval;
  2863 }
  2864 
  2865 SDL_Window *
  2866 SDL_GL_GetCurrentWindow(void)
  2867 {
  2868     if (!_this) {
  2869         SDL_UninitializedVideo();
  2870         return NULL;
  2871     }
  2872     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
  2873 }
  2874 
  2875 SDL_GLContext
  2876 SDL_GL_GetCurrentContext(void)
  2877 {
  2878     if (!_this) {
  2879         SDL_UninitializedVideo();
  2880         return NULL;
  2881     }
  2882     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
  2883 }
  2884 
  2885 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
  2886 {
  2887     CHECK_WINDOW_MAGIC(window, );
  2888 
  2889     if (_this->GL_GetDrawableSize) {
  2890         _this->GL_GetDrawableSize(_this, window, w, h);
  2891     } else {
  2892         SDL_GetWindowSize(window, w, h);
  2893     }
  2894 }
  2895 
  2896 int
  2897 SDL_GL_SetSwapInterval(int interval)
  2898 {
  2899     if (!_this) {
  2900         return SDL_UninitializedVideo();
  2901     } else if (SDL_GL_GetCurrentContext() == NULL) {
  2902         return SDL_SetError("No OpenGL context has been made current");
  2903     } else if (_this->GL_SetSwapInterval) {
  2904         return _this->GL_SetSwapInterval(_this, interval);
  2905     } else {
  2906         return SDL_SetError("Setting the swap interval is not supported");
  2907     }
  2908 }
  2909 
  2910 int
  2911 SDL_GL_GetSwapInterval(void)
  2912 {
  2913     if (!_this) {
  2914         return 0;
  2915     } else if (SDL_GL_GetCurrentContext() == NULL) {
  2916         return 0;
  2917     } else if (_this->GL_GetSwapInterval) {
  2918         return _this->GL_GetSwapInterval(_this);
  2919     } else {
  2920         return 0;
  2921     }
  2922 }
  2923 
  2924 void
  2925 SDL_GL_SwapWindow(SDL_Window * window)
  2926 {
  2927     CHECK_WINDOW_MAGIC(window, );
  2928 
  2929     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2930         SDL_SetError("The specified window isn't an OpenGL window");
  2931         return;
  2932     }
  2933 
  2934     if (SDL_GL_GetCurrentWindow() != window) {
  2935         SDL_SetError("The specified window has not been made current");
  2936         return;
  2937     }
  2938 
  2939     _this->GL_SwapWindow(_this, window);
  2940 }
  2941 
  2942 void
  2943 SDL_GL_DeleteContext(SDL_GLContext context)
  2944 {
  2945     if (!_this || !context) {
  2946         return;
  2947     }
  2948 
  2949     if (SDL_GL_GetCurrentContext() == context) {
  2950         SDL_GL_MakeCurrent(NULL, NULL);
  2951     }
  2952 
  2953     _this->GL_DeleteContext(_this, context);
  2954 }
  2955 
  2956 #if 0                           /* FIXME */
  2957 /*
  2958  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2959  * & 2 for alpha channel.
  2960  */
  2961 static void
  2962 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2963 {
  2964     int x, y;
  2965     Uint32 colorkey;
  2966 #define SET_MASKBIT(icon, x, y, mask) \
  2967     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2968 
  2969     colorkey = icon->format->colorkey;
  2970     switch (icon->format->BytesPerPixel) {
  2971     case 1:
  2972         {
  2973             Uint8 *pixels;
  2974             for (y = 0; y < icon->h; ++y) {
  2975                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2976                 for (x = 0; x < icon->w; ++x) {
  2977                     if (*pixels++ == colorkey) {
  2978                         SET_MASKBIT(icon, x, y, mask);
  2979                     }
  2980                 }
  2981             }
  2982         }
  2983         break;
  2984 
  2985     case 2:
  2986         {
  2987             Uint16 *pixels;
  2988             for (y = 0; y < icon->h; ++y) {
  2989                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2990                 for (x = 0; x < icon->w; ++x) {
  2991                     if ((flags & 1) && *pixels == colorkey) {
  2992                         SET_MASKBIT(icon, x, y, mask);
  2993                     } else if ((flags & 2)
  2994                                && (*pixels & icon->format->Amask) == 0) {
  2995                         SET_MASKBIT(icon, x, y, mask);
  2996                     }
  2997                     pixels++;
  2998                 }
  2999             }
  3000         }
  3001         break;
  3002 
  3003     case 4:
  3004         {
  3005             Uint32 *pixels;
  3006             for (y = 0; y < icon->h; ++y) {
  3007                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3008                 for (x = 0; x < icon->w; ++x) {
  3009                     if ((flags & 1) && *pixels == colorkey) {
  3010                         SET_MASKBIT(icon, x, y, mask);
  3011                     } else if ((flags & 2)
  3012                                && (*pixels & icon->format->Amask) == 0) {
  3013                         SET_MASKBIT(icon, x, y, mask);
  3014                     }
  3015                     pixels++;
  3016                 }
  3017             }
  3018         }
  3019         break;
  3020     }
  3021 }
  3022 
  3023 /*
  3024  * Sets the window manager icon for the display window.
  3025  */
  3026 void
  3027 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3028 {
  3029     if (icon && _this->SetIcon) {
  3030         /* Generate a mask if necessary, and create the icon! */
  3031         if (mask == NULL) {
  3032             int mask_len = icon->h * (icon->w + 7) / 8;
  3033             int flags = 0;
  3034             mask = (Uint8 *) SDL_malloc(mask_len);
  3035             if (mask == NULL) {
  3036                 return;
  3037             }
  3038             SDL_memset(mask, ~0, mask_len);
  3039             if (icon->flags & SDL_SRCCOLORKEY)
  3040                 flags |= 1;
  3041             if (icon->flags & SDL_SRCALPHA)
  3042                 flags |= 2;
  3043             if (flags) {
  3044                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3045             }
  3046             _this->SetIcon(_this, icon, mask);
  3047             SDL_free(mask);
  3048         } else {
  3049             _this->SetIcon(_this, icon, mask);
  3050         }
  3051     }
  3052 }
  3053 #endif
  3054 
  3055 SDL_bool
  3056 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3057 {
  3058     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3059 
  3060     if (!info) {
  3061         return SDL_FALSE;
  3062     }
  3063     info->subsystem = SDL_SYSWM_UNKNOWN;
  3064 
  3065     if (!_this->GetWindowWMInfo) {
  3066         return SDL_FALSE;
  3067     }
  3068     return (_this->GetWindowWMInfo(_this, window, info));
  3069 }
  3070 
  3071 void
  3072 SDL_StartTextInput(void)
  3073 {
  3074     SDL_Window *window;
  3075 
  3076     /* First, enable text events */
  3077     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3078     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3079 
  3080     /* Then show the on-screen keyboard, if any */
  3081     window = SDL_GetFocusWindow();
  3082     if (window && _this && _this->ShowScreenKeyboard) {
  3083         _this->ShowScreenKeyboard(_this, window);
  3084     }
  3085 
  3086     /* Finally start the text input system */
  3087     if (_this && _this->StartTextInput) {
  3088         _this->StartTextInput(_this);
  3089     }
  3090 }
  3091 
  3092 SDL_bool
  3093 SDL_IsTextInputActive(void)
  3094 {
  3095     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  3096 }
  3097 
  3098 void
  3099 SDL_StopTextInput(void)
  3100 {
  3101     SDL_Window *window;
  3102 
  3103     /* Stop the text input system */
  3104     if (_this && _this->StopTextInput) {
  3105         _this->StopTextInput(_this);
  3106     }
  3107 
  3108     /* Hide the on-screen keyboard, if any */
  3109     window = SDL_GetFocusWindow();
  3110     if (window && _this && _this->HideScreenKeyboard) {
  3111         _this->HideScreenKeyboard(_this, window);
  3112     }
  3113 
  3114     /* Finally disable text events */
  3115     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3116     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3117 }
  3118 
  3119 void
  3120 SDL_SetTextInputRect(SDL_Rect *rect)
  3121 {
  3122     if (_this && _this->SetTextInputRect) {
  3123         _this->SetTextInputRect(_this, rect);
  3124     }
  3125 }
  3126 
  3127 SDL_bool
  3128 SDL_HasScreenKeyboardSupport(void)
  3129 {
  3130     if (_this && _this->HasScreenKeyboardSupport) {
  3131         return _this->HasScreenKeyboardSupport(_this);
  3132     }
  3133     return SDL_FALSE;
  3134 }
  3135 
  3136 SDL_bool
  3137 SDL_IsScreenKeyboardShown(SDL_Window *window)
  3138 {
  3139     if (window && _this && _this->IsScreenKeyboardShown) {
  3140         return _this->IsScreenKeyboardShown(_this, window);
  3141     }
  3142     return SDL_FALSE;
  3143 }
  3144 
  3145 #if SDL_VIDEO_DRIVER_WINDOWS
  3146 #include "windows/SDL_windowsmessagebox.h"
  3147 #endif
  3148 #if SDL_VIDEO_DRIVER_COCOA
  3149 #include "cocoa/SDL_cocoamessagebox.h"
  3150 #endif
  3151 #if SDL_VIDEO_DRIVER_UIKIT
  3152 #include "uikit/SDL_uikitmessagebox.h"
  3153 #endif
  3154 #if SDL_VIDEO_DRIVER_X11
  3155 #include "x11/SDL_x11messagebox.h"
  3156 #endif
  3157 
  3158 static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
  3159 {
  3160     SDL_SysWMinfo info;
  3161     SDL_Window *window = messageboxdata->window;
  3162 
  3163     if (!window) {
  3164         return SDL_TRUE;
  3165     }
  3166 
  3167     SDL_VERSION(&info.version);
  3168     if (!SDL_GetWindowWMInfo(window, &info)) {
  3169         return SDL_TRUE;
  3170     } else {
  3171         return (info.subsystem == drivertype);
  3172     }
  3173 }
  3174 
  3175 int
  3176 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3177 {
  3178     int dummybutton;
  3179     int retval = -1;
  3180     SDL_bool relative_mode;
  3181     int show_cursor_prev;
  3182 
  3183     if (!messageboxdata) {
  3184         return SDL_InvalidParamError("messageboxdata");
  3185     }
  3186 
  3187     relative_mode = SDL_GetRelativeMouseMode();
  3188     SDL_SetRelativeMouseMode(SDL_FALSE);
  3189     show_cursor_prev = SDL_ShowCursor(1);
  3190 
  3191     if (!buttonid) {
  3192         buttonid = &dummybutton;
  3193     }
  3194 
  3195     if (_this && _this->ShowMessageBox) {
  3196         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
  3197     }
  3198 
  3199     /* It's completely fine to call this function before video is initialized */
  3200 #if SDL_VIDEO_DRIVER_WINDOWS
  3201     if (retval == -1 &&
  3202         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
  3203         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3204         retval = 0;
  3205     }
  3206 #endif
  3207 #if SDL_VIDEO_DRIVER_COCOA
  3208     if (retval == -1 &&
  3209         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
  3210         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3211         retval = 0;
  3212     }
  3213 #endif
  3214 #if SDL_VIDEO_DRIVER_UIKIT
  3215     if (retval == -1 &&
  3216         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
  3217         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3218         retval = 0;
  3219     }
  3220 #endif
  3221 #if SDL_VIDEO_DRIVER_X11
  3222     if (retval == -1 &&
  3223         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
  3224         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3225         retval = 0;
  3226     }
  3227 #endif
  3228     if (retval == -1) {
  3229         SDL_SetError("No message system available");
  3230     }
  3231 
  3232     SDL_ShowCursor(show_cursor_prev);
  3233     SDL_SetRelativeMouseMode(relative_mode);
  3234 
  3235     return retval;
  3236 }
  3237 
  3238 int
  3239 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3240 {
  3241     SDL_MessageBoxData data;
  3242     SDL_MessageBoxButtonData button;
  3243 
  3244     SDL_zero(data);
  3245     data.flags = flags;
  3246     data.title = title;
  3247     data.message = message;
  3248     data.numbuttons = 1;
  3249     data.buttons = &button;
  3250     data.window = window;
  3251 
  3252     SDL_zero(button);
  3253     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3254     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3255     button.text = "OK";
  3256 
  3257     return SDL_ShowMessageBox(&data, NULL);
  3258 }
  3259 
  3260 SDL_bool
  3261 SDL_ShouldAllowTopmost(void)
  3262 {
  3263     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3264     if (hint) {
  3265         if (*hint == '0') {
  3266             return SDL_FALSE;
  3267         } else {
  3268             return SDL_TRUE;
  3269         }
  3270     }
  3271     return SDL_TRUE;
  3272 }
  3273 
  3274 /* vi: set ts=4 sw=4 expandtab: */