src/video/SDL_video.c
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Thu, 25 Apr 2013 18:40:31 -0700
changeset 7112 a1a723edea64
parent 7107 2fcf7bf1d2b2
child 7135 20db445af8c7
permissions -rw-r--r--
Don't warp mouse on focus lost.

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