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