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