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