src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 24 Jan 2010 19:47:17 +0000
changeset 3694 b0a707f589a6
parent 3693 d3f330fc2009
child 3695 f6a8be3fefa0
permissions -rw-r--r--
Fixed bug #916

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