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