src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 21 Feb 2011 22:51:44 -0800
changeset 5384 93d53f8a2323
parent 5380 2de85077eb0b
child 5385 5f9c2515fc08
permissions -rw-r--r--
Don't automatically send minimized and maximized events, it's up to the windowing system to decide what to do with them.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* The high-level video driver subsystem */
    25 
    26 #include "SDL.h"
    27 #include "SDL_video.h"
    28 #include "SDL_sysvideo.h"
    29 #include "SDL_blit.h"
    30 #include "SDL_pixels_c.h"
    31 #include "SDL_rect_c.h"
    32 #include "../events/SDL_events_c.h"
    33 
    34 #if SDL_VIDEO_OPENGL
    35 #include "SDL_opengl.h"
    36 #endif /* SDL_VIDEO_OPENGL */
    37 
    38 #if SDL_VIDEO_OPENGL_ES
    39 #include "SDL_opengles.h"
    40 #endif /* SDL_VIDEO_OPENGL_ES */
    41 
    42 #if SDL_VIDEO_OPENGL_ES2
    43 #include "SDL_opengles2.h"
    44 #endif /* SDL_VIDEO_OPENGL_ES2 */
    45 
    46 #include "SDL_syswm.h"
    47 
    48 /* On Windows, windows.h defines CreateWindow */
    49 #ifdef CreateWindow
    50 #undef CreateWindow
    51 #endif
    52 
    53 /* Available video drivers */
    54 static VideoBootStrap *bootstrap[] = {
    55 #if SDL_VIDEO_DRIVER_COCOA
    56     &COCOA_bootstrap,
    57 #endif
    58 #if SDL_VIDEO_DRIVER_X11
    59     &X11_bootstrap,
    60 #endif
    61 #if SDL_VIDEO_DRIVER_DIRECTFB
    62     &DirectFB_bootstrap,
    63 #endif
    64 #if SDL_VIDEO_DRIVER_WINDOWS
    65     &WINDOWS_bootstrap,
    66 #endif
    67 #if SDL_VIDEO_DRIVER_BWINDOW
    68     &BWINDOW_bootstrap,
    69 #endif
    70 #if SDL_VIDEO_DRIVER_PANDORA
    71     &PND_bootstrap,
    72 #endif
    73 #if SDL_VIDEO_DRIVER_NDS
    74     &NDS_bootstrap,
    75 #endif
    76 #if SDL_VIDEO_DRIVER_UIKIT
    77     &UIKIT_bootstrap,
    78 #endif
    79 #if SDL_VIDEO_DRIVER_ANDROID
    80     &Android_bootstrap,
    81 #endif
    82 #if SDL_VIDEO_DRIVER_DUMMY
    83     &DUMMY_bootstrap,
    84 #endif
    85     NULL
    86 };
    87 
    88 static SDL_VideoDevice *_this = NULL;
    89 
    90 #define CHECK_WINDOW_MAGIC(window, retval) \
    91     if (!_this) { \
    92         SDL_UninitializedVideo(); \
    93         return retval; \
    94     } \
    95     if (!window || window->magic != &_this->window_magic) { \
    96         SDL_SetError("Invalid window"); \
    97         return retval; \
    98     }
    99 
   100 #define CHECK_DISPLAY_INDEX(displayIndex, retval) \
   101     if (!_this) { \
   102         SDL_UninitializedVideo(); \
   103         return retval; \
   104     } \
   105     if (displayIndex < 0 || displayIndex >= _this->num_displays) { \
   106         SDL_SetError("displayIndex must be in the range 0 - %d", \
   107                      _this->num_displays - 1); \
   108         return retval; \
   109     }
   110 
   111 /* Various local functions */
   112 static void SDL_UpdateWindowGrab(SDL_Window * window);
   113 
   114 /* Support for framebuffer emulation using an accelerated renderer */
   115 
   116 #define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
   117 
   118 typedef struct {
   119     SDL_Renderer *renderer;
   120     SDL_Texture *texture;
   121     void *pixels;
   122     int pitch;
   123     int bytes_per_pixel;
   124 } SDL_WindowTextureData;
   125 
   126 static SDL_bool
   127 ShouldUseTextureFramebuffer()
   128 {
   129     const char *hint;
   130 
   131     /* If there's no native framebuffer support then there's no option */
   132     if (!_this->CreateWindowFramebuffer) {
   133         return SDL_TRUE;
   134     }
   135 
   136     /* If the user has specified a software renderer we can't use a
   137        texture framebuffer, or renderer creation will go recursive.
   138      */
   139     hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
   140     if (hint && SDL_strcasecmp(hint, "software") == 0) {
   141         return SDL_FALSE;
   142     }
   143 
   144     /* See if the user or application wants a specific behavior */
   145     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   146     if (hint) {
   147         if (*hint == '0') {
   148             return SDL_FALSE;
   149         } else {
   150             return SDL_TRUE;
   151         }
   152     }
   153 
   154     /* Each platform has different performance characteristics */
   155 #if defined(__WIN32__)
   156     /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
   157      */
   158     return SDL_FALSE;
   159 
   160 #elif defined(__MACOSX__)
   161     /* Mac OS X uses OpenGL as the native fast path */
   162     return SDL_TRUE;
   163 
   164 #elif defined(__LINUX__)
   165     /* Properly configured OpenGL drivers are faster than MIT-SHM */
   166 #if SDL_VIDEO_OPENGL
   167     /* Ugh, find a way to cache this value! */
   168     {
   169         SDL_Window *window;
   170         SDL_GLContext context;
   171         SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
   172 
   173         window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL);
   174         if (window) {
   175             context = SDL_GL_CreateContext(window);
   176             if (context) {
   177                 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
   178                 const char *vendor = NULL;
   179 
   180                 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
   181                 if (glGetStringFunc) {
   182                     vendor = (const char *) glGetStringFunc(GL_VENDOR);
   183                 }
   184                 /* Add more vendors here at will... */
   185                 if (vendor &&
   186                     (SDL_strstr(vendor, "ATI Technologies") ||
   187                      SDL_strstr(vendor, "NVIDIA"))) {
   188                     hasAcceleratedOpenGL = SDL_TRUE;
   189                 }
   190                 SDL_GL_DeleteContext(context);
   191             }
   192             SDL_DestroyWindow(window);
   193         }
   194         return hasAcceleratedOpenGL;
   195     }
   196 #else
   197     return SDL_FALSE;
   198 #endif
   199 
   200 #else
   201     /* Play it safe, assume that if there is a framebuffer driver that it's
   202        optimized for the current platform.
   203     */
   204     return SDL_FALSE;
   205 #endif
   206 }
   207 
   208 static int
   209 SDL_CreateWindowTexture(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
   210 {
   211     SDL_WindowTextureData *data;
   212     SDL_RendererInfo info;
   213     Uint32 i;
   214 
   215     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   216     if (!data) {
   217         SDL_Renderer *renderer = NULL;
   218         SDL_RendererInfo info;
   219         int i;
   220         const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   221 
   222         /* Check to see if there's a specific driver requested */
   223         if (hint && *hint != '0' && *hint != '1' &&
   224             SDL_strcasecmp(hint, "software") != 0) {
   225             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   226                 SDL_GetRenderDriverInfo(i, &info);
   227                 if (SDL_strcasecmp(info.name, hint) == 0) {
   228                     renderer = SDL_CreateRenderer(window, i, 0);
   229                     break;
   230                 }
   231             }
   232         }
   233 
   234         if (!renderer) {
   235             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   236                 SDL_GetRenderDriverInfo(i, &info);
   237                 if (SDL_strcmp(info.name, "software") != 0) {
   238                     renderer = SDL_CreateRenderer(window, i, 0);
   239                     if (renderer) {
   240                         break;
   241                     }
   242                 }
   243             }
   244         }
   245         if (!renderer) {
   246             return -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 #elif SDL_VIDEO_OPENGL_ES
   492     _this->gl_config.major_version = 1;
   493     _this->gl_config.minor_version = 1;
   494 #elif SDL_VIDEO_OPENGL_ES2
   495     _this->gl_config.major_version = 2;
   496     _this->gl_config.minor_version = 0;
   497 #endif
   498 
   499     /* Initialize the video subsystem */
   500     if (_this->VideoInit(_this) < 0) {
   501         SDL_VideoQuit();
   502         return -1;
   503     }
   504 
   505     /* Make sure some displays were added */
   506     if (_this->num_displays == 0) {
   507         SDL_SetError("The video driver did not add any displays");
   508         SDL_VideoQuit();
   509         return (-1);
   510     }
   511 
   512     /* Add the renderer framebuffer emulation if desired */
   513     if (ShouldUseTextureFramebuffer()) {
   514         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
   515         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
   516         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
   517     }
   518 
   519     /* We're ready to go! */
   520     return 0;
   521 }
   522 
   523 const char *
   524 SDL_GetCurrentVideoDriver()
   525 {
   526     if (!_this) {
   527         SDL_UninitializedVideo();
   528         return NULL;
   529     }
   530     return _this->name;
   531 }
   532 
   533 SDL_VideoDevice *
   534 SDL_GetVideoDevice(void)
   535 {
   536     return _this;
   537 }
   538 
   539 int
   540 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   541 {
   542     SDL_VideoDisplay display;
   543 
   544     SDL_zero(display);
   545     if (desktop_mode) {
   546         display.desktop_mode = *desktop_mode;
   547     }
   548     display.current_mode = display.desktop_mode;
   549 
   550     return SDL_AddVideoDisplay(&display);
   551 }
   552 
   553 int
   554 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   555 {
   556     SDL_VideoDisplay *displays;
   557     int index = -1;
   558 
   559     displays =
   560         SDL_realloc(_this->displays,
   561                     (_this->num_displays + 1) * sizeof(*displays));
   562     if (displays) {
   563         index = _this->num_displays++;
   564         displays[index] = *display;
   565         displays[index].device = _this;
   566         _this->displays = displays;
   567     } else {
   568         SDL_OutOfMemory();
   569     }
   570     return index;
   571 }
   572 
   573 int
   574 SDL_GetNumVideoDisplays(void)
   575 {
   576     if (!_this) {
   577         SDL_UninitializedVideo();
   578         return 0;
   579     }
   580     return _this->num_displays;
   581 }
   582 
   583 int
   584 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
   585 {
   586     int displayIndex;
   587 
   588     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
   589         if (display == &_this->displays[displayIndex]) {
   590             return displayIndex;
   591         }
   592     }
   593 
   594     /* Couldn't find the display, just use index 0 */
   595     return 0;
   596 }
   597 
   598 int
   599 SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
   600 {
   601     CHECK_DISPLAY_INDEX(displayIndex, -1);
   602 
   603     if (rect) {
   604         SDL_VideoDisplay *display = &_this->displays[displayIndex];
   605 
   606         if (_this->GetDisplayBounds) {
   607             if (_this->GetDisplayBounds(_this, display, rect) == 0) {
   608                 return 0;
   609             }
   610         }
   611 
   612         /* Assume that the displays are left to right */
   613         if (displayIndex == 0) {
   614             rect->x = 0;
   615             rect->y = 0;
   616         } else {
   617             SDL_GetDisplayBounds(displayIndex-1, rect);
   618             rect->x += rect->w;
   619         }
   620         rect->w = display->desktop_mode.w;
   621         rect->h = display->desktop_mode.h;
   622     }
   623     return 0;
   624 }
   625 
   626 SDL_bool
   627 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   628 {
   629     SDL_DisplayMode *modes;
   630     int i, nmodes;
   631 
   632     /* Make sure we don't already have the mode in the list */
   633     modes = display->display_modes;
   634     nmodes = display->num_display_modes;
   635     for (i = nmodes; i--;) {
   636         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   637             return SDL_FALSE;
   638         }
   639     }
   640 
   641     /* Go ahead and add the new mode */
   642     if (nmodes == display->max_display_modes) {
   643         modes =
   644             SDL_realloc(modes,
   645                         (display->max_display_modes + 32) * sizeof(*modes));
   646         if (!modes) {
   647             return SDL_FALSE;
   648         }
   649         display->display_modes = modes;
   650         display->max_display_modes += 32;
   651     }
   652     modes[nmodes] = *mode;
   653     display->num_display_modes++;
   654 
   655     /* Re-sort video modes */
   656     SDL_qsort(display->display_modes, display->num_display_modes,
   657               sizeof(SDL_DisplayMode), cmpmodes);
   658 
   659     return SDL_TRUE;
   660 }
   661 
   662 SDL_VideoDisplay *
   663 SDL_GetFirstDisplay(void)
   664 {
   665     return &_this->displays[0];
   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 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     center.x = window->x + window->w / 2;
   937     center.y = window->y + window->h / 2;
   938     for (i = 0; i < _this->num_displays; ++i) {
   939         SDL_VideoDisplay *display = &_this->displays[i];
   940 
   941         SDL_GetDisplayBounds(i, &rect);
   942         if (display->fullscreen_window == window || SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   943             return i;
   944         }
   945 
   946         delta.x = center.x - (rect.x + rect.w / 2);
   947         delta.y = center.y - (rect.y + rect.h / 2);
   948         dist = (delta.x*delta.x + delta.y*delta.y);
   949         if (dist < closest_dist) {
   950             closest = i;
   951             closest_dist = dist;
   952         }
   953     }
   954     if (closest < 0) {
   955         SDL_SetError("Couldn't find any displays");
   956     }
   957     return closest;
   958 }
   959 
   960 SDL_VideoDisplay *
   961 SDL_GetDisplayForWindow(SDL_Window *window)
   962 {
   963     int displayIndex = SDL_GetWindowDisplay(window);
   964     if (displayIndex >= 0) {
   965         return &_this->displays[displayIndex];
   966     } else {
   967         return NULL;
   968     }
   969 }
   970 
   971 int
   972 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
   973 {
   974     CHECK_WINDOW_MAGIC(window, -1);
   975 
   976     if (mode) {
   977         window->fullscreen_mode = *mode;
   978     } else {
   979         SDL_zero(window->fullscreen_mode);
   980     }
   981     return 0;
   982 }
   983 
   984 int
   985 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
   986 {
   987     SDL_DisplayMode fullscreen_mode;
   988 
   989     CHECK_WINDOW_MAGIC(window, -1);
   990 
   991     fullscreen_mode = window->fullscreen_mode;
   992     if (!fullscreen_mode.w) {
   993         fullscreen_mode.w = window->w;
   994     }
   995     if (!fullscreen_mode.h) {
   996         fullscreen_mode.h = window->h;
   997     }
   998 
   999     if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
  1000                                              &fullscreen_mode,
  1001                                              &fullscreen_mode)) {
  1002         SDL_SetError("Couldn't find display mode match");
  1003         return -1;
  1004     }
  1005 
  1006     if (mode) {
  1007         *mode = fullscreen_mode;
  1008     }
  1009     return 0;
  1010 }
  1011 
  1012 Uint32
  1013 SDL_GetWindowPixelFormat(SDL_Window * window)
  1014 {
  1015     SDL_VideoDisplay *display;
  1016 
  1017     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1018 
  1019     display = SDL_GetDisplayForWindow(window);
  1020     return display->current_mode.format;
  1021 }
  1022 
  1023 static void
  1024 SDL_UpdateFullscreenMode(SDL_Window * window)
  1025 {
  1026     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1027     SDL_Window *other;
  1028 
  1029     if (FULLSCREEN_VISIBLE(window)) {
  1030         /* Hide any other fullscreen windows */
  1031         if (display->fullscreen_window &&
  1032             display->fullscreen_window != window) {
  1033             SDL_MinimizeWindow(display->fullscreen_window);
  1034         }
  1035     }
  1036 
  1037     /* See if anything needs to be done now */
  1038     if ((display->fullscreen_window == window) == FULLSCREEN_VISIBLE(window)) {
  1039         return;
  1040     }
  1041 
  1042     /* See if there are any fullscreen windows */
  1043     for (other = _this->windows; other; other = other->next) {
  1044         if (FULLSCREEN_VISIBLE(other) &&
  1045             SDL_GetDisplayForWindow(other) == display) {
  1046             SDL_DisplayMode fullscreen_mode;
  1047             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1048                 SDL_bool resized = SDL_TRUE;
  1049 
  1050                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1051                     resized = SDL_FALSE;
  1052                 }
  1053 
  1054                 SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1055                 if (_this->SetWindowFullscreen) {
  1056                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1057                 }
  1058                 display->fullscreen_window = other;
  1059 
  1060                 /* Generate a mode change event here */
  1061                 if (resized) {
  1062                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1063                                         fullscreen_mode.w, fullscreen_mode.h);
  1064                 } else {
  1065                     SDL_OnWindowResized(other);
  1066                 }
  1067                 return;
  1068             }
  1069         }
  1070     }
  1071 
  1072     /* Nope, restore the desktop mode */
  1073     SDL_SetDisplayModeForDisplay(display, NULL);
  1074 
  1075     if (_this->SetWindowFullscreen) {
  1076         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1077     }
  1078     display->fullscreen_window = NULL;
  1079 
  1080     /* Generate a mode change event here */
  1081     SDL_OnWindowResized(window);
  1082 }
  1083 
  1084 #define CREATE_FLAGS \
  1085     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE)
  1086 
  1087 static void
  1088 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1089 {
  1090     if (flags & SDL_WINDOW_MAXIMIZED) {
  1091         SDL_MaximizeWindow(window);
  1092     }
  1093     if (flags & SDL_WINDOW_MINIMIZED) {
  1094         SDL_MinimizeWindow(window);
  1095     }
  1096     if (flags & SDL_WINDOW_FULLSCREEN) {
  1097         SDL_SetWindowFullscreen(window, SDL_TRUE);
  1098     }
  1099     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1100         SDL_SetWindowGrab(window, SDL_TRUE);
  1101     }
  1102     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1103         SDL_ShowWindow(window);
  1104     }
  1105 }
  1106 
  1107 SDL_Window *
  1108 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1109 {
  1110     SDL_Window *window;
  1111 
  1112     if (!_this) {
  1113         /* Initialize the video system if needed */
  1114         if (SDL_VideoInit(NULL) < 0) {
  1115             return NULL;
  1116         }
  1117     }
  1118 
  1119     /* Some platforms have OpenGL enabled by default */
  1120 #if (SDL_VIDEO_OPENGL && __MACOSX__) || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  1121     flags |= SDL_WINDOW_OPENGL;
  1122 #endif
  1123     if (flags & SDL_WINDOW_OPENGL) {
  1124         if (!_this->GL_CreateContext) {
  1125             SDL_SetError("No OpenGL support in video driver");
  1126             return NULL;
  1127         }
  1128         SDL_GL_LoadLibrary(NULL);
  1129     }
  1130     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1131     window->magic = &_this->window_magic;
  1132     window->id = _this->next_object_id++;
  1133     window->x = x;
  1134     window->y = y;
  1135     window->w = w;
  1136     window->h = h;
  1137     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1138         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1139         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1140         int displayIndex;
  1141         SDL_Rect bounds;
  1142 
  1143         displayIndex = SDL_GetIndexOfDisplay(display);
  1144         SDL_GetDisplayBounds(displayIndex, &bounds);
  1145         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1146             window->x = bounds.x + (bounds.w - w) / 2;
  1147         }
  1148         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1149             window->y = bounds.y + (bounds.h - h) / 2;
  1150         }
  1151     }
  1152     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1153     window->next = _this->windows;
  1154     if (_this->windows) {
  1155         _this->windows->prev = window;
  1156     }
  1157     _this->windows = window;
  1158 
  1159     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1160         SDL_DestroyWindow(window);
  1161         return NULL;
  1162     }
  1163 
  1164     if (title) {
  1165         SDL_SetWindowTitle(window, title);
  1166     }
  1167     SDL_FinishWindowCreation(window, flags);
  1168 
  1169     return window;
  1170 }
  1171 
  1172 SDL_Window *
  1173 SDL_CreateWindowFrom(const void *data)
  1174 {
  1175     SDL_Window *window;
  1176 
  1177     if (!_this) {
  1178         SDL_UninitializedVideo();
  1179         return NULL;
  1180     }
  1181     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1182     window->magic = &_this->window_magic;
  1183     window->id = _this->next_object_id++;
  1184     window->flags = SDL_WINDOW_FOREIGN;
  1185     window->next = _this->windows;
  1186     if (_this->windows) {
  1187         _this->windows->prev = window;
  1188     }
  1189     _this->windows = window;
  1190 
  1191     if (!_this->CreateWindowFrom ||
  1192         _this->CreateWindowFrom(_this, window, data) < 0) {
  1193         SDL_DestroyWindow(window);
  1194         return NULL;
  1195     }
  1196     return window;
  1197 }
  1198 
  1199 int
  1200 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1201 {
  1202     char *title = window->title;
  1203 
  1204     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1205         SDL_SetError("No OpenGL support in video driver");
  1206         return -1;
  1207     }
  1208 
  1209     if (window->flags & SDL_WINDOW_FOREIGN) {
  1210         /* Can't destroy and re-create foreign windows, hrm */
  1211         flags |= SDL_WINDOW_FOREIGN;
  1212     } else {
  1213         flags &= ~SDL_WINDOW_FOREIGN;
  1214     }
  1215 
  1216     /* Restore video mode, etc. */
  1217     SDL_HideWindow(window);
  1218 
  1219     /* Tear down the old native window */
  1220     if (window->surface) {
  1221         window->surface->flags &= ~SDL_DONTFREE;
  1222         SDL_FreeSurface(window->surface);
  1223     }
  1224     if (_this->DestroyWindowFramebuffer) {
  1225         _this->DestroyWindowFramebuffer(_this, window);
  1226     }
  1227     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1228         _this->DestroyWindow(_this, window);
  1229     }
  1230 
  1231     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1232         if (flags & SDL_WINDOW_OPENGL) {
  1233             SDL_GL_LoadLibrary(NULL);
  1234         } else {
  1235             SDL_GL_UnloadLibrary();
  1236         }
  1237     }
  1238 
  1239     window->title = NULL;
  1240     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1241 
  1242     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1243         if (_this->CreateWindow(_this, window) < 0) {
  1244             if (flags & SDL_WINDOW_OPENGL) {
  1245                 SDL_GL_UnloadLibrary();
  1246             }
  1247             return -1;
  1248         }
  1249     }
  1250 
  1251     if (title) {
  1252         SDL_SetWindowTitle(window, title);
  1253         SDL_free(title);
  1254     }
  1255     SDL_FinishWindowCreation(window, flags);
  1256 
  1257     return 0;
  1258 }
  1259 
  1260 Uint32
  1261 SDL_GetWindowID(SDL_Window * window)
  1262 {
  1263     CHECK_WINDOW_MAGIC(window, 0);
  1264 
  1265     return window->id;
  1266 }
  1267 
  1268 SDL_Window *
  1269 SDL_GetWindowFromID(Uint32 id)
  1270 {
  1271     SDL_Window *window;
  1272 
  1273     if (!_this) {
  1274         return NULL;
  1275     }
  1276     for (window = _this->windows; window; window = window->next) {
  1277         if (window->id == id) {
  1278             return window;
  1279         }
  1280     }
  1281     return NULL;
  1282 }
  1283 
  1284 Uint32
  1285 SDL_GetWindowFlags(SDL_Window * window)
  1286 {
  1287     CHECK_WINDOW_MAGIC(window, 0);
  1288 
  1289     return window->flags;
  1290 }
  1291 
  1292 void
  1293 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1294 {
  1295     CHECK_WINDOW_MAGIC(window, );
  1296 
  1297     if (title == window->title) {
  1298         return;
  1299     }
  1300     if (window->title) {
  1301         SDL_free(window->title);
  1302     }
  1303     if (title && *title) {
  1304         window->title = SDL_strdup(title);
  1305     } else {
  1306         window->title = NULL;
  1307     }
  1308 
  1309     if (_this->SetWindowTitle) {
  1310         _this->SetWindowTitle(_this, window);
  1311     }
  1312 }
  1313 
  1314 const char *
  1315 SDL_GetWindowTitle(SDL_Window * window)
  1316 {
  1317     CHECK_WINDOW_MAGIC(window, "");
  1318 
  1319     return window->title ? window->title : "";
  1320 }
  1321 
  1322 void
  1323 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1324 {
  1325     CHECK_WINDOW_MAGIC(window, );
  1326 
  1327     if (!icon) {
  1328         return;
  1329     }
  1330 
  1331     if (_this->SetWindowIcon) {
  1332         _this->SetWindowIcon(_this, window, icon);
  1333     }
  1334 }
  1335 
  1336 void*
  1337 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1338 {
  1339     SDL_WindowUserData *prev, *data;
  1340 
  1341     CHECK_WINDOW_MAGIC(window, NULL);
  1342 
  1343     /* See if the named data already exists */
  1344     prev = NULL;
  1345     for (data = window->data; data; prev = data, data = data->next) {
  1346         if (SDL_strcmp(data->name, name) == 0) {
  1347             void *last_value = data->data;
  1348 
  1349             if (userdata) {
  1350                 /* Set the new value */
  1351                 data->data = userdata;
  1352             } else {
  1353                 /* Delete this value */
  1354                 if (prev) {
  1355                     prev->next = data->next;
  1356                 } else {
  1357                     window->data = data->next;
  1358                 }
  1359                 SDL_free(data->name);
  1360                 SDL_free(data);
  1361             }
  1362             return last_value;
  1363         }
  1364     }
  1365 
  1366     /* Add new data to the window */
  1367     if (userdata) {
  1368         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1369         data->name = SDL_strdup(name);
  1370         data->data = userdata;
  1371         data->next = window->data;
  1372         window->data = data;
  1373     }
  1374     return NULL;
  1375 }
  1376 
  1377 void *
  1378 SDL_GetWindowData(SDL_Window * window, const char *name)
  1379 {
  1380     SDL_WindowUserData *data;
  1381 
  1382     CHECK_WINDOW_MAGIC(window, NULL);
  1383 
  1384     for (data = window->data; data; data = data->next) {
  1385         if (SDL_strcmp(data->name, name) == 0) {
  1386             return data->data;
  1387         }
  1388     }
  1389     return NULL;
  1390 }
  1391 
  1392 void
  1393 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1394 {
  1395     CHECK_WINDOW_MAGIC(window, );
  1396 
  1397     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1398         window->x = x;
  1399     }
  1400     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1401         window->y = y;
  1402     }
  1403     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1404         if (_this->SetWindowPosition) {
  1405             _this->SetWindowPosition(_this, window);
  1406         }
  1407         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1408     }
  1409 }
  1410 
  1411 void
  1412 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1413 {
  1414     /* Clear the values */
  1415     if (x) {
  1416         *x = 0;
  1417     }
  1418     if (y) {
  1419         *y = 0;
  1420     }
  1421 
  1422     CHECK_WINDOW_MAGIC(window, );
  1423 
  1424     /* Fullscreen windows are always at their display's origin */
  1425     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1426     } else {
  1427         if (x) {
  1428             *x = window->x;
  1429         }
  1430         if (y) {
  1431             *y = window->y;
  1432         }
  1433     }
  1434 }
  1435 
  1436 void
  1437 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1438 {
  1439     CHECK_WINDOW_MAGIC(window, );
  1440 
  1441     /* FIXME: Should this change fullscreen modes? */
  1442     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1443         window->w = w;
  1444         window->h = h;
  1445         if (_this->SetWindowSize) {
  1446             _this->SetWindowSize(_this, window);
  1447         }
  1448         if (window->w == w && window->h == h) {
  1449             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1450             SDL_OnWindowResized(window);
  1451         }
  1452     }
  1453 }
  1454 
  1455 void
  1456 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1457 {
  1458     int dummy;
  1459 
  1460     if (!w) {
  1461         w = &dummy;
  1462     }
  1463     if (!h) {
  1464         h = &dummy;
  1465     }
  1466 
  1467     *w = 0;
  1468     *h = 0;
  1469 
  1470     CHECK_WINDOW_MAGIC(window, );
  1471 
  1472     if (_this && window && window->magic == &_this->window_magic) {
  1473         if (w) {
  1474             *w = window->w;
  1475         }
  1476         if (h) {
  1477             *h = window->h;
  1478         }
  1479     } else {
  1480         if (w) {
  1481             *w = 0;
  1482         }
  1483         if (h) {
  1484             *h = 0;
  1485         }
  1486     }
  1487 }
  1488 
  1489 void
  1490 SDL_ShowWindow(SDL_Window * window)
  1491 {
  1492     CHECK_WINDOW_MAGIC(window, );
  1493 
  1494     if (window->flags & SDL_WINDOW_SHOWN) {
  1495         return;
  1496     }
  1497 
  1498     if (_this->ShowWindow) {
  1499         _this->ShowWindow(_this, window);
  1500     }
  1501     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1502 }
  1503 
  1504 void
  1505 SDL_HideWindow(SDL_Window * window)
  1506 {
  1507     CHECK_WINDOW_MAGIC(window, );
  1508 
  1509     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1510         return;
  1511     }
  1512 
  1513     if (_this->HideWindow) {
  1514         _this->HideWindow(_this, window);
  1515     }
  1516     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1517 }
  1518 
  1519 void
  1520 SDL_RaiseWindow(SDL_Window * window)
  1521 {
  1522     CHECK_WINDOW_MAGIC(window, );
  1523 
  1524     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1525         return;
  1526     }
  1527     if (_this->RaiseWindow) {
  1528         _this->RaiseWindow(_this, window);
  1529     } else {
  1530         /* FIXME: What we really want is a way to request focus */
  1531         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
  1532     }
  1533 }
  1534 
  1535 void
  1536 SDL_MaximizeWindow(SDL_Window * window)
  1537 {
  1538     CHECK_WINDOW_MAGIC(window, );
  1539 
  1540     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1541         return;
  1542     }
  1543 
  1544     if (_this->MaximizeWindow) {
  1545         _this->MaximizeWindow(_this, window);
  1546     }
  1547 }
  1548 
  1549 void
  1550 SDL_MinimizeWindow(SDL_Window * window)
  1551 {
  1552     CHECK_WINDOW_MAGIC(window, );
  1553 
  1554     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1555         return;
  1556     }
  1557 
  1558     if (_this->MinimizeWindow) {
  1559         _this->MinimizeWindow(_this, window);
  1560     }
  1561 }
  1562 
  1563 void
  1564 SDL_RestoreWindow(SDL_Window * window)
  1565 {
  1566     CHECK_WINDOW_MAGIC(window, );
  1567 
  1568     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1569         return;
  1570     }
  1571 
  1572     if (_this->RestoreWindow) {
  1573         _this->RestoreWindow(_this, window);
  1574     }
  1575     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1576 }
  1577 
  1578 int
  1579 SDL_SetWindowFullscreen(SDL_Window * window, SDL_bool fullscreen)
  1580 {
  1581     CHECK_WINDOW_MAGIC(window, -1);
  1582 
  1583     if (fullscreen) {
  1584         fullscreen = SDL_WINDOW_FULLSCREEN;
  1585     }
  1586     if ((window->flags & SDL_WINDOW_FULLSCREEN) == fullscreen) {
  1587         return 0;
  1588     }
  1589     if (fullscreen) {
  1590         window->flags |= SDL_WINDOW_FULLSCREEN;
  1591     } else {
  1592         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1593     }
  1594     SDL_UpdateFullscreenMode(window);
  1595 
  1596     return 0;
  1597 }
  1598 
  1599 static SDL_Surface *
  1600 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1601 {
  1602     Uint32 format;
  1603     void *pixels;
  1604     int pitch;
  1605     int bpp;
  1606     Uint32 Rmask, Gmask, Bmask, Amask;
  1607 
  1608     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1609         return NULL;
  1610     }
  1611 
  1612     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1613         return NULL;
  1614     }
  1615 
  1616     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1617         return NULL;
  1618     }
  1619 
  1620     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1621 }
  1622 
  1623 SDL_Surface *
  1624 SDL_GetWindowSurface(SDL_Window * window)
  1625 {
  1626     CHECK_WINDOW_MAGIC(window, NULL);
  1627 
  1628     if (!window->surface_valid) {
  1629         if (window->surface) {
  1630             window->surface->flags &= ~SDL_DONTFREE;
  1631             SDL_FreeSurface(window->surface);
  1632         }
  1633         window->surface = SDL_CreateWindowFramebuffer(window);
  1634         if (window->surface) {
  1635             window->surface_valid = SDL_TRUE;
  1636             window->surface->flags |= SDL_DONTFREE;
  1637         }
  1638     }
  1639     return window->surface;
  1640 }
  1641 
  1642 int
  1643 SDL_UpdateWindowSurface(SDL_Window * window)
  1644 {
  1645     SDL_Rect full_rect;
  1646 
  1647     CHECK_WINDOW_MAGIC(window, -1);
  1648 
  1649     full_rect.x = 0;
  1650     full_rect.y = 0;
  1651     full_rect.w = window->w;
  1652     full_rect.h = window->h;
  1653     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1654 }
  1655 
  1656 int
  1657 SDL_UpdateWindowSurfaceRects(SDL_Window * window, SDL_Rect * rects,
  1658                              int numrects)
  1659 {
  1660     CHECK_WINDOW_MAGIC(window, -1);
  1661 
  1662     if (!window->surface_valid) {
  1663         SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1664         return -1;
  1665     }
  1666 
  1667     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1668 }
  1669 
  1670 void
  1671 SDL_SetWindowGrab(SDL_Window * window, int mode)
  1672 {
  1673     CHECK_WINDOW_MAGIC(window, );
  1674 
  1675     if ((!!mode == !!(window->flags & SDL_WINDOW_INPUT_GRABBED))) {
  1676         return;
  1677     }
  1678     if (mode) {
  1679         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1680     } else {
  1681         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1682     }
  1683     SDL_UpdateWindowGrab(window);
  1684 }
  1685 
  1686 static void
  1687 SDL_UpdateWindowGrab(SDL_Window * window)
  1688 {
  1689     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1690         _this->SetWindowGrab(_this, window);
  1691     }
  1692 }
  1693 
  1694 int
  1695 SDL_GetWindowGrab(SDL_Window * window)
  1696 {
  1697     CHECK_WINDOW_MAGIC(window, 0);
  1698 
  1699     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1700 }
  1701 
  1702 void
  1703 SDL_OnWindowShown(SDL_Window * window)
  1704 {
  1705     SDL_RaiseWindow(window);
  1706     SDL_UpdateFullscreenMode(window);
  1707 }
  1708 
  1709 void
  1710 SDL_OnWindowHidden(SDL_Window * window)
  1711 {
  1712     SDL_UpdateFullscreenMode(window);
  1713 }
  1714 
  1715 void
  1716 SDL_OnWindowResized(SDL_Window * window)
  1717 {
  1718     window->surface_valid = SDL_FALSE;
  1719     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  1720 }
  1721 
  1722 void
  1723 SDL_OnWindowMinimized(SDL_Window * window)
  1724 {
  1725     SDL_UpdateFullscreenMode(window);
  1726 }
  1727 
  1728 void
  1729 SDL_OnWindowRestored(SDL_Window * window)
  1730 {
  1731     SDL_RaiseWindow(window);
  1732     SDL_UpdateFullscreenMode(window);
  1733 }
  1734 
  1735 void
  1736 SDL_OnWindowFocusGained(SDL_Window * window)
  1737 {
  1738     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1739         && _this->SetWindowGrab) {
  1740         _this->SetWindowGrab(_this, window);
  1741     }
  1742 }
  1743 
  1744 void
  1745 SDL_OnWindowFocusLost(SDL_Window * window)
  1746 {
  1747     /* If we're fullscreen on a single-head system and lose focus, minimize */
  1748     if ((window->flags & SDL_WINDOW_FULLSCREEN) &&
  1749         _this->num_displays == 1) {
  1750         SDL_MinimizeWindow(window);
  1751     }
  1752 
  1753     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1754         && _this->SetWindowGrab) {
  1755         _this->SetWindowGrab(_this, window);
  1756     }
  1757 }
  1758 
  1759 SDL_Window *
  1760 SDL_GetFocusWindow(void)
  1761 {
  1762     SDL_Window *window;
  1763 
  1764     if (!_this) {
  1765         return NULL;
  1766     }
  1767     for (window = _this->windows; window; window = window->next) {
  1768         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1769             return window;
  1770         }
  1771     }
  1772     return NULL;
  1773 }
  1774 
  1775 void
  1776 SDL_DestroyWindow(SDL_Window * window)
  1777 {
  1778     SDL_VideoDisplay *display;
  1779 
  1780     CHECK_WINDOW_MAGIC(window, );
  1781 
  1782     /* Restore video mode, etc. */
  1783     SDL_HideWindow(window);
  1784 
  1785     if (window->surface) {
  1786         window->surface->flags &= ~SDL_DONTFREE;
  1787         SDL_FreeSurface(window->surface);
  1788     }
  1789     if (_this->DestroyWindowFramebuffer) {
  1790         _this->DestroyWindowFramebuffer(_this, window);
  1791     }
  1792     if (_this->DestroyWindow) {
  1793         _this->DestroyWindow(_this, window);
  1794     }
  1795     if (window->flags & SDL_WINDOW_OPENGL) {
  1796         SDL_GL_UnloadLibrary();
  1797     }
  1798 
  1799     display = SDL_GetDisplayForWindow(window);
  1800     if (display->fullscreen_window == window) {
  1801         display->fullscreen_window = NULL;
  1802     }
  1803 
  1804     /* Now invalidate magic */
  1805     window->magic = NULL;
  1806 
  1807     /* Free memory associated with the window */
  1808     if (window->title) {
  1809         SDL_free(window->title);
  1810     }
  1811     while (window->data) {
  1812         SDL_WindowUserData *data = window->data;
  1813 
  1814         window->data = data->next;
  1815         SDL_free(data->name);
  1816         SDL_free(data);
  1817     }
  1818 
  1819     /* Unlink the window from the list */
  1820     if (window->next) {
  1821         window->next->prev = window->prev;
  1822     }
  1823     if (window->prev) {
  1824         window->prev->next = window->next;
  1825     } else {
  1826         _this->windows = window->next;
  1827     }
  1828 
  1829     SDL_free(window);
  1830 }
  1831 
  1832 SDL_bool
  1833 SDL_IsScreenSaverEnabled()
  1834 {
  1835     if (!_this) {
  1836         return SDL_TRUE;
  1837     }
  1838     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  1839 }
  1840 
  1841 void
  1842 SDL_EnableScreenSaver()
  1843 {
  1844     if (!_this) {
  1845         return;
  1846     }
  1847     if (!_this->suspend_screensaver) {
  1848         return;
  1849     }
  1850     _this->suspend_screensaver = SDL_FALSE;
  1851     if (_this->SuspendScreenSaver) {
  1852         _this->SuspendScreenSaver(_this);
  1853     }
  1854 }
  1855 
  1856 void
  1857 SDL_DisableScreenSaver()
  1858 {
  1859     if (!_this) {
  1860         return;
  1861     }
  1862     if (_this->suspend_screensaver) {
  1863         return;
  1864     }
  1865     _this->suspend_screensaver = SDL_TRUE;
  1866     if (_this->SuspendScreenSaver) {
  1867         _this->SuspendScreenSaver(_this);
  1868     }
  1869 }
  1870 
  1871 void
  1872 SDL_VideoQuit(void)
  1873 {
  1874     int i, j;
  1875 
  1876     if (!_this) {
  1877         return;
  1878     }
  1879 
  1880     /* Halt event processing before doing anything else */
  1881     SDL_QuitQuit();
  1882     SDL_MouseQuit();
  1883     SDL_KeyboardQuit();
  1884     SDL_StopEventLoop();
  1885 
  1886     SDL_EnableScreenSaver();
  1887 
  1888     /* Clean up the system video */
  1889     while (_this->windows) {
  1890         SDL_DestroyWindow(_this->windows);
  1891     }
  1892     _this->VideoQuit(_this);
  1893 
  1894     for (i = _this->num_displays; i--;) {
  1895         SDL_VideoDisplay *display = &_this->displays[i];
  1896         for (j = display->num_display_modes; j--;) {
  1897             if (display->display_modes[j].driverdata) {
  1898                 SDL_free(display->display_modes[j].driverdata);
  1899                 display->display_modes[j].driverdata = NULL;
  1900             }
  1901         }
  1902         if (display->display_modes) {
  1903             SDL_free(display->display_modes);
  1904             display->display_modes = NULL;
  1905         }
  1906         if (display->desktop_mode.driverdata) {
  1907             SDL_free(display->desktop_mode.driverdata);
  1908             display->desktop_mode.driverdata = NULL;
  1909         }
  1910         if (display->driverdata) {
  1911             SDL_free(display->driverdata);
  1912             display->driverdata = NULL;
  1913         }
  1914     }
  1915     if (_this->displays) {
  1916         SDL_free(_this->displays);
  1917         _this->displays = NULL;
  1918     }
  1919     if (_this->clipboard_text) {
  1920         SDL_free(_this->clipboard_text);
  1921         _this->clipboard_text = NULL;
  1922     }
  1923     _this->free(_this);
  1924     _this = NULL;
  1925 }
  1926 
  1927 int
  1928 SDL_GL_LoadLibrary(const char *path)
  1929 {
  1930     int retval;
  1931 
  1932     if (!_this) {
  1933         SDL_UninitializedVideo();
  1934         return -1;
  1935     }
  1936     if (_this->gl_config.driver_loaded) {
  1937         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  1938             SDL_SetError("OpenGL library already loaded");
  1939             return -1;
  1940         }
  1941         retval = 0;
  1942     } else {
  1943         if (!_this->GL_LoadLibrary) {
  1944             SDL_SetError("No dynamic GL support in video driver");
  1945             return -1;
  1946         }
  1947         retval = _this->GL_LoadLibrary(_this, path);
  1948     }
  1949     if (retval == 0) {
  1950         ++_this->gl_config.driver_loaded;
  1951     }
  1952     return (retval);
  1953 }
  1954 
  1955 void *
  1956 SDL_GL_GetProcAddress(const char *proc)
  1957 {
  1958     void *func;
  1959 
  1960     if (!_this) {
  1961         SDL_UninitializedVideo();
  1962         return NULL;
  1963     }
  1964     func = NULL;
  1965     if (_this->GL_GetProcAddress) {
  1966         if (_this->gl_config.driver_loaded) {
  1967             func = _this->GL_GetProcAddress(_this, proc);
  1968         } else {
  1969             SDL_SetError("No GL driver has been loaded");
  1970         }
  1971     } else {
  1972         SDL_SetError("No dynamic GL support in video driver");
  1973     }
  1974     return func;
  1975 }
  1976 
  1977 void
  1978 SDL_GL_UnloadLibrary(void)
  1979 {
  1980     if (!_this) {
  1981         SDL_UninitializedVideo();
  1982         return;
  1983     }
  1984     if (_this->gl_config.driver_loaded > 0) {
  1985         if (--_this->gl_config.driver_loaded > 0) {
  1986             return;
  1987         }
  1988         if (_this->GL_UnloadLibrary) {
  1989             _this->GL_UnloadLibrary(_this);
  1990         }
  1991     }
  1992 }
  1993 
  1994 SDL_bool
  1995 SDL_GL_ExtensionSupported(const char *extension)
  1996 {
  1997 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  1998     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  1999     const char *extensions;
  2000     const char *start;
  2001     const char *where, *terminator;
  2002 
  2003     /* Extension names should not have spaces. */
  2004     where = SDL_strchr(extension, ' ');
  2005     if (where || *extension == '\0') {
  2006         return SDL_FALSE;
  2007     }
  2008     /* See if there's an environment variable override */
  2009     start = SDL_getenv(extension);
  2010     if (start && *start == '0') {
  2011         return SDL_FALSE;
  2012     }
  2013     /* Lookup the available extensions */
  2014     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2015     if (glGetStringFunc) {
  2016         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2017     } else {
  2018         extensions = NULL;
  2019     }
  2020     if (!extensions) {
  2021         return SDL_FALSE;
  2022     }
  2023     /*
  2024      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2025      * extensions string. Don't be fooled by sub-strings, etc.
  2026      */
  2027 
  2028     start = extensions;
  2029 
  2030     for (;;) {
  2031         where = SDL_strstr(start, extension);
  2032         if (!where)
  2033             break;
  2034 
  2035         terminator = where + SDL_strlen(extension);
  2036         if (where == start || *(where - 1) == ' ')
  2037             if (*terminator == ' ' || *terminator == '\0')
  2038                 return SDL_TRUE;
  2039 
  2040         start = terminator;
  2041     }
  2042     return SDL_FALSE;
  2043 #else
  2044     return SDL_FALSE;
  2045 #endif
  2046 }
  2047 
  2048 int
  2049 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2050 {
  2051 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2052     int retval;
  2053 
  2054     if (!_this) {
  2055         SDL_UninitializedVideo();
  2056         return -1;
  2057     }
  2058     retval = 0;
  2059     switch (attr) {
  2060     case SDL_GL_RED_SIZE:
  2061         _this->gl_config.red_size = value;
  2062         break;
  2063     case SDL_GL_GREEN_SIZE:
  2064         _this->gl_config.green_size = value;
  2065         break;
  2066     case SDL_GL_BLUE_SIZE:
  2067         _this->gl_config.blue_size = value;
  2068         break;
  2069     case SDL_GL_ALPHA_SIZE:
  2070         _this->gl_config.alpha_size = value;
  2071         break;
  2072     case SDL_GL_DOUBLEBUFFER:
  2073         _this->gl_config.double_buffer = value;
  2074         break;
  2075     case SDL_GL_BUFFER_SIZE:
  2076         _this->gl_config.buffer_size = value;
  2077         break;
  2078     case SDL_GL_DEPTH_SIZE:
  2079         _this->gl_config.depth_size = value;
  2080         break;
  2081     case SDL_GL_STENCIL_SIZE:
  2082         _this->gl_config.stencil_size = value;
  2083         break;
  2084     case SDL_GL_ACCUM_RED_SIZE:
  2085         _this->gl_config.accum_red_size = value;
  2086         break;
  2087     case SDL_GL_ACCUM_GREEN_SIZE:
  2088         _this->gl_config.accum_green_size = value;
  2089         break;
  2090     case SDL_GL_ACCUM_BLUE_SIZE:
  2091         _this->gl_config.accum_blue_size = value;
  2092         break;
  2093     case SDL_GL_ACCUM_ALPHA_SIZE:
  2094         _this->gl_config.accum_alpha_size = value;
  2095         break;
  2096     case SDL_GL_STEREO:
  2097         _this->gl_config.stereo = value;
  2098         break;
  2099     case SDL_GL_MULTISAMPLEBUFFERS:
  2100         _this->gl_config.multisamplebuffers = value;
  2101         break;
  2102     case SDL_GL_MULTISAMPLESAMPLES:
  2103         _this->gl_config.multisamplesamples = value;
  2104         break;
  2105     case SDL_GL_ACCELERATED_VISUAL:
  2106         _this->gl_config.accelerated = value;
  2107         break;
  2108     case SDL_GL_RETAINED_BACKING:
  2109         _this->gl_config.retained_backing = value;
  2110         break;
  2111     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2112         _this->gl_config.major_version = value;
  2113         break;
  2114     case SDL_GL_CONTEXT_MINOR_VERSION:
  2115         _this->gl_config.minor_version = value;
  2116         break;
  2117     default:
  2118         SDL_SetError("Unknown OpenGL attribute");
  2119         retval = -1;
  2120         break;
  2121     }
  2122     return retval;
  2123 #else
  2124     SDL_Unsupported();
  2125     return -1;
  2126 #endif /* SDL_VIDEO_OPENGL */
  2127 }
  2128 
  2129 int
  2130 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  2131 {
  2132 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  2133     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  2134     GLenum(APIENTRY * glGetErrorFunc) (void);
  2135     GLenum attrib = 0;
  2136     GLenum error = 0;
  2137 
  2138     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  2139     if (!glGetIntegervFunc) {
  2140         return -1;
  2141     }
  2142 
  2143     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  2144     if (!glGetErrorFunc) {
  2145         return -1;
  2146     }
  2147 
  2148     /* Clear value in any case */
  2149     *value = 0;
  2150 
  2151     switch (attr) {
  2152     case SDL_GL_RED_SIZE:
  2153         attrib = GL_RED_BITS;
  2154         break;
  2155     case SDL_GL_BLUE_SIZE:
  2156         attrib = GL_BLUE_BITS;
  2157         break;
  2158     case SDL_GL_GREEN_SIZE:
  2159         attrib = GL_GREEN_BITS;
  2160         break;
  2161     case SDL_GL_ALPHA_SIZE:
  2162         attrib = GL_ALPHA_BITS;
  2163         break;
  2164     case SDL_GL_DOUBLEBUFFER:
  2165 #if SDL_VIDEO_OPENGL
  2166         attrib = GL_DOUBLEBUFFER;
  2167         break;
  2168 #else
  2169         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  2170         /* parameter which switches double buffer to single buffer. OpenGL ES */
  2171         /* SDL driver must set proper value after initialization              */
  2172         *value = _this->gl_config.double_buffer;
  2173         return 0;
  2174 #endif
  2175     case SDL_GL_DEPTH_SIZE:
  2176         attrib = GL_DEPTH_BITS;
  2177         break;
  2178     case SDL_GL_STENCIL_SIZE:
  2179         attrib = GL_STENCIL_BITS;
  2180         break;
  2181 #if SDL_VIDEO_OPENGL
  2182     case SDL_GL_ACCUM_RED_SIZE:
  2183         attrib = GL_ACCUM_RED_BITS;
  2184         break;
  2185     case SDL_GL_ACCUM_GREEN_SIZE:
  2186         attrib = GL_ACCUM_GREEN_BITS;
  2187         break;
  2188     case SDL_GL_ACCUM_BLUE_SIZE:
  2189         attrib = GL_ACCUM_BLUE_BITS;
  2190         break;
  2191     case SDL_GL_ACCUM_ALPHA_SIZE:
  2192         attrib = GL_ACCUM_ALPHA_BITS;
  2193         break;
  2194     case SDL_GL_STEREO:
  2195         attrib = GL_STEREO;
  2196         break;
  2197 #else
  2198     case SDL_GL_ACCUM_RED_SIZE:
  2199     case SDL_GL_ACCUM_GREEN_SIZE:
  2200     case SDL_GL_ACCUM_BLUE_SIZE:
  2201     case SDL_GL_ACCUM_ALPHA_SIZE:
  2202     case SDL_GL_STEREO:
  2203         /* none of these are supported in OpenGL ES */
  2204         *value = 0;
  2205         return 0;
  2206 #endif
  2207     case SDL_GL_MULTISAMPLEBUFFERS:
  2208 #if SDL_VIDEO_OPENGL
  2209         attrib = GL_SAMPLE_BUFFERS_ARB;
  2210 #else
  2211         attrib = GL_SAMPLE_BUFFERS;
  2212 #endif
  2213         break;
  2214     case SDL_GL_MULTISAMPLESAMPLES:
  2215 #if SDL_VIDEO_OPENGL
  2216         attrib = GL_SAMPLES_ARB;
  2217 #else
  2218         attrib = GL_SAMPLES;
  2219 #endif
  2220         break;
  2221     case SDL_GL_BUFFER_SIZE:
  2222         {
  2223             GLint bits = 0;
  2224             GLint component;
  2225 
  2226             /*
  2227              * there doesn't seem to be a single flag in OpenGL
  2228              * for this!
  2229              */
  2230             glGetIntegervFunc(GL_RED_BITS, &component);
  2231             bits += component;
  2232             glGetIntegervFunc(GL_GREEN_BITS, &component);
  2233             bits += component;
  2234             glGetIntegervFunc(GL_BLUE_BITS, &component);
  2235             bits += component;
  2236             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  2237             bits += component;
  2238 
  2239             *value = bits;
  2240             return 0;
  2241         }
  2242     case SDL_GL_ACCELERATED_VISUAL:
  2243         {
  2244             /* FIXME: How do we get this information? */
  2245             *value = (_this->gl_config.accelerated != 0);
  2246             return 0;
  2247         }
  2248     case SDL_GL_RETAINED_BACKING:
  2249         {
  2250             *value = _this->gl_config.retained_backing;
  2251             return 0;
  2252         }
  2253     case SDL_GL_CONTEXT_MAJOR_VERSION:
  2254         {
  2255             *value = _this->gl_config.major_version;
  2256             return 0;
  2257         }
  2258     case SDL_GL_CONTEXT_MINOR_VERSION:
  2259         {
  2260             *value = _this->gl_config.minor_version;
  2261             return 0;
  2262         }
  2263     default:
  2264         SDL_SetError("Unknown OpenGL attribute");
  2265         return -1;
  2266     }
  2267 
  2268     glGetIntegervFunc(attrib, (GLint *) value);
  2269     error = glGetErrorFunc();
  2270     if (error != GL_NO_ERROR) {
  2271         switch (error) {
  2272         case GL_INVALID_ENUM:
  2273             {
  2274                 SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  2275             }
  2276             break;
  2277         case GL_INVALID_VALUE:
  2278             {
  2279                 SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  2280             }
  2281             break;
  2282         default:
  2283             {
  2284                 SDL_SetError("OpenGL error: %08X", error);
  2285             }
  2286             break;
  2287         }
  2288         return -1;
  2289     }
  2290     return 0;
  2291 #else
  2292     SDL_Unsupported();
  2293     return -1;
  2294 #endif /* SDL_VIDEO_OPENGL */
  2295 }
  2296 
  2297 SDL_GLContext
  2298 SDL_GL_CreateContext(SDL_Window * window)
  2299 {
  2300     CHECK_WINDOW_MAGIC(window, NULL);
  2301 
  2302     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2303         SDL_SetError("The specified window isn't an OpenGL window");
  2304         return NULL;
  2305     }
  2306     return _this->GL_CreateContext(_this, window);
  2307 }
  2308 
  2309 int
  2310 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext context)
  2311 {
  2312     CHECK_WINDOW_MAGIC(window, -1);
  2313 
  2314     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2315         SDL_SetError("The specified window isn't an OpenGL window");
  2316         return -1;
  2317     }
  2318     if (!context) {
  2319         window = NULL;
  2320     }
  2321     return _this->GL_MakeCurrent(_this, window, context);
  2322 }
  2323 
  2324 int
  2325 SDL_GL_SetSwapInterval(int interval)
  2326 {
  2327     if (!_this) {
  2328         SDL_UninitializedVideo();
  2329         return -1;
  2330     }
  2331     if (_this->GL_SetSwapInterval) {
  2332         return _this->GL_SetSwapInterval(_this, interval);
  2333     } else {
  2334         SDL_SetError("Setting the swap interval is not supported");
  2335         return -1;
  2336     }
  2337 }
  2338 
  2339 int
  2340 SDL_GL_GetSwapInterval(void)
  2341 {
  2342     if (!_this) {
  2343         SDL_UninitializedVideo();
  2344         return -1;
  2345     }
  2346     if (_this->GL_GetSwapInterval) {
  2347         return _this->GL_GetSwapInterval(_this);
  2348     } else {
  2349         SDL_SetError("Getting the swap interval is not supported");
  2350         return -1;
  2351     }
  2352 }
  2353 
  2354 void
  2355 SDL_GL_SwapWindow(SDL_Window * window)
  2356 {
  2357     CHECK_WINDOW_MAGIC(window, );
  2358 
  2359     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2360         SDL_SetError("The specified window isn't an OpenGL window");
  2361         return;
  2362     }
  2363     _this->GL_SwapWindow(_this, window);
  2364 }
  2365 
  2366 void
  2367 SDL_GL_DeleteContext(SDL_GLContext context)
  2368 {
  2369     if (!_this || !_this->gl_data || !context) {
  2370         return;
  2371     }
  2372     _this->GL_MakeCurrent(_this, NULL, NULL);
  2373     _this->GL_DeleteContext(_this, context);
  2374 }
  2375 
  2376 #if 0                           // FIXME
  2377 /*
  2378  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2379  * & 2 for alpha channel.
  2380  */
  2381 static void
  2382 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2383 {
  2384     int x, y;
  2385     Uint32 colorkey;
  2386 #define SET_MASKBIT(icon, x, y, mask) \
  2387 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2388 
  2389     colorkey = icon->format->colorkey;
  2390     switch (icon->format->BytesPerPixel) {
  2391     case 1:
  2392         {
  2393             Uint8 *pixels;
  2394             for (y = 0; y < icon->h; ++y) {
  2395                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2396                 for (x = 0; x < icon->w; ++x) {
  2397                     if (*pixels++ == colorkey) {
  2398                         SET_MASKBIT(icon, x, y, mask);
  2399                     }
  2400                 }
  2401             }
  2402         }
  2403         break;
  2404 
  2405     case 2:
  2406         {
  2407             Uint16 *pixels;
  2408             for (y = 0; y < icon->h; ++y) {
  2409                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2410                 for (x = 0; x < icon->w; ++x) {
  2411                     if ((flags & 1) && *pixels == colorkey) {
  2412                         SET_MASKBIT(icon, x, y, mask);
  2413                     } else if ((flags & 2)
  2414                                && (*pixels & icon->format->Amask) == 0) {
  2415                         SET_MASKBIT(icon, x, y, mask);
  2416                     }
  2417                     pixels++;
  2418                 }
  2419             }
  2420         }
  2421         break;
  2422 
  2423     case 4:
  2424         {
  2425             Uint32 *pixels;
  2426             for (y = 0; y < icon->h; ++y) {
  2427                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2428                 for (x = 0; x < icon->w; ++x) {
  2429                     if ((flags & 1) && *pixels == colorkey) {
  2430                         SET_MASKBIT(icon, x, y, mask);
  2431                     } else if ((flags & 2)
  2432                                && (*pixels & icon->format->Amask) == 0) {
  2433                         SET_MASKBIT(icon, x, y, mask);
  2434                     }
  2435                     pixels++;
  2436                 }
  2437             }
  2438         }
  2439         break;
  2440     }
  2441 }
  2442 
  2443 /*
  2444  * Sets the window manager icon for the display window.
  2445  */
  2446 void
  2447 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2448 {
  2449     if (icon && _this->SetIcon) {
  2450         /* Generate a mask if necessary, and create the icon! */
  2451         if (mask == NULL) {
  2452             int mask_len = icon->h * (icon->w + 7) / 8;
  2453             int flags = 0;
  2454             mask = (Uint8 *) SDL_malloc(mask_len);
  2455             if (mask == NULL) {
  2456                 return;
  2457             }
  2458             SDL_memset(mask, ~0, mask_len);
  2459             if (icon->flags & SDL_SRCCOLORKEY)
  2460                 flags |= 1;
  2461             if (icon->flags & SDL_SRCALPHA)
  2462                 flags |= 2;
  2463             if (flags) {
  2464                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2465             }
  2466             _this->SetIcon(_this, icon, mask);
  2467             SDL_free(mask);
  2468         } else {
  2469             _this->SetIcon(_this, icon, mask);
  2470         }
  2471     }
  2472 }
  2473 #endif
  2474 
  2475 SDL_bool
  2476 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2477 {
  2478     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2479 
  2480     if (!info) {
  2481         return SDL_FALSE;
  2482     }
  2483     info->subsystem = SDL_SYSWM_UNKNOWN;
  2484 
  2485     if (!_this->GetWindowWMInfo) {
  2486         return SDL_FALSE;
  2487     }
  2488     return (_this->GetWindowWMInfo(_this, window, info));
  2489 }
  2490 
  2491 void
  2492 SDL_StartTextInput(void)
  2493 {
  2494     if (_this && _this->StartTextInput) {
  2495         _this->StartTextInput(_this);
  2496     }
  2497     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2498     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2499 }
  2500 
  2501 void
  2502 SDL_StopTextInput(void)
  2503 {
  2504     if (_this && _this->StopTextInput) {
  2505         _this->StopTextInput(_this);
  2506     }
  2507     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2508     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2509 }
  2510 
  2511 void
  2512 SDL_SetTextInputRect(SDL_Rect *rect)
  2513 {
  2514     if (_this && _this->SetTextInputRect) {
  2515         _this->SetTextInputRect(_this, rect);
  2516     }
  2517 }
  2518 
  2519 /* vi: set ts=4 sw=4 expandtab: */