src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 20 Oct 2013 21:56:15 -0700
changeset 7860 2b0bcdea3a79
parent 7853 4861edda71d1
child 7865 f2a42ca4ddf0
permissions -rw-r--r--
Fixed bug 2129 - fix for bug 2121 breaks linking for mingw and throws multiple warnings

Andreas Ertelt

The problem in question is caused by changeset 7771 (http://hg.libsdl.org/SDL/rev/4434498bf4b9 / https://bugzilla.libsdl.org/show_bug.cgi?id=2121)

The redefinition of __inline__ (introduced by the addition of begin_code.h:128's "|| __STRICT_ANSI__") results in mingw's gcc throwing multiple

warning: always_inline function might not be inlinable [-Wattributes]

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