src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 24 Jan 2010 20:21:51 +0000
changeset 3695 f6a8be3fefa0
parent 3694 b0a707f589a6
child 3697 f7b03b6838cb
permissions -rw-r--r--
Added magic to detect already freed or otherwise invalid windows and textures.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* The high-level video driver subsystem */
    25 
    26 #include "SDL.h"
    27 #include "SDL_video.h"
    28 #include "SDL_sysvideo.h"
    29 #include "SDL_blit.h"
    30 #include "SDL_pixels_c.h"
    31 #include "SDL_renderer_gl.h"
    32 #include "SDL_renderer_gles.h"
    33 #include "SDL_renderer_sw.h"
    34 #include "../events/SDL_sysevents.h"
    35 #include "../events/SDL_events_c.h"
    36 
    37 #if SDL_VIDEO_OPENGL_ES
    38 #include "SDL_opengles.h"
    39 #endif /* SDL_VIDEO_OPENGL_ES */
    40 
    41 #if SDL_VIDEO_OPENGL
    42 #include "SDL_opengl.h"
    43 
    44 /* On Windows, windows.h defines CreateWindow */
    45 #ifdef CreateWindow
    46 #undef CreateWindow
    47 #endif
    48 #endif /* SDL_VIDEO_OPENGL */
    49 
    50 /* Available video drivers */
    51 static VideoBootStrap *bootstrap[] = {
    52 #if SDL_VIDEO_DRIVER_COCOA
    53     &COCOA_bootstrap,
    54 #endif
    55 #if SDL_VIDEO_DRIVER_X11
    56     &X11_bootstrap,
    57 #endif
    58 #if SDL_VIDEO_DRIVER_FBCON
    59     &FBCON_bootstrap,
    60 #endif
    61 #if SDL_VIDEO_DRIVER_DIRECTFB
    62     &DirectFB_bootstrap,
    63 #endif
    64 #if SDL_VIDEO_DRIVER_PS3
    65     &PS3_bootstrap,
    66 #endif
    67 #if SDL_VIDEO_DRIVER_SVGALIB
    68     &SVGALIB_bootstrap,
    69 #endif
    70 #if SDL_VIDEO_DRIVER_GAPI
    71     &GAPI_bootstrap,
    72 #endif
    73 #if SDL_VIDEO_DRIVER_WIN32
    74     &WIN32_bootstrap,
    75 #endif
    76 #if SDL_VIDEO_DRIVER_BWINDOW
    77     &BWINDOW_bootstrap,
    78 #endif
    79 #if SDL_VIDEO_DRIVER_PHOTON
    80     &photon_bootstrap,
    81 #endif
    82 #if SDL_VIDEO_DRIVER_QNXGF
    83     &qnxgf_bootstrap,
    84 #endif
    85 #if SDL_VIDEO_DRIVER_EPOC
    86     &EPOC_bootstrap,
    87 #endif
    88 #if SDL_VIDEO_DRIVER_RISCOS
    89     &RISCOS_bootstrap,
    90 #endif
    91 #if SDL_VIDEO_DRIVER_NDS
    92     &NDS_bootstrap,
    93 #endif
    94 #if SDL_VIDEO_DRIVER_UIKIT
    95     &UIKIT_bootstrap,
    96 #endif
    97 #if SDL_VIDEO_DRIVER_DUMMY
    98     &DUMMY_bootstrap,
    99 #endif
   100 #if SDL_VIDEO_DRIVER_PANDORA
   101     &PND_bootstrap,
   102 #endif
   103     NULL
   104 };
   105 
   106 static SDL_VideoDevice *_this = NULL;
   107 
   108 #define CHECK_WINDOW_MAGIC(window, retval) \
   109     if (!_this) { \
   110         SDL_UninitializedVideo(); \
   111         return retval; \
   112     } \
   113 	if (!window || window->magic != &_this->window_magic) { \
   114         SDL_SetError("Invalid window"); \
   115         return retval; \
   116     }
   117 
   118 #define CHECK_TEXTURE_MAGIC(texture, retval) \
   119     if (!_this) { \
   120         SDL_UninitializedVideo(); \
   121         return retval; \
   122     } \
   123 	if (!texture || texture->magic != &_this->texture_magic) { \
   124         SDL_SetError("Invalid texture"); \
   125         return retval; \
   126     }
   127 
   128 /* Various local functions */
   129 static void SDL_UpdateWindowGrab(SDL_Window * window);
   130 
   131 static int
   132 cmpmodes(const void *A, const void *B)
   133 {
   134     SDL_DisplayMode a = *(const SDL_DisplayMode *) A;
   135     SDL_DisplayMode b = *(const SDL_DisplayMode *) B;
   136 
   137     if (a.w != b.w) {
   138         return b.w - a.w;
   139     }
   140     if (a.h != b.h) {
   141         return b.h - a.h;
   142     }
   143     if (SDL_BITSPERPIXEL(a.format) != SDL_BITSPERPIXEL(b.format)) {
   144         return SDL_BITSPERPIXEL(b.format) - SDL_BITSPERPIXEL(a.format);
   145     }
   146     if (SDL_PIXELLAYOUT(a.format) != SDL_PIXELLAYOUT(b.format)) {
   147         return SDL_PIXELLAYOUT(b.format) - SDL_PIXELLAYOUT(a.format);
   148     }
   149     if (a.refresh_rate != b.refresh_rate) {
   150         return b.refresh_rate - a.refresh_rate;
   151     }
   152     return 0;
   153 }
   154 
   155 static void
   156 SDL_UninitializedVideo()
   157 {
   158     SDL_SetError("Video subsystem has not been initialized");
   159 }
   160 
   161 int
   162 SDL_GetNumVideoDrivers(void)
   163 {
   164     return SDL_arraysize(bootstrap) - 1;
   165 }
   166 
   167 const char *
   168 SDL_GetVideoDriver(int index)
   169 {
   170     if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
   171         return bootstrap[index]->name;
   172     }
   173     return NULL;
   174 }
   175 
   176 /*
   177  * Initialize the video and event subsystems -- determine native pixel format
   178  */
   179 int
   180 SDL_VideoInit(const char *driver_name, Uint32 flags)
   181 {
   182     SDL_VideoDevice *video;
   183     int index;
   184     int i;
   185 
   186     /* Check to make sure we don't overwrite '_this' */
   187     if (_this != NULL) {
   188         SDL_VideoQuit();
   189     }
   190 
   191     /* Toggle the event thread flags, based on OS requirements */
   192 #if defined(MUST_THREAD_EVENTS)
   193     flags |= SDL_INIT_EVENTTHREAD;
   194 #elif defined(CANT_THREAD_EVENTS)
   195     if ((flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD) {
   196         SDL_SetError("OS doesn't support threaded events");
   197         return -1;
   198     }
   199 #endif
   200 
   201     /* Start the event loop */
   202     if (SDL_StartEventLoop(flags) < 0) {
   203         return -1;
   204     }
   205 
   206     /* Select the proper video driver */
   207     index = 0;
   208     video = NULL;
   209     if (driver_name == NULL) {
   210         driver_name = SDL_getenv("SDL_VIDEODRIVER");
   211     }
   212     if (driver_name != NULL) {
   213         for (i = 0; bootstrap[i]; ++i) {
   214             if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
   215                 video = bootstrap[i]->create(index);
   216                 break;
   217             }
   218         }
   219     } else {
   220         for (i = 0; bootstrap[i]; ++i) {
   221             if (bootstrap[i]->available()) {
   222                 video = bootstrap[i]->create(index);
   223                 if (video != NULL) {
   224                     break;
   225                 }
   226             }
   227         }
   228     }
   229     if (video == NULL) {
   230         if (driver_name) {
   231             SDL_SetError("%s not available", driver_name);
   232         } else {
   233             SDL_SetError("No available video device");
   234         }
   235         return -1;
   236     }
   237     _this = video;
   238     _this->name = bootstrap[i]->name;
   239     _this->next_object_id = 1;
   240 
   241 
   242     /* Set some very sane GL defaults */
   243     _this->gl_config.driver_loaded = 0;
   244     _this->gl_config.dll_handle = NULL;
   245     _this->gl_config.red_size = 3;
   246     _this->gl_config.green_size = 3;
   247     _this->gl_config.blue_size = 2;
   248     _this->gl_config.alpha_size = 0;
   249     _this->gl_config.buffer_size = 0;
   250     _this->gl_config.depth_size = 16;
   251     _this->gl_config.stencil_size = 0;
   252     _this->gl_config.double_buffer = 1;
   253     _this->gl_config.accum_red_size = 0;
   254     _this->gl_config.accum_green_size = 0;
   255     _this->gl_config.accum_blue_size = 0;
   256     _this->gl_config.accum_alpha_size = 0;
   257     _this->gl_config.stereo = 0;
   258     _this->gl_config.multisamplebuffers = 0;
   259     _this->gl_config.multisamplesamples = 0;
   260     _this->gl_config.retained_backing = 1;
   261     _this->gl_config.accelerated = -1;  /* accelerated or not, both are fine */
   262     _this->gl_config.major_version = 2;
   263     _this->gl_config.minor_version = 1;
   264 
   265     /* Initialize the video subsystem */
   266     if (_this->VideoInit(_this) < 0) {
   267         SDL_VideoQuit();
   268         return -1;
   269     }
   270     /* Make sure some displays were added */
   271     if (_this->num_displays == 0) {
   272         SDL_SetError("The video driver did not add any displays");
   273         SDL_VideoQuit();
   274         return (-1);
   275     }
   276     /* The software renderer is always available */
   277     for (i = 0; i < _this->num_displays; ++i) {
   278         SDL_VideoDisplay *display = &_this->displays[i];
   279         if (_this->GL_CreateContext) {
   280 #if SDL_VIDEO_RENDER_OGL
   281             SDL_AddRenderDriver(display, &GL_RenderDriver);
   282 #endif
   283 #if SDL_VIDEO_RENDER_OGL_ES
   284             SDL_AddRenderDriver(display, &GL_ES_RenderDriver);
   285 #endif
   286         }
   287         if (display->num_render_drivers > 0) {
   288             SDL_AddRenderDriver(display, &SW_RenderDriver);
   289         }
   290     }
   291 
   292     /* We're ready to go! */
   293     return 0;
   294 }
   295 
   296 const char *
   297 SDL_GetCurrentVideoDriver()
   298 {
   299     if (!_this) {
   300         SDL_UninitializedVideo();
   301         return NULL;
   302     }
   303     return _this->name;
   304 }
   305 
   306 SDL_VideoDevice *
   307 SDL_GetVideoDevice()
   308 {
   309     return _this;
   310 }
   311 
   312 int
   313 SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode)
   314 {
   315     SDL_VideoDisplay display;
   316 
   317     SDL_zero(display);
   318     if (desktop_mode) {
   319         display.desktop_mode = *desktop_mode;
   320     }
   321     display.current_mode = display.desktop_mode;
   322 
   323     return SDL_AddVideoDisplay(&display);
   324 }
   325 
   326 int
   327 SDL_AddVideoDisplay(const SDL_VideoDisplay * display)
   328 {
   329     SDL_VideoDisplay *displays;
   330     int index = -1;
   331 
   332     displays =
   333         SDL_realloc(_this->displays,
   334                     (_this->num_displays + 1) * sizeof(*displays));
   335     if (displays) {
   336         index = _this->num_displays++;
   337         displays[index] = *display;
   338         displays[index].device = _this;
   339         _this->displays = displays;
   340     } else {
   341         SDL_OutOfMemory();
   342     }
   343     return index;
   344 }
   345 
   346 int
   347 SDL_GetNumVideoDisplays(void)
   348 {
   349     if (!_this) {
   350         SDL_UninitializedVideo();
   351         return 0;
   352     }
   353     return _this->num_displays;
   354 }
   355 
   356 int
   357 SDL_GetDisplayBounds(int index, SDL_Rect * rect)
   358 {
   359     if (!_this) {
   360         SDL_UninitializedVideo();
   361         return -1;
   362     }
   363     if (index < 0 || index >= _this->num_displays) {
   364         SDL_SetError("index must be in the range 0 - %d",
   365                      _this->num_displays - 1);
   366         return -1;
   367     }
   368     if (rect) {
   369         SDL_VideoDisplay *display = &_this->displays[index];
   370 
   371         if (_this->GetDisplayBounds) {
   372             if (_this->GetDisplayBounds(_this, display, rect) < 0) {
   373                 return -1;
   374             }
   375         } else {
   376             /* Assume that the displays are left to right */
   377             if (index == 0) {
   378                 rect->x = 0;
   379                 rect->y = 0;
   380             } else {
   381                 SDL_GetDisplayBounds(index-1, rect);
   382                 rect->x += rect->w;
   383             }
   384             rect->w = display->desktop_mode.w;
   385             rect->h = display->desktop_mode.h;
   386         }
   387     }
   388     return 0;
   389 }
   390 
   391 int
   392 SDL_SelectVideoDisplay(int index)
   393 {
   394     if (!_this) {
   395         SDL_UninitializedVideo();
   396         return (-1);
   397     }
   398     if (index < 0 || index >= _this->num_displays) {
   399         SDL_SetError("index must be in the range 0 - %d",
   400                      _this->num_displays - 1);
   401         return -1;
   402     }
   403     _this->current_display = index;
   404     return 0;
   405 }
   406 
   407 int
   408 SDL_GetCurrentVideoDisplay(void)
   409 {
   410     if (!_this) {
   411         SDL_UninitializedVideo();
   412         return (-1);
   413     }
   414     return _this->current_display;
   415 }
   416 
   417 SDL_bool
   418 SDL_AddDisplayMode(SDL_VideoDisplay * display,  const SDL_DisplayMode * mode)
   419 {
   420     SDL_DisplayMode *modes;
   421     int i, nmodes;
   422 
   423     /* Make sure we don't already have the mode in the list */
   424     modes = display->display_modes;
   425     nmodes = display->num_display_modes;
   426     for (i = nmodes; i--;) {
   427         if (SDL_memcmp(mode, &modes[i], sizeof(*mode)) == 0) {
   428             return SDL_FALSE;
   429         }
   430     }
   431 
   432     /* Go ahead and add the new mode */
   433     if (nmodes == display->max_display_modes) {
   434         modes =
   435             SDL_realloc(modes,
   436                         (display->max_display_modes + 32) * sizeof(*modes));
   437         if (!modes) {
   438             return SDL_FALSE;
   439         }
   440         display->display_modes = modes;
   441         display->max_display_modes += 32;
   442     }
   443     modes[nmodes] = *mode;
   444     display->num_display_modes++;
   445 
   446     /* Re-sort video modes */
   447     SDL_qsort(display->display_modes, display->num_display_modes,
   448               sizeof(SDL_DisplayMode), cmpmodes);
   449 
   450     return SDL_TRUE;
   451 }
   452 
   453 int
   454 SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display)
   455 {
   456     if (!display->num_display_modes && _this->GetDisplayModes) {
   457         _this->GetDisplayModes(_this, display);
   458         SDL_qsort(display->display_modes, display->num_display_modes,
   459                   sizeof(SDL_DisplayMode), cmpmodes);
   460     }
   461     return display->num_display_modes;
   462 }
   463 
   464 int
   465 SDL_GetNumDisplayModes()
   466 {
   467     if (_this) {
   468         return SDL_GetNumDisplayModesForDisplay(SDL_CurrentDisplay);
   469     }
   470     return 0;
   471 }
   472 
   473 int
   474 SDL_GetDisplayModeForDisplay(SDL_VideoDisplay * display, int index, SDL_DisplayMode * mode)
   475 {
   476     if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) {
   477         SDL_SetError("index must be in the range of 0 - %d",
   478                      SDL_GetNumDisplayModesForDisplay(display) - 1);
   479         return -1;
   480     }
   481     if (mode) {
   482         *mode = display->display_modes[index];
   483     }
   484     return 0;
   485 }
   486 
   487 int
   488 SDL_GetDisplayMode(int index, SDL_DisplayMode * mode)
   489 {
   490     return SDL_GetDisplayModeForDisplay(SDL_CurrentDisplay, index, mode);
   491 }
   492 
   493 int
   494 SDL_GetDesktopDisplayModeForDisplay(SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   495 {
   496     if (mode) {
   497         *mode = display->desktop_mode;
   498     }
   499     return 0;
   500 }
   501 
   502 int
   503 SDL_GetDesktopDisplayMode(SDL_DisplayMode * mode)
   504 {
   505     if (!_this) {
   506         SDL_UninitializedVideo();
   507         return -1;
   508     }
   509     return SDL_GetDesktopDisplayModeForDisplay(SDL_CurrentDisplay, mode);
   510 }
   511 
   512 int
   513 SDL_GetCurrentDisplayModeForDisplay(SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   514 {
   515     if (mode) {
   516         *mode = display->current_mode;
   517     }
   518     return 0;
   519 }
   520 
   521 int
   522 SDL_GetCurrentDisplayMode(SDL_DisplayMode * mode)
   523 {
   524     if (!_this) {
   525         SDL_UninitializedVideo();
   526         return -1;
   527     }
   528     return SDL_GetCurrentDisplayModeForDisplay(SDL_CurrentDisplay, mode);
   529 }
   530 
   531 SDL_DisplayMode *
   532 SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display,
   533                                     const SDL_DisplayMode * mode,
   534                                     SDL_DisplayMode * closest)
   535 {
   536     Uint32 target_format;
   537     int target_refresh_rate;
   538     int i;
   539     SDL_DisplayMode *current, *match;
   540 
   541     if (!mode || !closest) {
   542         SDL_SetError("Missing desired mode or closest mode parameter");
   543         return NULL;
   544     }
   545 
   546     /* Default to the desktop format */
   547     if (mode->format) {
   548         target_format = mode->format;
   549     } else {
   550         target_format = display->desktop_mode.format;
   551     }
   552 
   553     /* Default to the desktop refresh rate */
   554     if (mode->refresh_rate) {
   555         target_refresh_rate = mode->refresh_rate;
   556     } else {
   557         target_refresh_rate = display->desktop_mode.refresh_rate;
   558     }
   559 
   560     match = NULL;
   561     for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) {
   562         current = &display->display_modes[i];
   563 
   564         if (current->w && (current->w < mode->w)) {
   565             /* Out of sorted modes large enough here */
   566             break;
   567         }
   568         if (current->h && (current->h < mode->h)) {
   569             if (current->w && (current->w == mode->w)) {
   570                 /* Out of sorted modes large enough here */
   571                 break;
   572             }
   573             /* Wider, but not tall enough, due to a different
   574                aspect ratio. This mode must be skipped, but closer
   575                modes may still follow. */
   576             continue;
   577         }
   578         if (!match || current->w < match->w || current->h < match->h) {
   579             match = current;
   580             continue;
   581         }
   582         if (current->format != match->format) {
   583             /* Sorted highest depth to lowest */
   584             if (current->format == target_format ||
   585                 (SDL_BITSPERPIXEL(current->format) >=
   586                  SDL_BITSPERPIXEL(target_format)
   587                  && SDL_PIXELTYPE(current->format) ==
   588                  SDL_PIXELTYPE(target_format))) {
   589                 match = current;
   590             }
   591             continue;
   592         }
   593         if (current->refresh_rate != match->refresh_rate) {
   594             /* Sorted highest refresh to lowest */
   595             if (current->refresh_rate >= target_refresh_rate) {
   596                 match = current;
   597             }
   598         }
   599     }
   600     if (match) {
   601         if (match->format) {
   602             closest->format = match->format;
   603         } else {
   604             closest->format = mode->format;
   605         }
   606         if (match->w && match->h) {
   607             closest->w = match->w;
   608             closest->h = match->h;
   609         } else {
   610             closest->w = mode->w;
   611             closest->h = mode->h;
   612         }
   613         if (match->refresh_rate) {
   614             closest->refresh_rate = match->refresh_rate;
   615         } else {
   616             closest->refresh_rate = mode->refresh_rate;
   617         }
   618         closest->driverdata = match->driverdata;
   619 
   620         /*
   621          * Pick some reasonable defaults if the app and driver don't
   622          * care
   623          */
   624         if (!closest->format) {
   625             closest->format = SDL_PIXELFORMAT_RGB888;
   626         }
   627         if (!closest->w) {
   628             closest->w = 640;
   629         }
   630         if (!closest->h) {
   631             closest->h = 480;
   632         }
   633         return closest;
   634     }
   635     return NULL;
   636 }
   637 
   638 SDL_DisplayMode *
   639 SDL_GetClosestDisplayMode(const SDL_DisplayMode * mode,
   640                           SDL_DisplayMode * closest)
   641 {
   642     if (!_this) {
   643         SDL_UninitializedVideo();
   644         return NULL;
   645     }
   646     return SDL_GetClosestDisplayModeForDisplay(SDL_CurrentDisplay, mode, closest);
   647 }
   648 
   649 int
   650 SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode)
   651 {
   652     SDL_DisplayMode display_mode;
   653     SDL_DisplayMode current_mode;
   654     int ncolors;
   655 
   656     if (mode) {
   657         display_mode = *mode;
   658 
   659         /* Default to the current mode */
   660         if (!display_mode.format) {
   661             display_mode.format = display->current_mode.format;
   662         }
   663         if (!display_mode.w) {
   664             display_mode.w = display->current_mode.w;
   665         }
   666         if (!display_mode.h) {
   667             display_mode.h = display->current_mode.h;
   668         }
   669         if (!display_mode.refresh_rate) {
   670             display_mode.refresh_rate = display->current_mode.refresh_rate;
   671         }
   672 
   673         /* Get a good video mode, the closest one possible */
   674         if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) {
   675             SDL_SetError("No video mode large enough for %dx%d",
   676                          display_mode.w, display_mode.h);
   677             return -1;
   678         }
   679     } else {
   680         display_mode = display->desktop_mode;
   681     }
   682 
   683     /* See if there's anything left to do */
   684     SDL_GetCurrentDisplayModeForDisplay(display, &current_mode);
   685     if (SDL_memcmp(&display_mode, &current_mode, sizeof(display_mode)) == 0) {
   686         return 0;
   687     }
   688 
   689     /* Actually change the display mode */
   690     if (_this->SetDisplayMode(_this, display, &display_mode) < 0) {
   691         return -1;
   692     }
   693     display->current_mode = display_mode;
   694 
   695     /* Set up a palette, if necessary */
   696     if (SDL_ISPIXELFORMAT_INDEXED(display_mode.format)) {
   697         ncolors = (1 << SDL_BITSPERPIXEL(display_mode.format));
   698     } else {
   699         ncolors = 0;
   700     }
   701     if ((!ncolors && display->palette) || (ncolors && !display->palette)
   702         || (ncolors && ncolors != display->palette->ncolors)) {
   703         if (display->palette) {
   704             SDL_FreePalette(display->palette);
   705             display->palette = NULL;
   706         }
   707         if (ncolors) {
   708             display->palette = SDL_AllocPalette(ncolors);
   709             if (!display->palette) {
   710                 return -1;
   711             }
   712             SDL_DitherColors(display->palette->colors,
   713                              SDL_BITSPERPIXEL(display_mode.format));
   714         }
   715     }
   716 
   717     return 0;
   718 }
   719 
   720 int
   721 SDL_SetDisplayMode(const SDL_DisplayMode * mode)
   722 {
   723     if (!_this) {
   724         SDL_UninitializedVideo();
   725         return -1;
   726     }
   727     return SDL_SetDisplayModeForDisplay(SDL_CurrentDisplay, mode);
   728 }
   729 
   730 int
   731 SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode)
   732 {
   733     CHECK_WINDOW_MAGIC(window, -1);
   734 
   735     if (mode) {
   736         window->fullscreen_mode = *mode;
   737     } else {
   738         SDL_zero(window->fullscreen_mode);
   739     }
   740     return 0;
   741 }
   742 
   743 int
   744 SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
   745 {
   746     SDL_DisplayMode fullscreen_mode;
   747 
   748     CHECK_WINDOW_MAGIC(window, -1);
   749 
   750     fullscreen_mode = window->fullscreen_mode;
   751     if (!fullscreen_mode.w) {
   752         fullscreen_mode.w = window->w;
   753     }
   754     if (!fullscreen_mode.h) {
   755         fullscreen_mode.h = window->h;
   756     }
   757 
   758     if (!SDL_GetClosestDisplayModeForDisplay(window->display,
   759                                              &fullscreen_mode,
   760                                              &fullscreen_mode)) {
   761         SDL_SetError("Couldn't find display mode match");
   762         return -1;
   763     }
   764 
   765     if (mode) {
   766         *mode = fullscreen_mode;
   767     }
   768     return 0;
   769 }
   770 
   771 static void
   772 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool attempt)
   773 {
   774     SDL_VideoDisplay *display = window->display;
   775     int i;
   776 
   777     /* See if we're already processing a window */
   778     if (display->updating_fullscreen) {
   779         return;
   780     }
   781 
   782     display->updating_fullscreen = SDL_TRUE;
   783 
   784     /* See if we even want to do anything here */
   785     if ((window->flags & SDL_WINDOW_FULLSCREEN) &&
   786         (window->flags & SDL_WINDOW_SHOWN)) {
   787         if (attempt) {
   788             /* We just gained some state, try to gain all states */
   789             if (window->flags & SDL_WINDOW_MINIMIZED) {
   790                 SDL_RestoreWindow(window);
   791             } else {
   792                 SDL_RaiseWindow(window);
   793             }
   794         } else {
   795             /* We just lost some state, try to release all states */
   796             SDL_MinimizeWindow(window);
   797         }
   798     }
   799 
   800     if (FULLSCREEN_VISIBLE(window)) {
   801         /* Hide any other fullscreen windows */
   802         for (i = 0; i < display->num_windows; ++i) {
   803             SDL_Window *other = &display->windows[i];
   804             if (other != window && FULLSCREEN_VISIBLE(other)) {
   805                 SDL_MinimizeWindow(other);
   806             }
   807         }
   808     }
   809 
   810     display->updating_fullscreen = SDL_FALSE;
   811 
   812     /* See if there are any fullscreen windows */
   813     for (i = 0; i < display->num_windows; ++i) {
   814         window = &display->windows[i];
   815         if (FULLSCREEN_VISIBLE(window)) {
   816             SDL_DisplayMode fullscreen_mode;
   817             if (SDL_GetWindowDisplayMode(window, &fullscreen_mode) == 0) {
   818                 SDL_SetDisplayModeForDisplay(display, &fullscreen_mode);
   819                 display->fullscreen_window = window;
   820                 return;
   821             }
   822         }
   823     }
   824 
   825     /* Nope, restore the desktop mode */
   826     SDL_SetDisplayModeForDisplay(display, NULL);
   827     display->fullscreen_window = NULL;
   828 }
   829 
   830 int
   831 SDL_SetPaletteForDisplay(SDL_VideoDisplay * display, const SDL_Color * colors, int firstcolor, int ncolors)
   832 {
   833     SDL_Palette *palette;
   834     int status = 0;
   835 
   836     palette = display->palette;
   837     if (!palette) {
   838         SDL_SetError("Display mode does not have a palette");
   839         return -1;
   840     }
   841     status = SDL_SetPaletteColors(palette, colors, firstcolor, ncolors);
   842 
   843     if (_this->SetDisplayPalette) {
   844         if (_this->SetDisplayPalette(_this, display, palette) < 0) {
   845             status = -1;
   846         }
   847     }
   848     return status;
   849 }
   850 
   851 int
   852 SDL_SetDisplayPalette(const SDL_Color * colors, int firstcolor, int ncolors)
   853 {
   854     if (!_this) {
   855         SDL_UninitializedVideo();
   856         return -1;
   857     }
   858     return SDL_SetPaletteForDisplay(SDL_CurrentDisplay, colors, firstcolor, ncolors);
   859 }
   860 
   861 int
   862 SDL_GetPaletteForDisplay(SDL_VideoDisplay * display, SDL_Color * colors, int firstcolor, int ncolors)
   863 {
   864     SDL_Palette *palette;
   865 
   866     palette = display->palette;
   867     if (!palette || !palette->ncolors) {
   868         SDL_SetError("Display mode does not have a palette");
   869         return -1;
   870     }
   871     if (firstcolor < 0 || (firstcolor + ncolors) > palette->ncolors) {
   872         SDL_SetError("Palette indices are out of range");
   873         return -1;
   874     }
   875     SDL_memcpy(colors, &palette->colors[firstcolor],
   876                ncolors * sizeof(*colors));
   877     return 0;
   878 }
   879 
   880 int
   881 SDL_GetDisplayPalette(SDL_Color * colors, int firstcolor, int ncolors)
   882 {
   883     if (!_this) {
   884         SDL_UninitializedVideo();
   885         return -1;
   886     }
   887     return SDL_GetPaletteForDisplay(SDL_CurrentDisplay, colors, firstcolor, ncolors);
   888 }
   889 
   890 SDL_Window *
   891 SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
   892 {
   893     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
   894                                   SDL_WINDOW_OPENGL |
   895                                   SDL_WINDOW_BORDERLESS |
   896                                   SDL_WINDOW_RESIZABLE |
   897                                   SDL_WINDOW_INPUT_GRABBED);
   898     SDL_VideoDisplay *display;
   899     SDL_Window *window;
   900 
   901     if (!_this) {
   902         /* Initialize the video system if needed */
   903         if (SDL_VideoInit(NULL, 0) < 0) {
   904             return NULL;
   905         }
   906     }
   907     if (flags & SDL_WINDOW_OPENGL) {
   908         if (!_this->GL_CreateContext) {
   909             SDL_SetError("No OpenGL support in video driver");
   910             return NULL;
   911         }
   912         SDL_GL_LoadLibrary(NULL);
   913     }
   914     display = SDL_CurrentDisplay;
   915     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
   916     window->magic = &_this->window_magic;
   917     window->id = _this->next_object_id++;
   918     window->x = x;
   919     window->y = y;
   920     window->w = w;
   921     window->h = h;
   922     window->flags = (flags & allowed_flags);
   923     window->display = display;
   924     window->next = display->windows;
   925     if (display->windows) {
   926         display->windows->prev = window;
   927     }
   928     display->windows = window;
   929 
   930     if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) {
   931         SDL_DestroyWindow(window);
   932         return NULL;
   933     }
   934 
   935     if (title) {
   936         SDL_SetWindowTitle(window, title);
   937     }
   938     if (flags & SDL_WINDOW_MAXIMIZED) {
   939         SDL_MaximizeWindow(window);
   940     }
   941     if (flags & SDL_WINDOW_MINIMIZED) {
   942         SDL_MinimizeWindow(window);
   943     }
   944     if (flags & SDL_WINDOW_SHOWN) {
   945         SDL_ShowWindow(window);
   946     }
   947     SDL_UpdateWindowGrab(window);
   948 
   949     return window;
   950 }
   951 
   952 SDL_Window *
   953 SDL_CreateWindowFrom(const void *data)
   954 {
   955     SDL_VideoDisplay *display;
   956     SDL_Window *window;
   957 
   958     if (!_this) {
   959         SDL_UninitializedVideo();
   960         return NULL;
   961     }
   962     display = SDL_CurrentDisplay;
   963     window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
   964     window->magic = &_this->window_magic;
   965     window->id = _this->next_object_id++;
   966     window->flags = SDL_WINDOW_FOREIGN;
   967     window->display = display;
   968     window->next = display->windows;
   969     if (display->windows) {
   970         display->windows->prev = window;
   971     }
   972     display->windows = window;
   973 
   974     if (!_this->CreateWindowFrom ||
   975         _this->CreateWindowFrom(_this, window, data) < 0) {
   976         SDL_DestroyWindow(window);
   977         return NULL;
   978     }
   979     return window;
   980 }
   981 
   982 int
   983 SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
   984 {
   985     const Uint32 allowed_flags = (SDL_WINDOW_FULLSCREEN |
   986                                   SDL_WINDOW_OPENGL |
   987                                   SDL_WINDOW_BORDERLESS |
   988                                   SDL_WINDOW_RESIZABLE |
   989                                   SDL_WINDOW_INPUT_GRABBED |
   990                                   SDL_WINDOW_FOREIGN);
   991     char *title = window->title;
   992 
   993     if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) {
   994         SDL_SetError("No OpenGL support in video driver");
   995         return -1;
   996     }
   997     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
   998         if (flags & SDL_WINDOW_OPENGL) {
   999             SDL_GL_LoadLibrary(NULL);
  1000         } else {
  1001             SDL_GL_UnloadLibrary();
  1002         }
  1003     }
  1004 
  1005     if (window->flags & SDL_WINDOW_FOREIGN) {
  1006         /* Can't destroy and re-create foreign windows, hrm */
  1007         flags |= SDL_WINDOW_FOREIGN;
  1008     } else {
  1009         flags &= ~SDL_WINDOW_FOREIGN;
  1010     }
  1011 
  1012     if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1013         _this->DestroyWindow(_this, window);
  1014     }
  1015 
  1016     window->title = NULL;
  1017     window->flags = (flags & allowed_flags);
  1018 
  1019     if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) {
  1020         if (_this->CreateWindow(_this, window) < 0) {
  1021             if (flags & SDL_WINDOW_OPENGL) {
  1022                 SDL_GL_UnloadLibrary();
  1023             }
  1024             return -1;
  1025         }
  1026     }
  1027 
  1028     if (title) {
  1029         SDL_SetWindowTitle(window, title);
  1030         SDL_free(title);
  1031     }
  1032     if (flags & SDL_WINDOW_MAXIMIZED) {
  1033         SDL_MaximizeWindow(window);
  1034     }
  1035     if (flags & SDL_WINDOW_MINIMIZED) {
  1036         SDL_MinimizeWindow(window);
  1037     }
  1038     if (flags & SDL_WINDOW_SHOWN) {
  1039         SDL_ShowWindow(window);
  1040     }
  1041     SDL_UpdateWindowGrab(window);
  1042 
  1043     return 0;
  1044 }
  1045 
  1046 static __inline__ SDL_Renderer *
  1047 SDL_GetCurrentRenderer(SDL_bool create)
  1048 {
  1049     if (!_this) {
  1050         SDL_UninitializedVideo();
  1051         return NULL;
  1052     }
  1053     if (!SDL_CurrentRenderer) {
  1054         if (!create) {
  1055             SDL_SetError("Use SDL_CreateRenderer() to create a renderer");
  1056             return NULL;
  1057         }
  1058         if (SDL_CreateRenderer(0, -1, 0) < 0) {
  1059             return NULL;
  1060         }
  1061     }
  1062     return SDL_CurrentRenderer;
  1063 }
  1064 
  1065 Uint32
  1066 SDL_GetWindowID(SDL_Window * window)
  1067 {
  1068     CHECK_WINDOW_MAGIC(window, 0);
  1069 
  1070     return window->id;
  1071 }
  1072 
  1073 SDL_Window *
  1074 SDL_GetWindowFromID(Uint32 id)
  1075 {
  1076     SDL_Window *window;
  1077     int i;
  1078 
  1079     if (!_this) {
  1080         return NULL;
  1081     }
  1082     /* FIXME: Should we keep a separate hash table for these? */
  1083     for (i = _this->num_displays; i--;) {
  1084         SDL_VideoDisplay *display = &_this->displays[i];
  1085         for (window = display->windows; window; window = window->next) {
  1086             if (window->id == id) {
  1087                 return window;
  1088             }
  1089         }
  1090     }
  1091     return NULL;
  1092 }
  1093 
  1094 Uint32
  1095 SDL_GetWindowFlags(SDL_Window * window)
  1096 {
  1097     CHECK_WINDOW_MAGIC(window, 0);
  1098 
  1099     return window->flags;
  1100 }
  1101 
  1102 void
  1103 SDL_SetWindowTitle(SDL_Window * window, const char *title)
  1104 {
  1105     CHECK_WINDOW_MAGIC(window, );
  1106 
  1107     if (title == window->title) {
  1108         return;
  1109     }
  1110     if (window->title) {
  1111         SDL_free(window->title);
  1112     }
  1113     if (title) {
  1114         window->title = SDL_strdup(title);
  1115     } else {
  1116         window->title = NULL;
  1117     }
  1118 
  1119     if (_this->SetWindowTitle) {
  1120         _this->SetWindowTitle(_this, window);
  1121     }
  1122 }
  1123 
  1124 const char *
  1125 SDL_GetWindowTitle(SDL_Window * window)
  1126 {
  1127     CHECK_WINDOW_MAGIC(window, NULL);
  1128 
  1129     return window->title;
  1130 }
  1131 
  1132 void
  1133 SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon)
  1134 {
  1135     CHECK_WINDOW_MAGIC(window, );
  1136 
  1137     if (_this->SetWindowIcon) {
  1138         _this->SetWindowIcon(_this, window, icon);
  1139     }
  1140 }
  1141 
  1142 void
  1143 SDL_SetWindowData(SDL_Window * window, void *userdata)
  1144 {
  1145     CHECK_WINDOW_MAGIC(window, );
  1146 
  1147     window->userdata = userdata;
  1148 }
  1149 
  1150 void *
  1151 SDL_GetWindowData(SDL_Window * window)
  1152 {
  1153     CHECK_WINDOW_MAGIC(window, NULL);
  1154 
  1155     return window->userdata;
  1156 }
  1157 
  1158 void
  1159 SDL_SetWindowPosition(SDL_Window * window, int x, int y)
  1160 {
  1161     CHECK_WINDOW_MAGIC(window, );
  1162 
  1163     if (x != SDL_WINDOWPOS_UNDEFINED) {
  1164         window->x = x;
  1165     }
  1166     if (y != SDL_WINDOWPOS_UNDEFINED) {
  1167         window->y = y;
  1168     }
  1169     if (_this->SetWindowPosition) {
  1170         _this->SetWindowPosition(_this, window);
  1171     }
  1172     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
  1173 }
  1174 
  1175 void
  1176 SDL_GetWindowPosition(SDL_Window * window, int *x, int *y)
  1177 {
  1178     CHECK_WINDOW_MAGIC(window, );
  1179 
  1180     if (x) {
  1181         *x = window->x;
  1182     }
  1183     if (y) {
  1184         *y = window->y;
  1185     }
  1186 }
  1187 
  1188 void
  1189 SDL_SetWindowSize(SDL_Window * window, int w, int h)
  1190 {
  1191     CHECK_WINDOW_MAGIC(window, );
  1192 
  1193     window->w = w;
  1194     window->h = h;
  1195 
  1196     if (_this->SetWindowSize) {
  1197         _this->SetWindowSize(_this, window);
  1198     }
  1199     SDL_OnWindowResized(window);
  1200 }
  1201 
  1202 void
  1203 SDL_GetWindowSize(SDL_Window * window, int *w, int *h)
  1204 {
  1205     if (window) {
  1206         if (w) {
  1207             *w = window->w;
  1208         }
  1209         if (h) {
  1210             *h = window->h;
  1211         }
  1212     } else {
  1213         if (w) {
  1214             *w = 0;
  1215         }
  1216         if (h) {
  1217             *h = 0;
  1218         }
  1219     }
  1220 }
  1221 
  1222 void
  1223 SDL_ShowWindow(SDL_Window * window)
  1224 {
  1225     CHECK_WINDOW_MAGIC(window, );
  1226 
  1227     if (window->flags & SDL_WINDOW_SHOWN) {
  1228         return;
  1229     }
  1230 
  1231     if (_this->ShowWindow) {
  1232         _this->ShowWindow(_this, window);
  1233     }
  1234     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
  1235 }
  1236 
  1237 void
  1238 SDL_HideWindow(SDL_Window * window)
  1239 {
  1240     CHECK_WINDOW_MAGIC(window, );
  1241 
  1242     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1243         return;
  1244     }
  1245 
  1246     if (_this->HideWindow) {
  1247         _this->HideWindow(_this, window);
  1248     }
  1249     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  1250 }
  1251 
  1252 void
  1253 SDL_RaiseWindow(SDL_Window * window)
  1254 {
  1255     CHECK_WINDOW_MAGIC(window, );
  1256 
  1257     if (!(window->flags & SDL_WINDOW_SHOWN)) {
  1258         return;
  1259     }
  1260     if (_this->RaiseWindow) {
  1261         _this->RaiseWindow(_this, window);
  1262     } else {
  1263         /* FIXME: What we really want is a way to request focus */
  1264         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
  1265     }
  1266 }
  1267 
  1268 void
  1269 SDL_MaximizeWindow(SDL_Window * window)
  1270 {
  1271     CHECK_WINDOW_MAGIC(window, );
  1272 
  1273     if (window->flags & SDL_WINDOW_MAXIMIZED) {
  1274         return;
  1275     }
  1276 
  1277     if (_this->MaximizeWindow) {
  1278         _this->MaximizeWindow(_this, window);
  1279     }
  1280     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
  1281 }
  1282 
  1283 void
  1284 SDL_MinimizeWindow(SDL_Window * window)
  1285 {
  1286     CHECK_WINDOW_MAGIC(window, );
  1287 
  1288     if (window->flags & SDL_WINDOW_MINIMIZED) {
  1289         return;
  1290     }
  1291 
  1292     if (_this->MinimizeWindow) {
  1293         _this->MinimizeWindow(_this, window);
  1294     }
  1295     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
  1296 }
  1297 
  1298 void
  1299 SDL_RestoreWindow(SDL_Window * window)
  1300 {
  1301     CHECK_WINDOW_MAGIC(window, );
  1302 
  1303     if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) {
  1304         return;
  1305     }
  1306 
  1307     if (_this->RestoreWindow) {
  1308         _this->RestoreWindow(_this, window);
  1309     }
  1310     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
  1311 }
  1312 
  1313 int
  1314 SDL_SetWindowFullscreen(SDL_Window * window, int fullscreen)
  1315 {
  1316     CHECK_WINDOW_MAGIC(window, -1);
  1317 
  1318     if (fullscreen) {
  1319         fullscreen = SDL_WINDOW_FULLSCREEN;
  1320     }
  1321     if ((window->flags & SDL_WINDOW_FULLSCREEN) == fullscreen) {
  1322         return 0;
  1323     }
  1324     if (fullscreen) {
  1325         window->flags |= SDL_WINDOW_FULLSCREEN;
  1326 
  1327         SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1328     } else {
  1329         window->flags &= ~SDL_WINDOW_FULLSCREEN;
  1330 
  1331         SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1332     }
  1333     return 0;
  1334 }
  1335 
  1336 void
  1337 SDL_SetWindowGrab(SDL_Window * window, int mode)
  1338 {
  1339     CHECK_WINDOW_MAGIC(window, );
  1340 
  1341     if ((!!mode == !!(window->flags & SDL_WINDOW_INPUT_GRABBED))) {
  1342         return;
  1343     }
  1344     if (mode) {
  1345         window->flags |= SDL_WINDOW_INPUT_GRABBED;
  1346     } else {
  1347         window->flags &= ~SDL_WINDOW_INPUT_GRABBED;
  1348     }
  1349     SDL_UpdateWindowGrab(window);
  1350 }
  1351 
  1352 static void
  1353 SDL_UpdateWindowGrab(SDL_Window * window)
  1354 {
  1355     if ((window->flags & SDL_WINDOW_INPUT_FOCUS) && _this->SetWindowGrab) {
  1356         _this->SetWindowGrab(_this, window);
  1357     }
  1358 }
  1359 
  1360 int
  1361 SDL_GetWindowGrab(SDL_Window * window)
  1362 {
  1363     CHECK_WINDOW_MAGIC(window, 0);
  1364 
  1365     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
  1366 }
  1367 
  1368 void
  1369 SDL_OnWindowShown(SDL_Window * window)
  1370 {
  1371     SDL_RaiseWindow(window);
  1372     SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1373 }
  1374 
  1375 void
  1376 SDL_OnWindowHidden(SDL_Window * window)
  1377 {
  1378     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1379 }
  1380 
  1381 void
  1382 SDL_OnWindowResized(SDL_Window * window)
  1383 {
  1384     SDL_Renderer *renderer = window->renderer;
  1385 
  1386     if (renderer && renderer->DisplayModeChanged) {
  1387         renderer->DisplayModeChanged(renderer);
  1388     }
  1389 }
  1390 
  1391 void
  1392 SDL_OnWindowMinimized(SDL_Window * window)
  1393 {
  1394     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1395 }
  1396 
  1397 void
  1398 SDL_OnWindowRestored(SDL_Window * window)
  1399 {
  1400     SDL_RaiseWindow(window);
  1401     SDL_UpdateFullscreenMode(window, SDL_TRUE);
  1402 }
  1403 
  1404 void
  1405 SDL_OnWindowFocusGained(SDL_Window * window)
  1406 {
  1407     SDL_VideoDisplay *display = window->display;
  1408 
  1409     if (display->gamma && _this->SetDisplayGammaRamp) {
  1410         _this->SetDisplayGammaRamp(_this, display, display->gamma);
  1411     }
  1412     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1413         && _this->SetWindowGrab) {
  1414         _this->SetWindowGrab(_this, window);
  1415     }
  1416 }
  1417 
  1418 void
  1419 SDL_OnWindowFocusLost(SDL_Window * window)
  1420 {
  1421     SDL_VideoDisplay *display = window->display;
  1422 
  1423     /* If we're fullscreen on a single-head system and lose focus, minimize */
  1424     if ((window->flags & SDL_WINDOW_FULLSCREEN) &&
  1425         _this->num_displays == 1) {
  1426         SDL_MinimizeWindow(window);
  1427     }
  1428 
  1429     if (display->gamma && _this->SetDisplayGammaRamp) {
  1430         _this->SetDisplayGammaRamp(_this, display, display->saved_gamma);
  1431     }
  1432     if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
  1433         && _this->SetWindowGrab) {
  1434         _this->SetWindowGrab(_this, window);
  1435     }
  1436 }
  1437 
  1438 SDL_Window *
  1439 SDL_GetFocusWindow(void)
  1440 {
  1441     SDL_VideoDisplay *display;
  1442     SDL_Window *window;
  1443 
  1444     if (!_this) {
  1445         return NULL;
  1446     }
  1447     display = SDL_CurrentDisplay;
  1448     for (window = display->windows; window; window = window->next) {
  1449         if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
  1450             return window;
  1451         }
  1452     }
  1453     return NULL;
  1454 }
  1455 
  1456 void
  1457 SDL_DestroyWindow(SDL_Window * window)
  1458 {
  1459     SDL_VideoDisplay *display;
  1460 
  1461     CHECK_WINDOW_MAGIC(window, );
  1462     window->magic = NULL;
  1463 
  1464     if (window->title) {
  1465         SDL_free(window->title);
  1466     }
  1467     if (window->renderer) {
  1468         SDL_DestroyRenderer(window);
  1469     }
  1470 
  1471     /* Restore video mode, etc. */
  1472     SDL_UpdateFullscreenMode(window, SDL_FALSE);
  1473 
  1474     if (_this->DestroyWindow) {
  1475         _this->DestroyWindow(_this, window);
  1476     }
  1477     if (window->flags & SDL_WINDOW_OPENGL) {
  1478         SDL_GL_UnloadLibrary();
  1479     }
  1480 
  1481     /* Unlink the window from the list */
  1482     display = window->display;
  1483     if (window->next) {
  1484         window->next->prev = window->prev;
  1485     }
  1486     if (window->prev) {
  1487         window->prev->next = window->next;
  1488     } else {
  1489         display->windows = window->next;
  1490     }
  1491 
  1492     SDL_free(window);
  1493 }
  1494 
  1495 void
  1496 SDL_AddRenderDriver(SDL_VideoDisplay * display, const SDL_RenderDriver * driver)
  1497 {
  1498     SDL_RenderDriver *render_drivers;
  1499 
  1500     render_drivers =
  1501         SDL_realloc(display->render_drivers,
  1502                     (display->num_render_drivers +
  1503                      1) * sizeof(*render_drivers));
  1504     if (render_drivers) {
  1505         render_drivers[display->num_render_drivers] = *driver;
  1506         display->render_drivers = render_drivers;
  1507         display->num_render_drivers++;
  1508     }
  1509 }
  1510 
  1511 int
  1512 SDL_GetNumRenderDrivers(void)
  1513 {
  1514     if (_this) {
  1515         return SDL_CurrentDisplay->num_render_drivers;
  1516     }
  1517     return 0;
  1518 }
  1519 
  1520 int
  1521 SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
  1522 {
  1523     if (!_this) {
  1524         SDL_UninitializedVideo();
  1525         return -1;
  1526     }
  1527     if (index < 0 || index >= SDL_GetNumRenderDrivers()) {
  1528         SDL_SetError("index must be in the range of 0 - %d",
  1529                      SDL_GetNumRenderDrivers() - 1);
  1530         return -1;
  1531     }
  1532     *info = SDL_CurrentDisplay->render_drivers[index].info;
  1533     return 0;
  1534 }
  1535 
  1536 int
  1537 SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
  1538 {
  1539     CHECK_WINDOW_MAGIC(window, -1);
  1540 
  1541     /* Free any existing renderer */
  1542     SDL_DestroyRenderer(window);
  1543 
  1544     if (index < 0) {
  1545         char *override = SDL_getenv("SDL_VIDEO_RENDERER");
  1546         int n = SDL_GetNumRenderDrivers();
  1547 
  1548 #if SDL_VIDEO_RENDER_OGL
  1549         if (!override && (window->flags & SDL_WINDOW_OPENGL)) {
  1550             override = "opengl";
  1551         }
  1552 #endif /* SDL_VIDEO_RENDER_OGL */
  1553 #if SDL_VIDEO_RENDER_OGL_ES
  1554         if (!override && (window->flags & SDL_WINDOW_OPENGL)) {
  1555             override = "opengl_es";
  1556         }
  1557 #endif /* SDL_VIDEO_RENDER_OGL_ES */
  1558         if (override) {
  1559             for (index = 0; index < n; ++index) {
  1560                 SDL_RenderDriver *driver =
  1561                     &SDL_CurrentDisplay->render_drivers[index];
  1562 
  1563                 if (SDL_strcasecmp(override, driver->info.name) == 0) {
  1564                     /* Create a new renderer instance */
  1565                     window->renderer = driver->CreateRenderer(window, flags);
  1566                     break;
  1567                 }
  1568             }
  1569         } else {
  1570             for (index = 0; index < n; ++index) {
  1571                 SDL_RenderDriver *driver =
  1572                     &SDL_CurrentDisplay->render_drivers[index];
  1573 
  1574                 if ((driver->info.flags & flags) == flags) {
  1575                     /* Create a new renderer instance */
  1576                     window->renderer = driver->CreateRenderer(window, flags);
  1577                     if (window->renderer) {
  1578                         /* Yay, we got one! */
  1579                         break;
  1580                     }
  1581                 }
  1582             }
  1583         }
  1584         if (index == n) {
  1585             SDL_SetError("Couldn't find matching render driver");
  1586             return -1;
  1587         }
  1588     } else {
  1589         if (index >= SDL_GetNumRenderDrivers()) {
  1590             SDL_SetError("index must be -1 or in the range of 0 - %d",
  1591                          SDL_GetNumRenderDrivers() - 1);
  1592             return -1;
  1593         }
  1594         /* Create a new renderer instance */
  1595         window->renderer = SDL_CurrentDisplay->render_drivers[index].CreateRenderer(window, flags);
  1596     }
  1597 
  1598     if (window->renderer == NULL) {
  1599         /* Assuming renderer set its error */
  1600         return -1;
  1601     }
  1602 
  1603     SDL_SelectRenderer(window);
  1604 
  1605     return 0;
  1606 }
  1607 
  1608 int
  1609 SDL_SelectRenderer(SDL_Window * window)
  1610 {
  1611     SDL_Renderer *renderer;
  1612 
  1613     CHECK_WINDOW_MAGIC(window, -1);
  1614 
  1615     renderer = window->renderer;
  1616     if (!renderer) {
  1617         SDL_SetError("Use SDL_CreateRenderer() to create a renderer");
  1618         return -1;
  1619     }
  1620     if (renderer->ActivateRenderer) {
  1621         if (renderer->ActivateRenderer(renderer) < 0) {
  1622             return -1;
  1623         }
  1624     }
  1625     SDL_CurrentDisplay->current_renderer = renderer;
  1626     return 0;
  1627 }
  1628 
  1629 int
  1630 SDL_GetRendererInfo(SDL_RendererInfo * info)
  1631 {
  1632     SDL_Renderer *renderer = SDL_GetCurrentRenderer(SDL_FALSE);
  1633     if (!renderer) {
  1634         return -1;
  1635     }
  1636     *info = renderer->info;
  1637     return 0;
  1638 }
  1639 
  1640 SDL_Texture *
  1641 SDL_CreateTexture(Uint32 format, int access, int w, int h)
  1642 {
  1643     SDL_Renderer *renderer;
  1644     SDL_Texture *texture;
  1645 
  1646     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  1647     if (!renderer) {
  1648         return 0;
  1649     }
  1650     if (!renderer->CreateTexture) {
  1651         SDL_Unsupported();
  1652         return 0;
  1653     }
  1654     texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
  1655     if (!texture) {
  1656         SDL_OutOfMemory();
  1657         return 0;
  1658     }
  1659     texture->magic = &_this->texture_magic;
  1660     texture->format = format;
  1661     texture->access = access;
  1662     texture->w = w;
  1663     texture->h = h;
  1664     texture->r = 255;
  1665     texture->g = 255;
  1666     texture->b = 255;
  1667     texture->a = 255;
  1668     texture->renderer = renderer;
  1669     texture->next = renderer->textures;
  1670     if (renderer->textures) {
  1671         renderer->textures->prev = texture;
  1672     }
  1673     renderer->textures = texture;
  1674 
  1675     if (renderer->CreateTexture(renderer, texture) < 0) {
  1676         SDL_DestroyTexture(texture);
  1677         return 0;
  1678     }
  1679     return texture;
  1680 }
  1681 
  1682 SDL_Texture *
  1683 SDL_CreateTextureFromSurface(Uint32 format, SDL_Surface * surface)
  1684 {
  1685     SDL_Texture *texture;
  1686     Uint32 requested_format = format;
  1687     SDL_PixelFormat *fmt;
  1688     SDL_Renderer *renderer;
  1689     int bpp;
  1690     Uint32 Rmask, Gmask, Bmask, Amask;
  1691 
  1692     if (!surface) {
  1693         SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
  1694         return 0;
  1695     }
  1696     fmt = surface->format;
  1697 
  1698     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  1699     if (!renderer) {
  1700         return 0;
  1701     }
  1702 
  1703     if (format) {
  1704         if (!SDL_PixelFormatEnumToMasks
  1705             (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
  1706             SDL_SetError("Unknown pixel format");
  1707             return 0;
  1708         }
  1709     } else {
  1710         if (surface->format->Amask
  1711             || !(surface->map->info.flags &
  1712                  (SDL_COPY_COLORKEY | SDL_COPY_MASK | SDL_COPY_BLEND))) {
  1713             Uint32 it;
  1714             int pfmt;
  1715 
  1716             /* Pixel formats, sorted by best first */
  1717             static const Uint32 sdl_pformats[] = {
  1718                 SDL_PIXELFORMAT_ARGB8888,
  1719                 SDL_PIXELFORMAT_RGBA8888,
  1720                 SDL_PIXELFORMAT_ABGR8888,
  1721                 SDL_PIXELFORMAT_BGRA8888,
  1722                 SDL_PIXELFORMAT_RGB888,
  1723                 SDL_PIXELFORMAT_BGR888,
  1724                 SDL_PIXELFORMAT_RGB24,
  1725                 SDL_PIXELFORMAT_BGR24,
  1726                 SDL_PIXELFORMAT_RGB565,
  1727                 SDL_PIXELFORMAT_BGR565,
  1728                 SDL_PIXELFORMAT_ARGB1555,
  1729                 SDL_PIXELFORMAT_ABGR1555,
  1730                 SDL_PIXELFORMAT_RGB555,
  1731                 SDL_PIXELFORMAT_BGR555,
  1732                 SDL_PIXELFORMAT_ARGB4444,
  1733                 SDL_PIXELFORMAT_ABGR4444,
  1734                 SDL_PIXELFORMAT_RGB444,
  1735                 SDL_PIXELFORMAT_ARGB2101010,
  1736                 SDL_PIXELFORMAT_INDEX8,
  1737                 SDL_PIXELFORMAT_INDEX4LSB,
  1738                 SDL_PIXELFORMAT_INDEX4MSB,
  1739                 SDL_PIXELFORMAT_RGB332,
  1740                 SDL_PIXELFORMAT_INDEX1LSB,
  1741                 SDL_PIXELFORMAT_INDEX1MSB,
  1742                 SDL_PIXELFORMAT_UNKNOWN
  1743             };
  1744 
  1745             bpp = fmt->BitsPerPixel;
  1746             Rmask = fmt->Rmask;
  1747             Gmask = fmt->Gmask;
  1748             Bmask = fmt->Bmask;
  1749             Amask = fmt->Amask;
  1750 
  1751             format =
  1752                 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
  1753             if (!format) {
  1754                 SDL_SetError("Unknown pixel format");
  1755                 return 0;
  1756             }
  1757 
  1758             /* Search requested format in the supported texture */
  1759             /* formats by current renderer                      */
  1760             for (it = 0; it < renderer->info.num_texture_formats; it++) {
  1761                 if (renderer->info.texture_formats[it] == format) {
  1762                     break;
  1763                 }
  1764             }
  1765 
  1766             /* If requested format can't be found, search any best */
  1767             /* format which renderer provides                      */
  1768             if (it == renderer->info.num_texture_formats) {
  1769                 pfmt = 0;
  1770                 for (;;) {
  1771                     if (sdl_pformats[pfmt] == SDL_PIXELFORMAT_UNKNOWN) {
  1772                         break;
  1773                     }
  1774 
  1775                     for (it = 0; it < renderer->info.num_texture_formats;
  1776                          it++) {
  1777                         if (renderer->info.texture_formats[it] ==
  1778                             sdl_pformats[pfmt]) {
  1779                             break;
  1780                         }
  1781                     }
  1782 
  1783                     if (it != renderer->info.num_texture_formats) {
  1784                         /* The best format has been found */
  1785                         break;
  1786                     }
  1787                     pfmt++;
  1788                 }
  1789 
  1790                 /* If any format can't be found, then return an error */
  1791                 if (it == renderer->info.num_texture_formats) {
  1792                     SDL_SetError
  1793                         ("Any of the supported pixel formats can't be found");
  1794                     return 0;
  1795                 }
  1796 
  1797                 /* Convert found pixel format back to color masks */
  1798                 if (SDL_PixelFormatEnumToMasks
  1799                     (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
  1800                      &Bmask, &Amask) != SDL_TRUE) {
  1801                     SDL_SetError("Unknown pixel format");
  1802                     return 0;
  1803                 }
  1804             }
  1805         } else {
  1806             /* Need a format with alpha */
  1807             Uint32 it;
  1808             int apfmt;
  1809 
  1810             /* Pixel formats with alpha, sorted by best first */
  1811             static const Uint32 sdl_alpha_pformats[] = {
  1812                 SDL_PIXELFORMAT_ARGB8888,
  1813                 SDL_PIXELFORMAT_RGBA8888,
  1814                 SDL_PIXELFORMAT_ABGR8888,
  1815                 SDL_PIXELFORMAT_BGRA8888,
  1816                 SDL_PIXELFORMAT_ARGB1555,
  1817                 SDL_PIXELFORMAT_ABGR1555,
  1818                 SDL_PIXELFORMAT_ARGB4444,
  1819                 SDL_PIXELFORMAT_ABGR4444,
  1820                 SDL_PIXELFORMAT_ARGB2101010,
  1821                 SDL_PIXELFORMAT_UNKNOWN
  1822             };
  1823 
  1824             if (surface->format->Amask) {
  1825                 /* If surface already has alpha, then try an original */
  1826                 /* surface format first                               */
  1827                 bpp = fmt->BitsPerPixel;
  1828                 Rmask = fmt->Rmask;
  1829                 Gmask = fmt->Gmask;
  1830                 Bmask = fmt->Bmask;
  1831                 Amask = fmt->Amask;
  1832             } else {
  1833                 bpp = 32;
  1834                 Rmask = 0x00FF0000;
  1835                 Gmask = 0x0000FF00;
  1836                 Bmask = 0x000000FF;
  1837                 Amask = 0xFF000000;
  1838             }
  1839 
  1840             format =
  1841                 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
  1842             if (!format) {
  1843                 SDL_SetError("Unknown pixel format");
  1844                 return 0;
  1845             }
  1846 
  1847             /* Search this format in the supported texture formats */
  1848             /* by current renderer                                 */
  1849             for (it = 0; it < renderer->info.num_texture_formats; it++) {
  1850                 if (renderer->info.texture_formats[it] == format) {
  1851                     break;
  1852                 }
  1853             }
  1854 
  1855             /* If this format can't be found, search any best       */
  1856             /* compatible format with alpha which renderer provides */
  1857             if (it == renderer->info.num_texture_formats) {
  1858                 apfmt = 0;
  1859                 for (;;) {
  1860                     if (sdl_alpha_pformats[apfmt] == SDL_PIXELFORMAT_UNKNOWN) {
  1861                         break;
  1862                     }
  1863 
  1864                     for (it = 0; it < renderer->info.num_texture_formats;
  1865                          it++) {
  1866                         if (renderer->info.texture_formats[it] ==
  1867                             sdl_alpha_pformats[apfmt]) {
  1868                             break;
  1869                         }
  1870                     }
  1871 
  1872                     if (it != renderer->info.num_texture_formats) {
  1873                         /* Compatible format has been found */
  1874                         break;
  1875                     }
  1876                     apfmt++;
  1877                 }
  1878 
  1879                 /* If compatible format can't be found, then return an error */
  1880                 if (it == renderer->info.num_texture_formats) {
  1881                     SDL_SetError("Compatible pixel format can't be found");
  1882                     return 0;
  1883                 }
  1884 
  1885                 /* Convert found pixel format back to color masks */
  1886                 if (SDL_PixelFormatEnumToMasks
  1887                     (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
  1888                      &Bmask, &Amask) != SDL_TRUE) {
  1889                     SDL_SetError("Unknown pixel format");
  1890                     return 0;
  1891                 }
  1892             }
  1893         }
  1894 
  1895         format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
  1896         if (!format) {
  1897             SDL_SetError("Unknown pixel format");
  1898             return 0;
  1899         }
  1900     }
  1901 
  1902     texture =
  1903         SDL_CreateTexture(format, SDL_TEXTUREACCESS_STATIC, surface->w,
  1904                           surface->h);
  1905     if (!texture && !requested_format) {
  1906         SDL_DisplayMode desktop_mode;
  1907         SDL_GetDesktopDisplayMode(&desktop_mode);
  1908         format = desktop_mode.format;
  1909         texture =
  1910             SDL_CreateTexture(format, SDL_TEXTUREACCESS_STATIC, surface->w,
  1911                               surface->h);
  1912     }
  1913     if (!texture) {
  1914         return 0;
  1915     }
  1916     if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask
  1917         && Bmask == fmt->Bmask && Amask == fmt->Amask) {
  1918         if (SDL_MUSTLOCK(surface)) {
  1919             SDL_LockSurface(surface);
  1920             SDL_UpdateTexture(texture, NULL, surface->pixels,
  1921                               surface->pitch);
  1922             SDL_UnlockSurface(surface);
  1923         } else {
  1924             SDL_UpdateTexture(texture, NULL, surface->pixels,
  1925                               surface->pitch);
  1926         }
  1927     } else {
  1928         SDL_PixelFormat dst_fmt;
  1929         SDL_Surface *dst = NULL;
  1930 
  1931         /* Set up a destination surface for the texture update */
  1932         SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask);
  1933         if (SDL_ISPIXELFORMAT_INDEXED(format)) {
  1934             dst_fmt.palette =
  1935                 SDL_AllocPalette((1 << SDL_BITSPERPIXEL(format)));
  1936             if (dst_fmt.palette) {
  1937                 /*
  1938                  * FIXME: Should we try to copy
  1939                  * fmt->palette?
  1940                  */
  1941                 SDL_DitherColors(dst_fmt.palette->colors,
  1942                                  SDL_BITSPERPIXEL(format));
  1943             }
  1944         }
  1945         dst = SDL_ConvertSurface(surface, &dst_fmt, 0);
  1946         if (dst) {
  1947             SDL_UpdateTexture(texture, NULL, dst->pixels, dst->pitch);
  1948             SDL_FreeSurface(dst);
  1949         }
  1950         if (dst_fmt.palette) {
  1951             SDL_FreePalette(dst_fmt.palette);
  1952         }
  1953         if (!dst) {
  1954             SDL_DestroyTexture(texture);
  1955             return 0;
  1956         }
  1957     }
  1958 
  1959     {
  1960         Uint8 r, g, b, a;
  1961         int blendMode;
  1962         int scaleMode;
  1963 
  1964         SDL_GetSurfaceColorMod(surface, &r, &g, &b);
  1965         SDL_SetTextureColorMod(texture, r, g, b);
  1966 
  1967         SDL_GetSurfaceAlphaMod(surface, &a);
  1968         SDL_SetTextureAlphaMod(texture, a);
  1969 
  1970         SDL_GetSurfaceBlendMode(surface, &blendMode);
  1971         SDL_SetTextureBlendMode(texture, blendMode);
  1972 
  1973         SDL_GetSurfaceScaleMode(surface, &scaleMode);
  1974         SDL_SetTextureScaleMode(texture, scaleMode);
  1975     }
  1976 
  1977     if (SDL_ISPIXELFORMAT_INDEXED(format) && fmt->palette) {
  1978         SDL_SetTexturePalette(texture, fmt->palette->colors, 0,
  1979                               fmt->palette->ncolors);
  1980     }
  1981     return texture;
  1982 }
  1983 
  1984 int
  1985 SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
  1986                  int *w, int *h)
  1987 {
  1988     CHECK_TEXTURE_MAGIC(texture, -1);
  1989 
  1990     if (format) {
  1991         *format = texture->format;
  1992     }
  1993     if (access) {
  1994         *access = texture->access;
  1995     }
  1996     if (w) {
  1997         *w = texture->w;
  1998     }
  1999     if (h) {
  2000         *h = texture->h;
  2001     }
  2002     return 0;
  2003 }
  2004 
  2005 int
  2006 SDL_QueryTexturePixels(SDL_Texture * texture, void **pixels, int *pitch)
  2007 {
  2008     SDL_Renderer *renderer;
  2009 
  2010     CHECK_TEXTURE_MAGIC(texture, -1);
  2011 
  2012     renderer = texture->renderer;
  2013     if (!renderer->QueryTexturePixels) {
  2014         SDL_Unsupported();
  2015         return -1;
  2016     }
  2017     return renderer->QueryTexturePixels(renderer, texture, pixels, pitch);
  2018 }
  2019 
  2020 int
  2021 SDL_SetTexturePalette(SDL_Texture * texture, const SDL_Color * colors,
  2022                       int firstcolor, int ncolors)
  2023 {
  2024     SDL_Renderer *renderer;
  2025 
  2026     CHECK_TEXTURE_MAGIC(texture, -1);
  2027 
  2028     renderer = texture->renderer;
  2029     if (!renderer->SetTexturePalette) {
  2030         SDL_Unsupported();
  2031         return -1;
  2032     }
  2033     return renderer->SetTexturePalette(renderer, texture, colors, firstcolor,
  2034                                        ncolors);
  2035 }
  2036 
  2037 int
  2038 SDL_GetTexturePalette(SDL_Texture * texture, SDL_Color * colors,
  2039                       int firstcolor, int ncolors)
  2040 {
  2041     SDL_Renderer *renderer;
  2042 
  2043     CHECK_TEXTURE_MAGIC(texture, -1);
  2044 
  2045     renderer = texture->renderer;
  2046     if (!renderer->GetTexturePalette) {
  2047         SDL_Unsupported();
  2048         return -1;
  2049     }
  2050     return renderer->GetTexturePalette(renderer, texture, colors, firstcolor,
  2051                                        ncolors);
  2052 }
  2053 
  2054 int
  2055 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
  2056 {
  2057     SDL_Renderer *renderer;
  2058 
  2059     CHECK_TEXTURE_MAGIC(texture, -1);
  2060 
  2061     renderer = texture->renderer;
  2062     if (!renderer->SetTextureColorMod) {
  2063         SDL_Unsupported();
  2064         return -1;
  2065     }
  2066     if (r < 255 || g < 255 || b < 255) {
  2067         texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
  2068     } else {
  2069         texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
  2070     }
  2071     texture->r = r;
  2072     texture->g = g;
  2073     texture->b = b;
  2074     return renderer->SetTextureColorMod(renderer, texture);
  2075 }
  2076 
  2077 int
  2078 SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
  2079                        Uint8 * b)
  2080 {
  2081     SDL_Renderer *renderer;
  2082 
  2083     CHECK_TEXTURE_MAGIC(texture, -1);
  2084 
  2085     renderer = texture->renderer;
  2086     if (r) {
  2087         *r = texture->r;
  2088     }
  2089     if (g) {
  2090         *g = texture->g;
  2091     }
  2092     if (b) {
  2093         *b = texture->b;
  2094     }
  2095     return 0;
  2096 }
  2097 
  2098 int
  2099 SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
  2100 {
  2101     SDL_Renderer *renderer;
  2102 
  2103     CHECK_TEXTURE_MAGIC(texture, -1);
  2104 
  2105     renderer = texture->renderer;
  2106     if (!renderer->SetTextureAlphaMod) {
  2107         SDL_Unsupported();
  2108         return -1;
  2109     }
  2110     if (alpha < 255) {
  2111         texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
  2112     } else {
  2113         texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
  2114     }
  2115     texture->a = alpha;
  2116     return renderer->SetTextureAlphaMod(renderer, texture);
  2117 }
  2118 
  2119 int
  2120 SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
  2121 {
  2122     CHECK_TEXTURE_MAGIC(texture, -1);
  2123 
  2124     if (alpha) {
  2125         *alpha = texture->a;
  2126     }
  2127     return 0;
  2128 }
  2129 
  2130 int
  2131 SDL_SetTextureBlendMode(SDL_Texture * texture, int blendMode)
  2132 {
  2133     SDL_Renderer *renderer;
  2134 
  2135     CHECK_TEXTURE_MAGIC(texture, -1);
  2136 
  2137     renderer = texture->renderer;
  2138     if (!renderer->SetTextureBlendMode) {
  2139         SDL_Unsupported();
  2140         return -1;
  2141     }
  2142     texture->blendMode = blendMode;
  2143     return renderer->SetTextureBlendMode(renderer, texture);
  2144 }
  2145 
  2146 int
  2147 SDL_GetTextureBlendMode(SDL_Texture * texture, int *blendMode)
  2148 {
  2149     CHECK_TEXTURE_MAGIC(texture, -1);
  2150 
  2151     if (blendMode) {
  2152         *blendMode = texture->blendMode;
  2153     }
  2154     return 0;
  2155 }
  2156 
  2157 int
  2158 SDL_SetTextureScaleMode(SDL_Texture * texture, int scaleMode)
  2159 {
  2160     SDL_Renderer *renderer;
  2161 
  2162     CHECK_TEXTURE_MAGIC(texture, -1);
  2163 
  2164     renderer = texture->renderer;
  2165     if (!renderer->SetTextureScaleMode) {
  2166         SDL_Unsupported();
  2167         return -1;
  2168     }
  2169     texture->scaleMode = scaleMode;
  2170     return renderer->SetTextureScaleMode(renderer, texture);
  2171 }
  2172 
  2173 int
  2174 SDL_GetTextureScaleMode(SDL_Texture * texture, int *scaleMode)
  2175 {
  2176     CHECK_TEXTURE_MAGIC(texture, -1);
  2177 
  2178     if (scaleMode) {
  2179         *scaleMode = texture->scaleMode;
  2180     }
  2181     return 0;
  2182 }
  2183 
  2184 int
  2185 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
  2186                   const void *pixels, int pitch)
  2187 {
  2188     SDL_Renderer *renderer;
  2189     SDL_Rect full_rect;
  2190 
  2191     CHECK_TEXTURE_MAGIC(texture, -1);
  2192 
  2193     renderer = texture->renderer;
  2194     if (!renderer->UpdateTexture) {
  2195         SDL_Unsupported();
  2196         return -1;
  2197     }
  2198     if (!rect) {
  2199         full_rect.x = 0;
  2200         full_rect.y = 0;
  2201         full_rect.w = texture->w;
  2202         full_rect.h = texture->h;
  2203         rect = &full_rect;
  2204     }
  2205     return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
  2206 }
  2207 
  2208 int
  2209 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, int markDirty,
  2210                 void **pixels, int *pitch)
  2211 {
  2212     SDL_Renderer *renderer;
  2213     SDL_Rect full_rect;
  2214 
  2215     CHECK_TEXTURE_MAGIC(texture, -1);
  2216 
  2217     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  2218         SDL_SetError("SDL_LockTexture(): texture must be streaming");
  2219         return -1;
  2220     }
  2221     renderer = texture->renderer;
  2222     if (!renderer->LockTexture) {
  2223         SDL_Unsupported();
  2224         return -1;
  2225     }
  2226     if (!rect) {
  2227         full_rect.x = 0;
  2228         full_rect.y = 0;
  2229         full_rect.w = texture->w;
  2230         full_rect.h = texture->h;
  2231         rect = &full_rect;
  2232     }
  2233     return renderer->LockTexture(renderer, texture, rect, markDirty, pixels,
  2234                                  pitch);
  2235 }
  2236 
  2237 void
  2238 SDL_UnlockTexture(SDL_Texture * texture)
  2239 {
  2240     SDL_Renderer *renderer;
  2241 
  2242     CHECK_TEXTURE_MAGIC(texture, );
  2243 
  2244     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  2245         return;
  2246     }
  2247     renderer = texture->renderer;
  2248     if (!renderer->UnlockTexture) {
  2249         return;
  2250     }
  2251     renderer->UnlockTexture(renderer, texture);
  2252 }
  2253 
  2254 void
  2255 SDL_DirtyTexture(SDL_Texture * texture, int numrects,
  2256                  const SDL_Rect * rects)
  2257 {
  2258     SDL_Renderer *renderer;
  2259 
  2260     CHECK_TEXTURE_MAGIC(texture, );
  2261 
  2262     if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  2263         return;
  2264     }
  2265     renderer = texture->renderer;
  2266     if (!renderer->DirtyTexture) {
  2267         return;
  2268     }
  2269     renderer->DirtyTexture(renderer, texture, numrects, rects);
  2270 }
  2271 
  2272 int
  2273 SDL_SetRenderDrawColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  2274 {
  2275     SDL_Renderer *renderer;
  2276 
  2277     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2278     if (!renderer) {
  2279         return -1;
  2280     }
  2281     renderer->r = r;
  2282     renderer->g = g;
  2283     renderer->b = b;
  2284     renderer->a = a;
  2285     if (renderer->SetDrawColor) {
  2286         return renderer->SetDrawColor(renderer);
  2287     } else {
  2288         return 0;
  2289     }
  2290 }
  2291 
  2292 int
  2293 SDL_GetRenderDrawColor(Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
  2294 {
  2295     SDL_Renderer *renderer;
  2296 
  2297     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2298     if (!renderer) {
  2299         return -1;
  2300     }
  2301     if (r) {
  2302         *r = renderer->r;
  2303     }
  2304     if (g) {
  2305         *g = renderer->g;
  2306     }
  2307     if (b) {
  2308         *b = renderer->b;
  2309     }
  2310     if (a) {
  2311         *a = renderer->a;
  2312     }
  2313     return 0;
  2314 }
  2315 
  2316 int
  2317 SDL_SetRenderDrawBlendMode(int blendMode)
  2318 {
  2319     SDL_Renderer *renderer;
  2320 
  2321     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2322     if (!renderer) {
  2323         return -1;
  2324     }
  2325     renderer->blendMode = blendMode;
  2326     if (renderer->SetDrawBlendMode) {
  2327         return renderer->SetDrawBlendMode(renderer);
  2328     } else {
  2329         return 0;
  2330     }
  2331 }
  2332 
  2333 int
  2334 SDL_GetRenderDrawBlendMode(int *blendMode)
  2335 {
  2336     SDL_Renderer *renderer;
  2337 
  2338     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2339     if (!renderer) {
  2340         return -1;
  2341     }
  2342     *blendMode = renderer->blendMode;
  2343     return 0;
  2344 }
  2345 
  2346 int
  2347 SDL_RenderClear()
  2348 {
  2349     SDL_Renderer *renderer;
  2350 
  2351     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2352     if (!renderer) {
  2353         return -1;
  2354     }
  2355     if (!renderer->RenderClear) {
  2356         int blendMode = renderer->blendMode;
  2357         int status;
  2358 
  2359         if (blendMode >= SDL_BLENDMODE_BLEND) {
  2360             SDL_SetRenderDrawBlendMode(SDL_BLENDMODE_NONE);
  2361         }
  2362 
  2363         status = SDL_RenderFillRect(NULL);
  2364 
  2365         if (blendMode >= SDL_BLENDMODE_BLEND) {
  2366             SDL_SetRenderDrawBlendMode(blendMode);
  2367         }
  2368         return status;
  2369     }
  2370     return renderer->RenderClear(renderer);
  2371 }
  2372 
  2373 int
  2374 SDL_RenderDrawPoint(int x, int y)
  2375 {
  2376     SDL_Point point;
  2377 
  2378     point.x = x;
  2379     point.y = y;
  2380     return SDL_RenderDrawPoints(&point, 1);
  2381 }
  2382 
  2383 int
  2384 SDL_RenderDrawPoints(const SDL_Point * points, int count)
  2385 {
  2386     SDL_Renderer *renderer;
  2387 
  2388     if (!points) {
  2389         SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
  2390         return -1;
  2391     }
  2392 
  2393     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2394     if (!renderer) {
  2395         return -1;
  2396     }
  2397     if (!renderer->RenderDrawPoints) {
  2398         SDL_Unsupported();
  2399         return -1;
  2400     }
  2401     if (count < 1) {
  2402         return 0;
  2403     }
  2404     return renderer->RenderDrawPoints(renderer, points, count);
  2405 }
  2406 
  2407 int
  2408 SDL_RenderDrawLine(int x1, int y1, int x2, int y2)
  2409 {
  2410     SDL_Point points[2];
  2411 
  2412     points[0].x = x1;
  2413     points[0].y = y1;
  2414     points[1].x = x2;
  2415     points[1].y = y2;
  2416     return SDL_RenderDrawLines(points, 2);
  2417 }
  2418 
  2419 int
  2420 SDL_RenderDrawLines(const SDL_Point * points, int count)
  2421 {
  2422     SDL_Renderer *renderer;
  2423 
  2424     if (!points) {
  2425         SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
  2426         return -1;
  2427     }
  2428 
  2429     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2430     if (!renderer) {
  2431         return -1;
  2432     }
  2433     if (!renderer->RenderDrawLines) {
  2434         SDL_Unsupported();
  2435         return -1;
  2436     }
  2437     if (count < 2) {
  2438         return 0;
  2439     }
  2440     return renderer->RenderDrawLines(renderer, points, count);
  2441 }
  2442 
  2443 int
  2444 SDL_RenderDrawRect(const SDL_Rect * rect)
  2445 {
  2446     return SDL_RenderDrawRects(&rect, 1);
  2447 }
  2448 
  2449 int
  2450 SDL_RenderDrawRects(const SDL_Rect ** rects, int count)
  2451 {
  2452     SDL_Renderer *renderer;
  2453     int i;
  2454 
  2455     if (!rects) {
  2456         SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
  2457         return -1;
  2458     }
  2459 
  2460     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2461     if (!renderer) {
  2462         return -1;
  2463     }
  2464     if (!renderer->RenderDrawRects) {
  2465         SDL_Unsupported();
  2466         return -1;
  2467     }
  2468     if (count < 1) {
  2469         return 0;
  2470     }
  2471     /* Check for NULL rect, which means fill entire window */
  2472     for (i = 0; i < count; ++i) {
  2473         if (rects[i] == NULL) {
  2474             SDL_Window *window = renderer->window;
  2475             SDL_Rect full_rect;
  2476             const SDL_Rect *rect;
  2477 
  2478             full_rect.x = 0;
  2479             full_rect.y = 0;
  2480             full_rect.w = window->w;
  2481             full_rect.h = window->h;
  2482             rect = &full_rect;
  2483             return renderer->RenderDrawRects(renderer, &rect, 1);
  2484         }
  2485     }
  2486     return renderer->RenderDrawRects(renderer, rects, count);
  2487 }
  2488 
  2489 int
  2490 SDL_RenderFillRect(const SDL_Rect * rect)
  2491 {
  2492     return SDL_RenderFillRects(&rect, 1);
  2493 }
  2494 
  2495 int
  2496 SDL_RenderFillRects(const SDL_Rect ** rects, int count)
  2497 {
  2498     SDL_Renderer *renderer;
  2499     int i;
  2500 
  2501     if (!rects) {
  2502         SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
  2503         return -1;
  2504     }
  2505 
  2506     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2507     if (!renderer) {
  2508         return -1;
  2509     }
  2510     if (!renderer->RenderFillRects) {
  2511         SDL_Unsupported();
  2512         return -1;
  2513     }
  2514     if (count < 1) {
  2515         return 0;
  2516     }
  2517     /* Check for NULL rect, which means fill entire window */
  2518     for (i = 0; i < count; ++i) {
  2519         if (rects[i] == NULL) {
  2520             SDL_Window *window = renderer->window;
  2521             SDL_Rect full_rect;
  2522             const SDL_Rect *rect;
  2523 
  2524             full_rect.x = 0;
  2525             full_rect.y = 0;
  2526             full_rect.w = window->w;
  2527             full_rect.h = window->h;
  2528             rect = &full_rect;
  2529             return renderer->RenderFillRects(renderer, &rect, 1);
  2530         }
  2531     }
  2532     return renderer->RenderFillRects(renderer, rects, count);
  2533 }
  2534 
  2535 int
  2536 SDL_RenderCopy(SDL_Texture * texture, const SDL_Rect * srcrect,
  2537                const SDL_Rect * dstrect)
  2538 {
  2539     SDL_Renderer *renderer;
  2540     SDL_Window *window;
  2541     SDL_Rect real_srcrect;
  2542     SDL_Rect real_dstrect;
  2543 
  2544     CHECK_TEXTURE_MAGIC(texture, -1);
  2545 
  2546     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2547     if (!renderer) {
  2548         return -1;
  2549     }
  2550     if (texture->renderer != renderer) {
  2551         SDL_SetError("Texture was not created with this renderer");
  2552         return -1;
  2553     }
  2554     if (!renderer->RenderCopy) {
  2555         SDL_Unsupported();
  2556         return -1;
  2557     }
  2558     window = renderer->window;
  2559 
  2560     real_srcrect.x = 0;
  2561     real_srcrect.y = 0;
  2562     real_srcrect.w = texture->w;
  2563     real_srcrect.h = texture->h;
  2564     if (srcrect) {
  2565         if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
  2566             return 0;
  2567         }
  2568     }
  2569 
  2570     real_dstrect.x = 0;
  2571     real_dstrect.y = 0;
  2572     real_dstrect.w = window->w;
  2573     real_dstrect.h = window->h;
  2574     if (dstrect) {
  2575         if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) {
  2576             return 0;
  2577         }
  2578         /* Clip srcrect by the same amount as dstrect was clipped */
  2579         if (dstrect->w != real_dstrect.w) {
  2580             int deltax = (real_dstrect.x - dstrect->x);
  2581             int deltaw = (real_dstrect.w - dstrect->w);
  2582             real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w;
  2583             real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w;
  2584         }
  2585         if (dstrect->h != real_dstrect.h) {
  2586             int deltay = (real_dstrect.y - dstrect->y);
  2587             int deltah = (real_dstrect.h - dstrect->h);
  2588             real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h;
  2589             real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h;
  2590         }
  2591     }
  2592 
  2593     return renderer->RenderCopy(renderer, texture, &real_srcrect,
  2594                                 &real_dstrect);
  2595 }
  2596 
  2597 int
  2598 SDL_RenderReadPixels(const SDL_Rect * rect, Uint32 format,
  2599                      void * pixels, int pitch)
  2600 {
  2601     SDL_Renderer *renderer;
  2602     SDL_Window *window;
  2603     SDL_Rect real_rect;
  2604 
  2605     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2606     if (!renderer) {
  2607         return -1;
  2608     }
  2609     if (!renderer->RenderReadPixels) {
  2610         SDL_Unsupported();
  2611         return -1;
  2612     }
  2613     window = renderer->window;
  2614 
  2615     if (!format) {
  2616         format = window->display->current_mode.format;
  2617     }
  2618 
  2619     real_rect.x = 0;
  2620     real_rect.y = 0;
  2621     real_rect.w = window->w;
  2622     real_rect.h = window->h;
  2623     if (rect) {
  2624         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  2625             return 0;
  2626         }
  2627         if (real_rect.y > rect->y) {
  2628             pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  2629         }
  2630         if (real_rect.x > rect->x) {
  2631             Uint32 format = SDL_CurrentDisplay->current_mode.format;
  2632             int bpp = SDL_BYTESPERPIXEL(format);
  2633             pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  2634         }
  2635     }
  2636 
  2637     return renderer->RenderReadPixels(renderer, &real_rect,
  2638                                       format, pixels, pitch);
  2639 }
  2640 
  2641 int
  2642 SDL_RenderWritePixels(const SDL_Rect * rect, Uint32 format,
  2643                       const void * pixels, int pitch)
  2644 {
  2645     SDL_Renderer *renderer;
  2646     SDL_Window *window;
  2647     SDL_Rect real_rect;
  2648 
  2649     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2650     if (!renderer) {
  2651         return -1;
  2652     }
  2653     if (!renderer->RenderWritePixels) {
  2654         SDL_Unsupported();
  2655         return -1;
  2656     }
  2657     window = renderer->window;
  2658 
  2659     if (!format) {
  2660         format = window->display->current_mode.format;
  2661     }
  2662 
  2663     real_rect.x = 0;
  2664     real_rect.y = 0;
  2665     real_rect.w = window->w;
  2666     real_rect.h = window->h;
  2667     if (rect) {
  2668         if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
  2669             return 0;
  2670         }
  2671         if (real_rect.y > rect->y) {
  2672             pixels = (const Uint8 *)pixels + pitch * (real_rect.y - rect->y);
  2673         }
  2674         if (real_rect.x > rect->x) {
  2675             Uint32 format = SDL_CurrentDisplay->current_mode.format;
  2676             int bpp = SDL_BYTESPERPIXEL(format);
  2677             pixels = (const Uint8 *)pixels + bpp * (real_rect.x - rect->x);
  2678         }
  2679     }
  2680 
  2681     return renderer->RenderWritePixels(renderer, &real_rect,
  2682                                        format, pixels, pitch);
  2683 }
  2684 
  2685 void
  2686 SDL_RenderPresent(void)
  2687 {
  2688     SDL_Renderer *renderer;
  2689 
  2690     renderer = SDL_GetCurrentRenderer(SDL_TRUE);
  2691     if (!renderer || !renderer->RenderPresent) {
  2692         return;
  2693     }
  2694     renderer->RenderPresent(renderer);
  2695 }
  2696 
  2697 void
  2698 SDL_DestroyTexture(SDL_Texture * texture)
  2699 {
  2700     SDL_Renderer *renderer;
  2701 
  2702     CHECK_TEXTURE_MAGIC(texture, );
  2703     texture->magic = NULL;
  2704 
  2705     renderer = texture->renderer;
  2706     if (texture->next) {
  2707         texture->next->prev = texture->prev;
  2708     }
  2709     if (texture->prev) {
  2710         texture->prev->next = texture->next;
  2711     } else {
  2712         renderer->textures = texture->next;
  2713     }
  2714 
  2715     renderer->DestroyTexture(renderer, texture);
  2716     SDL_free(texture);
  2717 }
  2718 
  2719 void
  2720 SDL_DestroyRenderer(SDL_Window * window)
  2721 {
  2722     SDL_Renderer *renderer;
  2723 
  2724     CHECK_WINDOW_MAGIC(window, );
  2725 
  2726     renderer = window->renderer;
  2727     if (!renderer) {
  2728         return;
  2729     }
  2730 
  2731     /* Free existing textures for this renderer */
  2732     while (renderer->textures) {
  2733         SDL_DestroyTexture(renderer->textures);
  2734     }
  2735 
  2736     /* Free the renderer instance */
  2737     renderer->DestroyRenderer(renderer);
  2738 
  2739     /* Clear references */
  2740     window->renderer = NULL;
  2741     if (SDL_CurrentDisplay->current_renderer == renderer) {
  2742         SDL_CurrentDisplay->current_renderer = NULL;
  2743     }
  2744 }
  2745 
  2746 SDL_bool
  2747 SDL_IsScreenSaverEnabled()
  2748 {
  2749     if (!_this) {
  2750         return SDL_TRUE;
  2751     }
  2752     return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE;
  2753 }
  2754 
  2755 void
  2756 SDL_EnableScreenSaver()
  2757 {
  2758     if (!_this) {
  2759         return;
  2760     }
  2761     if (!_this->suspend_screensaver) {
  2762         return;
  2763     }
  2764     _this->suspend_screensaver = SDL_FALSE;
  2765     if (_this->SuspendScreenSaver) {
  2766         _this->SuspendScreenSaver(_this);
  2767     }
  2768 }
  2769 
  2770 void
  2771 SDL_DisableScreenSaver()
  2772 {
  2773     if (!_this) {
  2774         return;
  2775     }
  2776     if (_this->suspend_screensaver) {
  2777         return;
  2778     }
  2779     _this->suspend_screensaver = SDL_TRUE;
  2780     if (_this->SuspendScreenSaver) {
  2781         _this->SuspendScreenSaver(_this);
  2782     }
  2783 }
  2784 
  2785 void
  2786 SDL_VideoQuit(void)
  2787 {
  2788     int i, j;
  2789 
  2790     if (!_this) {
  2791         return;
  2792     }
  2793     /* Halt event processing before doing anything else */
  2794     SDL_StopEventLoop();
  2795     SDL_EnableScreenSaver();
  2796 
  2797     /* Clean up the system video */
  2798     for (i = _this->num_displays; i--;) {
  2799         SDL_VideoDisplay *display = &_this->displays[i];
  2800         while (display->windows) {
  2801             SDL_DestroyWindow(display->windows);
  2802         }
  2803         if (display->render_drivers) {
  2804             SDL_free(display->render_drivers);
  2805             display->render_drivers = NULL;
  2806         }
  2807         display->num_render_drivers = 0;
  2808     }
  2809     _this->VideoQuit(_this);
  2810 
  2811     for (i = _this->num_displays; i--;) {
  2812         SDL_VideoDisplay *display = &_this->displays[i];
  2813         for (j = display->num_display_modes; j--;) {
  2814             if (display->display_modes[j].driverdata) {
  2815                 SDL_free(display->display_modes[j].driverdata);
  2816                 display->display_modes[j].driverdata = NULL;
  2817             }
  2818         }
  2819         if (display->display_modes) {
  2820             SDL_free(display->display_modes);
  2821             display->display_modes = NULL;
  2822         }
  2823         if (display->desktop_mode.driverdata) {
  2824             SDL_free(display->desktop_mode.driverdata);
  2825             display->desktop_mode.driverdata = NULL;
  2826         }
  2827         if (display->palette) {
  2828             SDL_FreePalette(display->palette);
  2829             display->palette = NULL;
  2830         }
  2831         if (display->gamma) {
  2832             SDL_free(display->gamma);
  2833             display->gamma = NULL;
  2834         }
  2835         if (display->driverdata) {
  2836             SDL_free(display->driverdata);
  2837             display->driverdata = NULL;
  2838         }
  2839     }
  2840     if (_this->displays) {
  2841         SDL_free(_this->displays);
  2842         _this->displays = NULL;
  2843     }
  2844     _this->free(_this);
  2845     _this = NULL;
  2846 }
  2847 
  2848 int
  2849 SDL_GL_LoadLibrary(const char *path)
  2850 {
  2851     int retval;
  2852 
  2853     if (!_this) {
  2854         SDL_UninitializedVideo();
  2855         return -1;
  2856     }
  2857     if (_this->gl_config.driver_loaded) {
  2858         if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) {
  2859             SDL_SetError("OpenGL library already loaded");
  2860             return -1;
  2861         }
  2862         retval = 0;
  2863     } else {
  2864         if (!_this->GL_LoadLibrary) {
  2865             SDL_SetError("No dynamic GL support in video driver");
  2866             return -1;
  2867         }
  2868         retval = _this->GL_LoadLibrary(_this, path);
  2869     }
  2870     if (retval == 0) {
  2871         ++_this->gl_config.driver_loaded;
  2872     }
  2873     return (retval);
  2874 }
  2875 
  2876 void *
  2877 SDL_GL_GetProcAddress(const char *proc)
  2878 {
  2879     void *func;
  2880 
  2881     if (!_this) {
  2882         SDL_UninitializedVideo();
  2883         return NULL;
  2884     }
  2885     func = NULL;
  2886     if (_this->GL_GetProcAddress) {
  2887         if (_this->gl_config.driver_loaded) {
  2888             func = _this->GL_GetProcAddress(_this, proc);
  2889         } else {
  2890             SDL_SetError("No GL driver has been loaded");
  2891         }
  2892     } else {
  2893         SDL_SetError("No dynamic GL support in video driver");
  2894     }
  2895     return func;
  2896 }
  2897 
  2898 void
  2899 SDL_GL_UnloadLibrary(void)
  2900 {
  2901     if (!_this) {
  2902         SDL_UninitializedVideo();
  2903         return;
  2904     }
  2905     if (_this->gl_config.driver_loaded > 0) {
  2906         if (--_this->gl_config.driver_loaded > 0) {
  2907             return;
  2908         }
  2909         if (_this->GL_UnloadLibrary) {
  2910             _this->GL_UnloadLibrary(_this);
  2911         }
  2912     }
  2913 }
  2914 
  2915 SDL_bool
  2916 SDL_GL_ExtensionSupported(const char *extension)
  2917 {
  2918 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES
  2919     const GLubyte *(APIENTRY * glGetStringFunc) (GLenum);
  2920     const char *extensions;
  2921     const char *start;
  2922     const char *where, *terminator;
  2923 
  2924     /* Extension names should not have spaces. */
  2925     where = SDL_strchr(extension, ' ');
  2926     if (where || *extension == '\0') {
  2927         return SDL_FALSE;
  2928     }
  2929     /* See if there's an environment variable override */
  2930     start = SDL_getenv(extension);
  2931     if (start && *start == '0') {
  2932         return SDL_FALSE;
  2933     }
  2934     /* Lookup the available extensions */
  2935     glGetStringFunc = SDL_GL_GetProcAddress("glGetString");
  2936     if (glGetStringFunc) {
  2937         extensions = (const char *) glGetStringFunc(GL_EXTENSIONS);
  2938     } else {
  2939         extensions = NULL;
  2940     }
  2941     if (!extensions) {
  2942         return SDL_FALSE;
  2943     }
  2944     /*
  2945      * It takes a bit of care to be fool-proof about parsing the OpenGL
  2946      * extensions string. Don't be fooled by sub-strings, etc.
  2947      */
  2948 
  2949     start = extensions;
  2950 
  2951     for (;;) {
  2952         where = SDL_strstr(start, extension);
  2953         if (!where)
  2954             break;
  2955 
  2956         terminator = where + SDL_strlen(extension);
  2957         if (where == start || *(where - 1) == ' ')
  2958             if (*terminator == ' ' || *terminator == '\0')
  2959                 return SDL_TRUE;
  2960 
  2961         start = terminator;
  2962     }
  2963     return SDL_FALSE;
  2964 #else
  2965     return SDL_FALSE;
  2966 #endif
  2967 }
  2968 
  2969 int
  2970 SDL_GL_SetAttribute(SDL_GLattr attr, int value)
  2971 {
  2972 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES
  2973     int retval;
  2974 
  2975     if (!_this) {
  2976         SDL_UninitializedVideo();
  2977         return -1;
  2978     }
  2979     retval = 0;
  2980     switch (attr) {
  2981     case SDL_GL_RED_SIZE:
  2982         _this->gl_config.red_size = value;
  2983         break;
  2984     case SDL_GL_GREEN_SIZE:
  2985         _this->gl_config.green_size = value;
  2986         break;
  2987     case SDL_GL_BLUE_SIZE:
  2988         _this->gl_config.blue_size = value;
  2989         break;
  2990     case SDL_GL_ALPHA_SIZE:
  2991         _this->gl_config.alpha_size = value;
  2992         break;
  2993     case SDL_GL_DOUBLEBUFFER:
  2994         _this->gl_config.double_buffer = value;
  2995         break;
  2996     case SDL_GL_BUFFER_SIZE:
  2997         _this->gl_config.buffer_size = value;
  2998         break;
  2999     case SDL_GL_DEPTH_SIZE:
  3000         _this->gl_config.depth_size = value;
  3001         break;
  3002     case SDL_GL_STENCIL_SIZE:
  3003         _this->gl_config.stencil_size = value;
  3004         break;
  3005     case SDL_GL_ACCUM_RED_SIZE:
  3006         _this->gl_config.accum_red_size = value;
  3007         break;
  3008     case SDL_GL_ACCUM_GREEN_SIZE:
  3009         _this->gl_config.accum_green_size = value;
  3010         break;
  3011     case SDL_GL_ACCUM_BLUE_SIZE:
  3012         _this->gl_config.accum_blue_size = value;
  3013         break;
  3014     case SDL_GL_ACCUM_ALPHA_SIZE:
  3015         _this->gl_config.accum_alpha_size = value;
  3016         break;
  3017     case SDL_GL_STEREO:
  3018         _this->gl_config.stereo = value;
  3019         break;
  3020     case SDL_GL_MULTISAMPLEBUFFERS:
  3021         _this->gl_config.multisamplebuffers = value;
  3022         break;
  3023     case SDL_GL_MULTISAMPLESAMPLES:
  3024         _this->gl_config.multisamplesamples = value;
  3025         break;
  3026     case SDL_GL_ACCELERATED_VISUAL:
  3027         _this->gl_config.accelerated = value;
  3028         break;
  3029     case SDL_GL_RETAINED_BACKING:
  3030         _this->gl_config.retained_backing = value;
  3031         break;
  3032     case SDL_GL_CONTEXT_MAJOR_VERSION:
  3033         _this->gl_config.major_version = value;
  3034         break;
  3035     case SDL_GL_CONTEXT_MINOR_VERSION:
  3036         _this->gl_config.minor_version = value;
  3037         break;
  3038     default:
  3039         SDL_SetError("Unknown OpenGL attribute");
  3040         retval = -1;
  3041         break;
  3042     }
  3043     return retval;
  3044 #else
  3045     SDL_Unsupported();
  3046     return -1;
  3047 #endif /* SDL_VIDEO_OPENGL */
  3048 }
  3049 
  3050 int
  3051 SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
  3052 {
  3053 #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES
  3054     void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  3055     GLenum(APIENTRY * glGetErrorFunc) (void);
  3056     GLenum attrib = 0;
  3057     GLenum error = 0;
  3058 
  3059     glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  3060     if (!glGetIntegervFunc) {
  3061         return -1;
  3062     }
  3063 
  3064     glGetErrorFunc = SDL_GL_GetProcAddress("glGetError");
  3065     if (!glGetErrorFunc) {
  3066         return -1;
  3067     }
  3068 
  3069     /* Clear value in any case */
  3070     *value = 0;
  3071 
  3072     switch (attr) {
  3073     case SDL_GL_RETAINED_BACKING:
  3074         *value = _this->gl_config.retained_backing;
  3075         return 0;
  3076     case SDL_GL_RED_SIZE:
  3077         attrib = GL_RED_BITS;
  3078         break;
  3079     case SDL_GL_BLUE_SIZE:
  3080         attrib = GL_BLUE_BITS;
  3081         break;
  3082     case SDL_GL_GREEN_SIZE:
  3083         attrib = GL_GREEN_BITS;
  3084         break;
  3085     case SDL_GL_ALPHA_SIZE:
  3086         attrib = GL_ALPHA_BITS;
  3087         break;
  3088     case SDL_GL_DOUBLEBUFFER:
  3089 #ifndef SDL_VIDEO_OPENGL_ES
  3090         attrib = GL_DOUBLEBUFFER;
  3091         break;
  3092 #else
  3093         /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER      */
  3094         /* parameter which switches double buffer to single buffer. OpenGL ES */
  3095         /* SDL driver must set proper value after initialization              */
  3096         *value = _this->gl_config.double_buffer;
  3097         return 0;
  3098 #endif
  3099     case SDL_GL_DEPTH_SIZE:
  3100         attrib = GL_DEPTH_BITS;
  3101         break;
  3102     case SDL_GL_STENCIL_SIZE:
  3103         attrib = GL_STENCIL_BITS;
  3104         break;
  3105 #ifndef SDL_VIDEO_OPENGL_ES
  3106     case SDL_GL_ACCUM_RED_SIZE:
  3107         attrib = GL_ACCUM_RED_BITS;
  3108         break;
  3109     case SDL_GL_ACCUM_GREEN_SIZE:
  3110         attrib = GL_ACCUM_GREEN_BITS;
  3111         break;
  3112     case SDL_GL_ACCUM_BLUE_SIZE:
  3113         attrib = GL_ACCUM_BLUE_BITS;
  3114         break;
  3115     case SDL_GL_ACCUM_ALPHA_SIZE:
  3116         attrib = GL_ACCUM_ALPHA_BITS;
  3117         break;
  3118     case SDL_GL_STEREO:
  3119         attrib = GL_STEREO;
  3120         break;
  3121 #else
  3122     case SDL_GL_ACCUM_RED_SIZE:
  3123     case SDL_GL_ACCUM_GREEN_SIZE:
  3124     case SDL_GL_ACCUM_BLUE_SIZE:
  3125     case SDL_GL_ACCUM_ALPHA_SIZE:
  3126     case SDL_GL_STEREO:
  3127         /* none of these are supported in OpenGL ES */
  3128         *value = 0;
  3129         return 0;
  3130 #endif
  3131     case SDL_GL_MULTISAMPLEBUFFERS:
  3132 #ifndef SDL_VIDEO_OPENGL_ES
  3133         attrib = GL_SAMPLE_BUFFERS_ARB;
  3134 #else
  3135         attrib = GL_SAMPLE_BUFFERS;
  3136 #endif
  3137         break;
  3138     case SDL_GL_MULTISAMPLESAMPLES:
  3139 #ifndef SDL_VIDEO_OPENGL_ES
  3140         attrib = GL_SAMPLES_ARB;
  3141 #else
  3142         attrib = GL_SAMPLES;
  3143 #endif
  3144         break;
  3145     case SDL_GL_BUFFER_SIZE:
  3146         {
  3147             GLint bits = 0;
  3148             GLint component;
  3149 
  3150             /*
  3151              * there doesn't seem to be a single flag in OpenGL
  3152              * for this!
  3153              */
  3154             glGetIntegervFunc(GL_RED_BITS, &component);
  3155             bits += component;
  3156             glGetIntegervFunc(GL_GREEN_BITS, &component);
  3157             bits += component;
  3158             glGetIntegervFunc(GL_BLUE_BITS, &component);
  3159             bits += component;
  3160             glGetIntegervFunc(GL_ALPHA_BITS, &component);
  3161             bits += component;
  3162 
  3163             *value = bits;
  3164             return 0;
  3165         }
  3166     case SDL_GL_ACCELERATED_VISUAL:
  3167         {
  3168             /* FIXME: How do we get this information? */
  3169             *value = (_this->gl_config.accelerated != 0);
  3170             return 0;
  3171         }
  3172     default:
  3173         SDL_SetError("Unknown OpenGL attribute");
  3174         return -1;
  3175     }
  3176 
  3177     glGetIntegervFunc(attrib, (GLint *) value);
  3178     error = glGetErrorFunc();
  3179     if (error != GL_NO_ERROR) {
  3180         switch (error) {
  3181         case GL_INVALID_ENUM:
  3182             {
  3183                 SDL_SetError("OpenGL error: GL_INVALID_ENUM");
  3184             }
  3185             break;
  3186         case GL_INVALID_VALUE:
  3187             {
  3188                 SDL_SetError("OpenGL error: GL_INVALID_VALUE");
  3189             }
  3190             break;
  3191         default:
  3192             {
  3193                 SDL_SetError("OpenGL error: %08X", error);
  3194             }
  3195             break;
  3196         }
  3197         return -1;
  3198     }
  3199     return 0;
  3200 #else
  3201     SDL_Unsupported();
  3202     return -1;
  3203 #endif /* SDL_VIDEO_OPENGL */
  3204 }
  3205 
  3206 SDL_GLContext
  3207 SDL_GL_CreateContext(SDL_Window * window)
  3208 {
  3209     CHECK_WINDOW_MAGIC(window, NULL);
  3210 
  3211     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3212         SDL_SetError("The specified window isn't an OpenGL window");
  3213         return NULL;
  3214     }
  3215     return _this->GL_CreateContext(_this, window);
  3216 }
  3217 
  3218 int
  3219 SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext context)
  3220 {
  3221     CHECK_WINDOW_MAGIC(window, -1);
  3222 
  3223     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3224         SDL_SetError("The specified window isn't an OpenGL window");
  3225         return -1;
  3226     }
  3227     if (!context) {
  3228         window = NULL;
  3229     }
  3230     return _this->GL_MakeCurrent(_this, window, context);
  3231 }
  3232 
  3233 int
  3234 SDL_GL_SetSwapInterval(int interval)
  3235 {
  3236     if (!_this) {
  3237         SDL_UninitializedVideo();
  3238         return -1;
  3239     }
  3240     if (_this->GL_SetSwapInterval) {
  3241         return _this->GL_SetSwapInterval(_this, interval);
  3242     } else {
  3243         SDL_SetError("Setting the swap interval is not supported");
  3244         return -1;
  3245     }
  3246 }
  3247 
  3248 int
  3249 SDL_GL_GetSwapInterval(void)
  3250 {
  3251     if (!_this) {
  3252         SDL_UninitializedVideo();
  3253         return -1;
  3254     }
  3255     if (_this->GL_GetSwapInterval) {
  3256         return _this->GL_GetSwapInterval(_this);
  3257     } else {
  3258         SDL_SetError("Getting the swap interval is not supported");
  3259         return -1;
  3260     }
  3261 }
  3262 
  3263 void
  3264 SDL_GL_SwapWindow(SDL_Window * window)
  3265 {
  3266     CHECK_WINDOW_MAGIC(window, );
  3267 
  3268     if (!(window->flags & SDL_WINDOW_OPENGL)) {
  3269         SDL_SetError("The specified window isn't an OpenGL window");
  3270         return;
  3271     }
  3272     _this->GL_SwapWindow(_this, window);
  3273 }
  3274 
  3275 void
  3276 SDL_GL_DeleteContext(SDL_GLContext context)
  3277 {
  3278     if (!_this || !context) {
  3279         return;
  3280     }
  3281     _this->GL_MakeCurrent(_this, NULL, NULL);
  3282     _this->GL_DeleteContext(_this, context);
  3283 }
  3284 
  3285 #if 0                           // FIXME
  3286 /*
  3287  * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags
  3288  * & 2 for alpha channel.
  3289  */
  3290 static void
  3291 CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags)
  3292 {
  3293     int x, y;
  3294     Uint32 colorkey;
  3295 #define SET_MASKBIT(icon, x, y, mask) \
  3296 	mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8)))
  3297 
  3298     colorkey = icon->format->colorkey;
  3299     switch (icon->format->BytesPerPixel) {
  3300     case 1:
  3301         {
  3302             Uint8 *pixels;
  3303             for (y = 0; y < icon->h; ++y) {
  3304                 pixels = (Uint8 *) icon->pixels + y * icon->pitch;
  3305                 for (x = 0; x < icon->w; ++x) {
  3306                     if (*pixels++ == colorkey) {
  3307                         SET_MASKBIT(icon, x, y, mask);
  3308                     }
  3309                 }
  3310             }
  3311         }
  3312         break;
  3313 
  3314     case 2:
  3315         {
  3316             Uint16 *pixels;
  3317             for (y = 0; y < icon->h; ++y) {
  3318                 pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
  3319                 for (x = 0; x < icon->w; ++x) {
  3320                     if ((flags & 1) && *pixels == colorkey) {
  3321                         SET_MASKBIT(icon, x, y, mask);
  3322                     } else if ((flags & 2)
  3323                                && (*pixels & icon->format->Amask) == 0) {
  3324                         SET_MASKBIT(icon, x, y, mask);
  3325                     }
  3326                     pixels++;
  3327                 }
  3328             }
  3329         }
  3330         break;
  3331 
  3332     case 4:
  3333         {
  3334             Uint32 *pixels;
  3335             for (y = 0; y < icon->h; ++y) {
  3336                 pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
  3337                 for (x = 0; x < icon->w; ++x) {
  3338                     if ((flags & 1) && *pixels == colorkey) {
  3339                         SET_MASKBIT(icon, x, y, mask);
  3340                     } else if ((flags & 2)
  3341                                && (*pixels & icon->format->Amask) == 0) {
  3342                         SET_MASKBIT(icon, x, y, mask);
  3343                     }
  3344                     pixels++;
  3345                 }
  3346             }
  3347         }
  3348         break;
  3349     }
  3350 }
  3351 
  3352 /*
  3353  * Sets the window manager icon for the display window.
  3354  */
  3355 void
  3356 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  3357 {
  3358     if (icon && _this->SetIcon) {
  3359         /* Generate a mask if necessary, and create the icon! */
  3360         if (mask == NULL) {
  3361             int mask_len = icon->h * (icon->w + 7) / 8;
  3362             int flags = 0;
  3363             mask = (Uint8 *) SDL_malloc(mask_len);
  3364             if (mask == NULL) {
  3365                 return;
  3366             }
  3367             SDL_memset(mask, ~0, mask_len);
  3368             if (icon->flags & SDL_SRCCOLORKEY)
  3369                 flags |= 1;
  3370             if (icon->flags & SDL_SRCALPHA)
  3371                 flags |= 2;
  3372             if (flags) {
  3373                 CreateMaskFromColorKeyOrAlpha(icon, mask, flags);
  3374             }
  3375             _this->SetIcon(_this, icon, mask);
  3376             SDL_free(mask);
  3377         } else {
  3378             _this->SetIcon(_this, icon, mask);
  3379         }
  3380     }
  3381 }
  3382 #endif
  3383 
  3384 SDL_bool
  3385 SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info)
  3386 {
  3387     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
  3388 
  3389     if (!_this->GetWindowWMInfo) {
  3390         return SDL_FALSE;
  3391     }
  3392     return (_this->GetWindowWMInfo(_this, window, info));
  3393 }
  3394 
  3395 void
  3396 SDL_StartTextInput(void)
  3397 {
  3398     if (_this && _this->StartTextInput) {
  3399         _this->StartTextInput(_this);
  3400     }
  3401     SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
  3402     SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE);
  3403 }
  3404 
  3405 void
  3406 SDL_StopTextInput(void)
  3407 {
  3408     if (_this && _this->StopTextInput) {
  3409         _this->StopTextInput(_this);
  3410     }
  3411     SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
  3412     SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
  3413 }
  3414 
  3415 void
  3416 SDL_SetTextInputRect(SDL_Rect *rect)
  3417 {
  3418     if (_this && _this->SetTextInputRect) {
  3419         _this->SetTextInputRect(_this, rect);
  3420     }
  3421 }
  3422 
  3423 /* vi: set ts=4 sw=4 expandtab: */