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