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