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