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