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