src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 09 Nov 2015 08:54:49 -0800
changeset 9904 e9b49510e51b
parent 9887 77f017f7f16d
child 9905 fcf85090f816
permissions -rw-r--r--
SDL OSX implementation must account for the fact that going fullscreen can fail. improve the logic around retrying, make a few attempts before failing.
     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 we're switching between a fullscreen Space and "normal" fullscreen, we need to get back to normal first. */
  1142     if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN)) {
  1143         if (!Cocoa_SetWindowFullscreenSpace(window, SDL_FALSE)) {
  1144             return -1;
  1145         }
  1146     } else if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP)) {
  1147         display = SDL_GetDisplayForWindow(window);
  1148         SDL_SetDisplayModeForDisplay(display, NULL);
  1149         if (_this->SetWindowFullscreen) {
  1150             _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1151         }
  1152     }
  1153 
  1154     if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) {
  1155         if (Cocoa_IsWindowInFullscreenSpace(window) != fullscreen) {
  1156             return -1;
  1157         }
  1158         window->last_fullscreen_flags = window->flags;
  1159         return 0;
  1160     }
  1161 #endif
  1162 
  1163     display = SDL_GetDisplayForWindow(window);
  1164 
  1165     if (fullscreen) {
  1166         /* Hide any other fullscreen windows */
  1167         if (display->fullscreen_window &&
  1168             display->fullscreen_window != window) {
  1169             SDL_MinimizeWindow(display->fullscreen_window);
  1170         }
  1171     }
  1172 
  1173     /* See if anything needs to be done now */
  1174     if ((display->fullscreen_window == window) == fullscreen) {
  1175         if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) {
  1176             return 0;
  1177         }
  1178     }
  1179 
  1180     /* See if there are any fullscreen windows */
  1181     for (other = _this->windows; other; other = other->next) {
  1182         SDL_bool setDisplayMode = SDL_FALSE;
  1183 
  1184         if (other == window) {
  1185             setDisplayMode = fullscreen;
  1186         } else if (FULLSCREEN_VISIBLE(other) &&
  1187                    SDL_GetDisplayForWindow(other) == display) {
  1188             setDisplayMode = SDL_TRUE;
  1189         }
  1190 
  1191         if (setDisplayMode) {
  1192             SDL_DisplayMode fullscreen_mode;
  1193 
  1194             SDL_zero(fullscreen_mode);
  1195 
  1196             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1197                 SDL_bool resized = SDL_TRUE;
  1198 
  1199                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1200                     resized = SDL_FALSE;
  1201                 }
  1202 
  1203                 /* only do the mode change if we want exclusive fullscreen */
  1204                 if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1205                     if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
  1206                         return -1;
  1207                     }
  1208                 } else {
  1209                     if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
  1210                         return -1;
  1211                     }
  1212                 }
  1213 
  1214                 if (_this->SetWindowFullscreen) {
  1215                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1216                 }
  1217                 display->fullscreen_window = other;
  1218 
  1219                 /* Generate a mode change event here */
  1220                 if (resized) {
  1221                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1222                                         fullscreen_mode.w, fullscreen_mode.h);
  1223                 } else {
  1224                     SDL_OnWindowResized(other);
  1225                 }
  1226 
  1227                 SDL_RestoreMousePosition(other);
  1228 
  1229                 window->last_fullscreen_flags = window->flags;
  1230                 return 0;
  1231             }
  1232         }
  1233     }
  1234 
  1235     /* Nope, restore the desktop mode */
  1236     SDL_SetDisplayModeForDisplay(display, NULL);
  1237 
  1238     if (_this->SetWindowFullscreen) {
  1239         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1240     }
  1241     display->fullscreen_window = NULL;
  1242 
  1243     /* Generate a mode change event here */
  1244     SDL_OnWindowResized(window);
  1245 
  1246     /* Restore the cursor position */
  1247     SDL_RestoreMousePosition(window);
  1248 
  1249     window->last_fullscreen_flags = window->flags;
  1250     return 0;
  1251 }
  1252 
  1253 #define CREATE_FLAGS \
  1254     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI)
  1255 
  1256 static void
  1257 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1258 {
  1259     window->windowed.x = window->x;
  1260     window->windowed.y = window->y;
  1261     window->windowed.w = window->w;
  1262     window->windowed.h = window->h;
  1263 
  1264     if (flags & SDL_WINDOW_MAXIMIZED) {
  1265         SDL_MaximizeWindow(window);
  1266     }
  1267     if (flags & SDL_WINDOW_MINIMIZED) {
  1268         SDL_MinimizeWindow(window);
  1269     }
  1270     if (flags & SDL_WINDOW_FULLSCREEN) {
  1271         SDL_SetWindowFullscreen(window, flags);
  1272     }
  1273     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1274         SDL_SetWindowGrab(window, SDL_TRUE);
  1275     }
  1276     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1277         SDL_ShowWindow(window);
  1278     }
  1279 }
  1280 
  1281 SDL_Window *
  1282 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1283 {
  1284     SDL_Window *window;
  1285     const char *hint;
  1286 
  1287     if (!_this) {
  1288         /* Initialize the video system if needed */
  1289         if (SDL_VideoInit(NULL) < 0) {
  1290             return NULL;
  1291         }
  1292     }
  1293 
  1294     /* Some platforms can't create zero-sized windows */
  1295     if (w < 1) {
  1296         w = 1;
  1297     }
  1298     if (h < 1) {
  1299         h = 1;
  1300     }
  1301 
  1302     /* Some platforms blow up if the windows are too large. Raise it later? */
  1303     if ((w > 16384) || (h > 16384)) {
  1304         SDL_SetError("Window is too large.");
  1305         return NULL;
  1306     }
  1307 
  1308     /* Some platforms have OpenGL enabled by default */
  1309 #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__
  1310     flags |= SDL_WINDOW_OPENGL;
  1311 #endif
  1312     if (flags & SDL_WINDOW_OPENGL) {
  1313         if (!_this->GL_CreateContext) {
  1314             SDL_SetError("No OpenGL support in video driver");
  1315             return NULL;
  1316         }
  1317         if (SDL_GL_LoadLibrary(NULL) < 0) {
  1318             return NULL;
  1319         }
  1320     }
  1321 
  1322     /* Unless the user has specified the high-DPI disabling hint, respect the
  1323      * SDL_WINDOW_ALLOW_HIGHDPI flag.
  1324      */
  1325     if (flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1326         hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED);
  1327         if (hint && SDL_atoi(hint) > 0) {
  1328             flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
  1329         }
  1330     }
  1331 
  1332     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1333     if (!window) {
  1334         SDL_OutOfMemory();
  1335         return NULL;
  1336     }
  1337     window->magic = &_this->window_magic;
  1338     window->id = _this->next_object_id++;
  1339     window->x = x;
  1340     window->y = y;
  1341     window->w = w;
  1342     window->h = h;
  1343     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1344         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1345         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1346         int displayIndex;
  1347         SDL_Rect bounds;
  1348 
  1349         displayIndex = SDL_GetIndexOfDisplay(display);
  1350         SDL_GetDisplayBounds(displayIndex, &bounds);
  1351         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1352             window->x = bounds.x + (bounds.w - w) / 2;
  1353         }
  1354         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1355             window->y = bounds.y + (bounds.h - h) / 2;
  1356         }
  1357     }
  1358     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1359     window->last_fullscreen_flags = window->flags;
  1360     window->brightness = 1.0f;
  1361     window->next = _this->windows;
  1362     window->is_destroying = SDL_FALSE;
  1363 
  1364     if (_this->windows) {
  1365         _this->windows->prev = window;
  1366     }
  1367     _this->windows = window;
  1368 
  1369     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1370         SDL_DestroyWindow(window);
  1371         return NULL;
  1372     }
  1373 
  1374     if (title) {
  1375         SDL_SetWindowTitle(window, title);
  1376     }
  1377     SDL_FinishWindowCreation(window, flags);
  1378 
  1379     /* If the window was created fullscreen, make sure the mode code matches */
  1380     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1381 
  1382     return window;
  1383 }
  1384 
  1385 SDL_Window *
  1386 SDL_CreateWindowFrom(const void *data)
  1387 {
  1388     SDL_Window *window;
  1389 
  1390     if (!_this) {
  1391         SDL_UninitializedVideo();
  1392         return NULL;
  1393     }
  1394     if (!_this->CreateWindowFrom) {
  1395         SDL_Unsupported();
  1396         return NULL;
  1397     }
  1398     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1399     if (!window) {
  1400         SDL_OutOfMemory();
  1401         return NULL;
  1402     }
  1403     window->magic = &_this->window_magic;
  1404     window->id = _this->next_object_id++;
  1405     window->flags = SDL_WINDOW_FOREIGN;
  1406     window->last_fullscreen_flags = window->flags;
  1407     window->is_destroying = SDL_FALSE;
  1408     window->brightness = 1.0f;
  1409     window->next = _this->windows;
  1410     if (_this->windows) {
  1411         _this->windows->prev = window;
  1412     }
  1413     _this->windows = window;
  1414 
  1415     if (_this->CreateWindowFrom(_this, window, data) < 0) {
  1416         SDL_DestroyWindow(window);
  1417         return NULL;
  1418     }
  1419     return window;
  1420 }
  1421 
  1422 int
  1423 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1424 {
  1425     SDL_bool loaded_opengl = SDL_FALSE;
  1426 
  1427     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1428         return SDL_SetError("No OpenGL support in video driver");
  1429     }
  1430 
  1431     if (window->flags & SDL_WINDOW_FOREIGN) {
  1432         /* Can't destroy and re-create foreign windows, hrm */
  1433         flags |= SDL_WINDOW_FOREIGN;
  1434     } else {
  1435         flags &= ~SDL_WINDOW_FOREIGN;
  1436     }
  1437 
  1438     /* Restore video mode, etc. */
  1439     SDL_HideWindow(window);
  1440 
  1441     /* Tear down the old native window */
  1442     if (window->surface) {
  1443         window->surface->flags &= ~SDL_DONTFREE;
  1444         SDL_FreeSurface(window->surface);
  1445     }
  1446     if (_this->DestroyWindowFramebuffer) {
  1447         _this->DestroyWindowFramebuffer(_this, window);
  1448     }
  1449     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1450         _this->DestroyWindow(_this, window);
  1451     }
  1452 
  1453     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1454         if (flags & SDL_WINDOW_OPENGL) {
  1455             if (SDL_GL_LoadLibrary(NULL) < 0) {
  1456                 return -1;
  1457             }
  1458             loaded_opengl = SDL_TRUE;
  1459         } else {
  1460             SDL_GL_UnloadLibrary();
  1461         }
  1462     }
  1463 
  1464     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1465     window->last_fullscreen_flags = window->flags;
  1466     window->is_destroying = SDL_FALSE;
  1467 
  1468     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1469         if (_this->CreateWindow(_this, window) < 0) {
  1470             if (loaded_opengl) {
  1471                 SDL_GL_UnloadLibrary();
  1472                 window->flags &= ~SDL_WINDOW_OPENGL;
  1473             }
  1474             return -1;
  1475         }
  1476     }
  1477 
  1478     if (flags & SDL_WINDOW_FOREIGN) {
  1479         window->flags |= SDL_WINDOW_FOREIGN;
  1480     }
  1481 
  1482     if (_this->SetWindowTitle && window->title) {
  1483         _this->SetWindowTitle(_this, window);
  1484     }
  1485 
  1486     if (_this->SetWindowIcon && window->icon) {
  1487         _this->SetWindowIcon(_this, window, window->icon);
  1488     }
  1489 
  1490     if (window->hit_test) {
  1491         _this->SetWindowHitTest(window, SDL_TRUE);
  1492     }
  1493 
  1494     SDL_FinishWindowCreation(window, flags);
  1495 
  1496     return 0;
  1497 }
  1498 
  1499 Uint32
  1500 SDL_GetWindowID(SDL_Window * window)
  1501 {
  1502     CHECK_WINDOW_MAGIC(window, 0);
  1503 
  1504     return window->id;
  1505 }
  1506 
  1507 SDL_Window *
  1508 SDL_GetWindowFromID(Uint32 id)
  1509 {
  1510     SDL_Window *window;
  1511 
  1512     if (!_this) {
  1513         return NULL;
  1514     }
  1515     for (window = _this->windows; window; window = window->next) {
  1516         if (window->id == id) {
  1517             return window;
  1518         }
  1519     }
  1520     return NULL;
  1521 }
  1522 
  1523 Uint32
  1524 SDL_GetWindowFlags(SDL_Window * window)
  1525 {
  1526     CHECK_WINDOW_MAGIC(window, 0);
  1527 
  1528     return window->flags;
  1529 }
  1530 
  1531 void
  1532 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1533 {
  1534     CHECK_WINDOW_MAGIC(window,);
  1535 
  1536     if (title == window->title) {
  1537         return;
  1538     }
  1539     SDL_free(window->title);
  1540 
  1541     window->title = SDL_strdup(title ? title : "");
  1542 
  1543     if (_this->SetWindowTitle) {
  1544         _this->SetWindowTitle(_this, window);
  1545     }
  1546 }
  1547 
  1548 const char *
  1549 SDL_GetWindowTitle(SDL_Window * window)
  1550 {
  1551     CHECK_WINDOW_MAGIC(window, "");
  1552 
  1553     return window->title ? window->title : "";
  1554 }
  1555 
  1556 void
  1557 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1558 {
  1559     CHECK_WINDOW_MAGIC(window,);
  1560 
  1561     if (!icon) {
  1562         return;
  1563     }
  1564 
  1565     SDL_FreeSurface(window->icon);
  1566 
  1567     /* Convert the icon into ARGB8888 */
  1568     window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0);
  1569     if (!window->icon) {
  1570         return;
  1571     }
  1572 
  1573     if (_this->SetWindowIcon) {
  1574         _this->SetWindowIcon(_this, window, window->icon);
  1575     }
  1576 }
  1577 
  1578 void*
  1579 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1580 {
  1581     SDL_WindowUserData *prev, *data;
  1582 
  1583     CHECK_WINDOW_MAGIC(window, NULL);
  1584 
  1585     /* Input validation */
  1586     if (name == NULL || name[0] == '\0') {
  1587       SDL_InvalidParamError("name");
  1588       return NULL;
  1589     }
  1590 
  1591     /* See if the named data already exists */
  1592     prev = NULL;
  1593     for (data = window->data; data; prev = data, data = data->next) {
  1594         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1595             void *last_value = data->data;
  1596 
  1597             if (userdata) {
  1598                 /* Set the new value */
  1599                 data->data = userdata;
  1600             } else {
  1601                 /* Delete this value */
  1602                 if (prev) {
  1603                     prev->next = data->next;
  1604                 } else {
  1605                     window->data = data->next;
  1606                 }
  1607                 SDL_free(data->name);
  1608                 SDL_free(data);
  1609             }
  1610             return last_value;
  1611         }
  1612     }
  1613 
  1614     /* Add new data to the window */
  1615     if (userdata) {
  1616         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1617         data->name = SDL_strdup(name);
  1618         data->data = userdata;
  1619         data->next = window->data;
  1620         window->data = data;
  1621     }
  1622     return NULL;
  1623 }
  1624 
  1625 void *
  1626 SDL_GetWindowData(SDL_Window * window, const char *name)
  1627 {
  1628     SDL_WindowUserData *data;
  1629 
  1630     CHECK_WINDOW_MAGIC(window, NULL);
  1631 
  1632     /* Input validation */
  1633     if (name == NULL || name[0] == '\0') {
  1634       SDL_InvalidParamError("name");
  1635       return NULL;
  1636     }
  1637 
  1638     for (data = window->data; data; data = data->next) {
  1639         if (data->name && SDL_strcmp(data->name, name) == 0) {
  1640             return data->data;
  1641         }
  1642     }
  1643     return NULL;
  1644 }
  1645 
  1646 void
  1647 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1648 {
  1649     CHECK_WINDOW_MAGIC(window,);
  1650 
  1651     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1652         int displayIndex = (x & 0xFFFF);
  1653         SDL_Rect bounds;
  1654         if (displayIndex > _this->num_displays) {
  1655             displayIndex = 0;
  1656         }
  1657 
  1658         SDL_zero(bounds);
  1659 
  1660         SDL_GetDisplayBounds(displayIndex, &bounds);
  1661         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1662             x = bounds.x + (bounds.w - window->w) / 2;
  1663         }
  1664         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1665             y = bounds.y + (bounds.h - window->h) / 2;
  1666         }
  1667     }
  1668 
  1669     if ((window->flags & SDL_WINDOW_FULLSCREEN)) {
  1670         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1671             window->windowed.x = x;
  1672         }
  1673         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1674             window->windowed.y = y;
  1675         }
  1676     } else {
  1677         if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1678             window->x = x;
  1679         }
  1680         if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1681             window->y = y;
  1682         }
  1683 
  1684         if (_this->SetWindowPosition) {
  1685             _this->SetWindowPosition(_this, window);
  1686         }
  1687         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1688     }
  1689 }
  1690 
  1691 void
  1692 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1693 {
  1694     CHECK_WINDOW_MAGIC(window,);
  1695 
  1696     /* Fullscreen windows are always at their display's origin */
  1697     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1698         int displayIndex;
  1699         
  1700         if (x) {
  1701             *x = 0;
  1702         }
  1703         if (y) {
  1704             *y = 0;
  1705         }
  1706 
  1707         /* Find the window's monitor and update to the
  1708            monitor offset. */
  1709         displayIndex = SDL_GetWindowDisplayIndex(window);
  1710         if (displayIndex >= 0) {
  1711             SDL_Rect bounds;
  1712 
  1713             SDL_zero(bounds);
  1714 
  1715             SDL_GetDisplayBounds(displayIndex, &bounds);
  1716             if (x) {
  1717                 *x = bounds.x;
  1718             }
  1719             if (y) {
  1720                 *y = bounds.y;
  1721             }
  1722         }
  1723     } else {
  1724         if (x) {
  1725             *x = window->x;
  1726         }
  1727         if (y) {
  1728             *y = window->y;
  1729         }
  1730     }
  1731 }
  1732 
  1733 void
  1734 SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered)
  1735 {
  1736     CHECK_WINDOW_MAGIC(window,);
  1737     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1738         const int want = (bordered != SDL_FALSE);  /* normalize the flag. */
  1739         const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0);
  1740         if ((want != have) && (_this->SetWindowBordered)) {
  1741             if (want) {
  1742                 window->flags &= ~SDL_WINDOW_BORDERLESS;
  1743             } else {
  1744                 window->flags |= SDL_WINDOW_BORDERLESS;
  1745             }
  1746             _this->SetWindowBordered(_this, window, (SDL_bool) want);
  1747         }
  1748     }
  1749 }
  1750 
  1751 void
  1752 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1753 {
  1754     CHECK_WINDOW_MAGIC(window,);
  1755     if (w <= 0) {
  1756         SDL_InvalidParamError("w");
  1757         return;
  1758     }
  1759     if (h <= 0) {
  1760         SDL_InvalidParamError("h");
  1761         return;
  1762     }
  1763 
  1764     /* Make sure we don't exceed any window size limits */
  1765     if (window->min_w && w < window->min_w)
  1766     {
  1767         w = window->min_w;
  1768     }
  1769     if (window->max_w && w > window->max_w)
  1770     {
  1771         w = window->max_w;
  1772     }
  1773     if (window->min_h && h < window->min_h)
  1774     {
  1775         h = window->min_h;
  1776     }
  1777     if (window->max_h && h > window->max_h)
  1778     {
  1779         h = window->max_h;
  1780     }
  1781 
  1782     window->windowed.w = w;
  1783     window->windowed.h = h;
  1784 
  1785     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1786         if (FULLSCREEN_VISIBLE(window) && (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1787             window->last_fullscreen_flags = 0;
  1788             SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1789         }
  1790     } else {
  1791         window->w = w;
  1792         window->h = h;
  1793         if (_this->SetWindowSize) {
  1794             _this->SetWindowSize(_this, window);
  1795         }
  1796         if (window->w == w && window->h == h) {
  1797             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1798             SDL_OnWindowResized(window);
  1799         }
  1800     }
  1801 }
  1802 
  1803 void
  1804 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1805 {
  1806     CHECK_WINDOW_MAGIC(window,);
  1807     if (w) {
  1808         *w = window->w;
  1809     }
  1810     if (h) {
  1811         *h = window->h;
  1812     }
  1813 }
  1814 
  1815 void
  1816 SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h)
  1817 {
  1818     CHECK_WINDOW_MAGIC(window,);
  1819     if (min_w <= 0) {
  1820         SDL_InvalidParamError("min_w");
  1821         return;
  1822     }
  1823     if (min_h <= 0) {
  1824         SDL_InvalidParamError("min_h");
  1825         return;
  1826     }
  1827 
  1828     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1829         window->min_w = min_w;
  1830         window->min_h = min_h;
  1831         if (_this->SetWindowMinimumSize) {
  1832             _this->SetWindowMinimumSize(_this, window);
  1833         }
  1834         /* Ensure that window is not smaller than minimal size */
  1835         SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h));
  1836     }
  1837 }
  1838 
  1839 void
  1840 SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h)
  1841 {
  1842     CHECK_WINDOW_MAGIC(window,);
  1843     if (min_w) {
  1844         *min_w = window->min_w;
  1845     }
  1846     if (min_h) {
  1847         *min_h = window->min_h;
  1848     }
  1849 }
  1850 
  1851 void
  1852 SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h)
  1853 {
  1854     CHECK_WINDOW_MAGIC(window,);
  1855     if (max_w <= 0) {
  1856         SDL_InvalidParamError("max_w");
  1857         return;
  1858     }
  1859     if (max_h <= 0) {
  1860         SDL_InvalidParamError("max_h");
  1861         return;
  1862     }
  1863 
  1864     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1865         window->max_w = max_w;
  1866         window->max_h = max_h;
  1867         if (_this->SetWindowMaximumSize) {
  1868             _this->SetWindowMaximumSize(_this, window);
  1869         }
  1870         /* Ensure that window is not larger than maximal size */
  1871         SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h));
  1872     }
  1873 }
  1874 
  1875 void
  1876 SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h)
  1877 {
  1878     CHECK_WINDOW_MAGIC(window,);
  1879     if (max_w) {
  1880         *max_w = window->max_w;
  1881     }
  1882     if (max_h) {
  1883         *max_h = window->max_h;
  1884     }
  1885 }
  1886 
  1887 void
  1888 SDL_ShowWindow(SDL_Window * window)
  1889 {
  1890     CHECK_WINDOW_MAGIC(window,);
  1891 
  1892     if (window->flags & SDL_WINDOW_SHOWN) {
  1893         return;
  1894     }
  1895 
  1896     if (_this->ShowWindow) {
  1897         _this->ShowWindow(_this, window);
  1898     }
  1899     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1900 }
  1901 
  1902 void
  1903 SDL_HideWindow(SDL_Window * window)
  1904 {
  1905     CHECK_WINDOW_MAGIC(window,);
  1906 
  1907     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1908         return;
  1909     }
  1910 
  1911 	window->is_hiding = SDL_TRUE;
  1912     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1913 
  1914     if (_this->HideWindow) {
  1915         _this->HideWindow(_this, window);
  1916     }
  1917 	window->is_hiding = SDL_FALSE;
  1918     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1919 }
  1920 
  1921 void
  1922 SDL_RaiseWindow(SDL_Window * window)
  1923 {
  1924     CHECK_WINDOW_MAGIC(window,);
  1925 
  1926     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1927         return;
  1928     }
  1929     if (_this->RaiseWindow) {
  1930         _this->RaiseWindow(_this, window);
  1931     }
  1932 }
  1933 
  1934 void
  1935 SDL_MaximizeWindow(SDL_Window * window)
  1936 {
  1937     CHECK_WINDOW_MAGIC(window,);
  1938 
  1939     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1940         return;
  1941     }
  1942 
  1943     /* !!! FIXME: should this check if the window is resizable? */
  1944 
  1945     if (_this->MaximizeWindow) {
  1946         _this->MaximizeWindow(_this, window);
  1947     }
  1948 }
  1949 
  1950 void
  1951 SDL_MinimizeWindow(SDL_Window * window)
  1952 {
  1953     CHECK_WINDOW_MAGIC(window,);
  1954 
  1955     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1956         return;
  1957     }
  1958 
  1959     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1960 
  1961     if (_this->MinimizeWindow) {
  1962         _this->MinimizeWindow(_this, window);
  1963     }
  1964 }
  1965 
  1966 void
  1967 SDL_RestoreWindow(SDL_Window * window)
  1968 {
  1969     CHECK_WINDOW_MAGIC(window,);
  1970 
  1971     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1972         return;
  1973     }
  1974 
  1975     if (_this->RestoreWindow) {
  1976         _this->RestoreWindow(_this, window);
  1977     }
  1978 }
  1979 
  1980 int
  1981 SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags)
  1982 {
  1983     CHECK_WINDOW_MAGIC(window, -1);
  1984 
  1985     flags &= FULLSCREEN_MASK;
  1986 
  1987     if (flags == (window->flags & FULLSCREEN_MASK)) {
  1988         return 0;
  1989     }
  1990 
  1991     /* clear the previous flags and OR in the new ones */
  1992     window->flags &= ~FULLSCREEN_MASK;
  1993     window->flags |= flags;
  1994 
  1995     return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1996 }
  1997 
  1998 static SDL_Surface *
  1999 SDL_CreateWindowFramebuffer(SDL_Window * window)
  2000 {
  2001     Uint32 format;
  2002     void *pixels;
  2003     int pitch;
  2004     int bpp;
  2005     Uint32 Rmask, Gmask, Bmask, Amask;
  2006 
  2007     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  2008         return NULL;
  2009     }
  2010 
  2011     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  2012         return NULL;
  2013     }
  2014 
  2015     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  2016         return NULL;
  2017     }
  2018 
  2019     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  2020 }
  2021 
  2022 SDL_Surface *
  2023 SDL_GetWindowSurface(SDL_Window * window)
  2024 {
  2025     CHECK_WINDOW_MAGIC(window, NULL);
  2026 
  2027     if (!window->surface_valid) {
  2028         if (window->surface) {
  2029             window->surface->flags &= ~SDL_DONTFREE;
  2030             SDL_FreeSurface(window->surface);
  2031         }
  2032         window->surface = SDL_CreateWindowFramebuffer(window);
  2033         if (window->surface) {
  2034             window->surface_valid = SDL_TRUE;
  2035             window->surface->flags |= SDL_DONTFREE;
  2036         }
  2037     }
  2038     return window->surface;
  2039 }
  2040 
  2041 int
  2042 SDL_UpdateWindowSurface(SDL_Window * window)
  2043 {
  2044     SDL_Rect full_rect;
  2045 
  2046     CHECK_WINDOW_MAGIC(window, -1);
  2047 
  2048     full_rect.x = 0;
  2049     full_rect.y = 0;
  2050     full_rect.w = window->w;
  2051     full_rect.h = window->h;
  2052     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  2053 }
  2054 
  2055 int
  2056 SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects,
  2057                              int numrects)
  2058 {
  2059     CHECK_WINDOW_MAGIC(window, -1);
  2060 
  2061     if (!window->surface_valid) {
  2062         return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  2063     }
  2064 
  2065     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  2066 }
  2067 
  2068 int
  2069 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  2070 {
  2071     Uint16 ramp[256];
  2072     int status;
  2073 
  2074     CHECK_WINDOW_MAGIC(window, -1);
  2075 
  2076     SDL_CalculateGammaRamp(brightness, ramp);
  2077     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  2078     if (status == 0) {
  2079         window->brightness = brightness;
  2080     }
  2081     return status;
  2082 }
  2083 
  2084 float
  2085 SDL_GetWindowBrightness(SDL_Window * window)
  2086 {
  2087     CHECK_WINDOW_MAGIC(window, 1.0f);
  2088 
  2089     return window->brightness;
  2090 }
  2091 
  2092 int
  2093 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  2094                                             const Uint16 * green,
  2095                                             const Uint16 * blue)
  2096 {
  2097     CHECK_WINDOW_MAGIC(window, -1);
  2098 
  2099     if (!_this->SetWindowGammaRamp) {
  2100         return SDL_Unsupported();
  2101     }
  2102 
  2103     if (!window->gamma) {
  2104         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  2105             return -1;
  2106         }
  2107         SDL_assert(window->gamma != NULL);
  2108     }
  2109 
  2110     if (red) {
  2111         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  2112     }
  2113     if (green) {
  2114         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  2115     }
  2116     if (blue) {
  2117         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  2118     }
  2119     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2120         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  2121     } else {
  2122         return 0;
  2123     }
  2124 }
  2125 
  2126 int
  2127 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  2128                                             Uint16 * green,
  2129                                             Uint16 * blue)
  2130 {
  2131     CHECK_WINDOW_MAGIC(window, -1);
  2132 
  2133     if (!window->gamma) {
  2134         int i;
  2135 
  2136         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  2137         if (!window->gamma) {
  2138             return SDL_OutOfMemory();
  2139         }
  2140         window->saved_gamma = window->gamma + 3*256;
  2141 
  2142         if (_this->GetWindowGammaRamp) {
  2143             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  2144                 return -1;
  2145             }
  2146         } else {
  2147             /* Create an identity gamma ramp */
  2148             for (i = 0; i < 256; ++i) {
  2149                 Uint16 value = (Uint16)((i << 8) | i);
  2150 
  2151                 window->gamma[0*256+i] = value;
  2152                 window->gamma[1*256+i] = value;
  2153                 window->gamma[2*256+i] = value;
  2154             }
  2155         }
  2156         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  2157     }
  2158 
  2159     if (red) {
  2160         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  2161     }
  2162     if (green) {
  2163         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  2164     }
  2165     if (blue) {
  2166         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  2167     }
  2168     return 0;
  2169 }
  2170 
  2171 void
  2172 SDL_UpdateWindowGrab(SDL_Window * window)
  2173 {
  2174     SDL_Window *grabbed_window;
  2175     SDL_bool grabbed;
  2176     if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
  2177          (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  2178         grabbed = SDL_TRUE;
  2179     } else {
  2180         grabbed = SDL_FALSE;
  2181     }
  2182 
  2183     grabbed_window = _this->grabbed_window;
  2184     if (grabbed) {
  2185         if (grabbed_window && (grabbed_window != window)) {
  2186             /* stealing a grab from another window! */
  2187             grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2188             if (_this->SetWindowGrab) {
  2189                 _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE);
  2190             }
  2191         }
  2192         _this->grabbed_window = window;
  2193     } else if (grabbed_window == window) {
  2194         _this->grabbed_window = NULL;  /* ungrabbing. */
  2195     }
  2196 
  2197     if (_this->SetWindowGrab) {
  2198         _this->SetWindowGrab(_this, window, grabbed);
  2199     }
  2200 }
  2201 
  2202 void
  2203 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  2204 {
  2205     CHECK_WINDOW_MAGIC(window,);
  2206 
  2207     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  2208         return;
  2209     }
  2210     if (grabbed) {
  2211         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  2212     } else {
  2213         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  2214     }
  2215     SDL_UpdateWindowGrab(window);
  2216 }
  2217 
  2218 SDL_bool
  2219 SDL_GetWindowGrab(SDL_Window * window)
  2220 {
  2221     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2222     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
  2223     return window == _this->grabbed_window;
  2224 }
  2225 
  2226 SDL_Window *
  2227 SDL_GetGrabbedWindow(void)
  2228 {
  2229     SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
  2230     return _this->grabbed_window;
  2231 }
  2232 
  2233 void
  2234 SDL_OnWindowShown(SDL_Window * window)
  2235 {
  2236     SDL_OnWindowRestored(window);
  2237 }
  2238 
  2239 void
  2240 SDL_OnWindowHidden(SDL_Window * window)
  2241 {
  2242     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2243 }
  2244 
  2245 void
  2246 SDL_OnWindowResized(SDL_Window * window)
  2247 {
  2248     window->surface_valid = SDL_FALSE;
  2249     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  2250 }
  2251 
  2252 void
  2253 SDL_OnWindowMinimized(SDL_Window * window)
  2254 {
  2255     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  2256 }
  2257 
  2258 void
  2259 SDL_OnWindowRestored(SDL_Window * window)
  2260 {
  2261     /*
  2262      * FIXME: Is this fine to just remove this, or should it be preserved just
  2263      * for the fullscreen case? In principle it seems like just hiding/showing
  2264      * windows shouldn't affect the stacking order; maybe the right fix is to
  2265      * re-decouple OnWindowShown and OnWindowRestored.
  2266      */
  2267     /*SDL_RaiseWindow(window);*/
  2268 
  2269     if (FULLSCREEN_VISIBLE(window)) {
  2270         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  2271     }
  2272 }
  2273 
  2274 void
  2275 SDL_OnWindowEnter(SDL_Window * window)
  2276 {
  2277     if (_this->OnWindowEnter) {
  2278         _this->OnWindowEnter(_this, window);
  2279     }
  2280 }
  2281 
  2282 void
  2283 SDL_OnWindowLeave(SDL_Window * window)
  2284 {
  2285 }
  2286 
  2287 void
  2288 SDL_OnWindowFocusGained(SDL_Window * window)
  2289 {
  2290     SDL_Mouse *mouse = SDL_GetMouse();
  2291 
  2292     if (window->gamma && _this->SetWindowGammaRamp) {
  2293         _this->SetWindowGammaRamp(_this, window, window->gamma);
  2294     }
  2295 
  2296     if (mouse && mouse->relative_mode) {
  2297         SDL_SetMouseFocus(window);
  2298         SDL_WarpMouseInWindow(window, window->w/2, window->h/2);
  2299     }
  2300 
  2301     SDL_UpdateWindowGrab(window);
  2302 }
  2303 
  2304 static SDL_bool
  2305 ShouldMinimizeOnFocusLoss(SDL_Window * window)
  2306 {
  2307     const char *hint;
  2308 
  2309     if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) {
  2310         return SDL_FALSE;
  2311     }
  2312 
  2313 #ifdef __MACOSX__
  2314     if (Cocoa_IsWindowInFullscreenSpace(window)) {
  2315         return SDL_FALSE;
  2316     }
  2317 #endif
  2318 
  2319     hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
  2320     if (hint) {
  2321         if (*hint == '0') {
  2322             return SDL_FALSE;
  2323         } else {
  2324             return SDL_TRUE;
  2325         }
  2326     }
  2327 
  2328     return SDL_TRUE;
  2329 }
  2330 
  2331 void
  2332 SDL_OnWindowFocusLost(SDL_Window * window)
  2333 {
  2334     if (window->gamma && _this->SetWindowGammaRamp) {
  2335         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  2336     }
  2337 
  2338     SDL_UpdateWindowGrab(window);
  2339 
  2340     if (ShouldMinimizeOnFocusLoss(window)) {
  2341         SDL_MinimizeWindow(window);
  2342     }
  2343 }
  2344 
  2345 /* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
  2346    !!! FIXME:  Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
  2347 SDL_Window *
  2348 SDL_GetFocusWindow(void)
  2349 {
  2350     SDL_Window *window;
  2351 
  2352     if (!_this) {
  2353         return NULL;
  2354     }
  2355     for (window = _this->windows; window; window = window->next) {
  2356         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  2357             return window;
  2358         }
  2359     }
  2360     return NULL;
  2361 }
  2362 
  2363 void
  2364 SDL_DestroyWindow(SDL_Window * window)
  2365 {
  2366     SDL_VideoDisplay *display;
  2367 
  2368     CHECK_WINDOW_MAGIC(window,);
  2369 
  2370     window->is_destroying = SDL_TRUE;
  2371 
  2372     /* Restore video mode, etc. */
  2373     SDL_HideWindow(window);
  2374 
  2375     /* Make sure this window no longer has focus */
  2376     if (SDL_GetKeyboardFocus() == window) {
  2377         SDL_SetKeyboardFocus(NULL);
  2378     }
  2379     if (SDL_GetMouseFocus() == window) {
  2380         SDL_SetMouseFocus(NULL);
  2381     }
  2382 
  2383     /* make no context current if this is the current context window. */
  2384     if (window->flags & SDL_WINDOW_OPENGL) {
  2385         if (_this->current_glwin == window) {
  2386             SDL_GL_MakeCurrent(window, NULL);
  2387         }
  2388     }
  2389 
  2390     if (window->surface) {
  2391         window->surface->flags &= ~SDL_DONTFREE;
  2392         SDL_FreeSurface(window->surface);
  2393     }
  2394     if (_this->DestroyWindowFramebuffer) {
  2395         _this->DestroyWindowFramebuffer(_this, window);
  2396     }
  2397     if (_this->DestroyWindow) {
  2398         _this->DestroyWindow(_this, window);
  2399     }
  2400     if (window->flags & SDL_WINDOW_OPENGL) {
  2401         SDL_GL_UnloadLibrary();
  2402     }
  2403 
  2404     display = SDL_GetDisplayForWindow(window);
  2405     if (display->fullscreen_window == window) {
  2406         display->fullscreen_window = NULL;
  2407     }
  2408 
  2409     /* Now invalidate magic */
  2410     window->magic = NULL;
  2411 
  2412     /* Free memory associated with the window */
  2413     SDL_free(window->title);
  2414     SDL_FreeSurface(window->icon);
  2415     SDL_free(window->gamma);
  2416     while (window->data) {
  2417         SDL_WindowUserData *data = window->data;
  2418 
  2419         window->data = data->next;
  2420         SDL_free(data->name);
  2421         SDL_free(data);
  2422     }
  2423 
  2424     /* Unlink the window from the list */
  2425     if (window->next) {
  2426         window->next->prev = window->prev;
  2427     }
  2428     if (window->prev) {
  2429         window->prev->next = window->next;
  2430     } else {
  2431         _this->windows = window->next;
  2432     }
  2433 
  2434     SDL_free(window);
  2435 }
  2436 
  2437 SDL_bool
  2438 SDL_IsScreenSaverEnabled()
  2439 {
  2440     if (!_this) {
  2441         return SDL_TRUE;
  2442     }
  2443     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2444 }
  2445 
  2446 void
  2447 SDL_EnableScreenSaver()
  2448 {
  2449     if (!_this) {
  2450         return;
  2451     }
  2452     if (!_this->suspend_screensaver) {
  2453         return;
  2454     }
  2455     _this->suspend_screensaver = SDL_FALSE;
  2456     if (_this->SuspendScreenSaver) {
  2457         _this->SuspendScreenSaver(_this);
  2458     }
  2459 }
  2460 
  2461 void
  2462 SDL_DisableScreenSaver()
  2463 {
  2464     if (!_this) {
  2465         return;
  2466     }
  2467     if (_this->suspend_screensaver) {
  2468         return;
  2469     }
  2470     _this->suspend_screensaver = SDL_TRUE;
  2471     if (_this->SuspendScreenSaver) {
  2472         _this->SuspendScreenSaver(_this);
  2473     }
  2474 }
  2475 
  2476 void
  2477 SDL_VideoQuit(void)
  2478 {
  2479     int i, j;
  2480 
  2481     if (!_this) {
  2482         return;
  2483     }
  2484 
  2485     /* Halt event processing before doing anything else */
  2486     SDL_TouchQuit();
  2487     SDL_MouseQuit();
  2488     SDL_KeyboardQuit();
  2489     SDL_QuitSubSystem(SDL_INIT_EVENTS);
  2490 
  2491     SDL_EnableScreenSaver();
  2492 
  2493     /* Clean up the system video */
  2494     while (_this->windows) {
  2495         SDL_DestroyWindow(_this->windows);
  2496     }
  2497     _this->VideoQuit(_this);
  2498 
  2499     for (i = 0; i < _this->num_displays; ++i) {
  2500         SDL_VideoDisplay *display = &_this->displays[i];
  2501         for (j = display->num_display_modes; j--;) {
  2502             SDL_free(display->display_modes[j].driverdata);
  2503             display->display_modes[j].driverdata = NULL;
  2504         }
  2505         SDL_free(display->display_modes);
  2506         display->display_modes = NULL;
  2507         SDL_free(display->desktop_mode.driverdata);
  2508         display->desktop_mode.driverdata = NULL;
  2509         SDL_free(display->driverdata);
  2510         display->driverdata = NULL;
  2511     }
  2512     if (_this->displays) {
  2513         for (i = 0; i < _this->num_displays; ++i) {
  2514             SDL_free(_this->displays[i].name);
  2515         }
  2516         SDL_free(_this->displays);
  2517         _this->displays = NULL;
  2518         _this->num_displays = 0;
  2519     }
  2520     SDL_free(_this->clipboard_text);
  2521     _this->clipboard_text = NULL;
  2522     _this->free(_this);
  2523     _this = NULL;
  2524 }
  2525 
  2526 int
  2527 SDL_GL_LoadLibrary(const char *path)
  2528 {
  2529     int retval;
  2530 
  2531     if (!_this) {
  2532         return SDL_UninitializedVideo();
  2533     }
  2534     if (_this->gl_config.driver_loaded) {
  2535         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2536             return SDL_SetError("OpenGL library already loaded");
  2537         }
  2538         retval = 0;
  2539     } else {
  2540         if (!_this->GL_LoadLibrary) {
  2541             return SDL_SetError("No dynamic GL support in video driver");
  2542         }
  2543         retval = _this->GL_LoadLibrary(_this, path);
  2544     }
  2545     if (retval == 0) {
  2546         ++_this->gl_config.driver_loaded;
  2547     } else {
  2548         if (_this->GL_UnloadLibrary) {
  2549             _this->GL_UnloadLibrary(_this);
  2550         }
  2551     }
  2552     return (retval);
  2553 }
  2554 
  2555 void *
  2556 SDL_GL_GetProcAddress(const char *proc)
  2557 {
  2558     void *func;
  2559 
  2560     if (!_this) {
  2561         SDL_UninitializedVideo();
  2562         return NULL;
  2563     }
  2564     func = NULL;
  2565     if (_this->GL_GetProcAddress) {
  2566         if (_this->gl_config.driver_loaded) {
  2567             func = _this->GL_GetProcAddress(_this, proc);
  2568         } else {
  2569             SDL_SetError("No GL driver has been loaded");
  2570         }
  2571     } else {
  2572         SDL_SetError("No dynamic GL support in video driver");
  2573     }
  2574     return func;
  2575 }
  2576 
  2577 void
  2578 SDL_GL_UnloadLibrary(void)
  2579 {
  2580     if (!_this) {
  2581         SDL_UninitializedVideo();
  2582         return;
  2583     }
  2584     if (_this->gl_config.driver_loaded > 0) {
  2585         if (--_this->gl_config.driver_loaded > 0) {
  2586             return;
  2587         }
  2588         if (_this->GL_UnloadLibrary) {
  2589             _this->GL_UnloadLibrary(_this);
  2590         }
  2591     }
  2592 }
  2593 
  2594 static SDL_INLINE SDL_bool
  2595 isAtLeastGL3(const char *verstr)
  2596 {
  2597     return (verstr && (SDL_atoi(verstr) >= 3));
  2598 }
  2599 
  2600 SDL_bool
  2601 SDL_GL_ExtensionSupported(const char *extension)
  2602 {
  2603 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2604     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2605     const char *extensions;
  2606     const char *start;
  2607     const char *where, *terminator;
  2608 
  2609     /* Extension names should not have spaces. */
  2610     where = SDL_strchr(extension, ' ');
  2611     if (where || *extension == '\0') {
  2612         return SDL_FALSE;
  2613     }
  2614     /* See if there's an environment variable override */
  2615     start = SDL_getenv(extension);
  2616     if (start && *start == '0') {
  2617         return SDL_FALSE;
  2618     }
  2619 
  2620     /* Lookup the available extensions */
  2621 
  2622     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2623     if (!glGetStringFunc) {
  2624         return SDL_FALSE;
  2625     }
  2626 
  2627     if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  2628         const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint);
  2629         void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2630         GLint num_exts = 0;
  2631         GLint i;
  2632 
  2633         glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi");
  2634         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2635         if ((!glGetStringiFunc) || (!glGetIntegervFunc)) {
  2636             return SDL_FALSE;
  2637         }
  2638 
  2639         #ifndef GL_NUM_EXTENSIONS
  2640         #define GL_NUM_EXTENSIONS 0x821D
  2641         #endif
  2642         glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts);
  2643         for (i = 0; i < num_exts; i++) {
  2644             const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i);
  2645             if (SDL_strcmp(thisext, extension) == 0) {
  2646                 return SDL_TRUE;
  2647             }
  2648         }
  2649 
  2650         return SDL_FALSE;
  2651     }
  2652 
  2653     /* Try the old way with glGetString(GL_EXTENSIONS) ... */
  2654 
  2655     extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2656     if (!extensions) {
  2657         return SDL_FALSE;
  2658     }
  2659     /*
  2660      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2661      * extensions string. Don't be fooled by sub-strings, etc.
  2662      */
  2663 
  2664     start = extensions;
  2665 
  2666     for (;;) {
  2667         where = SDL_strstr(start, extension);
  2668         if (!where)
  2669             break;
  2670 
  2671         terminator = where + SDL_strlen(extension);
  2672         if (where == start || *(where - 1) == ' ')
  2673             if (*terminator == ' ' || *terminator == '\0')
  2674                 return SDL_TRUE;
  2675 
  2676         start = terminator;
  2677     }
  2678     return SDL_FALSE;
  2679 #else
  2680     return SDL_FALSE;
  2681 #endif
  2682 }
  2683 
  2684 void
  2685 SDL_GL_ResetAttributes()
  2686 {
  2687     if (!_this) {
  2688         return;
  2689     }
  2690 
  2691     _this->gl_config.red_size = 3;
  2692     _this->gl_config.green_size = 3;
  2693     _this->gl_config.blue_size = 2;
  2694     _this->gl_config.alpha_size = 0;
  2695     _this->gl_config.buffer_size = 0;
  2696     _this->gl_config.depth_size = 16;
  2697     _this->gl_config.stencil_size = 0;
  2698     _this->gl_config.double_buffer = 1;
  2699     _this->gl_config.accum_red_size = 0;
  2700     _this->gl_config.accum_green_size = 0;
  2701     _this->gl_config.accum_blue_size = 0;
  2702     _this->gl_config.accum_alpha_size = 0;
  2703     _this->gl_config.stereo = 0;
  2704     _this->gl_config.multisamplebuffers = 0;
  2705     _this->gl_config.multisamplesamples = 0;
  2706     _this->gl_config.retained_backing = 1;
  2707     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
  2708     _this->gl_config.profile_mask = 0;
  2709 #if SDL_VIDEO_OPENGL
  2710     _this->gl_config.major_version = 2;
  2711     _this->gl_config.minor_version = 1;
  2712 #elif SDL_VIDEO_OPENGL_ES2
  2713     _this->gl_config.major_version = 2;
  2714     _this->gl_config.minor_version = 0;
  2715     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2716 #elif SDL_VIDEO_OPENGL_ES
  2717     _this->gl_config.major_version = 1;
  2718     _this->gl_config.minor_version = 1;
  2719     _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
  2720 #endif
  2721     _this->gl_config.flags = 0;
  2722     _this->gl_config.framebuffer_srgb_capable = 0;
  2723     _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH;
  2724 
  2725     _this->gl_config.share_with_current_context = 0;
  2726 }
  2727 
  2728 int
  2729 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2730 {
  2731 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2732     int retval;
  2733 
  2734     if (!_this) {
  2735         return SDL_UninitializedVideo();
  2736     }
  2737     retval = 0;
  2738     switch (attr) {
  2739     case SDL_GL_RED_SIZE:
  2740         _this->gl_config.red_size = value;
  2741         break;
  2742     case SDL_GL_GREEN_SIZE:
  2743         _this->gl_config.green_size = value;
  2744         break;
  2745     case SDL_GL_BLUE_SIZE:
  2746         _this->gl_config.blue_size = value;
  2747         break;
  2748     case SDL_GL_ALPHA_SIZE:
  2749         _this->gl_config.alpha_size = value;
  2750         break;
  2751     case SDL_GL_DOUBLEBUFFER:
  2752         _this->gl_config.double_buffer = value;
  2753         break;
  2754     case SDL_GL_BUFFER_SIZE:
  2755         _this->gl_config.buffer_size = value;
  2756         break;
  2757     case SDL_GL_DEPTH_SIZE:
  2758         _this->gl_config.depth_size = value;
  2759         break;
  2760     case SDL_GL_STENCIL_SIZE:
  2761         _this->gl_config.stencil_size = value;
  2762         break;
  2763     case SDL_GL_ACCUM_RED_SIZE:
  2764         _this->gl_config.accum_red_size = value;
  2765         break;
  2766     case SDL_GL_ACCUM_GREEN_SIZE:
  2767         _this->gl_config.accum_green_size = value;
  2768         break;
  2769     case SDL_GL_ACCUM_BLUE_SIZE:
  2770         _this->gl_config.accum_blue_size = value;
  2771         break;
  2772     case SDL_GL_ACCUM_ALPHA_SIZE:
  2773         _this->gl_config.accum_alpha_size = value;
  2774         break;
  2775     case SDL_GL_STEREO:
  2776         _this->gl_config.stereo = value;
  2777         break;
  2778     case SDL_GL_MULTISAMPLEBUFFERS:
  2779         _this->gl_config.multisamplebuffers = value;
  2780         break;
  2781     case SDL_GL_MULTISAMPLESAMPLES:
  2782         _this->gl_config.multisamplesamples = value;
  2783         break;
  2784     case SDL_GL_ACCELERATED_VISUAL:
  2785         _this->gl_config.accelerated = value;
  2786         break;
  2787     case SDL_GL_RETAINED_BACKING:
  2788         _this->gl_config.retained_backing = value;
  2789         break;
  2790     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2791         _this->gl_config.major_version = value;
  2792         break;
  2793     case SDL_GL_CONTEXT_MINOR_VERSION:
  2794         _this->gl_config.minor_version = value;
  2795         break;
  2796     case SDL_GL_CONTEXT_EGL:
  2797         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  2798         if (value != 0) {
  2799             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
  2800         } else {
  2801             SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  2802         };
  2803         break;
  2804     case SDL_GL_CONTEXT_FLAGS:
  2805         if (value & ~(SDL_GL_CONTEXT_DEBUG_FLAG |
  2806                       SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG |
  2807                       SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG |
  2808                       SDL_GL_CONTEXT_RESET_ISOLATION_FLAG)) {
  2809             retval = SDL_SetError("Unknown OpenGL context flag %d", value);
  2810             break;
  2811         }
  2812         _this->gl_config.flags = value;
  2813         break;
  2814     case SDL_GL_CONTEXT_PROFILE_MASK:
  2815         if (value != 0 &&
  2816             value != SDL_GL_CONTEXT_PROFILE_CORE &&
  2817             value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY &&
  2818             value != SDL_GL_CONTEXT_PROFILE_ES) {
  2819             retval = SDL_SetError("Unknown OpenGL context profile %d", value);
  2820             break;
  2821         }
  2822         _this->gl_config.profile_mask = value;
  2823         break;
  2824     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  2825         _this->gl_config.share_with_current_context = value;
  2826         break;
  2827     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  2828         _this->gl_config.framebuffer_srgb_capable = value;
  2829         break;
  2830     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
  2831         _this->gl_config.release_behavior = value;
  2832         break;
  2833     default:
  2834         retval = SDL_SetError("Unknown OpenGL attribute");
  2835         break;
  2836     }
  2837     return retval;
  2838 #else
  2839     return SDL_Unsupported();
  2840 #endif /* SDL_VIDEO_OPENGL */
  2841 }
  2842 
  2843 int
  2844 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2845 {
  2846 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2847     GLenum (APIENTRY *glGetErrorFunc) (void);
  2848     GLenum attrib = 0;
  2849     GLenum error = 0;
  2850 
  2851     /*
  2852      * Some queries in Core Profile desktop OpenGL 3+ contexts require
  2853      * glGetFramebufferAttachmentParameteriv instead of glGetIntegerv. Note that
  2854      * the enums we use for the former function don't exist in OpenGL ES 2, and
  2855      * the function itself doesn't exist prior to OpenGL 3 and OpenGL ES 2.
  2856      */
  2857 #if SDL_VIDEO_OPENGL
  2858     const GLubyte *(APIENTRY *glGetStringFunc) (GLenum name);
  2859     void (APIENTRY *glGetFramebufferAttachmentParameterivFunc) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
  2860     GLenum attachment = GL_BACK_LEFT;
  2861     GLenum attachmentattrib = 0;
  2862 
  2863     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2864     if (!glGetStringFunc) {
  2865         return SDL_SetError("Failed getting OpenGL glGetString entry point");
  2866     }
  2867 #endif
  2868 
  2869     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2870     if (!glGetErrorFunc) {
  2871         return SDL_SetError("Failed getting OpenGL glGetError entry point");
  2872     }
  2873 
  2874     /* Clear value in any case */
  2875     *value = 0;
  2876 
  2877     switch (attr) {
  2878     case SDL_GL_RED_SIZE:
  2879 #if SDL_VIDEO_OPENGL
  2880         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE;
  2881 #endif
  2882         attrib = GL_RED_BITS;
  2883         break;
  2884     case SDL_GL_BLUE_SIZE:
  2885 #if SDL_VIDEO_OPENGL
  2886         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE;
  2887 #endif
  2888         attrib = GL_BLUE_BITS;
  2889         break;
  2890     case SDL_GL_GREEN_SIZE:
  2891 #if SDL_VIDEO_OPENGL
  2892         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE;
  2893 #endif
  2894         attrib = GL_GREEN_BITS;
  2895         break;
  2896     case SDL_GL_ALPHA_SIZE:
  2897 #if SDL_VIDEO_OPENGL
  2898         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE;
  2899 #endif
  2900         attrib = GL_ALPHA_BITS;
  2901         break;
  2902     case SDL_GL_DOUBLEBUFFER:
  2903 #if SDL_VIDEO_OPENGL
  2904         attrib = GL_DOUBLEBUFFER;
  2905         break;
  2906 #else
  2907         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2908         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2909         /* SDL driver must set proper value after initialization              */
  2910         *value = _this->gl_config.double_buffer;
  2911         return 0;
  2912 #endif
  2913     case SDL_GL_DEPTH_SIZE:
  2914 #if SDL_VIDEO_OPENGL
  2915         attachment = GL_DEPTH;
  2916         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE;
  2917 #endif
  2918         attrib = GL_DEPTH_BITS;
  2919         break;
  2920     case SDL_GL_STENCIL_SIZE:
  2921 #if SDL_VIDEO_OPENGL
  2922         attachment = GL_STENCIL;
  2923         attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE;
  2924 #endif
  2925         attrib = GL_STENCIL_BITS;
  2926         break;
  2927 #if SDL_VIDEO_OPENGL
  2928     case SDL_GL_ACCUM_RED_SIZE:
  2929         attrib = GL_ACCUM_RED_BITS;
  2930         break;
  2931     case SDL_GL_ACCUM_GREEN_SIZE:
  2932         attrib = GL_ACCUM_GREEN_BITS;
  2933         break;
  2934     case SDL_GL_ACCUM_BLUE_SIZE:
  2935         attrib = GL_ACCUM_BLUE_BITS;
  2936         break;
  2937     case SDL_GL_ACCUM_ALPHA_SIZE:
  2938         attrib = GL_ACCUM_ALPHA_BITS;
  2939         break;
  2940     case SDL_GL_STEREO:
  2941         attrib = GL_STEREO;
  2942         break;
  2943 #else
  2944     case SDL_GL_ACCUM_RED_SIZE:
  2945     case SDL_GL_ACCUM_GREEN_SIZE:
  2946     case SDL_GL_ACCUM_BLUE_SIZE:
  2947     case SDL_GL_ACCUM_ALPHA_SIZE:
  2948     case SDL_GL_STEREO:
  2949         /* none of these are supported in OpenGL ES */
  2950         *value = 0;
  2951         return 0;
  2952 #endif
  2953     case SDL_GL_MULTISAMPLEBUFFERS:
  2954         attrib = GL_SAMPLE_BUFFERS;
  2955         break;
  2956     case SDL_GL_MULTISAMPLESAMPLES:
  2957         attrib = GL_SAMPLES;
  2958         break;
  2959     case SDL_GL_CONTEXT_RELEASE_BEHAVIOR:
  2960 #if SDL_VIDEO_OPENGL
  2961         attrib = GL_CONTEXT_RELEASE_BEHAVIOR;
  2962 #else
  2963         attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR;
  2964 #endif
  2965         break;
  2966     case SDL_GL_BUFFER_SIZE:
  2967         {
  2968             int rsize = 0, gsize = 0, bsize = 0, asize = 0;
  2969 
  2970             /* There doesn't seem to be a single flag in OpenGL for this! */
  2971             if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &rsize) < 0) {
  2972                 return -1;
  2973             }
  2974             if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gsize) < 0) {
  2975                 return -1;
  2976             }
  2977             if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &bsize) < 0) {
  2978                 return -1;
  2979             }
  2980             if (SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &asize) < 0) {
  2981                 return -1;
  2982             }
  2983 
  2984             *value = rsize + gsize + bsize + asize;
  2985             return 0;
  2986         }
  2987     case SDL_GL_ACCELERATED_VISUAL:
  2988         {
  2989             /* FIXME: How do we get this information? */
  2990             *value = (_this->gl_config.accelerated != 0);
  2991             return 0;
  2992         }
  2993     case SDL_GL_RETAINED_BACKING:
  2994         {
  2995             *value = _this->gl_config.retained_backing;
  2996             return 0;
  2997         }
  2998     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2999         {
  3000             *value = _this->gl_config.major_version;
  3001             return 0;
  3002         }
  3003     case SDL_GL_CONTEXT_MINOR_VERSION:
  3004         {
  3005             *value = _this->gl_config.minor_version;
  3006             return 0;
  3007         }
  3008     case SDL_GL_CONTEXT_EGL:
  3009         /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */
  3010         {
  3011             if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  3012                 *value = 1;
  3013             }
  3014             else {
  3015                 *value = 0;
  3016             }
  3017             return 0;
  3018         }
  3019     case SDL_GL_CONTEXT_FLAGS:
  3020         {
  3021             *value = _this->gl_config.flags;
  3022             return 0;
  3023         }
  3024     case SDL_GL_CONTEXT_PROFILE_MASK:
  3025         {
  3026             *value = _this->gl_config.profile_mask;
  3027             return 0;
  3028         }
  3029     case SDL_GL_SHARE_WITH_CURRENT_CONTEXT:
  3030         {
  3031             *value = _this->gl_config.share_with_current_context;
  3032             return 0;
  3033         }
  3034     case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE:
  3035         {
  3036             *value = _this->gl_config.framebuffer_srgb_capable;
  3037             return 0;
  3038         }
  3039     default:
  3040         return SDL_SetError("Unknown OpenGL attribute");
  3041     }
  3042 
  3043 #if SDL_VIDEO_OPENGL
  3044     if (attachmentattrib && isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) {
  3045         glGetFramebufferAttachmentParameterivFunc = SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameteriv");
  3046 
  3047         if (glGetFramebufferAttachmentParameterivFunc) {
  3048             glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *) value);
  3049         } else {
  3050             return SDL_SetError("Failed getting OpenGL glGetFramebufferAttachmentParameteriv entry point");
  3051         }
  3052     } else
  3053 #endif
  3054     {
  3055         void (APIENTRY *glGetIntegervFunc) (GLenum pname, GLint * params);
  3056         glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  3057         if (glGetIntegervFunc) {
  3058             glGetIntegervFunc(attrib, (GLint *) value);
  3059         } else {
  3060             return SDL_SetError("Failed getting OpenGL glGetIntegerv entry point");
  3061         }
  3062     }
  3063 
  3064     error = glGetErrorFunc();
  3065     if (error != GL_NO_ERROR) {
  3066         if (error == GL_INVALID_ENUM) {
  3067             return SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  3068         } else if (error == GL_INVALID_VALUE) {
  3069             return SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  3070         }
  3071         return SDL_SetError("OpenGL error: %08X", error);
  3072     }
  3073     return 0;
  3074 #else
  3075     return SDL_Unsupported();
  3076 #endif /* SDL_VIDEO_OPENGL */
  3077 }
  3078 
  3079 SDL_GLContext
  3080 SDL_GL_CreateContext(SDL_Window * window)
  3081 {
  3082     SDL_GLContext ctx = NULL;
  3083     CHECK_WINDOW_MAGIC(window, NULL);
  3084 
  3085     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3086         SDL_SetError("The specified window isn't an OpenGL window");
  3087         return NULL;
  3088     }
  3089 
  3090     ctx = _this->GL_CreateContext(_this, window);
  3091 
  3092     /* Creating a context is assumed to make it current in the SDL driver. */
  3093     if (ctx) {
  3094         _this->current_glwin = window;
  3095         _this->current_glctx = ctx;
  3096         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  3097         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  3098     }
  3099     return ctx;
  3100 }
  3101 
  3102 int
  3103 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  3104 {
  3105     int retval;
  3106 
  3107     if (window == SDL_GL_GetCurrentWindow() &&
  3108         ctx == SDL_GL_GetCurrentContext()) {
  3109         /* We're already current. */
  3110         return 0;
  3111     }
  3112 
  3113     if (!ctx) {
  3114         window = NULL;
  3115     } else {
  3116         CHECK_WINDOW_MAGIC(window, -1);
  3117 
  3118         if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3119             return SDL_SetError("The specified window isn't an OpenGL window");
  3120         }
  3121     }
  3122 
  3123     retval = _this->GL_MakeCurrent(_this, window, ctx);
  3124     if (retval == 0) {
  3125         _this->current_glwin = window;
  3126         _this->current_glctx = ctx;
  3127         SDL_TLSSet(_this->current_glwin_tls, window, NULL);
  3128         SDL_TLSSet(_this->current_glctx_tls, ctx, NULL);
  3129     }
  3130     return retval;
  3131 }
  3132 
  3133 SDL_Window *
  3134 SDL_GL_GetCurrentWindow(void)
  3135 {
  3136     if (!_this) {
  3137         SDL_UninitializedVideo();
  3138         return NULL;
  3139     }
  3140     return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls);
  3141 }
  3142 
  3143 SDL_GLContext
  3144 SDL_GL_GetCurrentContext(void)
  3145 {
  3146     if (!_this) {
  3147         SDL_UninitializedVideo();
  3148         return NULL;
  3149     }
  3150     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
  3151 }
  3152 
  3153 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
  3154 {
  3155     CHECK_WINDOW_MAGIC(window,);
  3156 
  3157     if (_this->GL_GetDrawableSize) {
  3158         _this->GL_GetDrawableSize(_this, window, w, h);
  3159     } else {
  3160         SDL_GetWindowSize(window, w, h);
  3161     }
  3162 }
  3163 
  3164 int
  3165 SDL_GL_SetSwapInterval(int interval)
  3166 {
  3167     if (!_this) {
  3168         return SDL_UninitializedVideo();
  3169     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3170         return SDL_SetError("No OpenGL context has been made current");
  3171     } else if (_this->GL_SetSwapInterval) {
  3172         return _this->GL_SetSwapInterval(_this, interval);
  3173     } else {
  3174         return SDL_SetError("Setting the swap interval is not supported");
  3175     }
  3176 }
  3177 
  3178 int
  3179 SDL_GL_GetSwapInterval(void)
  3180 {
  3181     if (!_this) {
  3182         return 0;
  3183     } else if (SDL_GL_GetCurrentContext() == NULL) {
  3184         return 0;
  3185     } else if (_this->GL_GetSwapInterval) {
  3186         return _this->GL_GetSwapInterval(_this);
  3187     } else {
  3188         return 0;
  3189     }
  3190 }
  3191 
  3192 void
  3193 SDL_GL_SwapWindow(SDL_Window * window)
  3194 {
  3195     CHECK_WINDOW_MAGIC(window,);
  3196 
  3197     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3198         SDL_SetError("The specified window isn't an OpenGL window");
  3199         return;
  3200     }
  3201 
  3202     if (SDL_GL_GetCurrentWindow() != window) {
  3203         SDL_SetError("The specified window has not been made current");
  3204         return;
  3205     }
  3206 
  3207     _this->GL_SwapWindow(_this, window);
  3208 }
  3209 
  3210 void
  3211 SDL_GL_DeleteContext(SDL_GLContext context)
  3212 {
  3213     if (!_this || !context) {
  3214         return;
  3215     }
  3216 
  3217     if (SDL_GL_GetCurrentContext() == context) {
  3218         SDL_GL_MakeCurrent(NULL, NULL);
  3219     }
  3220 
  3221     _this->GL_DeleteContext(_this, context);
  3222 }
  3223 
  3224 #if 0                           /* FIXME */
  3225 /*
  3226  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  3227  * & 2 for alpha channel.
  3228  */
  3229 static void
  3230 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  3231 {
  3232     int x, y;
  3233     Uint32 colorkey;
  3234 #define SET_MASKBIT(icon, x, y, mask) \
  3235     mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  3236 
  3237     colorkey = icon->format->colorkey;
  3238     switch (icon->format->BytesPerPixel) {
  3239     case 1:
  3240         {
  3241             Uint8 *pixels;
  3242             for (y = 0; y < icon->h; ++y) {
  3243                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  3244                 for (x = 0; x < icon->w; ++x) {
  3245                     if (*pixels++ == colorkey) {
  3246                         SET_MASKBIT(icon, x, y, mask);
  3247                     }
  3248                 }
  3249             }
  3250         }
  3251         break;
  3252 
  3253     case 2:
  3254         {
  3255             Uint16 *pixels;
  3256             for (y = 0; y < icon->h; ++y) {
  3257                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  3258                 for (x = 0; x < icon->w; ++x) {
  3259                     if ((flags & 1) && *pixels == colorkey) {
  3260                         SET_MASKBIT(icon, x, y, mask);
  3261                     } else if ((flags & 2)
  3262                                && (*pixels & icon->format->Amask) == 0) {
  3263                         SET_MASKBIT(icon, x, y, mask);
  3264                     }
  3265                     pixels++;
  3266                 }
  3267             }
  3268         }
  3269         break;
  3270 
  3271     case 4:
  3272         {
  3273             Uint32 *pixels;
  3274             for (y = 0; y < icon->h; ++y) {
  3275                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3276                 for (x = 0; x < icon->w; ++x) {
  3277                     if ((flags & 1) && *pixels == colorkey) {
  3278                         SET_MASKBIT(icon, x, y, mask);
  3279                     } else if ((flags & 2)
  3280                                && (*pixels & icon->format->Amask) == 0) {
  3281                         SET_MASKBIT(icon, x, y, mask);
  3282                     }
  3283                     pixels++;
  3284                 }
  3285             }
  3286         }
  3287         break;
  3288     }
  3289 }
  3290 
  3291 /*
  3292  * Sets the window manager icon for the display window.
  3293  */
  3294 void
  3295 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3296 {
  3297     if (icon && _this->SetIcon) {
  3298         /* Generate a mask if necessary, and create the icon! */
  3299         if (mask == NULL) {
  3300             int mask_len = icon->h * (icon->w + 7) / 8;
  3301             int flags = 0;
  3302             mask = (Uint8 *) SDL_malloc(mask_len);
  3303             if (mask == NULL) {
  3304                 return;
  3305             }
  3306             SDL_memset(mask, ~0, mask_len);
  3307             if (icon->flags & SDL_SRCCOLORKEY)
  3308                 flags |= 1;
  3309             if (icon->flags & SDL_SRCALPHA)
  3310                 flags |= 2;
  3311             if (flags) {
  3312                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3313             }
  3314             _this->SetIcon(_this, icon, mask);
  3315             SDL_free(mask);
  3316         } else {
  3317             _this->SetIcon(_this, icon, mask);
  3318         }
  3319     }
  3320 }
  3321 #endif
  3322 
  3323 SDL_bool
  3324 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3325 {
  3326     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3327 
  3328     if (!info) {
  3329         SDL_InvalidParamError("info");
  3330         return SDL_FALSE;
  3331     }
  3332     info->subsystem = SDL_SYSWM_UNKNOWN;
  3333 
  3334     if (!_this->GetWindowWMInfo) {
  3335         SDL_Unsupported();
  3336         return SDL_FALSE;
  3337     }
  3338     return (_this->GetWindowWMInfo(_this, window, info));
  3339 }
  3340 
  3341 void
  3342 SDL_StartTextInput(void)
  3343 {
  3344     SDL_Window *window;
  3345 
  3346     /* First, enable text events */
  3347     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3348     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3349 
  3350     /* Then show the on-screen keyboard, if any */
  3351     window = SDL_GetFocusWindow();
  3352     if (window && _this && _this->ShowScreenKeyboard) {
  3353         _this->ShowScreenKeyboard(_this, window);
  3354     }
  3355 
  3356     /* Finally start the text input system */
  3357     if (_this && _this->StartTextInput) {
  3358         _this->StartTextInput(_this);
  3359     }
  3360 }
  3361 
  3362 SDL_bool
  3363 SDL_IsTextInputActive(void)
  3364 {
  3365     return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE);
  3366 }
  3367 
  3368 void
  3369 SDL_StopTextInput(void)
  3370 {
  3371     SDL_Window *window;
  3372 
  3373     /* Stop the text input system */
  3374     if (_this && _this->StopTextInput) {
  3375         _this->StopTextInput(_this);
  3376     }
  3377 
  3378     /* Hide the on-screen keyboard, if any */
  3379     window = SDL_GetFocusWindow();
  3380     if (window && _this && _this->HideScreenKeyboard) {
  3381         _this->HideScreenKeyboard(_this, window);
  3382     }
  3383 
  3384     /* Finally disable text events */
  3385     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3386     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3387 }
  3388 
  3389 void
  3390 SDL_SetTextInputRect(SDL_Rect *rect)
  3391 {
  3392     if (_this && _this->SetTextInputRect) {
  3393         _this->SetTextInputRect(_this, rect);
  3394     }
  3395 }
  3396 
  3397 SDL_bool
  3398 SDL_HasScreenKeyboardSupport(void)
  3399 {
  3400     if (_this && _this->HasScreenKeyboardSupport) {
  3401         return _this->HasScreenKeyboardSupport(_this);
  3402     }
  3403     return SDL_FALSE;
  3404 }
  3405 
  3406 SDL_bool
  3407 SDL_IsScreenKeyboardShown(SDL_Window *window)
  3408 {
  3409     if (window && _this && _this->IsScreenKeyboardShown) {
  3410         return _this->IsScreenKeyboardShown(_this, window);
  3411     }
  3412     return SDL_FALSE;
  3413 }
  3414 
  3415 #if SDL_VIDEO_DRIVER_ANDROID
  3416 #include "android/SDL_androidmessagebox.h"
  3417 #endif
  3418 #if SDL_VIDEO_DRIVER_WINDOWS
  3419 #include "windows/SDL_windowsmessagebox.h"
  3420 #endif
  3421 #if SDL_VIDEO_DRIVER_WINRT
  3422 #include "winrt/SDL_winrtmessagebox.h"
  3423 #endif
  3424 #if SDL_VIDEO_DRIVER_COCOA
  3425 #include "cocoa/SDL_cocoamessagebox.h"
  3426 #endif
  3427 #if SDL_VIDEO_DRIVER_UIKIT
  3428 #include "uikit/SDL_uikitmessagebox.h"
  3429 #endif
  3430 #if SDL_VIDEO_DRIVER_X11
  3431 #include "x11/SDL_x11messagebox.h"
  3432 #endif
  3433 
  3434 // This function will be unused if none of the above video drivers are present.
  3435 SDL_UNUSED static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
  3436 {
  3437     SDL_SysWMinfo info;
  3438     SDL_Window *window = messageboxdata->window;
  3439 
  3440     if (!window) {
  3441         return SDL_TRUE;
  3442     }
  3443 
  3444     SDL_VERSION(&info.version);
  3445     if (!SDL_GetWindowWMInfo(window, &info)) {
  3446         return SDL_TRUE;
  3447     } else {
  3448         return (info.subsystem == drivertype);
  3449     }
  3450 }
  3451 
  3452 int
  3453 SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
  3454 {
  3455     int dummybutton;
  3456     int retval = -1;
  3457     SDL_bool relative_mode;
  3458     int show_cursor_prev;
  3459     SDL_bool mouse_captured;
  3460     SDL_Window *current_window;
  3461 
  3462     if (!messageboxdata) {
  3463         return SDL_InvalidParamError("messageboxdata");
  3464     }
  3465 
  3466     current_window = SDL_GetKeyboardFocus();
  3467     mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
  3468     relative_mode = SDL_GetRelativeMouseMode();
  3469     SDL_CaptureMouse(SDL_FALSE);
  3470     SDL_SetRelativeMouseMode(SDL_FALSE);
  3471     show_cursor_prev = SDL_ShowCursor(1);
  3472     SDL_ResetKeyboard();
  3473 
  3474     if (!buttonid) {
  3475         buttonid = &dummybutton;
  3476     }
  3477 
  3478     if (_this && _this->ShowMessageBox) {
  3479         retval = _this->ShowMessageBox(_this, messageboxdata, buttonid);
  3480     }
  3481 
  3482     /* It's completely fine to call this function before video is initialized */
  3483 #if SDL_VIDEO_DRIVER_ANDROID
  3484     if (retval == -1 &&
  3485         Android_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3486         retval = 0;
  3487     }
  3488 #endif
  3489 #if SDL_VIDEO_DRIVER_WINDOWS
  3490     if (retval == -1 &&
  3491         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) &&
  3492         WIN_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3493         retval = 0;
  3494     }
  3495 #endif
  3496 #if SDL_VIDEO_DRIVER_WINRT
  3497     if (retval == -1 &&
  3498         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
  3499         WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3500         retval = 0;
  3501     }
  3502 #endif
  3503 #if SDL_VIDEO_DRIVER_COCOA
  3504     if (retval == -1 &&
  3505         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&
  3506         Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3507         retval = 0;
  3508     }
  3509 #endif
  3510 #if SDL_VIDEO_DRIVER_UIKIT
  3511     if (retval == -1 &&
  3512         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) &&
  3513         UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3514         retval = 0;
  3515     }
  3516 #endif
  3517 #if SDL_VIDEO_DRIVER_X11
  3518     if (retval == -1 &&
  3519         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
  3520         X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
  3521         retval = 0;
  3522     }
  3523 #endif
  3524     if (retval == -1) {
  3525         SDL_SetError("No message system available");
  3526     }
  3527 
  3528     if (current_window) {
  3529         SDL_RaiseWindow(current_window);
  3530         if (mouse_captured) {
  3531             SDL_CaptureMouse(SDL_TRUE);
  3532         }
  3533     }
  3534 
  3535     SDL_ShowCursor(show_cursor_prev);
  3536     SDL_SetRelativeMouseMode(relative_mode);
  3537 
  3538     return retval;
  3539 }
  3540 
  3541 int
  3542 SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
  3543 {
  3544     SDL_MessageBoxData data;
  3545     SDL_MessageBoxButtonData button;
  3546 
  3547     SDL_zero(data);
  3548     data.flags = flags;
  3549     data.title = title;
  3550     data.message = message;
  3551     data.numbuttons = 1;
  3552     data.buttons = &button;
  3553     data.window = window;
  3554 
  3555     SDL_zero(button);
  3556     button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
  3557     button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
  3558     button.text = "OK";
  3559 
  3560     return SDL_ShowMessageBox(&data, NULL);
  3561 }
  3562 
  3563 SDL_bool
  3564 SDL_ShouldAllowTopmost(void)
  3565 {
  3566     const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST);
  3567     if (hint) {
  3568         if (*hint == '0') {
  3569             return SDL_FALSE;
  3570         } else {
  3571             return SDL_TRUE;
  3572         }
  3573     }
  3574     return SDL_TRUE;
  3575 }
  3576 
  3577 int
  3578 SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
  3579 {
  3580     CHECK_WINDOW_MAGIC(window, -1);
  3581 
  3582     if (!_this->SetWindowHitTest) {
  3583         return SDL_Unsupported();
  3584     } else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
  3585         return -1;
  3586     }
  3587 
  3588     window->hit_test = callback;
  3589     window->hit_test_data = userdata;
  3590 
  3591     return 0;
  3592 }
  3593 
  3594 float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
  3595 {
  3596 	float den2 = hinches * hinches + vinches * vinches;
  3597 	if ( den2 <= 0.0f ) {
  3598 		return 0.0f;
  3599 	}
  3600 		
  3601 	return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) /
  3602 				   SDL_sqrt((double)den2));
  3603 }
  3604 
  3605 /* vi: set ts=4 sw=4 expandtab: */