src/SDL_compat.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Dec 2009 08:11:06 +0000
changeset 3565 f43c8f688f77
parent 3518 abefdc334970
child 3581 15eea7a1fa97
permissions -rw-r--r--
Fixed bug #906

Added better error reporting for OpenGL context creation failing.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* This file contains functions for backwards compatibility with SDL 1.2 */
    25 
    26 #include "SDL.h"
    27 #include "SDL_syswm.h"
    28 
    29 #include "video/SDL_sysvideo.h"
    30 #include "video/SDL_pixels_c.h"
    31 #include "video/SDL_yuv_sw_c.h"
    32 
    33 static SDL_WindowID SDL_VideoWindow = 0;
    34 static SDL_RendererInfo SDL_VideoRendererInfo;
    35 static SDL_TextureID SDL_VideoTexture = 0;
    36 static SDL_Surface *SDL_VideoSurface = NULL;
    37 static SDL_Surface *SDL_ShadowSurface = NULL;
    38 static SDL_Surface *SDL_PublicSurface = NULL;
    39 static SDL_GLContext *SDL_VideoContext = NULL;
    40 static Uint32 SDL_VideoFlags = 0;
    41 static char *wm_title = NULL;
    42 static SDL_Surface *SDL_VideoIcon;
    43 static int SDL_enabled_UNICODE = 0;
    44 
    45 char *
    46 SDL_AudioDriverName(char *namebuf, int maxlen)
    47 {
    48     const char *name = SDL_GetCurrentAudioDriver();
    49     if (name) {
    50         SDL_strlcpy(namebuf, name, maxlen);
    51         return namebuf;
    52     }
    53     return NULL;
    54 }
    55 
    56 char *
    57 SDL_VideoDriverName(char *namebuf, int maxlen)
    58 {
    59     const char *name = SDL_GetCurrentVideoDriver();
    60     if (name) {
    61         SDL_strlcpy(namebuf, name, maxlen);
    62         return namebuf;
    63     }
    64     return NULL;
    65 }
    66 
    67 static void
    68 SelectVideoDisplay()
    69 {
    70     const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY");
    71     if ( !variable ) {
    72         variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD");
    73     }
    74     if ( variable ) {
    75         SDL_SelectVideoDisplay(SDL_atoi(variable));
    76     }
    77 }
    78 
    79 const SDL_VideoInfo *
    80 SDL_GetVideoInfo(void)
    81 {
    82     static SDL_VideoInfo info;
    83     SDL_DisplayMode mode;
    84 
    85     SelectVideoDisplay();
    86 
    87     /* Memory leak, compatibility code, who cares? */
    88     if (!info.vfmt && SDL_GetDesktopDisplayMode(&mode) == 0) {
    89         int bpp;
    90         Uint32 Rmask, Gmask, Bmask, Amask;
    91 
    92         SDL_PixelFormatEnumToMasks(mode.format, &bpp, &Rmask, &Gmask, &Bmask,
    93                                    &Amask);
    94         info.vfmt = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
    95         info.current_w = mode.w;
    96         info.current_h = mode.h;
    97     }
    98     return &info;
    99 }
   100 
   101 int
   102 SDL_VideoModeOK(int width, int height, int bpp, Uint32 flags)
   103 {
   104     int i, actual_bpp = 0;
   105 
   106     if (!SDL_GetVideoDevice()) {
   107         return 0;
   108     }
   109 
   110     SelectVideoDisplay();
   111 
   112     if (!(flags & SDL_FULLSCREEN)) {
   113         SDL_DisplayMode mode;
   114         SDL_GetDesktopDisplayMode(&mode);
   115         return SDL_BITSPERPIXEL(mode.format);
   116     }
   117 
   118     for (i = 0; i < SDL_GetNumDisplayModes(); ++i) {
   119         SDL_DisplayMode mode;
   120         SDL_GetDisplayMode(i, &mode);
   121         if (!mode.w || !mode.h || (width == mode.w && height == mode.h)) {
   122             if (!mode.format) {
   123                 return bpp;
   124             }
   125             if (SDL_BITSPERPIXEL(mode.format) >= (Uint32) bpp) {
   126                 actual_bpp = SDL_BITSPERPIXEL(mode.format);
   127             }
   128         }
   129     }
   130     return actual_bpp;
   131 }
   132 
   133 SDL_Rect **
   134 SDL_ListModes(const SDL_PixelFormat * format, Uint32 flags)
   135 {
   136     int i, nmodes;
   137     SDL_Rect **modes;
   138 
   139     if (!SDL_GetVideoDevice()) {
   140         return NULL;
   141     }
   142 
   143     SelectVideoDisplay();
   144 
   145     if (!(flags & SDL_FULLSCREEN)) {
   146         return (SDL_Rect **) (-1);
   147     }
   148 
   149     if (!format) {
   150         format = SDL_GetVideoInfo()->vfmt;
   151     }
   152 
   153     /* Memory leak, but this is a compatibility function, who cares? */
   154     nmodes = 0;
   155     modes = NULL;
   156     for (i = 0; i < SDL_GetNumDisplayModes(); ++i) {
   157         SDL_DisplayMode mode;
   158         SDL_GetDisplayMode(i, &mode);
   159         if (!mode.w || !mode.h) {
   160             return (SDL_Rect **) (-1);
   161         }
   162         if (SDL_BITSPERPIXEL(mode.format) != format->BitsPerPixel) {
   163             continue;
   164         }
   165         if (nmodes > 0 && modes[nmodes - 1]->w == mode.w
   166             && modes[nmodes - 1]->h == mode.h) {
   167             continue;
   168         }
   169 
   170         modes = SDL_realloc(modes, (nmodes + 2) * sizeof(*modes));
   171         if (!modes) {
   172             return NULL;
   173         }
   174         modes[nmodes] = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect));
   175         if (!modes[nmodes]) {
   176             return NULL;
   177         }
   178         modes[nmodes]->x = 0;
   179         modes[nmodes]->y = 0;
   180         modes[nmodes]->w = mode.w;
   181         modes[nmodes]->h = mode.h;
   182         ++nmodes;
   183     }
   184     if (modes) {
   185         modes[nmodes] = NULL;
   186     }
   187     return modes;
   188 }
   189 
   190 static int
   191 SDL_CompatEventFilter(void *userdata, SDL_Event * event)
   192 {
   193     SDL_Event fake;
   194 
   195     switch (event->type) {
   196     case SDL_WINDOWEVENT:
   197         switch (event->window.event) {
   198         case SDL_WINDOWEVENT_EXPOSED:
   199             if (!SDL_HasEvent(SDL_VIDEOEXPOSEMASK)) {
   200                 fake.type = SDL_VIDEOEXPOSE;
   201                 SDL_PushEvent(&fake);
   202             }
   203             break;
   204         case SDL_WINDOWEVENT_RESIZED:
   205             SDL_PeepEvents(&fake, 1, SDL_GETEVENT, SDL_VIDEORESIZEMASK);
   206             fake.type = SDL_VIDEORESIZE;
   207             fake.resize.w = event->window.data1;
   208             fake.resize.h = event->window.data2;
   209             SDL_PushEvent(&fake);
   210             break;
   211         case SDL_WINDOWEVENT_MINIMIZED:
   212             fake.type = SDL_ACTIVEEVENT;
   213             fake.active.gain = 0;
   214             fake.active.state = SDL_APPACTIVE;
   215             SDL_PushEvent(&fake);
   216             break;
   217         case SDL_WINDOWEVENT_RESTORED:
   218             fake.type = SDL_ACTIVEEVENT;
   219             fake.active.gain = 1;
   220             fake.active.state = SDL_APPACTIVE;
   221             SDL_PushEvent(&fake);
   222             break;
   223         case SDL_WINDOWEVENT_ENTER:
   224             fake.type = SDL_ACTIVEEVENT;
   225             fake.active.gain = 1;
   226             fake.active.state = SDL_APPMOUSEFOCUS;
   227             SDL_PushEvent(&fake);
   228             break;
   229         case SDL_WINDOWEVENT_LEAVE:
   230             fake.type = SDL_ACTIVEEVENT;
   231             fake.active.gain = 0;
   232             fake.active.state = SDL_APPMOUSEFOCUS;
   233             SDL_PushEvent(&fake);
   234             break;
   235         case SDL_WINDOWEVENT_FOCUS_GAINED:
   236             fake.type = SDL_ACTIVEEVENT;
   237             fake.active.gain = 1;
   238             fake.active.state = SDL_APPINPUTFOCUS;
   239             SDL_PushEvent(&fake);
   240             break;
   241         case SDL_WINDOWEVENT_FOCUS_LOST:
   242             fake.type = SDL_ACTIVEEVENT;
   243             fake.active.gain = 0;
   244             fake.active.state = SDL_APPINPUTFOCUS;
   245             SDL_PushEvent(&fake);
   246             break;
   247         case SDL_WINDOWEVENT_CLOSE:
   248             fake.type = SDL_QUIT;
   249             SDL_PushEvent(&fake);
   250             break;
   251         }
   252     case SDL_KEYDOWN:
   253     case SDL_KEYUP:
   254         {
   255             Uint32 unicode = 0;
   256             if (event->key.type == SDL_KEYDOWN && event->key.keysym.sym < 256) {
   257                 unicode = event->key.keysym.sym;
   258                 if (unicode >= 'a' && unicode <= 'z') {
   259                     int shifted = !!(event->key.keysym.mod & KMOD_SHIFT);
   260                     int capslock = !!(event->key.keysym.mod & KMOD_CAPS);
   261                     if ((shifted ^ capslock) != 0) {
   262                         unicode = SDL_toupper(unicode);
   263                     }
   264                 }
   265             }
   266             if (unicode) {
   267                 event->key.keysym.unicode = unicode;
   268             }
   269             break;
   270         }
   271     case SDL_TEXTINPUT:
   272         {
   273             /* FIXME: Generate an old style key repeat event if needed */
   274             //printf("TEXTINPUT: '%s'\n", event->text.text);
   275             break;
   276         }
   277     case SDL_MOUSEWHEEL:
   278         {
   279             Uint8 button;
   280             int selected;
   281             int x, y;
   282 
   283             if (event->wheel.y == 0) {
   284                 break;
   285             }
   286 
   287             selected = SDL_SelectMouse(event->wheel.which);
   288             SDL_GetMouseState(selected, &x, &y);
   289             SDL_SelectMouse(selected);
   290 
   291             if (event->wheel.y > 0) {
   292                 button = SDL_BUTTON_WHEELUP;
   293             } else {
   294                 button = SDL_BUTTON_WHEELDOWN;
   295             }
   296 
   297             fake.button.which = event->wheel.windowID;
   298             fake.button.button = button;
   299             fake.button.x = x;
   300             fake.button.y = y;
   301             fake.button.windowID = event->wheel.windowID;
   302 
   303             fake.type = SDL_MOUSEBUTTONDOWN;
   304             fake.button.state = SDL_PRESSED;
   305             SDL_PushEvent(&fake);
   306 
   307             fake.type = SDL_MOUSEBUTTONUP;
   308             fake.button.state = SDL_RELEASED;
   309             SDL_PushEvent(&fake);
   310             break;
   311         }
   312 
   313     }
   314     return 1;
   315 }
   316 
   317 static int
   318 SDL_VideoPaletteChanged(void *userdata, SDL_Palette * palette)
   319 {
   320     if (userdata == SDL_ShadowSurface) {
   321         /* If the shadow palette changed, make the changes visible */
   322         if (!SDL_VideoSurface->format->palette) {
   323             SDL_UpdateRect(SDL_ShadowSurface, 0, 0, 0, 0);
   324         }
   325     }
   326     if (userdata == SDL_VideoSurface) {
   327         if (SDL_SetDisplayPalette(palette->colors, 0, palette->ncolors) < 0) {
   328             return -1;
   329         }
   330         if (SDL_SetTexturePalette
   331             (SDL_VideoTexture, palette->colors, 0, palette->ncolors) < 0) {
   332             return -1;
   333         }
   334     }
   335     return 0;
   336 }
   337 
   338 static void
   339 GetEnvironmentWindowPosition(int w, int h, int *x, int *y)
   340 {
   341     const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
   342     const char *center = SDL_getenv("SDL_VIDEO_CENTERED");
   343     if (window) {
   344         if (SDL_sscanf(window, "%d,%d", x, y) == 2) {
   345             return;
   346         }
   347         if (SDL_strcmp(window, "center") == 0) {
   348             center = window;
   349         }
   350     }
   351     if (center) {
   352         SDL_DisplayMode mode;
   353         SDL_GetDesktopDisplayMode(&mode);
   354         *x = (mode.w - w) / 2;
   355         *y = (mode.h - h) / 2;
   356     }
   357 }
   358 
   359 static SDL_Surface *
   360 CreateVideoSurface(SDL_TextureID textureID)
   361 {
   362     SDL_Surface *surface;
   363     Uint32 format;
   364     int w, h;
   365     int bpp;
   366     Uint32 Rmask, Gmask, Bmask, Amask;
   367     void *pixels;
   368     int pitch;
   369 
   370     if (SDL_QueryTexture(textureID, &format, NULL, &w, &h) < 0) {
   371         return NULL;
   372     }
   373 
   374     if (!SDL_PixelFormatEnumToMasks
   375         (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   376         SDL_SetError("Unknown texture format");
   377         return NULL;
   378     }
   379 
   380     if (SDL_QueryTexturePixels(textureID, &pixels, &pitch) == 0) {
   381         surface =
   382             SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask, Gmask,
   383                                      Bmask, Amask);
   384     } else {
   385         surface =
   386             SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask);
   387     }
   388     return surface;
   389 }
   390 
   391 static void
   392 ClearVideoSurface()
   393 {
   394     Uint32 black;
   395 
   396     /* Clear the surface for display */
   397     black = SDL_MapRGB(SDL_PublicSurface->format, 0, 0, 0);
   398     SDL_FillRect(SDL_PublicSurface, NULL, black);
   399     SDL_UpdateRect(SDL_PublicSurface, 0, 0, 0, 0);
   400 }
   401 
   402 static void
   403 SetupScreenSaver(int flags)
   404 {
   405     const char *env;
   406     SDL_bool allow_screensaver;
   407 
   408     /* Allow environment override of screensaver disable */
   409     env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
   410     if (env) {
   411         allow_screensaver = SDL_atoi(env) ? SDL_TRUE : SDL_FALSE;
   412     } else if (flags & SDL_FULLSCREEN) {
   413         allow_screensaver = SDL_FALSE;
   414     } else {
   415         allow_screensaver = SDL_TRUE;
   416     }
   417     if (allow_screensaver) {
   418         SDL_EnableScreenSaver();
   419     } else {
   420         SDL_DisableScreenSaver();
   421     }
   422 }
   423 
   424 int
   425 SDL_ResizeVideoMode(int width, int height, int bpp, Uint32 flags)
   426 {
   427     int w, h;
   428     Uint32 format;
   429     int access;
   430     void *pixels;
   431     int pitch;
   432 
   433     /* We can't resize something we don't have... */
   434     if (!SDL_VideoWindow) {
   435         return -1;
   436     }
   437 
   438     /* We probably have to recreate the window in fullscreen mode */
   439     if (flags & SDL_FULLSCREEN) {
   440         return -1;
   441     }
   442 
   443     /* I don't think there's any change we can gracefully make in flags */
   444     if (flags != SDL_VideoFlags) {
   445         return -1;
   446     }
   447 
   448     /* Resize the window */
   449     SDL_GetWindowSize(SDL_VideoWindow, &w, &h);
   450     if (w != width || h != height) {
   451         SDL_SetWindowSize(SDL_VideoWindow, width, height);
   452     }
   453 
   454     /* If we're in OpenGL mode, just resize the stub surface and we're done! */
   455     if (flags & SDL_OPENGL) {
   456         SDL_VideoSurface->w = width;
   457         SDL_VideoSurface->h = height;
   458         return 0;
   459     }
   460 
   461     /* Destroy the screen texture and recreate it */
   462     SDL_QueryTexture(SDL_VideoTexture, &format, &access, &w, &h);
   463     SDL_DestroyTexture(SDL_VideoTexture);
   464     SDL_VideoTexture = SDL_CreateTexture(format, access, width, height);
   465     if (!SDL_VideoTexture) {
   466         return -1;
   467     }
   468 
   469     SDL_VideoSurface->w = width;
   470     SDL_VideoSurface->h = height;
   471     if (SDL_QueryTexturePixels(SDL_VideoTexture, &pixels, &pitch) == 0) {
   472         SDL_VideoSurface->pixels = pixels;
   473         SDL_VideoSurface->pitch = pitch;
   474     } else {
   475         SDL_CalculatePitch(SDL_VideoSurface);
   476         SDL_VideoSurface->pixels =
   477             SDL_realloc(SDL_VideoSurface->pixels,
   478                         SDL_VideoSurface->h * SDL_VideoSurface->pitch);
   479     }
   480     SDL_SetClipRect(SDL_VideoSurface, NULL);
   481     SDL_InvalidateMap(SDL_VideoSurface->map);
   482 
   483     if (SDL_ShadowSurface) {
   484         SDL_ShadowSurface->w = width;
   485         SDL_ShadowSurface->h = height;
   486         SDL_ShadowSurface->pitch = SDL_CalculatePitch(SDL_ShadowSurface);
   487         SDL_ShadowSurface->pixels =
   488             SDL_realloc(SDL_ShadowSurface->pixels,
   489                         SDL_ShadowSurface->h * SDL_ShadowSurface->pitch);
   490         SDL_SetClipRect(SDL_ShadowSurface, NULL);
   491         SDL_InvalidateMap(SDL_ShadowSurface->map);
   492     }
   493 
   494     ClearVideoSurface();
   495 
   496     return 0;
   497 }
   498 
   499 SDL_Surface *
   500 SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
   501 {
   502     SDL_DisplayMode desktop_mode;
   503     int window_x = SDL_WINDOWPOS_UNDEFINED;
   504     int window_y = SDL_WINDOWPOS_UNDEFINED;
   505     Uint32 window_flags;
   506     Uint32 desktop_format;
   507     Uint32 desired_format;
   508     Uint32 surface_flags;
   509 
   510     if (!SDL_GetVideoDevice()) {
   511         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) {
   512             return NULL;
   513         }
   514     }
   515 
   516     SelectVideoDisplay();
   517 
   518     SDL_GetDesktopDisplayMode(&desktop_mode);
   519 
   520     if (width == 0) {
   521         width = desktop_mode.w;
   522     }
   523     if (height == 0) {
   524         height = desktop_mode.h;
   525     }
   526 
   527     /* See if we can simply resize the existing window and surface */
   528     if (SDL_ResizeVideoMode(width, height, bpp, flags) == 0) {
   529         return SDL_PublicSurface;
   530     }
   531 
   532     /* Destroy existing window */
   533     SDL_PublicSurface = NULL;
   534     if (SDL_ShadowSurface) {
   535         SDL_FreeSurface(SDL_ShadowSurface);
   536         SDL_ShadowSurface = NULL;
   537     }
   538     if (SDL_VideoSurface) {
   539         SDL_DelPaletteWatch(SDL_VideoSurface->format->palette,
   540                             SDL_VideoPaletteChanged, NULL);
   541         SDL_FreeSurface(SDL_VideoSurface);
   542         SDL_VideoSurface = NULL;
   543     }
   544     if (SDL_VideoContext) {
   545         /* SDL_GL_MakeCurrent(0, NULL); *//* Doesn't do anything */
   546         SDL_GL_DeleteContext(SDL_VideoContext);
   547         SDL_VideoContext = NULL;
   548     }
   549     if (SDL_VideoWindow) {
   550         SDL_GetWindowPosition(SDL_VideoWindow, &window_x, &window_y);
   551         SDL_DestroyWindow(SDL_VideoWindow);
   552     }
   553 
   554     /* Set up the event filter */
   555     if (!SDL_GetEventFilter(NULL, NULL)) {
   556         SDL_SetEventFilter(SDL_CompatEventFilter, NULL);
   557     }
   558 
   559     /* Create a new window */
   560     window_flags = SDL_WINDOW_SHOWN;
   561     if (flags & SDL_FULLSCREEN) {
   562         window_flags |= SDL_WINDOW_FULLSCREEN;
   563     }
   564     if (flags & SDL_OPENGL) {
   565         window_flags |= SDL_WINDOW_OPENGL;
   566     }
   567     if (flags & SDL_RESIZABLE) {
   568         window_flags |= SDL_WINDOW_RESIZABLE;
   569     }
   570     if (flags & SDL_NOFRAME) {
   571         window_flags |= SDL_WINDOW_BORDERLESS;
   572     }
   573     GetEnvironmentWindowPosition(width, height, &window_x, &window_y);
   574     SDL_VideoWindow =
   575         SDL_CreateWindow(wm_title, window_x, window_y, width, height,
   576                          window_flags);
   577     if (!SDL_VideoWindow) {
   578         return NULL;
   579     }
   580     SDL_SetWindowIcon(SDL_VideoWindow, SDL_VideoIcon);
   581 
   582     window_flags = SDL_GetWindowFlags(SDL_VideoWindow);
   583     surface_flags = 0;
   584     if (window_flags & SDL_WINDOW_FULLSCREEN) {
   585         surface_flags |= SDL_FULLSCREEN;
   586     }
   587     if (window_flags & SDL_WINDOW_OPENGL) {
   588         surface_flags |= SDL_OPENGL;
   589     }
   590     if (window_flags & SDL_WINDOW_RESIZABLE) {
   591         surface_flags |= SDL_RESIZABLE;
   592     }
   593     if (window_flags & SDL_WINDOW_BORDERLESS) {
   594         surface_flags |= SDL_NOFRAME;
   595     }
   596 
   597     /* Set up the desired display mode */
   598     desktop_format = desktop_mode.format;
   599     if (desktop_format && ((flags & SDL_ANYFORMAT)
   600                            || (bpp == SDL_BITSPERPIXEL(desktop_format)))) {
   601         desired_format = desktop_format;
   602     } else {
   603         switch (bpp) {
   604         case 0:
   605             if (desktop_format) {
   606                 desired_format = desktop_format;
   607             } else {
   608                 desired_format = SDL_PIXELFORMAT_RGB888;
   609             }
   610             bpp = SDL_BITSPERPIXEL(desired_format);
   611             break;
   612         case 8:
   613             desired_format = SDL_PIXELFORMAT_INDEX8;
   614             break;
   615         case 15:
   616             desired_format = SDL_PIXELFORMAT_RGB555;
   617             break;
   618         case 16:
   619             desired_format = SDL_PIXELFORMAT_RGB565;
   620             break;
   621         case 24:
   622             desired_format = SDL_PIXELFORMAT_RGB24;
   623             break;
   624         case 32:
   625             desired_format = SDL_PIXELFORMAT_RGB888;
   626             break;
   627         default:
   628             SDL_SetError("Unsupported bpp in SDL_SetVideoMode()");
   629             return NULL;
   630         }
   631     }
   632 
   633     /* Set up the desired display mode */
   634     if (flags & SDL_FULLSCREEN) {
   635         SDL_DisplayMode mode;
   636 
   637         SDL_zero(mode);
   638         mode.format = desired_format;
   639         if (SDL_SetWindowDisplayMode(SDL_VideoWindow, &mode) < 0) {
   640             return NULL;
   641         }
   642     }
   643 
   644     /* If we're in OpenGL mode, just create a stub surface and we're done! */
   645     if (flags & SDL_OPENGL) {
   646         SDL_VideoContext = SDL_GL_CreateContext(SDL_VideoWindow);
   647         if (!SDL_VideoContext) {
   648             return NULL;
   649         }
   650         if (SDL_GL_MakeCurrent(SDL_VideoWindow, SDL_VideoContext) < 0) {
   651             return NULL;
   652         }
   653         SDL_VideoSurface =
   654             SDL_CreateRGBSurfaceFrom(NULL, width, height, bpp, 0, 0, 0, 0, 0);
   655         if (!SDL_VideoSurface) {
   656             return NULL;
   657         }
   658         SDL_VideoSurface->flags |= surface_flags;
   659         SDL_PublicSurface = SDL_VideoSurface;
   660         return SDL_PublicSurface;
   661     }
   662 
   663     /* Create a renderer for the window */
   664     if (SDL_CreateRenderer
   665         (SDL_VideoWindow, -1,
   666          SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD) < 0) {
   667         return NULL;
   668     }
   669     SDL_GetRendererInfo(&SDL_VideoRendererInfo);
   670 
   671     /* Create a texture for the screen surface */
   672     SDL_VideoTexture =
   673         SDL_CreateTexture(desired_format, SDL_TEXTUREACCESS_STREAMING, width,
   674                           height);
   675 
   676     if (!SDL_VideoTexture) {
   677         SDL_VideoTexture =
   678             SDL_CreateTexture(desktop_format,
   679                               SDL_TEXTUREACCESS_STREAMING, width, height);
   680     }
   681     if (!SDL_VideoTexture) {
   682         return NULL;
   683     }
   684 
   685     /* Create the screen surface */
   686     SDL_VideoSurface = CreateVideoSurface(SDL_VideoTexture);
   687     if (!SDL_VideoSurface) {
   688         return NULL;
   689     }
   690     SDL_VideoSurface->flags |= surface_flags;
   691 
   692     /* Set a default screen palette */
   693     if (SDL_VideoSurface->format->palette) {
   694         SDL_VideoSurface->flags |= SDL_HWPALETTE;
   695         SDL_DitherColors(SDL_VideoSurface->format->palette->colors,
   696                          SDL_VideoSurface->format->BitsPerPixel);
   697         SDL_AddPaletteWatch(SDL_VideoSurface->format->palette,
   698                             SDL_VideoPaletteChanged, SDL_VideoSurface);
   699         SDL_SetPaletteColors(SDL_VideoSurface->format->palette,
   700                              SDL_VideoSurface->format->palette->colors, 0,
   701                              SDL_VideoSurface->format->palette->ncolors);
   702     }
   703 
   704     /* Create a shadow surface if necessary */
   705     if ((bpp != SDL_VideoSurface->format->BitsPerPixel)
   706         && !(flags & SDL_ANYFORMAT)) {
   707         SDL_ShadowSurface =
   708             SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0);
   709         if (!SDL_ShadowSurface) {
   710             return NULL;
   711         }
   712         SDL_ShadowSurface->flags |= surface_flags;
   713 
   714         /* 8-bit SDL_ShadowSurface surfaces report that they have exclusive palette */
   715         if (SDL_ShadowSurface->format->palette) {
   716             SDL_ShadowSurface->flags |= SDL_HWPALETTE;
   717             if (SDL_VideoSurface->format->palette) {
   718                 SDL_SetSurfacePalette(SDL_ShadowSurface,
   719                                       SDL_VideoSurface->format->palette);
   720             } else {
   721                 SDL_DitherColors(SDL_ShadowSurface->format->palette->colors,
   722                                  SDL_ShadowSurface->format->BitsPerPixel);
   723             }
   724             SDL_AddPaletteWatch(SDL_ShadowSurface->format->palette,
   725                                 SDL_VideoPaletteChanged, SDL_ShadowSurface);
   726         }
   727     }
   728     SDL_PublicSurface =
   729         (SDL_ShadowSurface ? SDL_ShadowSurface : SDL_VideoSurface);
   730 
   731     SDL_VideoFlags = flags;
   732 
   733     ClearVideoSurface();
   734 
   735     SetupScreenSaver(flags);
   736 
   737     /* We're finally done! */
   738     return SDL_PublicSurface;
   739 }
   740 
   741 SDL_Surface *
   742 SDL_GetVideoSurface(void)
   743 {
   744     return SDL_PublicSurface;
   745 }
   746 
   747 int
   748 SDL_SetAlpha(SDL_Surface * surface, Uint32 flag, Uint8 value)
   749 {
   750     if (flag & SDL_SRCALPHA) {
   751         /* According to the docs, value is ignored for alpha surfaces */
   752         if (surface->format->Amask) {
   753             value = 0xFF;
   754         }
   755         SDL_SetSurfaceAlphaMod(surface, value);
   756         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   757     } else {
   758         SDL_SetSurfaceAlphaMod(surface, 0xFF);
   759         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
   760     }
   761     SDL_SetSurfaceRLE(surface, (flag & SDL_RLEACCEL));
   762 
   763     return 0;
   764 }
   765 
   766 SDL_Surface *
   767 SDL_DisplayFormat(SDL_Surface * surface)
   768 {
   769     SDL_PixelFormat *format;
   770 
   771     if (!SDL_PublicSurface) {
   772         SDL_SetError("No video mode has been set");
   773         return NULL;
   774     }
   775     format = SDL_PublicSurface->format;
   776 
   777     /* Set the flags appropriate for copying to display surface */
   778     return SDL_ConvertSurface(surface, format, SDL_RLEACCEL);
   779 }
   780 
   781 SDL_Surface *
   782 SDL_DisplayFormatAlpha(SDL_Surface * surface)
   783 {
   784     SDL_PixelFormat *vf;
   785     SDL_PixelFormat *format;
   786     SDL_Surface *converted;
   787     /* default to ARGB8888 */
   788     Uint32 amask = 0xff000000;
   789     Uint32 rmask = 0x00ff0000;
   790     Uint32 gmask = 0x0000ff00;
   791     Uint32 bmask = 0x000000ff;
   792 
   793     if (!SDL_PublicSurface) {
   794         SDL_SetError("No video mode has been set");
   795         return NULL;
   796     }
   797     vf = SDL_PublicSurface->format;
   798 
   799     switch (vf->BytesPerPixel) {
   800     case 2:
   801         /* For XGY5[56]5, use, AXGY8888, where {X, Y} = {R, B}.
   802            For anything else (like ARGB4444) it doesn't matter
   803            since we have no special code for it anyway */
   804         if ((vf->Rmask == 0x1f) &&
   805             (vf->Bmask == 0xf800 || vf->Bmask == 0x7c00)) {
   806             rmask = 0xff;
   807             bmask = 0xff0000;
   808         }
   809         break;
   810 
   811     case 3:
   812     case 4:
   813         /* Keep the video format, as long as the high 8 bits are
   814            unused or alpha */
   815         if ((vf->Rmask == 0xff) && (vf->Bmask == 0xff0000)) {
   816             rmask = 0xff;
   817             bmask = 0xff0000;
   818         }
   819         break;
   820 
   821     default:
   822         /* We have no other optimised formats right now. When/if a new
   823            optimised alpha format is written, add the converter here */
   824         break;
   825     }
   826     format = SDL_AllocFormat(32, rmask, gmask, bmask, amask);
   827     converted = SDL_ConvertSurface(surface, format, SDL_RLEACCEL);
   828     SDL_FreeFormat(format);
   829     return converted;
   830 }
   831 
   832 int
   833 SDL_Flip(SDL_Surface * screen)
   834 {
   835     SDL_UpdateRect(screen, 0, 0, 0, 0);
   836     return 0;
   837 }
   838 
   839 void
   840 SDL_UpdateRect(SDL_Surface * screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
   841 {
   842     if (screen) {
   843         SDL_Rect rect;
   844 
   845         /* Fill the rectangle */
   846         rect.x = (int) x;
   847         rect.y = (int) y;
   848         rect.w = (int) (w ? w : screen->w);
   849         rect.h = (int) (h ? h : screen->h);
   850         SDL_UpdateRects(screen, 1, &rect);
   851     }
   852 }
   853 
   854 void
   855 SDL_UpdateRects(SDL_Surface * screen, int numrects, SDL_Rect * rects)
   856 {
   857     int i;
   858 
   859     if (screen == SDL_ShadowSurface) {
   860         for (i = 0; i < numrects; ++i) {
   861             SDL_LowerBlit(SDL_ShadowSurface, &rects[i], SDL_VideoSurface,
   862                           &rects[i]);
   863         }
   864 
   865         /* Fall through to video surface update */
   866         screen = SDL_VideoSurface;
   867     }
   868     if (screen == SDL_VideoSurface) {
   869         if (screen->flags & SDL_PREALLOC) {
   870             /* The surface memory is maintained by the renderer */
   871             SDL_DirtyTexture(SDL_VideoTexture, numrects, rects);
   872         } else {
   873             /* The surface memory needs to be copied to texture */
   874             int pitch = screen->pitch;
   875             int psize = screen->format->BytesPerPixel;
   876             for (i = 0; i < numrects; ++i) {
   877                 const SDL_Rect *rect = &rects[i];
   878                 void *pixels =
   879                     (Uint8 *) screen->pixels + rect->y * pitch +
   880                     rect->x * psize;
   881                 SDL_UpdateTexture(SDL_VideoTexture, rect, pixels, pitch);
   882             }
   883         }
   884         if (SDL_VideoRendererInfo.flags & SDL_RENDERER_PRESENTCOPY) {
   885             for (i = 0; i < numrects; ++i) {
   886                 SDL_RenderCopy(SDL_VideoTexture, &rects[i], &rects[i]);
   887             }
   888         } else {
   889             SDL_Rect rect;
   890             rect.x = 0;
   891             rect.y = 0;
   892             rect.w = screen->w;
   893             rect.h = screen->h;
   894             SDL_RenderCopy(SDL_VideoTexture, &rect, &rect);
   895         }
   896         SDL_RenderPresent();
   897     }
   898 }
   899 
   900 void
   901 SDL_WM_SetCaption(const char *title, const char *icon)
   902 {
   903     if (wm_title) {
   904         SDL_free(wm_title);
   905     }
   906     if (title) {
   907         wm_title = SDL_strdup(title);
   908     } else {
   909         wm_title = NULL;
   910     }
   911     SDL_SetWindowTitle(SDL_VideoWindow, wm_title);
   912 }
   913 
   914 void
   915 SDL_WM_GetCaption(const char **title, const char **icon)
   916 {
   917     if (title) {
   918         *title = wm_title;
   919     }
   920     if (icon) {
   921         *icon = "";
   922     }
   923 }
   924 
   925 void
   926 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
   927 {
   928     SDL_VideoIcon = icon;
   929 }
   930 
   931 int
   932 SDL_WM_IconifyWindow(void)
   933 {
   934     SDL_MinimizeWindow(SDL_VideoWindow);
   935     return 0;
   936 }
   937 
   938 int
   939 SDL_WM_ToggleFullScreen(SDL_Surface * surface)
   940 {
   941     if (SDL_GetWindowFlags(SDL_VideoWindow) & SDL_WINDOW_FULLSCREEN) {
   942         if (SDL_SetWindowFullscreen(SDL_VideoWindow, 0) < 0) {
   943             return 0;
   944         }
   945         SDL_PublicSurface->flags &= ~SDL_FULLSCREEN;
   946     } else {
   947         if (SDL_SetWindowFullscreen(SDL_VideoWindow, 1) < 0) {
   948             return 0;
   949         }
   950         SDL_PublicSurface->flags |= SDL_FULLSCREEN;
   951     }
   952     return 1;
   953 }
   954 
   955 SDL_GrabMode
   956 SDL_WM_GrabInput(SDL_GrabMode mode)
   957 {
   958     if (mode != SDL_GRAB_QUERY) {
   959         SDL_SetWindowGrab(SDL_VideoWindow, mode);
   960     }
   961     return (SDL_GrabMode) SDL_GetWindowGrab(SDL_VideoWindow);
   962 }
   963 
   964 void
   965 SDL_WarpMouse(Uint16 x, Uint16 y)
   966 {
   967     SDL_WarpMouseInWindow(SDL_VideoWindow, x, y);
   968 }
   969 
   970 Uint8
   971 SDL_GetAppState(void)
   972 {
   973     Uint8 state = 0;
   974     Uint32 flags = 0;
   975 
   976     flags = SDL_GetWindowFlags(SDL_VideoWindow);
   977     if ((flags & SDL_WINDOW_SHOWN) && !(flags & SDL_WINDOW_MINIMIZED)) {
   978         state |= SDL_APPACTIVE;
   979     }
   980     if (flags & SDL_WINDOW_INPUT_FOCUS) {
   981         state |= SDL_APPINPUTFOCUS;
   982     }
   983     if (flags & SDL_WINDOW_MOUSE_FOCUS) {
   984         state |= SDL_APPMOUSEFOCUS;
   985     }
   986     return state;
   987 }
   988 
   989 const SDL_version *
   990 SDL_Linked_Version(void)
   991 {
   992     static SDL_version version;
   993     SDL_VERSION(&version);
   994     return &version;
   995 }
   996 
   997 int
   998 SDL_SetPalette(SDL_Surface * surface, int flags, const SDL_Color * colors,
   999                int firstcolor, int ncolors)
  1000 {
  1001     return SDL_SetColors(surface, colors, firstcolor, ncolors);
  1002 }
  1003 
  1004 int
  1005 SDL_SetColors(SDL_Surface * surface, const SDL_Color * colors, int firstcolor,
  1006               int ncolors)
  1007 {
  1008     if (SDL_SetPaletteColors
  1009         (surface->format->palette, colors, firstcolor, ncolors) == 0) {
  1010         return 1;
  1011     } else {
  1012         return 0;
  1013     }
  1014 }
  1015 
  1016 int
  1017 SDL_GetWMInfo(SDL_SysWMinfo * info)
  1018 {
  1019     return SDL_GetWindowWMInfo(SDL_VideoWindow, info);
  1020 }
  1021 
  1022 #if 0
  1023 void
  1024 SDL_MoveCursor(int x, int y)
  1025 {
  1026     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1027 
  1028     /* Erase and update the current mouse position */
  1029     if (SHOULD_DRAWCURSOR(SDL_cursorstate)) {
  1030         /* Erase and redraw mouse cursor in new position */
  1031         SDL_LockCursor();
  1032         SDL_EraseCursor(SDL_VideoSurface);
  1033         SDL_cursor->area.x = (x - SDL_cursor->hot_x);
  1034         SDL_cursor->area.y = (y - SDL_cursor->hot_y);
  1035         SDL_DrawCursor(SDL_VideoSurface);
  1036         SDL_UnlockCursor();
  1037     } else if (_this->MoveWMCursor) {
  1038         _this->MoveWMCursor(_this, x, y);
  1039     }
  1040 }
  1041 
  1042 /* Keep track of the current cursor colors */
  1043 static int palette_changed = 1;
  1044 static Uint8 pixels8[2];
  1045 
  1046 void
  1047 SDL_CursorPaletteChanged(void)
  1048 {
  1049     palette_changed = 1;
  1050 }
  1051 
  1052 void
  1053 SDL_MouseRect(SDL_Rect * area)
  1054 {
  1055     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1056     int clip_diff;
  1057 
  1058     *area = SDL_cursor->area;
  1059     if (area->x < 0) {
  1060         area->w += area->x;
  1061         area->x = 0;
  1062     }
  1063     if (area->y < 0) {
  1064         area->h += area->y;
  1065         area->y = 0;
  1066     }
  1067     clip_diff = (area->x + area->w) - SDL_VideoSurface->w;
  1068     if (clip_diff > 0) {
  1069         area->w = area->w < clip_diff ? 0 : area->w - clip_diff;
  1070     }
  1071     clip_diff = (area->y + area->h) - SDL_VideoSurface->h;
  1072     if (clip_diff > 0) {
  1073         area->h = area->h < clip_diff ? 0 : area->h - clip_diff;
  1074     }
  1075 }
  1076 
  1077 static void
  1078 SDL_DrawCursorFast(SDL_Surface * screen, SDL_Rect * area)
  1079 {
  1080     const Uint32 pixels[2] = { 0xFFFFFFFF, 0x00000000 };
  1081     int i, w, h;
  1082     Uint8 *data, datab;
  1083     Uint8 *mask, maskb;
  1084 
  1085     data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
  1086     mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
  1087     switch (screen->format->BytesPerPixel) {
  1088 
  1089     case 1:
  1090         {
  1091             Uint8 *dst;
  1092             int dstskip;
  1093 
  1094             if (palette_changed) {
  1095                 pixels8[0] =
  1096                     (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
  1097                 pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
  1098                 palette_changed = 0;
  1099             }
  1100             dst = (Uint8 *) screen->pixels +
  1101                 (SDL_cursor->area.y + area->y) * screen->pitch +
  1102                 SDL_cursor->area.x;
  1103             dstskip = screen->pitch - area->w;
  1104 
  1105             for (h = area->h; h; h--) {
  1106                 for (w = area->w / 8; w; w--) {
  1107                     maskb = *mask++;
  1108                     datab = *data++;
  1109                     for (i = 0; i < 8; ++i) {
  1110                         if (maskb & 0x80) {
  1111                             *dst = pixels8[datab >> 7];
  1112                         }
  1113                         maskb <<= 1;
  1114                         datab <<= 1;
  1115                         dst++;
  1116                     }
  1117                 }
  1118                 dst += dstskip;
  1119             }
  1120         }
  1121         break;
  1122 
  1123     case 2:
  1124         {
  1125             Uint16 *dst;
  1126             int dstskip;
  1127 
  1128             dst = (Uint16 *) screen->pixels +
  1129                 (SDL_cursor->area.y + area->y) * screen->pitch / 2 +
  1130                 SDL_cursor->area.x;
  1131             dstskip = (screen->pitch / 2) - area->w;
  1132 
  1133             for (h = area->h; h; h--) {
  1134                 for (w = area->w / 8; w; w--) {
  1135                     maskb = *mask++;
  1136                     datab = *data++;
  1137                     for (i = 0; i < 8; ++i) {
  1138                         if (maskb & 0x80) {
  1139                             *dst = (Uint16) pixels[datab >> 7];
  1140                         }
  1141                         maskb <<= 1;
  1142                         datab <<= 1;
  1143                         dst++;
  1144                     }
  1145                 }
  1146                 dst += dstskip;
  1147             }
  1148         }
  1149         break;
  1150 
  1151     case 3:
  1152         {
  1153             Uint8 *dst;
  1154             int dstskip;
  1155 
  1156             dst = (Uint8 *) screen->pixels +
  1157                 (SDL_cursor->area.y + area->y) * screen->pitch +
  1158                 SDL_cursor->area.x * 3;
  1159             dstskip = screen->pitch - area->w * 3;
  1160 
  1161             for (h = area->h; h; h--) {
  1162                 for (w = area->w / 8; w; w--) {
  1163                     maskb = *mask++;
  1164                     datab = *data++;
  1165                     for (i = 0; i < 8; ++i) {
  1166                         if (maskb & 0x80) {
  1167                             SDL_memset(dst, pixels[datab >> 7], 3);
  1168                         }
  1169                         maskb <<= 1;
  1170                         datab <<= 1;
  1171                         dst += 3;
  1172                     }
  1173                 }
  1174                 dst += dstskip;
  1175             }
  1176         }
  1177         break;
  1178 
  1179     case 4:
  1180         {
  1181             Uint32 *dst;
  1182             int dstskip;
  1183 
  1184             dst = (Uint32 *) screen->pixels +
  1185                 (SDL_cursor->area.y + area->y) * screen->pitch / 4 +
  1186                 SDL_cursor->area.x;
  1187             dstskip = (screen->pitch / 4) - area->w;
  1188 
  1189             for (h = area->h; h; h--) {
  1190                 for (w = area->w / 8; w; w--) {
  1191                     maskb = *mask++;
  1192                     datab = *data++;
  1193                     for (i = 0; i < 8; ++i) {
  1194                         if (maskb & 0x80) {
  1195                             *dst = pixels[datab >> 7];
  1196                         }
  1197                         maskb <<= 1;
  1198                         datab <<= 1;
  1199                         dst++;
  1200                     }
  1201                 }
  1202                 dst += dstskip;
  1203             }
  1204         }
  1205         break;
  1206     }
  1207 }
  1208 
  1209 static void
  1210 SDL_DrawCursorSlow(SDL_Surface * screen, SDL_Rect * area)
  1211 {
  1212     const Uint32 pixels[2] = { 0xFFFFFF, 0x000000 };
  1213     int h;
  1214     int x, minx, maxx;
  1215     Uint8 *data, datab = 0;
  1216     Uint8 *mask, maskb = 0;
  1217     Uint8 *dst;
  1218     int dstbpp, dstskip;
  1219 
  1220     data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
  1221     mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
  1222     dstbpp = screen->format->BytesPerPixel;
  1223     dst = (Uint8 *) screen->pixels +
  1224         (SDL_cursor->area.y + area->y) * screen->pitch +
  1225         SDL_cursor->area.x * dstbpp;
  1226     dstskip = screen->pitch - SDL_cursor->area.w * dstbpp;
  1227 
  1228     minx = area->x;
  1229     maxx = area->x + area->w;
  1230     if (screen->format->BytesPerPixel == 1) {
  1231         if (palette_changed) {
  1232             pixels8[0] = (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
  1233             pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
  1234             palette_changed = 0;
  1235         }
  1236         for (h = area->h; h; h--) {
  1237             for (x = 0; x < SDL_cursor->area.w; ++x) {
  1238                 if ((x % 8) == 0) {
  1239                     maskb = *mask++;
  1240                     datab = *data++;
  1241                 }
  1242                 if ((x >= minx) && (x < maxx)) {
  1243                     if (maskb & 0x80) {
  1244                         SDL_memset(dst, pixels8[datab >> 7], dstbpp);
  1245                     }
  1246                 }
  1247                 maskb <<= 1;
  1248                 datab <<= 1;
  1249                 dst += dstbpp;
  1250             }
  1251             dst += dstskip;
  1252         }
  1253     } else {
  1254         for (h = area->h; h; h--) {
  1255             for (x = 0; x < SDL_cursor->area.w; ++x) {
  1256                 if ((x % 8) == 0) {
  1257                     maskb = *mask++;
  1258                     datab = *data++;
  1259                 }
  1260                 if ((x >= minx) && (x < maxx)) {
  1261                     if (maskb & 0x80) {
  1262                         SDL_memset(dst, pixels[datab >> 7], dstbpp);
  1263                     }
  1264                 }
  1265                 maskb <<= 1;
  1266                 datab <<= 1;
  1267                 dst += dstbpp;
  1268             }
  1269             dst += dstskip;
  1270         }
  1271     }
  1272 }
  1273 
  1274 /* This handles the ugly work of converting the saved cursor background from
  1275    the pixel format of the shadow surface to that of the video surface.
  1276    This is only necessary when blitting from a shadow surface of a different
  1277    pixel format than the video surface, and using a software rendered cursor.
  1278 */
  1279 static void
  1280 SDL_ConvertCursorSave(SDL_Surface * screen, int w, int h)
  1281 {
  1282     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1283     SDL_BlitInfo info;
  1284     SDL_loblit RunBlit;
  1285 
  1286     /* Make sure we can steal the blit mapping */
  1287     if (screen->map->dst != SDL_VideoSurface) {
  1288         return;
  1289     }
  1290 
  1291     /* Set up the blit information */
  1292     info.s_pixels = SDL_cursor->save[1];
  1293     info.s_width = w;
  1294     info.s_height = h;
  1295     info.s_skip = 0;
  1296     info.d_pixels = SDL_cursor->save[0];
  1297     info.d_width = w;
  1298     info.d_height = h;
  1299     info.d_skip = 0;
  1300     info.aux_data = screen->map->sw_data->aux_data;
  1301     info.src = screen->format;
  1302     info.table = screen->map->table;
  1303     info.dst = SDL_VideoSurface->format;
  1304     RunBlit = screen->map->sw_data->blit;
  1305 
  1306     /* Run the actual software blit */
  1307     RunBlit(&info);
  1308 }
  1309 
  1310 void
  1311 SDL_DrawCursorNoLock(SDL_Surface * screen)
  1312 {
  1313     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1314     SDL_Rect area;
  1315 
  1316     /* Get the mouse rectangle, clipped to the screen */
  1317     SDL_MouseRect(&area);
  1318     if ((area.w == 0) || (area.h == 0)) {
  1319         return;
  1320     }
  1321 
  1322     /* Copy mouse background */
  1323     {
  1324         int w, h, screenbpp;
  1325         Uint8 *src, *dst;
  1326 
  1327         /* Set up the copy pointers */
  1328         screenbpp = screen->format->BytesPerPixel;
  1329         if ((screen == SDL_VideoSurface) ||
  1330             FORMAT_EQUAL(screen->format, SDL_VideoSurface->format)) {
  1331             dst = SDL_cursor->save[0];
  1332         } else {
  1333             dst = SDL_cursor->save[1];
  1334         }
  1335         src = (Uint8 *) screen->pixels + area.y * screen->pitch +
  1336             area.x * screenbpp;
  1337 
  1338         /* Perform the copy */
  1339         w = area.w * screenbpp;
  1340         h = area.h;
  1341         while (h--) {
  1342             SDL_memcpy(dst, src, w);
  1343             dst += w;
  1344             src += screen->pitch;
  1345         }
  1346     }
  1347 
  1348     /* Draw the mouse cursor */
  1349     area.x -= SDL_cursor->area.x;
  1350     area.y -= SDL_cursor->area.y;
  1351     if ((area.x == 0) && (area.w == SDL_cursor->area.w)) {
  1352         SDL_DrawCursorFast(screen, &area);
  1353     } else {
  1354         SDL_DrawCursorSlow(screen, &area);
  1355     }
  1356 }
  1357 
  1358 void
  1359 SDL_DrawCursor(SDL_Surface * screen)
  1360 {
  1361     /* Lock the screen if necessary */
  1362     if (screen == NULL) {
  1363         return;
  1364     }
  1365     if (SDL_MUSTLOCK(screen)) {
  1366         if (SDL_LockSurface(screen) < 0) {
  1367             return;
  1368         }
  1369     }
  1370 
  1371     SDL_DrawCursorNoLock(screen);
  1372 
  1373     /* Unlock the screen and update if necessary */
  1374     if (SDL_MUSTLOCK(screen)) {
  1375         SDL_UnlockSurface(screen);
  1376     }
  1377     if (screen->flags & SDL_SCREEN_SURFACE) {
  1378         SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1379         SDL_Window *window;
  1380         SDL_Rect area;
  1381 
  1382         window = SDL_GetWindowFromSurface(screen);
  1383         if (!window) {
  1384             return;
  1385         }
  1386 
  1387         SDL_MouseRect(&area);
  1388 
  1389         if (_this->UpdateWindowSurface) {
  1390             _this->UpdateWindowSurface(_this, window, 1, &area);
  1391         }
  1392     }
  1393 }
  1394 
  1395 void
  1396 SDL_EraseCursorNoLock(SDL_Surface * screen)
  1397 {
  1398     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1399     SDL_Window *window;
  1400     SDL_Rect area;
  1401 
  1402     /* Get the window associated with the surface */
  1403     window = SDL_GetWindowFromSurface(screen);
  1404     if (!window || !window->surface) {
  1405         return;
  1406     }
  1407 
  1408     /* Get the mouse rectangle, clipped to the screen */
  1409     SDL_MouseRect(&area);
  1410     if ((area.w == 0) || (area.h == 0)) {
  1411         return;
  1412     }
  1413 
  1414     /* Copy mouse background */
  1415     {
  1416         int w, h, screenbpp;
  1417         Uint8 *src, *dst;
  1418 
  1419         /* Set up the copy pointers */
  1420         screenbpp = screen->format->BytesPerPixel;
  1421         if ((screen->flags & SDL_SCREEN_SURFACE) ||
  1422             FORMAT_EQUAL(screen->format, window->surface->format)) {
  1423             src = SDL_cursor->save[0];
  1424         } else {
  1425             src = SDL_cursor->save[1];
  1426         }
  1427         dst = (Uint8 *) screen->pixels + area.y * screen->pitch +
  1428             area.x * screenbpp;
  1429 
  1430         /* Perform the copy */
  1431         w = area.w * screenbpp;
  1432         h = area.h;
  1433         while (h--) {
  1434             SDL_memcpy(dst, src, w);
  1435             src += w;
  1436             dst += screen->pitch;
  1437         }
  1438 
  1439         /* Perform pixel conversion on cursor background */
  1440         if (src > SDL_cursor->save[1]) {
  1441             SDL_ConvertCursorSave(screen, area.w, area.h);
  1442         }
  1443     }
  1444 }
  1445 
  1446 void
  1447 SDL_EraseCursor(SDL_Surface * screen)
  1448 {
  1449     /* Lock the screen if necessary */
  1450     if (screen == NULL) {
  1451         return;
  1452     }
  1453     if (SDL_MUSTLOCK(screen)) {
  1454         if (SDL_LockSurface(screen) < 0) {
  1455             return;
  1456         }
  1457     }
  1458 
  1459     SDL_EraseCursorNoLock(screen);
  1460 
  1461     /* Unlock the screen and update if necessary */
  1462     if (SDL_MUSTLOCK(screen)) {
  1463         SDL_UnlockSurface(screen);
  1464     }
  1465     if (screen->flags & SDL_SCREEN_SURFACE) {
  1466         SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1467         SDL_Window *window;
  1468         SDL_Rect area;
  1469 
  1470         window = SDL_GetWindowFromSurface(screen);
  1471         if (!window) {
  1472             return;
  1473         }
  1474 
  1475         SDL_MouseRect(&area);
  1476 
  1477         if (_this->UpdateWindowSurface) {
  1478             _this->UpdateWindowSurface(_this, window, 1, &area);
  1479         }
  1480     }
  1481 }
  1482 
  1483 /* Reset the cursor on video mode change
  1484    FIXME:  Keep track of all cursors, and reset them all.
  1485  */
  1486 void
  1487 SDL_ResetCursor(void)
  1488 {
  1489     int savelen;
  1490 
  1491     if (SDL_cursor) {
  1492         savelen = SDL_cursor->area.w * 4 * SDL_cursor->area.h;
  1493         SDL_cursor->area.x = 0;
  1494         SDL_cursor->area.y = 0;
  1495         SDL_memset(SDL_cursor->save[0], 0, savelen);
  1496     }
  1497 }
  1498 #endif
  1499 
  1500 struct private_yuvhwdata
  1501 {
  1502     Uint16 pitches[3];
  1503     Uint8 *planes[3];
  1504 
  1505     SDL_SW_YUVTexture *sw;
  1506 
  1507     SDL_TextureID textureID;
  1508     Uint32 texture_format;
  1509 };
  1510 
  1511 SDL_Overlay *
  1512 SDL_CreateYUVOverlay(int w, int h, Uint32 format, SDL_Surface * display)
  1513 {
  1514     SDL_Overlay *overlay;
  1515     Uint32 texture_format;
  1516 
  1517     if ((display->flags & SDL_OPENGL) == SDL_OPENGL) {
  1518         SDL_SetError("YUV overlays are not supported in OpenGL mode");
  1519         return NULL;
  1520     }
  1521 
  1522     if (display != SDL_PublicSurface) {
  1523         SDL_SetError("YUV display is only supported on the screen surface");
  1524         return NULL;
  1525     }
  1526 
  1527     switch (format) {
  1528     case SDL_YV12_OVERLAY:
  1529         texture_format = SDL_PIXELFORMAT_YV12;
  1530         break;
  1531     case SDL_IYUV_OVERLAY:
  1532         texture_format = SDL_PIXELFORMAT_IYUV;
  1533         break;
  1534     case SDL_YUY2_OVERLAY:
  1535         texture_format = SDL_PIXELFORMAT_YUY2;
  1536         break;
  1537     case SDL_UYVY_OVERLAY:
  1538         texture_format = SDL_PIXELFORMAT_UYVY;
  1539         break;
  1540     case SDL_YVYU_OVERLAY:
  1541         texture_format = SDL_PIXELFORMAT_YVYU;
  1542         break;
  1543     default:
  1544         SDL_SetError("Unknown YUV format");
  1545         return NULL;
  1546     }
  1547 
  1548     overlay = (SDL_Overlay *) SDL_malloc(sizeof(*overlay));
  1549     if (!overlay) {
  1550         SDL_OutOfMemory();
  1551         return NULL;
  1552     }
  1553     SDL_zerop(overlay);
  1554 
  1555     overlay->hwdata =
  1556         (struct private_yuvhwdata *) SDL_malloc(sizeof(*overlay->hwdata));
  1557     if (!overlay->hwdata) {
  1558         SDL_free(overlay);
  1559         SDL_OutOfMemory();
  1560         return NULL;
  1561     }
  1562 
  1563     overlay->format = format;
  1564     overlay->w = w;
  1565     overlay->h = h;
  1566     if (format == SDL_YV12_OVERLAY || format == SDL_IYUV_OVERLAY) {
  1567         overlay->planes = 3;
  1568     } else {
  1569         overlay->planes = 1;
  1570     }
  1571     overlay->pitches = overlay->hwdata->pitches;
  1572     overlay->pixels = overlay->hwdata->planes;
  1573 
  1574     switch (format) {
  1575     case SDL_YV12_OVERLAY:
  1576     case SDL_IYUV_OVERLAY:
  1577         overlay->pitches[0] = overlay->w;
  1578         overlay->pitches[1] = overlay->w / 2;
  1579         overlay->pitches[2] = overlay->w / 2;
  1580         break;
  1581     case SDL_YUY2_OVERLAY:
  1582     case SDL_UYVY_OVERLAY:
  1583     case SDL_YVYU_OVERLAY:
  1584         overlay->pitches[0] = overlay->w * 2;
  1585         break;
  1586     }
  1587 
  1588     overlay->hwdata->textureID =
  1589         SDL_CreateTexture(texture_format, SDL_TEXTUREACCESS_STREAMING, w, h);
  1590     if (overlay->hwdata->textureID) {
  1591         overlay->hwdata->sw = NULL;
  1592     } else {
  1593         SDL_DisplayMode current_mode;
  1594 
  1595         overlay->hwdata->sw = SDL_SW_CreateYUVTexture(texture_format, w, h);
  1596         if (!overlay->hwdata->sw) {
  1597             SDL_FreeYUVOverlay(overlay);
  1598             return NULL;
  1599         }
  1600 
  1601         /* Create a supported RGB format texture for display */
  1602         SDL_GetCurrentDisplayMode(&current_mode);
  1603         texture_format = current_mode.format;
  1604         overlay->hwdata->textureID =
  1605             SDL_CreateTexture(texture_format,
  1606                               SDL_TEXTUREACCESS_STREAMING, w, h);
  1607     }
  1608     if (!overlay->hwdata->textureID) {
  1609         SDL_FreeYUVOverlay(overlay);
  1610         return NULL;
  1611     }
  1612     overlay->hwdata->texture_format = texture_format;
  1613 
  1614     return overlay;
  1615 }
  1616 
  1617 int
  1618 SDL_LockYUVOverlay(SDL_Overlay * overlay)
  1619 {
  1620     void *pixels;
  1621     int pitch;
  1622 
  1623     if (!overlay) {
  1624         SDL_SetError("Passed a NULL overlay");
  1625         return -1;
  1626     }
  1627     if (overlay->hwdata->sw) {
  1628         if (SDL_SW_QueryYUVTexturePixels(overlay->hwdata->sw, &pixels, &pitch)
  1629             < 0) {
  1630             return -1;
  1631         }
  1632     } else {
  1633         if (SDL_LockTexture
  1634             (overlay->hwdata->textureID, NULL, 1, &pixels, &pitch)
  1635             < 0) {
  1636             return -1;
  1637         }
  1638     }
  1639     overlay->pixels[0] = (Uint8 *) pixels;
  1640     overlay->pitches[0] = pitch;
  1641     switch (overlay->format) {
  1642     case SDL_YV12_OVERLAY:
  1643     case SDL_IYUV_OVERLAY:
  1644         overlay->pitches[1] = pitch / 2;
  1645         overlay->pitches[2] = pitch / 2;
  1646         overlay->pixels[1] =
  1647             overlay->pixels[0] + overlay->pitches[0] * overlay->h;
  1648         overlay->pixels[2] =
  1649             overlay->pixels[1] + overlay->pitches[1] * overlay->h / 2;
  1650         break;
  1651     case SDL_YUY2_OVERLAY:
  1652     case SDL_UYVY_OVERLAY:
  1653     case SDL_YVYU_OVERLAY:
  1654         break;
  1655     }
  1656     return 0;
  1657 }
  1658 
  1659 void
  1660 SDL_UnlockYUVOverlay(SDL_Overlay * overlay)
  1661 {
  1662     if (!overlay) {
  1663         return;
  1664     }
  1665     if (overlay->hwdata->sw) {
  1666         void *pixels;
  1667         int pitch;
  1668         if (SDL_LockTexture
  1669             (overlay->hwdata->textureID, NULL, 1, &pixels, &pitch) == 0) {
  1670             SDL_Rect srcrect;
  1671 
  1672             srcrect.x = 0;
  1673             srcrect.y = 0;
  1674             srcrect.w = overlay->w;
  1675             srcrect.h = overlay->h;
  1676             SDL_SW_CopyYUVToRGB(overlay->hwdata->sw, &srcrect,
  1677                                 overlay->hwdata->texture_format,
  1678                                 overlay->w, overlay->h, pixels, pitch);
  1679             SDL_UnlockTexture(overlay->hwdata->textureID);
  1680         }
  1681     } else {
  1682         SDL_UnlockTexture(overlay->hwdata->textureID);
  1683     }
  1684 }
  1685 
  1686 int
  1687 SDL_DisplayYUVOverlay(SDL_Overlay * overlay, SDL_Rect * dstrect)
  1688 {
  1689     if (!overlay || !dstrect) {
  1690         SDL_SetError("Passed a NULL overlay or dstrect");
  1691         return -1;
  1692     }
  1693     if (SDL_RenderCopy(overlay->hwdata->textureID, NULL, dstrect) < 0) {
  1694         return -1;
  1695     }
  1696     SDL_RenderPresent();
  1697     return 0;
  1698 }
  1699 
  1700 void
  1701 SDL_FreeYUVOverlay(SDL_Overlay * overlay)
  1702 {
  1703     if (!overlay) {
  1704         return;
  1705     }
  1706     if (overlay->hwdata) {
  1707         if (overlay->hwdata->textureID) {
  1708             SDL_DestroyTexture(overlay->hwdata->textureID);
  1709         }
  1710         SDL_free(overlay->hwdata);
  1711     }
  1712     SDL_free(overlay);
  1713 }
  1714 
  1715 void
  1716 SDL_GL_SwapBuffers(void)
  1717 {
  1718     SDL_GL_SwapWindow(SDL_VideoWindow);
  1719 }
  1720 
  1721 
  1722 int
  1723 SDL_EnableKeyRepeat(int delay, int interval)
  1724 {
  1725     return 0;
  1726 }
  1727 
  1728 void
  1729 SDL_GetKeyRepeat(int *delay, int *interval)
  1730 {
  1731     if (delay) {
  1732         *delay = SDL_DEFAULT_REPEAT_DELAY;
  1733     }
  1734     if (interval) {
  1735         *interval = SDL_DEFAULT_REPEAT_INTERVAL;
  1736     }
  1737 }
  1738 
  1739 int
  1740 SDL_EnableUNICODE(int enable)
  1741 {
  1742     int previous = SDL_enabled_UNICODE;
  1743 
  1744     switch (enable) {
  1745     case 1:
  1746         SDL_enabled_UNICODE = 1;
  1747         SDL_StartTextInput();
  1748         break;
  1749     case 0:
  1750         SDL_enabled_UNICODE = 0;
  1751         SDL_StopTextInput();
  1752         break;
  1753     }
  1754     return previous;
  1755 }
  1756 
  1757 /* vi: set ts=4 sw=4 expandtab: */