src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 03 Mar 2009 04:21:51 +0000
changeset 3083 0bc41e0361d3
parent 3058 17c5930f498e
child 3091 32efcc94b3da
permissions -rw-r--r--
Date: Mon, 2 Mar 2009 16:27:42 +0200
From: "Mike Gorchak"
Subject: About QNX support in SDL 1.3

Right now I'm working on QNX SDL 1.3 drivers implementation and looks like a
lot of code must be completely reworked. But I'm ready for it :) Also I want
to add QNX Graphics Framework SDL driver, which is fullscreen graphics
framework, with support of hardware accelerated OpenGL ES implementations.
This Graphics Framework (called GF in QNX) could also use QNX Photon (window
manager GUI) as window manager.

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