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