src/video/SDL_video.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 20 Jan 2011 18:04:05 -0800
changeset 5062 e8916fe9cfc8
parent 5048 187d7d446306
child 5103 797b37c0c046
permissions -rw-r--r--
Fixed bug #925

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