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