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