src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Mar 2011 18:38:29 -0800
changeset 5480 55a687c55676
parent 5479 5c4635640bf9
child 5535 96594ac5fd1a
permissions -rw-r--r--
Fixed operator precedence

Frank Zago to SDL

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