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