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