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