src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 31 Oct 2011 05:56:58 -0400
changeset 6044 35448a5ea044
parent 5571 a036283f779d
child 6063 44cd82d8ea65
permissions -rw-r--r--
Lots of fixes importing SDL source wholesale into a new iOS project
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* The high-level video driver subsystem */
    24 
    25 #include "SDL.h"
    26 #include "SDL_video.h"
    27 #include "SDL_sysvideo.h"
    28 #include "SDL_blit.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_rect_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 /* Support for framebuffer emulation using an accelerated renderer */
   111 
   112 #define SDL_WINDOWTEXTUREDATA   "_SDL_WindowTextureData"
   113 
   114 typedef struct {
   115     SDL_Renderer *renderer;
   116     SDL_Texture *texture;
   117     void *pixels;
   118     int pitch;
   119     int bytes_per_pixel;
   120 } SDL_WindowTextureData;
   121 
   122 static SDL_bool
   123 ShouldUseTextureFramebuffer()
   124 {
   125     const char *hint;
   126 
   127     /* If there's no native framebuffer support then there's no option */
   128     if (!_this->CreateWindowFramebuffer) {
   129         return SDL_TRUE;
   130     }
   131 
   132     /* If the user has specified a software renderer we can't use a
   133        texture framebuffer, or renderer creation will go recursive.
   134      */
   135     hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER);
   136     if (hint && SDL_strcasecmp(hint, "software") == 0) {
   137         return SDL_FALSE;
   138     }
   139 
   140     /* See if the user or application wants a specific behavior */
   141     hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   142     if (hint) {
   143         if (*hint == '0') {
   144             return SDL_FALSE;
   145         } else {
   146             return SDL_TRUE;
   147         }
   148     }
   149 
   150     /* Each platform has different performance characteristics */
   151 #if defined(__WIN32__)
   152     /* GDI BitBlt() is way faster than Direct3D dynamic textures right now.
   153      */
   154     return SDL_FALSE;
   155 
   156 #elif defined(__MACOSX__)
   157     /* Mac OS X uses OpenGL as the native fast path */
   158     return SDL_TRUE;
   159 
   160 #elif defined(__LINUX__)
   161     /* Properly configured OpenGL drivers are faster than MIT-SHM */
   162 #if SDL_VIDEO_OPENGL
   163     /* Ugh, find a way to cache this value! */
   164     {
   165         SDL_Window *window;
   166         SDL_GLContext context;
   167         SDL_bool hasAcceleratedOpenGL = SDL_FALSE;
   168 
   169         window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN);
   170         if (window) {
   171             context = SDL_GL_CreateContext(window);
   172             if (context) {
   173                 const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
   174                 const char *vendor = NULL;
   175 
   176                 glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
   177                 if (glGetStringFunc) {
   178                     vendor = (const char *) glGetStringFunc(GL_VENDOR);
   179                 }
   180                 /* Add more vendors here at will... */
   181                 if (vendor &&
   182                     (SDL_strstr(vendor, "ATI Technologies") ||
   183                      SDL_strstr(vendor, "NVIDIA"))) {
   184                     hasAcceleratedOpenGL = SDL_TRUE;
   185                 }
   186                 SDL_GL_DeleteContext(context);
   187             }
   188             SDL_DestroyWindow(window);
   189         }
   190         return hasAcceleratedOpenGL;
   191     }
   192 #else
   193     return SDL_FALSE;
   194 #endif
   195 
   196 #else
   197     /* Play it safe, assume that if there is a framebuffer driver that it's
   198        optimized for the current platform.
   199     */
   200     return SDL_FALSE;
   201 #endif
   202 }
   203 
   204 static int
   205 SDL_CreateWindowTexture(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
   206 {
   207     SDL_WindowTextureData *data;
   208     SDL_RendererInfo info;
   209     Uint32 i;
   210 
   211     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   212     if (!data) {
   213         SDL_Renderer *renderer = NULL;
   214         SDL_RendererInfo info;
   215         int i;
   216         const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION);
   217 
   218         /* Check to see if there's a specific driver requested */
   219         if (hint && *hint != '0' && *hint != '1' &&
   220             SDL_strcasecmp(hint, "software") != 0) {
   221             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   222                 SDL_GetRenderDriverInfo(i, &info);
   223                 if (SDL_strcasecmp(info.name, hint) == 0) {
   224                     renderer = SDL_CreateRenderer(window, i, 0);
   225                     break;
   226                 }
   227             }
   228         }
   229 
   230         if (!renderer) {
   231             for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
   232                 SDL_GetRenderDriverInfo(i, &info);
   233                 if (SDL_strcmp(info.name, "software") != 0) {
   234                     renderer = SDL_CreateRenderer(window, i, 0);
   235                     if (renderer) {
   236                         break;
   237                     }
   238                 }
   239             }
   240         }
   241         if (!renderer) {
   242             return -1;
   243         }
   244 
   245         /* Create the data after we successfully create the renderer (bug #1116) */
   246         data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
   247         if (!data) {
   248             SDL_DestroyRenderer(renderer);
   249             SDL_OutOfMemory();
   250             return -1;
   251         }
   252         SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data);
   253 
   254         data->renderer = renderer;
   255     }
   256 
   257     /* Free any old texture and pixel data */
   258     if (data->texture) {
   259         SDL_DestroyTexture(data->texture);
   260         data->texture = NULL;
   261     }
   262     if (data->pixels) {
   263         SDL_free(data->pixels);
   264         data->pixels = NULL;
   265     }
   266 
   267     if (SDL_GetRendererInfo(data->renderer, &info) < 0) {
   268         return -1;
   269     }
   270 
   271     /* Find the first format without an alpha channel */
   272     *format = info.texture_formats[0];
   273     for (i = 0; i < info.num_texture_formats; ++i) {
   274         if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) &&
   275             !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) {
   276             *format = info.texture_formats[i];
   277             break;
   278         }
   279     }
   280 
   281     data->texture = SDL_CreateTexture(data->renderer, *format,
   282                                       SDL_TEXTUREACCESS_STREAMING,
   283                                       window->w, window->h);
   284     if (!data->texture) {
   285         return -1;
   286     }
   287 
   288     /* Create framebuffer data */
   289     data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
   290     data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
   291     data->pixels = SDL_malloc(window->h * data->pitch);
   292     if (!data->pixels) {
   293         SDL_OutOfMemory();
   294         return -1;
   295     }
   296 
   297     *pixels = data->pixels;
   298     *pitch = data->pitch;
   299 
   300     /* Make sure we're not double-scaling the viewport */
   301     SDL_RenderSetViewport(data->renderer, NULL);
   302 
   303     return 0;
   304 }
   305 
   306 static int
   307 SDL_UpdateWindowTexture(_THIS, SDL_Window * window, SDL_Rect * rects, int numrects)
   308 {
   309     SDL_WindowTextureData *data;
   310     SDL_Rect rect;
   311     void *src;
   312 
   313     data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
   314     if (!data || !data->texture) {
   315         SDL_SetError("No window texture data");
   316         return -1;
   317     }
   318 
   319     /* Update a single rect that contains subrects for best DMA performance */
   320     if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
   321         src = (void *)((Uint8 *)data->pixels +
   322                         rect.y * data->pitch +
   323                         rect.x * data->bytes_per_pixel);
   324         if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) {
   325             return -1;
   326         }
   327 
   328         if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) {
   329             return -1;
   330         }
   331 
   332         SDL_RenderPresent(data->renderer);
   333     }
   334     return 0;
   335 }
   336 
   337 static void
   338 SDL_DestroyWindowTexture(_THIS, SDL_Window * window)
   339 {
   340     SDL_WindowTextureData *data;
   341 
   342     data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL);
   343     if (!data) {
   344         return;
   345     }
   346     if (data->texture) {
   347         SDL_DestroyTexture(data->texture);
   348     }
   349     if (data->renderer) {
   350         SDL_DestroyRenderer(data->renderer);
   351     }
   352     if (data->pixels) {
   353         SDL_free(data->pixels);
   354     }
   355     SDL_free(data);
   356 }
   357 
   358 
   359 static int
   360 cmpmodes(const void *A, const void *B)
   361 {
   362     SDL_DisplayMode a = *(const SDL_DisplayMode *) A;
   363     SDL_DisplayMode b = *(const SDL_DisplayMode *) B;
   364 
   365     if (a.w != b.w) {
   366         return b.w - a.w;
   367     }
   368     if (a.h != b.h) {
   369         return b.h - a.h;
   370     }
   371     if (SDL_BITSPERPIXEL(a.format) != SDL_BITSPERPIXEL(b.format)) {
   372         return SDL_BITSPERPIXEL(b.format) - SDL_BITSPERPIXEL(a.format);
   373     }
   374     if (SDL_PIXELLAYOUT(a.format) != SDL_PIXELLAYOUT(b.format)) {
   375         return SDL_PIXELLAYOUT(b.format) - SDL_PIXELLAYOUT(a.format);
   376     }
   377     if (a.refresh_rate != b.refresh_rate) {
   378         return b.refresh_rate - a.refresh_rate;
   379     }
   380     return 0;
   381 }
   382 
   383 static void
   384 SDL_UninitializedVideo()
   385 {
   386     SDL_SetError("Video subsystem has not been initialized");
   387 }
   388 
   389 int
   390 SDL_GetNumVideoDrivers(void)
   391 {
   392     return SDL_arraysize(bootstrap) - 1;
   393 }
   394 
   395 const char *
   396 SDL_GetVideoDriver(int index)
   397 {
   398     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
   399         return bootstrap[index]->name;
   400     }
   401     return NULL;
   402 }
   403 
   404 /*
   405  * Initialize the video and event subsystems -- determine native pixel format
   406  */
   407 int
   408 SDL_VideoInit(const char *driver_name)
   409 {
   410     SDL_VideoDevice *video;
   411     int index;
   412     int i;
   413 
   414     /* Check to make sure we don't overwrite '_this' */
   415     if (_this != NULL) {
   416         SDL_VideoQuit();
   417     }
   418 
   419     /* Start the event loop */
   420     if (SDL_StartEventLoop() < 0 ||
   421         SDL_KeyboardInit() < 0 ||
   422         SDL_MouseInit() < 0 ||
   423         SDL_TouchInit() < 0 ||
   424         SDL_QuitInit() < 0) {
   425         return -1;
   426     }
   427 
   428     /* Select the proper video driver */
   429     index = 0;
   430     video = NULL;
   431     if (driver_name == NULL) {
   432         driver_name = SDL_getenv("SDL_VIDEODRIVER");
   433     }
   434     if (driver_name != NULL) {
   435         for (i = 0; bootstrap[i]; ++i) {
   436             if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
   437                 video = bootstrap[i]->create(index);
   438                 break;
   439             }
   440         }
   441     } else {
   442         for (i = 0; bootstrap[i]; ++i) {
   443             if (bootstrap[i]->available()) {
   444                 video = bootstrap[i]->create(index);
   445                 if (video != NULL) {
   446                     break;
   447                 }
   448             }
   449         }
   450     }
   451     if (video == NULL) {
   452         if (driver_name) {
   453             SDL_SetError("%s not available", driver_name);
   454         } else {
   455             SDL_SetError("No available video device");
   456         }
   457         return -1;
   458     }
   459     _this = video;
   460     _this->name = bootstrap[i]->name;
   461     _this->next_object_id = 1;
   462 
   463 
   464     /* Set some very sane GL defaults */
   465     _this->gl_config.driver_loaded = 0;
   466     _this->gl_config.dll_handle = NULL;
   467     _this->gl_config.red_size = 3;
   468     _this->gl_config.green_size = 3;
   469     _this->gl_config.blue_size = 2;
   470     _this->gl_config.alpha_size = 0;
   471     _this->gl_config.buffer_size = 0;
   472     _this->gl_config.depth_size = 16;
   473     _this->gl_config.stencil_size = 0;
   474     _this->gl_config.double_buffer = 1;
   475     _this->gl_config.accum_red_size = 0;
   476     _this->gl_config.accum_green_size = 0;
   477     _this->gl_config.accum_blue_size = 0;
   478     _this->gl_config.accum_alpha_size = 0;
   479     _this->gl_config.stereo = 0;
   480     _this->gl_config.multisamplebuffers = 0;
   481     _this->gl_config.multisamplesamples = 0;
   482     _this->gl_config.retained_backing = 1;
   483     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
   484 #if SDL_VIDEO_OPENGL
   485     _this->gl_config.major_version = 2;
   486     _this->gl_config.minor_version = 1;
   487 #elif SDL_VIDEO_OPENGL_ES
   488     _this->gl_config.major_version = 1;
   489     _this->gl_config.minor_version = 1;
   490 #elif SDL_VIDEO_OPENGL_ES2
   491     _this->gl_config.major_version = 2;
   492     _this->gl_config.minor_version = 0;
   493 #endif
   494 
   495     /* Initialize the video subsystem */
   496     if (_this->VideoInit(_this) < 0) {
   497         SDL_VideoQuit();
   498         return -1;
   499     }
   500 
   501     /* Make sure some displays were added */
   502     if (_this->num_displays == 0) {
   503         SDL_SetError("The video driver did not add any displays");
   504         SDL_VideoQuit();
   505         return (-1);
   506     }
   507 
   508     /* Add the renderer framebuffer emulation if desired */
   509     if (ShouldUseTextureFramebuffer()) {
   510         _this->CreateWindowFramebuffer = SDL_CreateWindowTexture;
   511         _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture;
   512         _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture;
   513     }
   514 
   515     /* We're ready to go! */
   516     return 0;
   517 }
   518 
   519 const char *
   520 SDL_GetCurrentVideoDriver()
   521 {
   522     if (!_this) {
   523         SDL_UninitializedVideo();
   524         return NULL;
   525     }
   526     return _this->name;
   527 }
   528 
   529 SDL_VideoDevice *
   530 SDL_GetVideoDevice(void)
   531 {
   532     return _this;
   533 }
   534 
   535 int
   536 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   537 {
   538     SDL_VideoDisplay display;
   539 
   540     SDL_zero(display);
   541     if (desktop_mode) {
   542         display.desktop_mode = *desktop_mode;
   543     }
   544     display.current_mode = display.desktop_mode;
   545 
   546     return SDL_AddVideoDisplay(&display);
   547 }
   548 
   549 int
   550 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   551 {
   552     SDL_VideoDisplay *displays;
   553     int index = -1;
   554 
   555     displays =
   556         SDL_realloc(_this->displays,
   557                     (_this->num_displays + 1) * sizeof(*displays));
   558     if (displays) {
   559         index = _this->num_displays++;
   560         displays[index] = *display;
   561         displays[index].device = _this;
   562         _this->displays = displays;
   563     } else {
   564         SDL_OutOfMemory();
   565     }
   566     return index;
   567 }
   568 
   569 int
   570 SDL_GetNumVideoDisplays(void)
   571 {
   572     if (!_this) {
   573         SDL_UninitializedVideo();
   574         return 0;
   575     }
   576     return _this->num_displays;
   577 }
   578 
   579 static int
   580 SDL_GetIndexOfDisplay(SDL_VideoDisplay *display)
   581 {
   582     int displayIndex;
   583 
   584     for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) {
   585         if (display == &_this->displays[displayIndex]) {
   586             return displayIndex;
   587         }
   588     }
   589 
   590     /* Couldn't find the display, just use index 0 */
   591     return 0;
   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 static int
   659 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   660 {
   661     if (!display->num_display_modes && _this->GetDisplayModes) {
   662         _this->GetDisplayModes(_this, display);
   663         SDL_qsort(display->display_modes, display->num_display_modes,
   664                   sizeof(SDL_DisplayMode), cmpmodes);
   665     }
   666     return display->num_display_modes;
   667 }
   668 
   669 int
   670 SDL_GetNumDisplayModes(int displayIndex)
   671 {
   672     CHECK_DISPLAY_INDEX(displayIndex, -1);
   673 
   674     return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]);
   675 }
   676 
   677 int
   678 SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode)
   679 {
   680     SDL_VideoDisplay *display;
   681 
   682     CHECK_DISPLAY_INDEX(displayIndex, -1);
   683 
   684     display = &_this->displays[displayIndex];
   685     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   686         SDL_SetError("index must be in the range of 0 - %d",
   687                      SDL_GetNumDisplayModesForDisplay(display) - 1);
   688         return -1;
   689     }
   690     if (mode) {
   691         *mode = display->display_modes[index];
   692     }
   693     return 0;
   694 }
   695 
   696 int
   697 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   698 {
   699     SDL_VideoDisplay *display;
   700 
   701     CHECK_DISPLAY_INDEX(displayIndex, -1);
   702 
   703     display = &_this->displays[displayIndex];
   704     if (mode) {
   705         *mode = display->desktop_mode;
   706     }
   707     return 0;
   708 }
   709 
   710 int
   711 SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode)
   712 {
   713     SDL_VideoDisplay *display;
   714 
   715     CHECK_DISPLAY_INDEX(displayIndex, -1);
   716 
   717     display = &_this->displays[displayIndex];
   718     if (mode) {
   719         *mode = display->current_mode;
   720     }
   721     return 0;
   722 }
   723 
   724 static SDL_DisplayMode *
   725 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   726                                     const SDL_DisplayMode * mode,
   727                                     SDL_DisplayMode * closest)
   728 {
   729     Uint32 target_format;
   730     int target_refresh_rate;
   731     int i;
   732     SDL_DisplayMode *current, *match;
   733 
   734     if (!mode || !closest) {
   735         SDL_SetError("Missing desired mode or closest mode parameter");
   736         return NULL;
   737     }
   738 
   739     /* Default to the desktop format */
   740     if (mode->format) {
   741         target_format = mode->format;
   742     } else {
   743         target_format = display->desktop_mode.format;
   744     }
   745 
   746     /* Default to the desktop refresh rate */
   747     if (mode->refresh_rate) {
   748         target_refresh_rate = mode->refresh_rate;
   749     } else {
   750         target_refresh_rate = display->desktop_mode.refresh_rate;
   751     }
   752 
   753     match = NULL;
   754     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   755         current = &display->display_modes[i];
   756 
   757         if (current->w && (current->w < mode->w)) {
   758             /* Out of sorted modes large enough here */
   759             break;
   760         }
   761         if (current->h && (current->h < mode->h)) {
   762             if (current->w && (current->w == mode->w)) {
   763                 /* Out of sorted modes large enough here */
   764                 break;
   765             }
   766             /* Wider, but not tall enough, due to a different
   767                aspect ratio. This mode must be skipped, but closer
   768                modes may still follow. */
   769             continue;
   770         }
   771         if (!match || current->w < match->w || current->h < match->h) {
   772             match = current;
   773             continue;
   774         }
   775         if (current->format != match->format) {
   776             /* Sorted highest depth to lowest */
   777             if (current->format == target_format ||
   778                 (SDL_BITSPERPIXEL(current->format) >=
   779                  SDL_BITSPERPIXEL(target_format)
   780                  && SDL_PIXELTYPE(current->format) ==
   781                  SDL_PIXELTYPE(target_format))) {
   782                 match = current;
   783             }
   784             continue;
   785         }
   786         if (current->refresh_rate != match->refresh_rate) {
   787             /* Sorted highest refresh to lowest */
   788             if (current->refresh_rate >= target_refresh_rate) {
   789                 match = current;
   790             }
   791         }
   792     }
   793     if (match) {
   794         if (match->format) {
   795             closest->format = match->format;
   796         } else {
   797             closest->format = mode->format;
   798         }
   799         if (match->w && match->h) {
   800             closest->w = match->w;
   801             closest->h = match->h;
   802         } else {
   803             closest->w = mode->w;
   804             closest->h = mode->h;
   805         }
   806         if (match->refresh_rate) {
   807             closest->refresh_rate = match->refresh_rate;
   808         } else {
   809             closest->refresh_rate = mode->refresh_rate;
   810         }
   811         closest->driverdata = match->driverdata;
   812 
   813         /*
   814          * Pick some reasonable defaults if the app and driver don't
   815          * care
   816          */
   817         if (!closest->format) {
   818             closest->format = SDL_PIXELFORMAT_RGB888;
   819         }
   820         if (!closest->w) {
   821             closest->w = 640;
   822         }
   823         if (!closest->h) {
   824             closest->h = 480;
   825         }
   826         return closest;
   827     }
   828     return NULL;
   829 }
   830 
   831 SDL_DisplayMode *
   832 SDL_GetClosestDisplayMode(int displayIndex,
   833                           const SDL_DisplayMode * mode,
   834                           SDL_DisplayMode * closest)
   835 {
   836     SDL_VideoDisplay *display;
   837 
   838     CHECK_DISPLAY_INDEX(displayIndex, NULL);
   839 
   840     display = &_this->displays[displayIndex];
   841     return SDL_GetClosestDisplayModeForDisplay(display, mode, closest);
   842 }
   843 
   844 static int
   845 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   846 {
   847     SDL_DisplayMode display_mode;
   848     SDL_DisplayMode current_mode;
   849 
   850     if (mode) {
   851         display_mode = *mode;
   852 
   853         /* Default to the current mode */
   854         if (!display_mode.format) {
   855             display_mode.format = display->current_mode.format;
   856         }
   857         if (!display_mode.w) {
   858             display_mode.w = display->current_mode.w;
   859         }
   860         if (!display_mode.h) {
   861             display_mode.h = display->current_mode.h;
   862         }
   863         if (!display_mode.refresh_rate) {
   864             display_mode.refresh_rate = display->current_mode.refresh_rate;
   865         }
   866 
   867         /* Get a good video mode, the closest one possible */
   868         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   869             SDL_SetError("No video mode large enough for %dx%d",
   870                          display_mode.w, display_mode.h);
   871             return -1;
   872         }
   873     } else {
   874         display_mode = display->desktop_mode;
   875     }
   876 
   877     /* See if there's anything left to do */
   878     current_mode = display->current_mode;
   879     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   880         return 0;
   881     }
   882 
   883     /* Actually change the display mode */
   884     if (!_this->SetDisplayMode) {
   885         SDL_SetError("Video driver doesn't support changing display mode");
   886         return -1;
   887     }
   888     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   889         return -1;
   890     }
   891     display->current_mode = display_mode;
   892     return 0;
   893 }
   894 
   895 int
   896 SDL_GetWindowDisplay(SDL_Window * window)
   897 {
   898     int displayIndex;
   899     int i, dist;
   900     int closest = -1;
   901     int closest_dist = 0x7FFFFFFF;
   902     SDL_Point center;
   903     SDL_Point delta;
   904     SDL_Rect rect;
   905 
   906     CHECK_WINDOW_MAGIC(window, -1);
   907 
   908     if (SDL_WINDOWPOS_ISUNDEFINED(window->x) ||
   909         SDL_WINDOWPOS_ISCENTERED(window->x)) {
   910         displayIndex = (window->x & 0xFFFF);
   911         if (displayIndex >= _this->num_displays) {
   912             displayIndex = 0;
   913         }
   914         return displayIndex;
   915     }
   916     if (SDL_WINDOWPOS_ISUNDEFINED(window->y) ||
   917         SDL_WINDOWPOS_ISCENTERED(window->y)) {
   918         displayIndex = (window->y & 0xFFFF);
   919         if (displayIndex >= _this->num_displays) {
   920             displayIndex = 0;
   921         }
   922         return displayIndex;
   923     }
   924 
   925     /* Find the display containing the window */
   926     center.x = window->x + window->w / 2;
   927     center.y = window->y + window->h / 2;
   928     for (i = 0; i < _this->num_displays; ++i) {
   929         SDL_VideoDisplay *display = &_this->displays[i];
   930 
   931         SDL_GetDisplayBounds(i, &rect);
   932         if (display->fullscreen_window == window || SDL_EnclosePoints(&center, 1, &rect, NULL)) {
   933             return i;
   934         }
   935 
   936         delta.x = center.x - (rect.x + rect.w / 2);
   937         delta.y = center.y - (rect.y + rect.h / 2);
   938         dist = (delta.x*delta.x + delta.y*delta.y);
   939         if (dist < closest_dist) {
   940             closest = i;
   941             closest_dist = dist;
   942         }
   943     }
   944     if (closest < 0) {
   945         SDL_SetError("Couldn't find any displays");
   946     }
   947     return closest;
   948 }
   949 
   950 SDL_VideoDisplay *
   951 SDL_GetDisplayForWindow(SDL_Window *window)
   952 {
   953     int displayIndex = SDL_GetWindowDisplay(window);
   954     if (displayIndex >= 0) {
   955         return &_this->displays[displayIndex];
   956     } else {
   957         return NULL;
   958     }
   959 }
   960 
   961 int
   962 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
   963 {
   964     CHECK_WINDOW_MAGIC(window, -1);
   965 
   966     if (mode) {
   967         window->fullscreen_mode = *mode;
   968     } else {
   969         SDL_zero(window->fullscreen_mode);
   970     }
   971     return 0;
   972 }
   973 
   974 int
   975 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
   976 {
   977     SDL_DisplayMode fullscreen_mode;
   978 
   979     CHECK_WINDOW_MAGIC(window, -1);
   980 
   981     fullscreen_mode = window->fullscreen_mode;
   982     if (!fullscreen_mode.w) {
   983         fullscreen_mode.w = window->w;
   984     }
   985     if (!fullscreen_mode.h) {
   986         fullscreen_mode.h = window->h;
   987     }
   988 
   989     if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
   990                                              &fullscreen_mode,
   991                                              &fullscreen_mode)) {
   992         SDL_SetError("Couldn't find display mode match");
   993         return -1;
   994     }
   995 
   996     if (mode) {
   997         *mode = fullscreen_mode;
   998     }
   999     return 0;
  1000 }
  1001 
  1002 Uint32
  1003 SDL_GetWindowPixelFormat(SDL_Window * window)
  1004 {
  1005     SDL_VideoDisplay *display;
  1006 
  1007     CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN);
  1008 
  1009     display = SDL_GetDisplayForWindow(window);
  1010     return display->current_mode.format;
  1011 }
  1012 
  1013 static void
  1014 SDL_RestoreMousePosition(SDL_Window *window)
  1015 {
  1016     int x, y;
  1017 
  1018     if (window == SDL_GetMouseFocus()) {
  1019         SDL_GetMouseState(&x, &y);
  1020         SDL_WarpMouseInWindow(window, x, y);
  1021     }
  1022 }
  1023 
  1024 static void
  1025 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
  1026 {
  1027     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1028     SDL_Window *other;
  1029 
  1030     if (fullscreen) {
  1031         /* Hide any other fullscreen windows */
  1032         if (display->fullscreen_window &&
  1033             display->fullscreen_window != window) {
  1034             SDL_MinimizeWindow(display->fullscreen_window);
  1035         }
  1036     }
  1037 
  1038     /* See if anything needs to be done now */
  1039     if ((display->fullscreen_window == window) == fullscreen) {
  1040         return;
  1041     }
  1042 
  1043     /* See if there are any fullscreen windows */
  1044     for (other = _this->windows; other; other = other->next) {
  1045         SDL_bool setDisplayMode = SDL_FALSE;
  1046 
  1047         if (other == window) {
  1048             setDisplayMode = fullscreen;
  1049         } else if (FULLSCREEN_VISIBLE(other) &&
  1050                    SDL_GetDisplayForWindow(other) == display) {
  1051             setDisplayMode = SDL_TRUE;
  1052         }
  1053 
  1054         if (setDisplayMode) {
  1055             SDL_DisplayMode fullscreen_mode;
  1056 
  1057             if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) {
  1058                 SDL_bool resized = SDL_TRUE;
  1059 
  1060                 if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) {
  1061                     resized = SDL_FALSE;
  1062                 }
  1063 
  1064                 SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
  1065                 if (_this->SetWindowFullscreen) {
  1066                     _this->SetWindowFullscreen(_this, other, display, SDL_TRUE);
  1067                 }
  1068                 display->fullscreen_window = other;
  1069 
  1070                 /* Generate a mode change event here */
  1071                 if (resized) {
  1072                     SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED,
  1073                                         fullscreen_mode.w, fullscreen_mode.h);
  1074                 } else {
  1075                     SDL_OnWindowResized(other);
  1076                 }
  1077 
  1078                 SDL_RestoreMousePosition(other);
  1079                 return;
  1080             }
  1081         }
  1082     }
  1083 
  1084     /* Nope, restore the desktop mode */
  1085     SDL_SetDisplayModeForDisplay(display, NULL);
  1086 
  1087     if (_this->SetWindowFullscreen) {
  1088         _this->SetWindowFullscreen(_this, window, display, SDL_FALSE);
  1089     }
  1090     display->fullscreen_window = NULL;
  1091 
  1092     /* Generate a mode change event here */
  1093     SDL_OnWindowResized(window);
  1094 
  1095     /* Restore the cursor position */
  1096     SDL_RestoreMousePosition(window);
  1097 }
  1098 
  1099 #define CREATE_FLAGS \
  1100     (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE)
  1101 
  1102 static void
  1103 SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags)
  1104 {
  1105     window->windowed.x = window->x;
  1106     window->windowed.y = window->y;
  1107     window->windowed.w = window->w;
  1108     window->windowed.h = window->h;
  1109 
  1110     if (flags & SDL_WINDOW_MAXIMIZED) {
  1111         SDL_MaximizeWindow(window);
  1112     }
  1113     if (flags & SDL_WINDOW_MINIMIZED) {
  1114         SDL_MinimizeWindow(window);
  1115     }
  1116     if (flags & SDL_WINDOW_FULLSCREEN) {
  1117         SDL_SetWindowFullscreen(window, SDL_TRUE);
  1118     }
  1119     if (flags & SDL_WINDOW_INPUT_GRABBED) {
  1120         SDL_SetWindowGrab(window, SDL_TRUE);
  1121     }
  1122     if (!(flags & SDL_WINDOW_HIDDEN)) {
  1123         SDL_ShowWindow(window);
  1124     }
  1125 }
  1126 
  1127 SDL_Window *
  1128 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
  1129 {
  1130     SDL_Window *window;
  1131 
  1132     if (!_this) {
  1133         /* Initialize the video system if needed */
  1134         if (SDL_VideoInit(NULL) < 0) {
  1135             return NULL;
  1136         }
  1137     }
  1138 
  1139     /* Some platforms have OpenGL enabled by default */
  1140 #if (SDL_VIDEO_OPENGL && __MACOSX__) || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2
  1141     flags |= SDL_WINDOW_OPENGL;
  1142 #endif
  1143     if (flags & SDL_WINDOW_OPENGL) {
  1144         if (!_this->GL_CreateContext) {
  1145             SDL_SetError("No OpenGL support in video driver");
  1146             return NULL;
  1147         }
  1148         SDL_GL_LoadLibrary(NULL);
  1149     }
  1150     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1151     window->magic = &_this->window_magic;
  1152     window->id = _this->next_object_id++;
  1153     window->x = x;
  1154     window->y = y;
  1155     window->w = w;
  1156     window->h = h;
  1157     if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) ||
  1158         SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1159         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1160         int displayIndex;
  1161         SDL_Rect bounds;
  1162 
  1163         displayIndex = SDL_GetIndexOfDisplay(display);
  1164         SDL_GetDisplayBounds(displayIndex, &bounds);
  1165         if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) {
  1166             window->x = bounds.x + (bounds.w - w) / 2;
  1167         }
  1168         if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1169             window->y = bounds.y + (bounds.h - h) / 2;
  1170         }
  1171     }
  1172     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1173     window->brightness = 1.0f;
  1174     window->next = _this->windows;
  1175     if (_this->windows) {
  1176         _this->windows->prev = window;
  1177     }
  1178     _this->windows = window;
  1179 
  1180     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
  1181         SDL_DestroyWindow(window);
  1182         return NULL;
  1183     }
  1184 
  1185     if (title) {
  1186         SDL_SetWindowTitle(window, title);
  1187     }
  1188     SDL_FinishWindowCreation(window, flags);
  1189 
  1190     return window;
  1191 }
  1192 
  1193 SDL_Window *
  1194 SDL_CreateWindowFrom(const void *data)
  1195 {
  1196     SDL_Window *window;
  1197 
  1198     if (!_this) {
  1199         SDL_UninitializedVideo();
  1200         return NULL;
  1201     }
  1202     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
  1203     window->magic = &_this->window_magic;
  1204     window->id = _this->next_object_id++;
  1205     window->flags = SDL_WINDOW_FOREIGN;
  1206     window->brightness = 1.0f;
  1207     window->next = _this->windows;
  1208     if (_this->windows) {
  1209         _this->windows->prev = window;
  1210     }
  1211     _this->windows = window;
  1212 
  1213     if (!_this->CreateWindowFrom ||
  1214         _this->CreateWindowFrom(_this, window, data) < 0) {
  1215         SDL_DestroyWindow(window);
  1216         return NULL;
  1217     }
  1218     return window;
  1219 }
  1220 
  1221 int
  1222 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
  1223 {
  1224     char *title = window->title;
  1225 
  1226     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
  1227         SDL_SetError("No OpenGL support in video driver");
  1228         return -1;
  1229     }
  1230 
  1231     if (window->flags & SDL_WINDOW_FOREIGN) {
  1232         /* Can't destroy and re-create foreign windows, hrm */
  1233         flags |= SDL_WINDOW_FOREIGN;
  1234     } else {
  1235         flags &= ~SDL_WINDOW_FOREIGN;
  1236     }
  1237 
  1238     /* Restore video mode, etc. */
  1239     SDL_HideWindow(window);
  1240 
  1241     /* Tear down the old native window */
  1242     if (window->surface) {
  1243         window->surface->flags &= ~SDL_DONTFREE;
  1244         SDL_FreeSurface(window->surface);
  1245     }
  1246     if (_this->DestroyWindowFramebuffer) {
  1247         _this->DestroyWindowFramebuffer(_this, window);
  1248     }
  1249     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1250         _this->DestroyWindow(_this, window);
  1251     }
  1252 
  1253     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
  1254         if (flags & SDL_WINDOW_OPENGL) {
  1255             SDL_GL_LoadLibrary(NULL);
  1256         } else {
  1257             SDL_GL_UnloadLibrary();
  1258         }
  1259     }
  1260 
  1261     window->title = NULL;
  1262     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
  1263 
  1264     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1265         if (_this->CreateWindow(_this, window) < 0) {
  1266             if (flags & SDL_WINDOW_OPENGL) {
  1267                 SDL_GL_UnloadLibrary();
  1268             }
  1269             return -1;
  1270         }
  1271     }
  1272 
  1273     if (title) {
  1274         SDL_SetWindowTitle(window, title);
  1275         SDL_free(title);
  1276     }
  1277     SDL_FinishWindowCreation(window, flags);
  1278 
  1279     return 0;
  1280 }
  1281 
  1282 Uint32
  1283 SDL_GetWindowID(SDL_Window * window)
  1284 {
  1285     CHECK_WINDOW_MAGIC(window, 0);
  1286 
  1287     return window->id;
  1288 }
  1289 
  1290 SDL_Window *
  1291 SDL_GetWindowFromID(Uint32 id)
  1292 {
  1293     SDL_Window *window;
  1294 
  1295     if (!_this) {
  1296         return NULL;
  1297     }
  1298     for (window = _this->windows; window; window = window->next) {
  1299         if (window->id == id) {
  1300             return window;
  1301         }
  1302     }
  1303     return NULL;
  1304 }
  1305 
  1306 Uint32
  1307 SDL_GetWindowFlags(SDL_Window * window)
  1308 {
  1309     CHECK_WINDOW_MAGIC(window, 0);
  1310 
  1311     return window->flags;
  1312 }
  1313 
  1314 void
  1315 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1316 {
  1317     CHECK_WINDOW_MAGIC(window, );
  1318 
  1319     if (title == window->title) {
  1320         return;
  1321     }
  1322     if (window->title) {
  1323         SDL_free(window->title);
  1324     }
  1325     if (title && *title) {
  1326         window->title = SDL_strdup(title);
  1327     } else {
  1328         window->title = NULL;
  1329     }
  1330 
  1331     if (_this->SetWindowTitle) {
  1332         _this->SetWindowTitle(_this, window);
  1333     }
  1334 }
  1335 
  1336 const char *
  1337 SDL_GetWindowTitle(SDL_Window * window)
  1338 {
  1339     CHECK_WINDOW_MAGIC(window, "");
  1340 
  1341     return window->title ? window->title : "";
  1342 }
  1343 
  1344 void
  1345 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1346 {
  1347     CHECK_WINDOW_MAGIC(window, );
  1348 
  1349     if (!icon) {
  1350         return;
  1351     }
  1352 
  1353     if (_this->SetWindowIcon) {
  1354         _this->SetWindowIcon(_this, window, icon);
  1355     }
  1356 }
  1357 
  1358 void*
  1359 SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata)
  1360 {
  1361     SDL_WindowUserData *prev, *data;
  1362 
  1363     CHECK_WINDOW_MAGIC(window, NULL);
  1364 
  1365     /* See if the named data already exists */
  1366     prev = NULL;
  1367     for (data = window->data; data; prev = data, data = data->next) {
  1368         if (SDL_strcmp(data->name, name) == 0) {
  1369             void *last_value = data->data;
  1370 
  1371             if (userdata) {
  1372                 /* Set the new value */
  1373                 data->data = userdata;
  1374             } else {
  1375                 /* Delete this value */
  1376                 if (prev) {
  1377                     prev->next = data->next;
  1378                 } else {
  1379                     window->data = data->next;
  1380                 }
  1381                 SDL_free(data->name);
  1382                 SDL_free(data);
  1383             }
  1384             return last_value;
  1385         }
  1386     }
  1387 
  1388     /* Add new data to the window */
  1389     if (userdata) {
  1390         data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data));
  1391         data->name = SDL_strdup(name);
  1392         data->data = userdata;
  1393         data->next = window->data;
  1394         window->data = data;
  1395     }
  1396     return NULL;
  1397 }
  1398 
  1399 void *
  1400 SDL_GetWindowData(SDL_Window * window, const char *name)
  1401 {
  1402     SDL_WindowUserData *data;
  1403 
  1404     CHECK_WINDOW_MAGIC(window, NULL);
  1405 
  1406     for (data = window->data; data; data = data->next) {
  1407         if (SDL_strcmp(data->name, name) == 0) {
  1408             return data->data;
  1409         }
  1410     }
  1411     return NULL;
  1412 }
  1413 
  1414 void
  1415 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1416 {
  1417     CHECK_WINDOW_MAGIC(window, );
  1418 
  1419     if (!SDL_WINDOWPOS_ISUNDEFINED(x)) {
  1420         window->x = x;
  1421     }
  1422     if (!SDL_WINDOWPOS_ISUNDEFINED(y)) {
  1423         window->y = y;
  1424     }
  1425     if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) {
  1426         SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1427         int displayIndex;
  1428         SDL_Rect bounds;
  1429 
  1430         displayIndex = SDL_GetIndexOfDisplay(display);
  1431         SDL_GetDisplayBounds(displayIndex, &bounds);
  1432         if (SDL_WINDOWPOS_ISCENTERED(x)) {
  1433             window->x = bounds.x + (bounds.w - window->w) / 2;
  1434         }
  1435         if (SDL_WINDOWPOS_ISCENTERED(y)) {
  1436             window->y = bounds.y + (bounds.h - window->h) / 2;
  1437         }
  1438     }
  1439     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1440         if (_this->SetWindowPosition) {
  1441             _this->SetWindowPosition(_this, window);
  1442         }
  1443         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1444     }
  1445 }
  1446 
  1447 void
  1448 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1449 {
  1450     /* Clear the values */
  1451     if (x) {
  1452         *x = 0;
  1453     }
  1454     if (y) {
  1455         *y = 0;
  1456     }
  1457 
  1458     CHECK_WINDOW_MAGIC(window, );
  1459 
  1460     /* Fullscreen windows are always at their display's origin */
  1461     if (window->flags & SDL_WINDOW_FULLSCREEN) {
  1462     } else {
  1463         if (x) {
  1464             *x = window->x;
  1465         }
  1466         if (y) {
  1467             *y = window->y;
  1468         }
  1469     }
  1470 }
  1471 
  1472 void
  1473 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1474 {
  1475     CHECK_WINDOW_MAGIC(window, );
  1476 
  1477     /* FIXME: Should this change fullscreen modes? */
  1478     if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1479         window->w = w;
  1480         window->h = h;
  1481         if (_this->SetWindowSize) {
  1482             _this->SetWindowSize(_this, window);
  1483         }
  1484         if (window->w == w && window->h == h) {
  1485             /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */
  1486             SDL_OnWindowResized(window);
  1487         }
  1488     }
  1489 }
  1490 
  1491 void
  1492 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1493 {
  1494     int dummy;
  1495 
  1496     if (!w) {
  1497         w = &dummy;
  1498     }
  1499     if (!h) {
  1500         h = &dummy;
  1501     }
  1502 
  1503     *w = 0;
  1504     *h = 0;
  1505 
  1506     CHECK_WINDOW_MAGIC(window, );
  1507 
  1508     if (_this && window && window->magic == &_this->window_magic) {
  1509         if (w) {
  1510             *w = window->w;
  1511         }
  1512         if (h) {
  1513             *h = window->h;
  1514         }
  1515     } else {
  1516         if (w) {
  1517             *w = 0;
  1518         }
  1519         if (h) {
  1520             *h = 0;
  1521         }
  1522     }
  1523 }
  1524 
  1525 void
  1526 SDL_ShowWindow(SDL_Window * window)
  1527 {
  1528     CHECK_WINDOW_MAGIC(window, );
  1529 
  1530     if (window->flags & SDL_WINDOW_SHOWN) {
  1531         return;
  1532     }
  1533 
  1534     if (_this->ShowWindow) {
  1535         _this->ShowWindow(_this, window);
  1536     }
  1537     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1538 }
  1539 
  1540 void
  1541 SDL_HideWindow(SDL_Window * window)
  1542 {
  1543     CHECK_WINDOW_MAGIC(window, );
  1544 
  1545     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1546         return;
  1547     }
  1548 
  1549     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1550 
  1551     if (_this->HideWindow) {
  1552         _this->HideWindow(_this, window);
  1553     }
  1554     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1555 }
  1556 
  1557 void
  1558 SDL_RaiseWindow(SDL_Window * window)
  1559 {
  1560     CHECK_WINDOW_MAGIC(window, );
  1561 
  1562     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1563         return;
  1564     }
  1565     if (_this->RaiseWindow) {
  1566         _this->RaiseWindow(_this, window);
  1567     }
  1568 }
  1569 
  1570 void
  1571 SDL_MaximizeWindow(SDL_Window * window)
  1572 {
  1573     CHECK_WINDOW_MAGIC(window, );
  1574 
  1575     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1576         return;
  1577     }
  1578 
  1579     if (_this->MaximizeWindow) {
  1580         _this->MaximizeWindow(_this, window);
  1581     }
  1582 }
  1583 
  1584 void
  1585 SDL_MinimizeWindow(SDL_Window * window)
  1586 {
  1587     CHECK_WINDOW_MAGIC(window, );
  1588 
  1589     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1590         return;
  1591     }
  1592 
  1593     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1594 
  1595     if (_this->MinimizeWindow) {
  1596         _this->MinimizeWindow(_this, window);
  1597     }
  1598 }
  1599 
  1600 void
  1601 SDL_RestoreWindow(SDL_Window * window)
  1602 {
  1603     CHECK_WINDOW_MAGIC(window, );
  1604 
  1605     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1606         return;
  1607     }
  1608 
  1609     if (_this->RestoreWindow) {
  1610         _this->RestoreWindow(_this, window);
  1611     }
  1612 }
  1613 
  1614 int
  1615 SDL_SetWindowFullscreen(SDL_Window * window, SDL_bool fullscreen)
  1616 {
  1617     CHECK_WINDOW_MAGIC(window, -1);
  1618 
  1619     if (!!fullscreen == !!(window->flags & SDL_WINDOW_FULLSCREEN)) {
  1620         return 0;
  1621     }
  1622     if (fullscreen) {
  1623         window->flags |= SDL_WINDOW_FULLSCREEN;
  1624     } else {
  1625         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1626     }
  1627     SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window));
  1628 
  1629     return 0;
  1630 }
  1631 
  1632 static SDL_Surface *
  1633 SDL_CreateWindowFramebuffer(SDL_Window * window)
  1634 {
  1635     Uint32 format;
  1636     void *pixels;
  1637     int pitch;
  1638     int bpp;
  1639     Uint32 Rmask, Gmask, Bmask, Amask;
  1640 
  1641     if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) {
  1642         return NULL;
  1643     }
  1644 
  1645     if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) {
  1646         return NULL;
  1647     }
  1648 
  1649     if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1650         return NULL;
  1651     }
  1652 
  1653     return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask);
  1654 }
  1655 
  1656 SDL_Surface *
  1657 SDL_GetWindowSurface(SDL_Window * window)
  1658 {
  1659     CHECK_WINDOW_MAGIC(window, NULL);
  1660 
  1661     if (!window->surface_valid) {
  1662         if (window->surface) {
  1663             window->surface->flags &= ~SDL_DONTFREE;
  1664             SDL_FreeSurface(window->surface);
  1665         }
  1666         window->surface = SDL_CreateWindowFramebuffer(window);
  1667         if (window->surface) {
  1668             window->surface_valid = SDL_TRUE;
  1669             window->surface->flags |= SDL_DONTFREE;
  1670         }
  1671     }
  1672     return window->surface;
  1673 }
  1674 
  1675 int
  1676 SDL_UpdateWindowSurface(SDL_Window * window)
  1677 {
  1678     SDL_Rect full_rect;
  1679 
  1680     CHECK_WINDOW_MAGIC(window, -1);
  1681 
  1682     full_rect.x = 0;
  1683     full_rect.y = 0;
  1684     full_rect.w = window->w;
  1685     full_rect.h = window->h;
  1686     return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
  1687 }
  1688 
  1689 int
  1690 SDL_UpdateWindowSurfaceRects(SDL_Window * window, SDL_Rect * rects,
  1691                              int numrects)
  1692 {
  1693     CHECK_WINDOW_MAGIC(window, -1);
  1694 
  1695     if (!window->surface_valid) {
  1696         SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface");
  1697         return -1;
  1698     }
  1699 
  1700     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
  1701 }
  1702 
  1703 int
  1704 SDL_SetWindowBrightness(SDL_Window * window, float brightness)
  1705 {
  1706     Uint16 ramp[256];
  1707     int status;
  1708 
  1709     CHECK_WINDOW_MAGIC(window, -1);
  1710 
  1711     SDL_CalculateGammaRamp(brightness, ramp);
  1712     status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
  1713     if (status == 0) {
  1714         window->brightness = brightness;
  1715     }
  1716     return status;
  1717 }
  1718 
  1719 float
  1720 SDL_GetWindowBrightness(SDL_Window * window)
  1721 {
  1722     CHECK_WINDOW_MAGIC(window, 1.0f);
  1723 
  1724     return window->brightness;
  1725 }
  1726 
  1727 int
  1728 SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
  1729                                             const Uint16 * green,
  1730                                             const Uint16 * blue)
  1731 {
  1732     CHECK_WINDOW_MAGIC(window, -1);
  1733 
  1734     if (!_this->SetWindowGammaRamp) {
  1735         SDL_Unsupported();
  1736         return -1;
  1737     }
  1738 
  1739     if (!window->gamma) {
  1740         if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
  1741             return -1;
  1742         }
  1743     }
  1744 
  1745     if (red) {
  1746         SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
  1747     }
  1748     if (green) {
  1749         SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
  1750     }
  1751     if (blue) {
  1752         SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
  1753     }
  1754     if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1755         return _this->SetWindowGammaRamp(_this, window, window->gamma);
  1756     } else {
  1757         return 0;
  1758     }
  1759 }
  1760 
  1761 int
  1762 SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
  1763                                             Uint16 * green,
  1764                                             Uint16 * blue)
  1765 {
  1766     CHECK_WINDOW_MAGIC(window, -1);
  1767 
  1768     if (!window->gamma) {
  1769         int i;
  1770 
  1771         window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
  1772         if (!window->gamma) {
  1773             SDL_OutOfMemory();
  1774             return -1;
  1775         }
  1776         window->saved_gamma = window->gamma + 3*256;
  1777 
  1778         if (_this->GetWindowGammaRamp) {
  1779             if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
  1780                 return -1;
  1781             }
  1782         } else {
  1783             /* Create an identity gamma ramp */
  1784             for (i = 0; i < 256; ++i) {
  1785                 Uint16 value = (Uint16)((i << 8) | i);
  1786 
  1787                 window->gamma[0*256+i] = value;
  1788                 window->gamma[1*256+i] = value;
  1789                 window->gamma[2*256+i] = value;
  1790             }
  1791         }
  1792         SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
  1793     }
  1794 
  1795     if (red) {
  1796         SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
  1797     }
  1798     if (green) {
  1799         SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
  1800     }
  1801     if (blue) {
  1802         SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
  1803     }
  1804     return 0;
  1805 }
  1806 
  1807 static void
  1808 SDL_UpdateWindowGrab(SDL_Window * window)
  1809 {
  1810     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1811         _this->SetWindowGrab(_this, window);
  1812     }
  1813 }
  1814 
  1815 void
  1816 SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed)
  1817 {
  1818     CHECK_WINDOW_MAGIC(window, );
  1819 
  1820     if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
  1821         return;
  1822     }
  1823     if (grabbed) {
  1824         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1825     } else {
  1826         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1827     }
  1828     SDL_UpdateWindowGrab(window);
  1829 }
  1830 
  1831 SDL_bool
  1832 SDL_GetWindowGrab(SDL_Window * window)
  1833 {
  1834     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  1835 
  1836     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1837 }
  1838 
  1839 void
  1840 SDL_OnWindowShown(SDL_Window * window)
  1841 {
  1842     SDL_OnWindowRestored(window);
  1843 }
  1844 
  1845 void
  1846 SDL_OnWindowHidden(SDL_Window * window)
  1847 {
  1848     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1849 }
  1850 
  1851 void
  1852 SDL_OnWindowResized(SDL_Window * window)
  1853 {
  1854     window->surface_valid = SDL_FALSE;
  1855     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
  1856 }
  1857 
  1858 void
  1859 SDL_OnWindowMinimized(SDL_Window * window)
  1860 {
  1861     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1862 }
  1863 
  1864 void
  1865 SDL_OnWindowRestored(SDL_Window * window)
  1866 {
  1867     SDL_RaiseWindow(window);
  1868 
  1869     if (FULLSCREEN_VISIBLE(window)) {
  1870         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1871     }
  1872 }
  1873 
  1874 void
  1875 SDL_OnWindowFocusGained(SDL_Window * window)
  1876 {
  1877     if (window->gamma && _this->SetWindowGammaRamp) {
  1878         _this->SetWindowGammaRamp(_this, window, window->gamma);
  1879     }
  1880 
  1881     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
  1882         _this->SetWindowGrab) {
  1883         _this->SetWindowGrab(_this, window);
  1884     }
  1885 }
  1886 
  1887 void
  1888 SDL_OnWindowFocusLost(SDL_Window * window)
  1889 {
  1890     if (window->gamma && _this->SetWindowGammaRamp) {
  1891         _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
  1892     }
  1893 
  1894     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN)) &&
  1895         _this->SetWindowGrab) {
  1896         _this->SetWindowGrab(_this, window);
  1897     }
  1898 
  1899     /* If we're fullscreen on a single-head system and lose focus, minimize */
  1900     if ((window->flags & SDL_WINDOW_FULLSCREEN) && _this->num_displays == 1) {
  1901         SDL_MinimizeWindow(window);
  1902     }
  1903 }
  1904 
  1905 SDL_Window *
  1906 SDL_GetFocusWindow(void)
  1907 {
  1908     SDL_Window *window;
  1909 
  1910     if (!_this) {
  1911         return NULL;
  1912     }
  1913     for (window = _this->windows; window; window = window->next) {
  1914         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1915             return window;
  1916         }
  1917     }
  1918     return NULL;
  1919 }
  1920 
  1921 void
  1922 SDL_DestroyWindow(SDL_Window * window)
  1923 {
  1924     SDL_VideoDisplay *display;
  1925 
  1926     CHECK_WINDOW_MAGIC(window, );
  1927 
  1928     /* make no context current if this is the current context window. */
  1929     if (window->flags & SDL_WINDOW_OPENGL) {
  1930         if (_this->current_glwin == window) {
  1931             SDL_GL_MakeCurrent(NULL, NULL);
  1932         }
  1933     }
  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     SDL_GLContext ctx = NULL;
  2457     CHECK_WINDOW_MAGIC(window, NULL);
  2458 
  2459     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2460         SDL_SetError("The specified window isn't an OpenGL window");
  2461         return NULL;
  2462     }
  2463 
  2464     ctx = _this->GL_CreateContext(_this, window);
  2465 
  2466     /* Creating a context is assumed to make it current in the SDL driver. */
  2467     _this->current_glwin = window;
  2468     _this->current_glctx = ctx;
  2469 
  2470     return ctx;
  2471 }
  2472 
  2473 int
  2474 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
  2475 {
  2476     int retval;
  2477 
  2478     CHECK_WINDOW_MAGIC(window, -1);
  2479 
  2480     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2481         SDL_SetError("The specified window isn't an OpenGL window");
  2482         return -1;
  2483     }
  2484     if (!ctx) {
  2485         window = NULL;
  2486     }
  2487 
  2488     if ((window == _this->current_glwin) && (ctx == _this->current_glctx)) {
  2489         retval = 0;  /* we're already current. */
  2490     } else {
  2491         retval = _this->GL_MakeCurrent(_this, window, ctx);
  2492         if (retval == 0) {
  2493             _this->current_glwin = window;
  2494             _this->current_glctx = ctx;
  2495         }
  2496     }
  2497 
  2498     return retval;
  2499 }
  2500 
  2501 int
  2502 SDL_GL_SetSwapInterval(int interval)
  2503 {
  2504     if (!_this) {
  2505         SDL_UninitializedVideo();
  2506         return -1;
  2507     } else if (_this->current_glctx == NULL) {
  2508         SDL_SetError("No OpenGL context has been made current");
  2509         return -1;
  2510     } else if (_this->GL_SetSwapInterval) {
  2511         return _this->GL_SetSwapInterval(_this, interval);
  2512     } else {
  2513         SDL_SetError("Setting the swap interval is not supported");
  2514         return -1;
  2515     }
  2516 }
  2517 
  2518 int
  2519 SDL_GL_GetSwapInterval(void)
  2520 {
  2521     if (!_this) {
  2522         SDL_UninitializedVideo();
  2523         return -1;
  2524     } else if (_this->current_glctx == NULL) {
  2525         SDL_SetError("No OpenGL context has been made current");
  2526         return -1;
  2527     } else if (_this->GL_GetSwapInterval) {
  2528         return _this->GL_GetSwapInterval(_this);
  2529     } else {
  2530         SDL_SetError("Getting the swap interval is not supported");
  2531         return -1;
  2532     }
  2533 }
  2534 
  2535 void
  2536 SDL_GL_SwapWindow(SDL_Window * window)
  2537 {
  2538     CHECK_WINDOW_MAGIC(window, );
  2539 
  2540     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  2541         SDL_SetError("The specified window isn't an OpenGL window");
  2542         return;
  2543     }
  2544     _this->GL_SwapWindow(_this, window);
  2545 }
  2546 
  2547 void
  2548 SDL_GL_DeleteContext(SDL_GLContext context)
  2549 {
  2550     if (!_this || !_this->gl_data || !context) {
  2551         return;
  2552     }
  2553     _this->GL_MakeCurrent(_this, NULL, NULL);
  2554     _this->GL_DeleteContext(_this, context);
  2555 }
  2556 
  2557 #if 0                           // FIXME
  2558 /*
  2559  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  2560  * & 2 for alpha channel.
  2561  */
  2562 static void
  2563 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  2564 {
  2565     int x, y;
  2566     Uint32 colorkey;
  2567 #define SET_MASKBIT(icon, x, y, mask) \
  2568 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  2569 
  2570     colorkey = icon->format->colorkey;
  2571     switch (icon->format->BytesPerPixel) {
  2572     case 1:
  2573         {
  2574             Uint8 *pixels;
  2575             for (y = 0; y < icon->h; ++y) {
  2576                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  2577                 for (x = 0; x < icon->w; ++x) {
  2578                     if (*pixels++ == colorkey) {
  2579                         SET_MASKBIT(icon, x, y, mask);
  2580                     }
  2581                 }
  2582             }
  2583         }
  2584         break;
  2585 
  2586     case 2:
  2587         {
  2588             Uint16 *pixels;
  2589             for (y = 0; y < icon->h; ++y) {
  2590                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  2591                 for (x = 0; x < icon->w; ++x) {
  2592                     if ((flags & 1) && *pixels == colorkey) {
  2593                         SET_MASKBIT(icon, x, y, mask);
  2594                     } else if ((flags & 2)
  2595                                && (*pixels & icon->format->Amask) == 0) {
  2596                         SET_MASKBIT(icon, x, y, mask);
  2597                     }
  2598                     pixels++;
  2599                 }
  2600             }
  2601         }
  2602         break;
  2603 
  2604     case 4:
  2605         {
  2606             Uint32 *pixels;
  2607             for (y = 0; y < icon->h; ++y) {
  2608                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  2609                 for (x = 0; x < icon->w; ++x) {
  2610                     if ((flags & 1) && *pixels == colorkey) {
  2611                         SET_MASKBIT(icon, x, y, mask);
  2612                     } else if ((flags & 2)
  2613                                && (*pixels & icon->format->Amask) == 0) {
  2614                         SET_MASKBIT(icon, x, y, mask);
  2615                     }
  2616                     pixels++;
  2617                 }
  2618             }
  2619         }
  2620         break;
  2621     }
  2622 }
  2623 
  2624 /*
  2625  * Sets the window manager icon for the display window.
  2626  */
  2627 void
  2628 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  2629 {
  2630     if (icon && _this->SetIcon) {
  2631         /* Generate a mask if necessary, and create the icon! */
  2632         if (mask == NULL) {
  2633             int mask_len = icon->h * (icon->w + 7) / 8;
  2634             int flags = 0;
  2635             mask = (Uint8 *) SDL_malloc(mask_len);
  2636             if (mask == NULL) {
  2637                 return;
  2638             }
  2639             SDL_memset(mask, ~0, mask_len);
  2640             if (icon->flags & SDL_SRCCOLORKEY)
  2641                 flags |= 1;
  2642             if (icon->flags & SDL_SRCALPHA)
  2643                 flags |= 2;
  2644             if (flags) {
  2645                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  2646             }
  2647             _this->SetIcon(_this, icon, mask);
  2648             SDL_free(mask);
  2649         } else {
  2650             _this->SetIcon(_this, icon, mask);
  2651         }
  2652     }
  2653 }
  2654 #endif
  2655 
  2656 SDL_bool
  2657 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  2658 {
  2659     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  2660 
  2661     if (!info) {
  2662         return SDL_FALSE;
  2663     }
  2664     info->subsystem = SDL_SYSWM_UNKNOWN;
  2665 
  2666     if (!_this->GetWindowWMInfo) {
  2667         return SDL_FALSE;
  2668     }
  2669     return (_this->GetWindowWMInfo(_this, window, info));
  2670 }
  2671 
  2672 void
  2673 SDL_StartTextInput(void)
  2674 {
  2675     if (_this && _this->StartTextInput) {
  2676         _this->StartTextInput(_this);
  2677     }
  2678     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  2679     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  2680 }
  2681 
  2682 void
  2683 SDL_StopTextInput(void)
  2684 {
  2685     if (_this && _this->StopTextInput) {
  2686         _this->StopTextInput(_this);
  2687     }
  2688     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  2689     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  2690 }
  2691 
  2692 void
  2693 SDL_SetTextInputRect(SDL_Rect *rect)
  2694 {
  2695     if (_this && _this->SetTextInputRect) {
  2696         _this->SetTextInputRect(_this, rect);
  2697     }
  2698 }
  2699 
  2700 /* vi: set ts=4 sw=4 expandtab: */