src/SDL12_compat.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 07 Mar 2013 22:34:19 -0500
changeset 16 ad3e9ebcfd90
parent 15 fd1b88f919e7
child 17 473158daa1de
permissions -rw-r--r--
Make the static variables not be prefixed with "SDL_"

Otherwise, I'm risking symbol clashes and confusion.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /* This file contains functions for backwards compatibility with SDL 1.2 */
    23 
    24 #include "SDL.h"
    25 
    26 #if !SDL_VERSION_ATLEAST(2,0,0)
    27 #error You need to compile against SDL 2.0 headers.
    28 #endif
    29 
    30 #include "SDL_syswm.h"
    31 
    32 #include <stdarg.h>
    33 
    34 //#include "video/SDL_sysvideo.h"
    35 //#include "video/SDL_pixels_c.h"
    36 //#include "render/SDL_yuv_sw_c.h"
    37 
    38 // !!! IMPLEMENT_ME SDL_ConvertSurface
    39 // !!! IMPLEMENT_ME SDL_CreateCursor
    40 // !!! IMPLEMENT_ME SDL_CreateThread
    41 // !!! IMPLEMENT_ME SDL_EventState
    42 // !!! IMPLEMENT_ME SDL_FillRect
    43 // !!! IMPLEMENT_ME SDL_FreeCursor
    44 // !!! IMPLEMENT_ME SDL_FreeSurface
    45 // !!! IMPLEMENT_ME SDL_GL_GetAttribute
    46 // !!! IMPLEMENT_ME SDL_GL_GetProcAddress
    47 // !!! IMPLEMENT_ME SDL_GL_LoadLibrary
    48 // !!! IMPLEMENT_ME SDL_GL_Lock
    49 // !!! IMPLEMENT_ME SDL_GL_SetAttribute
    50 // !!! IMPLEMENT_ME SDL_GL_Unlock
    51 // !!! IMPLEMENT_ME SDL_GL_UpdateRects
    52 // !!! IMPLEMENT_ME SDL_GetClipRect
    53 // !!! IMPLEMENT_ME SDL_GetCursor
    54 // !!! IMPLEMENT_ME SDL_GetEventFilter
    55 // !!! IMPLEMENT_ME SDL_GetKeyName
    56 // !!! IMPLEMENT_ME SDL_GetKeyState
    57 // !!! IMPLEMENT_ME SDL_GetModState
    58 // !!! IMPLEMENT_ME SDL_GetMouseState
    59 // !!! IMPLEMENT_ME SDL_GetRGB
    60 // !!! IMPLEMENT_ME SDL_GetRGBA
    61 // !!! IMPLEMENT_ME SDL_GetRelativeMouseState
    62 // !!! IMPLEMENT_ME SDL_LockSurface
    63 // !!! IMPLEMENT_ME SDL_LowerBlit
    64 // !!! IMPLEMENT_ME SDL_MapRGB
    65 // !!! IMPLEMENT_ME SDL_MapRGBA
    66 // !!! IMPLEMENT_ME SDL_PeepEvents
    67 // !!! IMPLEMENT_ME SDL_PollEvent
    68 // !!! IMPLEMENT_ME SDL_PumpEvents
    69 // !!! IMPLEMENT_ME SDL_PushEvent
    70 // !!! IMPLEMENT_ME SDL_SetClipRect
    71 // !!! IMPLEMENT_ME SDL_SetColorKey
    72 // !!! IMPLEMENT_ME SDL_SetCursor
    73 // !!! IMPLEMENT_ME SDL_SetEventFilter
    74 // !!! IMPLEMENT_ME SDL_SetModState
    75 // !!! IMPLEMENT_ME SDL_ShowCursor
    76 // !!! IMPLEMENT_ME SDL_SoftStretch
    77 // !!! IMPLEMENT_ME SDL_UnlockSurface
    78 // !!! IMPLEMENT_ME SDL_UpperBlit
    79 // !!! IMPLEMENT_ME SDL_WaitEvent
    80 // !!! IMPLEMENT_ME X11_KeyToUnicode
    81 
    82 
    83 #define SDL20_SYM(rc,fn,params,args,ret) \
    84     typedef rc (*SDL20_##fn##_t) params; \
    85     static SDL20_##fn##_t SDL20_##fn = NULL;
    86 #define SDL20_SYM_PASSTHROUGH(rc,fn,params,args,ret) \
    87     SDL20_SYM(rc,fn,params,args,ret)
    88 #include "SDL20_syms.h"
    89 #undef SDL20_SYM_PASSTHROUGH
    90 #undef SDL20_SYM
    91 
    92 typedef void (*SDL20_SetError_t)(const char *fmt, ...);
    93 static SDL20_SetError_t SDL20_SetError = NULL;
    94 
    95 
    96 
    97 #define SDL12_INIT_TIMER       0x00000001
    98 #define SDL12_INIT_AUDIO       0x00000010
    99 #define SDL12_INIT_VIDEO       0x00000020
   100 #define SDL12_INIT_CDROM       0x00000100
   101 #define SDL12_INIT_JOYSTICK    0x00000200
   102 #define SDL12_INIT_NOPARACHUTE 0x00100000
   103 #define SDL12_INIT_EVENTTHREAD 0x01000000
   104 #define SDL12_INIT_EVERYTHING  0x0000FFFF
   105 
   106 typedef struct SDL12_Palette
   107 {
   108     int       ncolors;
   109     SDL_Color *colors;
   110 } SDL12_Palette;
   111 
   112 typedef struct SDL12_PixelFormat
   113 {
   114     SDL12_Palette *palette;
   115     Uint8 BitsPerPixel;
   116     Uint8 BytesPerPixel;
   117     Uint8 Rloss;
   118     Uint8 Gloss;
   119     Uint8 Bloss;
   120     Uint8 Aloss;
   121     Uint8 Rshift;
   122     Uint8 Gshift;
   123     Uint8 Bshift;
   124     Uint8 Ashift;
   125     Uint32 Rmask;
   126     Uint32 Gmask;
   127     Uint32 Bmask;
   128     Uint32 Amask;
   129     Uint32 colorkey;
   130     Uint8 alpha;
   131 } SDL12_PixelFormat;
   132 
   133 typedef struct
   134 {
   135     Uint32 hw_available :1;
   136     Uint32 wm_available :1;
   137     Uint32 UnusedBits1  :6;
   138     Uint32 UnusedBits2  :1;
   139     Uint32 blit_hw      :1;
   140     Uint32 blit_hw_CC   :1;
   141     Uint32 blit_hw_A    :1;
   142     Uint32 blit_sw      :1;
   143     Uint32 blit_sw_CC   :1;
   144     Uint32 blit_sw_A    :1;
   145     Uint32 blit_fill    :1;
   146     Uint32 UnusedBits3  :16;
   147     Uint32 video_mem;
   148     SDL_PixelFormat *vfmt;
   149     int current_w;
   150     int current_h;
   151 } SDL12_VideoInfo;
   152 
   153 
   154 #define SDL12_HWSURFACE 0x00000001
   155 #define SDL12_ASYNCBLIT 0x00000004
   156 #define SDL12_ANYFORMAT 0x10000000
   157 #define SDL12_HWPALETTE 0x20000000
   158 #define SDL12_DOUBLEBUF 0x40000000
   159 #define SDL12_FULLSCREEN 0x80000000
   160 #define SDL12_OPENGL 0x00000002
   161 #define SDL12_OPENGLBLIT 0x0000000A
   162 #define SDL12_RESIZABLE 0x00000010
   163 #define SDL12_NOFRAME 0x00000020
   164 #define SDL12_HWACCEL 0x00000100
   165 #define SDL12_SRCCOLORKEY 0x00001000
   166 #define SDL12_RLEACCELOK 0x00002000
   167 #define SDL12_RLEACCEL 0x00004000
   168 #define SDL12_SRCALPHA 0x00010000
   169 #define SDL12_PREALLOC 0x01000000
   170 
   171 
   172 static SDL_Window *VideoWindow = NULL;
   173 static SDL_Surface *WindowSurface = NULL;
   174 static SDL_Surface *VideoSurface = NULL;
   175 static SDL_Surface *ShadowSurface = NULL;
   176 static SDL_Surface *PublicSurface = NULL;
   177 static SDL_GLContext *VideoContext = NULL;
   178 static Uint32 VideoFlags = 0;
   179 static SDL_Rect VideoViewport;
   180 static char *WindowTitle = NULL;
   181 static char *WindowIconTitle = NULL;
   182 static SDL_Surface *VideoIcon;
   183 static int EnabledUnicode = 0;
   184 static int VideoDisplayIndex = 0;
   185 static int CDRomInit = 0;
   186 
   187 /* Obviously we can't use SDL_LoadObject() to load SDL2.  :)  */
   188 #if defined(_WINDOWS)
   189     #define SDL20_LIBNAME "SDL2.dll"
   190     static HANDLE Loaded_SDL20 = NULL;
   191     #define LoadSDL20Library() ((Loaded_SDL20 = LoadLibraryA(SDL20_LIBNAME)) != NULL)
   192     #define LookupSDL20Sym(sym) GetProcAddress(Loaded_SDL20, sym)
   193     #define CloseSDL20Library() { { if (Loaded_SDL20) { FreeLibrary(Loaded_SDL20); Loaded_SDL20 = NULL; } }
   194 #elif defined(unix)
   195     #ifdef __APPLE__
   196     #define SDL20_LIBNAME "libSDL2.dylib"
   197     #else
   198     #define SDL20_LIBNAME "libSDL2-2.0.so.0"
   199     #endif
   200     static void *Loaded_SDL20 = NULL;
   201     #define LoadSDL20Library() ((Loaded_SDL20 = dlopen(SDL20_LIBNAME, RTLD_LOCAL)) != NULL)
   202     #define LookupSDL20Sym(sym) dlsym(Loaded_SDL20, sym)
   203     #define CloseSDL20Library() { if (Loaded_SDL20) { dlclose(Loaded_SDL20); Loaded_SDL20 = NULL; } }
   204 #else
   205     #error Please define your platform.
   206 #endif
   207 
   208 static void *
   209 LoadSDL20Symbol(const char *fn, int *okay)
   210 {
   211     void *retval = NULL;
   212     if (*okay)  /* only bother trying if we haven't previously failed. */
   213     {
   214         retval = LookupSDL20Sym(fn);
   215         if (retval == NULL)
   216             *okay = 0;
   217     }
   218     return retval;
   219 }
   220 
   221 static void
   222 UnloadSDL20(void)
   223 {
   224     #define SDL20_SYM(rc,fn,params,args,ret) SDL20_##fn = NULL;
   225     #define SDL20_SYM_PASSTHROUGH(rc,fn,params,args,ret) SDL20_##fn = NULL;
   226     #include "SDL20_syms.h"
   227     #undef SDL20_SYM_PASSTHROUGH
   228     #undef SDL20_SYM
   229     SDL20_SetError = NULL;
   230     CloseSDL20Library();
   231 }
   232 
   233 static int
   234 LoadSDL20(void)
   235 {
   236     int okay = 1;
   237     if (!Loaded_SDL20)
   238     {
   239         okay = LoadSDL20Library();
   240         #define SDL20_SYM(rc,fn,params,args,ret) SDL20_##fn = (SDL20_##fn##_t) LoadSDL20Symbol("SDL_" #fn, &okay);
   241         #define SDL20_SYM_PASSTHROUGH(rc,fn,params,args,ret) SDL20_SYM(rc,fn,params,args,ret)
   242         #include "SDL20_syms.h"
   243         #undef SDL20_SYM_PASSTHROUGH
   244         #undef SDL20_SYM
   245         SDL20_SetError = (SDL20_SetError_t) LoadSDL20Symbol("SDL_SetError", &okay);
   246         if (!okay)
   247             UnloadSDL20();
   248     }
   249     return okay;
   250 }
   251 
   252 
   253 static int
   254 GetVideoDisplay()
   255 {
   256     // !!! FIXME: cache this value during SDL_Init() so it doesn't change.
   257     const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY");
   258     if ( !variable ) {
   259         variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD");
   260     }
   261     if ( variable ) {
   262         return SDL_atoi(variable);
   263     } else {
   264         return 0;
   265     }
   266 }
   267 
   268 static int
   269 DoSDLInit(const int justsubs, Uint32 sdl12flags)
   270 {
   271     Uint32 sdl20flags = 0;
   272     int rc;
   273 
   274     if (!LoadSDL20())
   275         return -1;
   276 
   277     #define SETFLAG(x) if (sdl12flags & SDL12_INIT_##flag) sdl20flags |= SDL_INIT_##flag)
   278     SETFLAG(TIMER);
   279     SETFLAG(AUDIO);
   280     SETFLAG(VIDEO);
   281     SETFLAG(JOYSTICK);
   282     SETFLAG(NOPARACHUTE);
   283     #undef SETFLAG
   284 
   285     // There's no CDROM in 2.0, but we'll just pretend it succeeded.
   286     if (sdl12flags & SDL12_INIT_CDROM)
   287         CDRomInit = 1;
   288 
   289     // !!! FIXME: do something about SDL12_INIT_EVENTTHREAD
   290 
   291     rc = justsubs ? SDL20_InitSubSystem(sdl20flags) : SDL20_Init(sdl20flags);
   292     if ((rc == 0) && (sdl20flags & SDL_INIT_VIDEO))
   293         VideoDisplayIndex = GetVideoDisplay();
   294     return rc;
   295 }
   296 
   297 int
   298 SDL_InitSubSystem(Uint32 sdl12flags)
   299 {
   300     return DoSDLInit(1, sdl12flags);
   301 }
   302 
   303 int
   304 SDL_Init(Uint32 sdl12flags)
   305 {
   306     return DoSDLInit(0, sdl12flags);
   307 }
   308 
   309 Uint32
   310 SDL_WasInit(Uint32 sdl12flags)
   311 {
   312     // !!! FIXME: this is cut and pasted several places.
   313     Uint32 sdl20flags = 0;
   314     Uint32 extraflags = 0;
   315 
   316     #define SETFLAG(x) if (sdl12flags & SDL12_INIT_##flag) sdl20flags |= SDL_INIT_##flag)
   317     SETFLAG(TIMER);
   318     SETFLAG(AUDIO);
   319     SETFLAG(VIDEO);
   320     SETFLAG(JOYSTICK);
   321     SETFLAG(NOPARACHUTE);
   322     #undef SETFLAG
   323 
   324     if ((sdl12flags & SDL12_INIT_CDROM) && (CDRomInit))
   325         extraflags |= SDL12_INIT_CDROM;
   326 
   327     // !!! FIXME: do something about SDL12_INIT_EVENTTHREAD
   328 
   329     // !!! FIXME: convert back to 1.2
   330     return SDL20_WasInit(sdl20flags) | extraflags;
   331 }
   332 
   333 void
   334 SDL_QuitSubSystem(Uint32 sdl12flags)
   335 {
   336     Uint32 sdl20flags = 0;
   337 
   338     #define SETFLAG(x) if (sdl12flags & SDL12_INIT_##flag) sdl20flags |= SDL_INIT_##flag)
   339     SETFLAG(TIMER);
   340     SETFLAG(AUDIO);
   341     SETFLAG(VIDEO);
   342     SETFLAG(JOYSTICK);
   343     SETFLAG(NOPARACHUTE);
   344     // There's no CDROM in 2.0, but we'll just pretend it succeeded.
   345     #undef SETFLAG
   346 
   347     if (sdl12flags & SDL12_INIT_CDROM)
   348         CDRomInit = 0;
   349 
   350     // !!! FIXME: do something about SDL12_INIT_EVENTTHREAD
   351     SDL20_QuitSubSystem(sdl20flags);
   352 
   353     // !!! FIXME: UnloadSDL20() ?
   354 }
   355 
   356 void
   357 SDL_Quit(void)
   358 {
   359     CDRomInit = 0;
   360     SDL20_Quit();
   361     UnloadSDL20();
   362 }
   363 
   364 void
   365 SDL_SetError(const char *fmt, ...)
   366 {
   367     char *str = NULL;
   368     va_list ap;
   369     va_start(ap, fmt);
   370     vasprintf(&str, fmt, ap);
   371     va_end(ap);
   372     if (!str)
   373         SDL20_OutOfMemory();
   374     else
   375     {
   376         SDL20_SetError("%s", str);
   377         free(str);
   378     }
   379 }
   380 
   381 char *
   382 SDL_GetError(void)
   383 {
   384     if (!Loaded_SDL20)
   385     {
   386         static char noload_errstr[] = "Failed to load SDL 2.0 shared library";
   387         return noload_errstr;
   388     }
   389     return SDL20_GetError();
   390 }
   391 
   392 
   393 static const char *
   394 GetDriverName(const char *name, char *namebuf, int maxlen)
   395 {
   396     if (name) {
   397         if (namebuf) {
   398             SDL20_strlcpy(namebuf, name, maxlen);
   399             return namebuf;
   400         } else {
   401             return name;
   402         }
   403     }
   404     return NULL;
   405 }
   406 
   407 const char *
   408 SDL_AudioDriverName(char *namebuf, int maxlen)
   409 {
   410     return GetDriverName(SDL20_GetCurrentAudioDriver(), namebuf, maxlen);
   411 }
   412 
   413 const char *
   414 SDL_VideoDriverName(char *namebuf, int maxlen)
   415 {
   416     return GetDriverName(SDL20_GetCurrentVideoDriver(), namebuf, maxlen);
   417 }
   418 
   419 typedef struct SDL12_Surface
   420 {
   421     Uint32 flags;
   422     SDL12_PixelFormat *format;
   423     int w;
   424     int h;
   425     Uint16 pitch;
   426     void *pixels;
   427     int offset;
   428     void *hwdata;
   429     SDL_Rect clip_rect;
   430     Uint32 unused1;
   431     Uint32 locked;
   432     void *blitmap;
   433     unsigned int format_version;
   434     int refcount;
   435 } SDL12_Surface;
   436 
   437 SDL12_Surface *
   438 Surface20to12(SDL_Surface *surface20)
   439 {
   440     SDL12_Surface *surface12 = NULL;
   441     SDL12_Palette *palette12 = NULL;
   442     SDL12_PixelFormat *format12 = NULL;
   443     UInt32 flags = 0;
   444 
   445     if (!surface20)
   446         return NULL;
   447 
   448     surface12 = (SDL12_Surface *) SDL20_malloc(sizeof (SDL12_Surface));
   449     if (!surface12)
   450         goto failed;
   451 
   452     palette12 = (SDL12_Palette *) SDL20_malloc(sizeof (SDL12_Palette));
   453     if (!palette12)
   454         goto failed;
   455 
   456     format12 = (SDL12_PixelFormat *) SDL20_malloc(sizeof (SDL12_PixelFormat));
   457     if (!format12)
   458         goto failed;
   459 
   460     SDL_zerop(palette12);
   461     palette12->ncolors = surface20->palette->ncolors;
   462     palette12->colors = surface20->palette->colors;
   463 
   464     SDL_zerop(format12);
   465     format12->palette = palette12;
   466     format12->BitsPerPixel = surface20->format->BitsPerPixel;
   467     format12->BytesPerPixel = surface20->format->BytesPerPixel;
   468     format12->Rloss = surface20->format->Rloss;
   469     format12->Gloss = surface20->format->Gloss;
   470     format12->Bloss = surface20->format->Bloss;
   471     format12->Aloss = surface20->format->Aloss;
   472     format12->Rshift = surface20->format->Rshift;
   473     format12->Gshift = surface20->format->Gshift;
   474     format12->Bshift = surface20->format->Bshift;
   475     format12->Ashift = surface20->format->Ashift;
   476     format12->Rmask = surface20->format->Rmask;
   477     format12->Gmask = surface20->format->Gmask;
   478     format12->Bmask = surface20->format->Bmask;
   479     format12->Amask = surface20->format->Amask;
   480     /* !!! FIXME: format12->colorkey; */
   481     /* !!! FIXME: format12->alpha; */
   482 
   483     SDL_zerop(surface12);
   484     flags = surface20->flags;
   485     #define MAPSURFACEFLAGS(fl) { if (surface20->flags & SDL_##fl) { surface12->flags |= SDL12_##fl; flags &= ~SDL_##fl; } }
   486     MAPSURFACEFLAGS(PREALLOC);
   487     MAPSURFACEFLAGS(RLEACCEL);
   488     MAPSURFACEFLAGS(DONTFREE);
   489     #undef MAPSURFACEFLAGS
   490     SDL_assert(flags == 0);  /* non-zero if there's a flag we didn't map. */
   491 
   492     surface12->format = format12;
   493     surface12->w = surface20->w;
   494     surface12->h = surface20->h;
   495     surface12->pitch = (Uint16) surface20->pitch;  /* !!! FIXME: make sure this fits in a Uint16 */
   496     surface12->pixels = surface20->pixels;
   497     surface12->offset = 0;
   498     surface12->hwdata = surface20;
   499     SDL20_memcpy(&surface12->clip_rect, &surface20->clip_rect, sizeof (SDL_Rect));
   500     surface12->refcount = surface20->refcount;
   501 
   502     return surface12;
   503 
   504 failed:
   505     SDL20_free(surface12);
   506     SDL20_free(palette12);
   507     SDL20_free(format12);
   508     return NULL;
   509 }
   510 
   511 SDL12_Surface *
   512 SDL_CreateRGBSurface(Uint32 sdl12flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   513 {
   514     SDL_Surface *surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
   515     SDL12_Surface *surface12 = Surface20to12(surface20);
   516     if (!surface12) {
   517         SDL20_FreeSurface(surface20);
   518         return NULL;
   519     }
   520 
   521     SDL_assert(surface12->flags == 0);  // shouldn't have prealloc, rleaccel, or dontfree.
   522     return surface12;
   523 }
   524 
   525 SDL12_Surface *
   526 SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   527 {
   528     SDL_Surface *surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, Rmask, Gmask, Bmask, Amask);
   529     SDL12_Surface *surface12 = Surface20to12(surface20);
   530     if (!surface12) {
   531         SDL20_FreeSurface(surface20);
   532         return NULL;
   533     }
   534 
   535     SDL_assert(surface12->flags == SDL12_PREALLOC);  // should _only_ have prealloc.
   536     return surface12;
   537 }
   538 
   539 void SDL_FreeSurface(SDL12_Surface *surface12)
   540 {
   541     if (surface12) {
   542         SDL20_FreeSurface((SDL_Surface *) surface12->hwdata);
   543         if (surface12->format) {
   544             SDL20_free(surface12->format->palette);
   545             SDL20_free(surface12->format);
   546         }
   547         SDL20_free(surface12);
   548     }
   549 }
   550 
   551 
   552 const SDL12_VideoInfo *
   553 SDL_GetVideoInfo(void)
   554 {
   555     static SDL12_VideoInfo info;
   556     SDL_DisplayMode mode;
   557 
   558     /* !!! FIXME: Memory leak, compatibility code, who cares? */
   559     if (!info.vfmt && SDL20_GetDesktopDisplayMode(VideoDisplayIndex, &mode) == 0) {
   560         info.vfmt = SDL20_AllocFormat(mode.format);
   561         info.current_w = mode.w;
   562         info.current_h = mode.h;
   563         // !!! FIXME
   564         //info.wm_available = 1;
   565         //info.video_mem = 1024 * 256;
   566     }
   567     return &info;
   568 }
   569 
   570 int
   571 SDL_VideoModeOK(int width, int height, int bpp, Uint32 sdl12flags)
   572 {
   573     int i, nummodes, actual_bpp = 0;
   574 
   575     if (!SDL20_WasInit(SDL_INIT_VIDEO)) {
   576         return 0;
   577     }
   578 
   579     if (!(sdl12flags & SDL12_FULLSCREEN)) {
   580         SDL_DisplayMode mode;
   581         SDL20_GetDesktopDisplayMode(VideoDisplayIndex, &mode);
   582         return SDL_BITSPERPIXEL(mode.format);
   583     }
   584 
   585     nummodes = SDL20_GetNumDisplayModes(VideoDisplayIndex);
   586     for (i = 0; i < nummodes; ++i) {
   587         SDL_DisplayMode mode;
   588         SDL20_GetDisplayMode(VideoDisplayIndex, i, &mode);
   589         if (!mode.w || !mode.h || (width == mode.w && height == mode.h)) {
   590             if (!mode.format) {
   591                 return bpp;
   592             }
   593             if (SDL_BITSPERPIXEL(mode.format) >= (Uint32) bpp) {
   594                 actual_bpp = SDL_BITSPERPIXEL(mode.format);
   595             }
   596         }
   597     }
   598     return actual_bpp;
   599 }
   600 
   601 SDL_Rect **
   602 SDL_ListModes(const SDL12_PixelFormat * format, Uint32 flags)
   603 {
   604     int i, nmodes;
   605     SDL_Rect **modes;
   606 
   607     if (!SDL20_WasInit(SDL_INIT_VIDEO)) {
   608         return NULL;
   609     }
   610 
   611     if (!(flags & SDL12_FULLSCREEN)) {
   612         return (SDL_Rect **) (-1);
   613     }
   614 
   615     if (!format) {
   616         format = SDL_GetVideoInfo()->vfmt;
   617     }
   618 
   619     /* Memory leak, but this is a compatibility function, who cares? */
   620     nmodes = 0;
   621     modes = NULL;
   622     for (i = 0; i < SDL20_GetNumDisplayModes(VideoDisplayIndex); ++i) {
   623         SDL_DisplayMode mode;
   624         int bpp;
   625 
   626         SDL20_GetDisplayMode(VideoDisplayIndex, i, &mode);
   627         if (!mode.w || !mode.h) {
   628             return (SDL_Rect **) (-1);
   629         }
   630         
   631         /* Copied from src/video/SDL_pixels.c:SDL_PixelFormatEnumToMasks */
   632         if (SDL_BYTESPERPIXEL(mode.format) <= 2) {
   633             bpp = SDL_BITSPERPIXEL(mode.format);
   634         } else {
   635             bpp = SDL_BYTESPERPIXEL(mode.format) * 8;
   636         }
   637 
   638         if (bpp != format->BitsPerPixel) {
   639             continue;
   640         }
   641         if (nmodes > 0 && modes[nmodes - 1]->w == mode.w
   642             && modes[nmodes - 1]->h == mode.h) {
   643             continue;
   644         }
   645 
   646         modes = SDL_realloc(modes, (nmodes + 2) * sizeof(*modes));
   647         if (!modes) {
   648             return NULL;
   649         }
   650         modes[nmodes] = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect));
   651         if (!modes[nmodes]) {
   652             return NULL;
   653         }
   654         modes[nmodes]->x = 0;
   655         modes[nmodes]->y = 0;
   656         modes[nmodes]->w = mode.w;
   657         modes[nmodes]->h = mode.h;
   658         ++nmodes;
   659     }
   660     if (modes) {
   661         modes[nmodes] = NULL;
   662     }
   663     return modes;
   664 }
   665 
   666 static int
   667 SDL_CompatEventFilter(void *userdata, SDL_Event * event)
   668 {
   669     SDL_Event fake;
   670 
   671     switch (event->type) {
   672     case SDL_WINDOWEVENT:
   673         switch (event->window.event) {
   674         case SDL_WINDOWEVENT_EXPOSED:
   675             if (!SDL_HasEvent(SDL_VIDEOEXPOSE)) {
   676                 fake.type = SDL_VIDEOEXPOSE;
   677                 SDL_PushEvent(&fake);
   678             }
   679             break;
   680         case SDL_WINDOWEVENT_RESIZED:
   681             SDL_FlushEvent(SDL_VIDEORESIZE);
   682             /* We don't want to expose that the window width and height will
   683                be different if we don't get the desired fullscreen mode.
   684             */
   685             if (VideoWindow && !(SDL_GetWindowFlags(VideoWindow) & SDL_WINDOW_FULLSCREEN)) {
   686                 fake.type = SDL_VIDEORESIZE;
   687                 fake.resize.w = event->window.data1;
   688                 fake.resize.h = event->window.data2;
   689                 SDL_PushEvent(&fake);
   690             }
   691             break;
   692         case SDL_WINDOWEVENT_MINIMIZED:
   693             fake.type = SDL_ACTIVEEVENT;
   694             fake.active.gain = 0;
   695             fake.active.state = SDL_APPACTIVE;
   696             SDL_PushEvent(&fake);
   697             break;
   698         case SDL_WINDOWEVENT_RESTORED:
   699             fake.type = SDL_ACTIVEEVENT;
   700             fake.active.gain = 1;
   701             fake.active.state = SDL_APPACTIVE;
   702             SDL_PushEvent(&fake);
   703             break;
   704         case SDL_WINDOWEVENT_ENTER:
   705             fake.type = SDL_ACTIVEEVENT;
   706             fake.active.gain = 1;
   707             fake.active.state = SDL_APPMOUSEFOCUS;
   708             SDL_PushEvent(&fake);
   709             break;
   710         case SDL_WINDOWEVENT_LEAVE:
   711             fake.type = SDL_ACTIVEEVENT;
   712             fake.active.gain = 0;
   713             fake.active.state = SDL_APPMOUSEFOCUS;
   714             SDL_PushEvent(&fake);
   715             break;
   716         case SDL_WINDOWEVENT_FOCUS_GAINED:
   717             fake.type = SDL_ACTIVEEVENT;
   718             fake.active.gain = 1;
   719             fake.active.state = SDL_APPINPUTFOCUS;
   720             SDL_PushEvent(&fake);
   721             break;
   722         case SDL_WINDOWEVENT_FOCUS_LOST:
   723             fake.type = SDL_ACTIVEEVENT;
   724             fake.active.gain = 0;
   725             fake.active.state = SDL_APPINPUTFOCUS;
   726             SDL_PushEvent(&fake);
   727             break;
   728         case SDL_WINDOWEVENT_CLOSE:
   729             fake.type = SDL_QUIT;
   730             SDL_PushEvent(&fake);
   731             break;
   732         }
   733     case SDL_KEYDOWN:
   734     case SDL_KEYUP:
   735         {
   736             Uint32 unicode = 0;
   737             if (event->key.type == SDL_KEYDOWN && event->key.keysym.sym < 256) {
   738                 unicode = event->key.keysym.sym;
   739                 if (unicode >= 'a' && unicode <= 'z') {
   740                     int shifted = !!(event->key.keysym.mod & KMOD_SHIFT);
   741                     int capslock = !!(event->key.keysym.mod & KMOD_CAPS);
   742                     if ((shifted ^ capslock) != 0) {
   743                         unicode = SDL_toupper(unicode);
   744                     }
   745                 }
   746             }
   747             if (unicode) {
   748                 event->key.keysym.unicode = unicode;
   749             }
   750             break;
   751         }
   752     case SDL_TEXTINPUT:
   753         {
   754             /* FIXME: Generate an old style key repeat event if needed */
   755             //printf("TEXTINPUT: '%s'\n", event->text.text);
   756             break;
   757         }
   758     case SDL_MOUSEMOTION:
   759         {
   760             event->motion.x -= VideoViewport.x;
   761             event->motion.y -= VideoViewport.y;
   762             break;
   763         }
   764     case SDL_MOUSEBUTTONDOWN:
   765     case SDL_MOUSEBUTTONUP:
   766         {
   767             event->button.x -= VideoViewport.x;
   768             event->button.y -= VideoViewport.y;
   769             break;
   770         }
   771     case SDL_MOUSEWHEEL:
   772         {
   773             Uint8 button;
   774             int x, y;
   775 
   776             if (event->wheel.y == 0) {
   777                 break;
   778             }
   779 
   780             SDL_GetMouseState(&x, &y);
   781 
   782             if (event->wheel.y > 0) {
   783                 button = SDL_BUTTON_WHEELUP;
   784             } else {
   785                 button = SDL_BUTTON_WHEELDOWN;
   786             }
   787 
   788             fake.button.button = button;
   789             fake.button.x = x;
   790             fake.button.y = y;
   791             fake.button.windowID = event->wheel.windowID;
   792 
   793             fake.type = SDL_MOUSEBUTTONDOWN;
   794             fake.button.state = SDL_PRESSED;
   795             SDL_PushEvent(&fake);
   796 
   797             fake.type = SDL_MOUSEBUTTONUP;
   798             fake.button.state = SDL_RELEASED;
   799             SDL_PushEvent(&fake);
   800             break;
   801         }
   802 
   803     }
   804     return 1;
   805 }
   806 
   807 static void
   808 GetEnvironmentWindowPosition(int w, int h, int *x, int *y)
   809 {
   810     int display = VideoDisplayIndex;
   811     const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
   812     const char *center = SDL_getenv("SDL_VIDEO_CENTERED");
   813     if (window) {
   814         if (SDL_sscanf(window, "%d,%d", x, y) == 2) {
   815             return;
   816         }
   817         if (SDL_strcmp(window, "center") == 0) {
   818             center = window;
   819         }
   820     }
   821     if (center) {
   822         *x = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
   823         *y = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
   824     }
   825 }
   826 
   827 static void
   828 ClearVideoSurface()
   829 {
   830     if (ShadowSurface) {
   831         SDL_FillRect(ShadowSurface, NULL,
   832             SDL_MapRGB(ShadowSurface->format, 0, 0, 0));
   833     }
   834     SDL_FillRect(WindowSurface, NULL, 0);
   835     SDL_UpdateWindowSurface(VideoWindow);
   836 }
   837 
   838 static void
   839 SetupScreenSaver(int flags)
   840 {
   841     const char *env;
   842     SDL_bool allow_screensaver;
   843 
   844     /* Allow environment override of screensaver disable */
   845     env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
   846     if (env) {
   847         allow_screensaver = SDL_atoi(env) ? SDL_TRUE : SDL_FALSE;
   848     } else if (flags & SDL_FULLSCREEN) {
   849         allow_screensaver = SDL_FALSE;
   850     } else {
   851         allow_screensaver = SDL_TRUE;
   852     }
   853     if (allow_screensaver) {
   854         SDL_EnableScreenSaver();
   855     } else {
   856         SDL_DisableScreenSaver();
   857     }
   858 }
   859 
   860 static int
   861 SDL_ResizeVideoMode(int width, int height, int bpp, Uint32 flags)
   862 {
   863     int w, h;
   864 
   865     /* We can't resize something we don't have... */
   866     if (!VideoSurface) {
   867         return -1;
   868     }
   869 
   870     /* We probably have to recreate the window in fullscreen mode */
   871     if (flags & SDL_FULLSCREEN) {
   872         return -1;
   873     }
   874 
   875     /* I don't think there's any change we can gracefully make in flags */
   876     if (flags != VideoFlags) {
   877         return -1;
   878     }
   879     if (bpp != VideoSurface->format->BitsPerPixel) {
   880         return -1;
   881     }
   882 
   883     /* Resize the window */
   884     SDL_GetWindowSize(VideoWindow, &w, &h);
   885     if (w != width || h != height) {
   886         SDL_SetWindowSize(VideoWindow, width, height);
   887     }
   888 
   889     /* If we're in OpenGL mode, just resize the stub surface and we're done! */
   890     if (flags & SDL_OPENGL) {
   891         VideoSurface->w = width;
   892         VideoSurface->h = height;
   893         return 0;
   894     }
   895 
   896     WindowSurface = SDL_GetWindowSurface(VideoWindow);
   897     if (!WindowSurface) {
   898         return -1;
   899     }
   900     if (VideoSurface->format != WindowSurface->format) {
   901         return -1;
   902     }
   903     VideoSurface->w = width;
   904     VideoSurface->h = height;
   905     VideoSurface->pixels = WindowSurface->pixels;
   906     VideoSurface->pitch = WindowSurface->pitch;
   907     SDL_SetClipRect(VideoSurface, NULL);
   908 
   909     if (ShadowSurface) {
   910         ShadowSurface->w = width;
   911         ShadowSurface->h = height;
   912         ShadowSurface->pitch = SDL_CalculatePitch(ShadowSurface);
   913         ShadowSurface->pixels =
   914             SDL_realloc(ShadowSurface->pixels,
   915                         ShadowSurface->h * ShadowSurface->pitch);
   916         SDL_SetClipRect(ShadowSurface, NULL);
   917         SDL_InvalidateMap(ShadowSurface->map);
   918     } else {
   919         PublicSurface = VideoSurface;
   920     }
   921 
   922     ClearVideoSurface();
   923 
   924     return 0;
   925 }
   926 
   927 SDL_Surface *
   928 SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
   929 {
   930     SDL_DisplayMode desktop_mode;
   931     int display = VideoDisplayIndex;
   932     int window_x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display);
   933     int window_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display);
   934     int window_w;
   935     int window_h;
   936     Uint32 window_flags;
   937     Uint32 surface_flags;
   938 
   939     if (!SDL_GetVideoDevice()) {
   940         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) {
   941             return NULL;
   942         }
   943     }
   944 
   945     SDL_GetDesktopDisplayMode(display, &desktop_mode);
   946 
   947     if (width == 0) {
   948         width = desktop_mode.w;
   949     }
   950     if (height == 0) {
   951         height = desktop_mode.h;
   952     }
   953     if (bpp == 0) {
   954         bpp = SDL_BITSPERPIXEL(desktop_mode.format);
   955     }
   956 
   957     /* See if we can simply resize the existing window and surface */
   958     if (SDL_ResizeVideoMode(width, height, bpp, flags) == 0) {
   959         return PublicSurface;
   960     }
   961 
   962     /* Destroy existing window */
   963     PublicSurface = NULL;
   964     if (ShadowSurface) {
   965         ShadowSurface->flags &= ~SDL_DONTFREE;
   966         SDL_FreeSurface(ShadowSurface);
   967         ShadowSurface = NULL;
   968     }
   969     if (VideoSurface) {
   970         VideoSurface->flags &= ~SDL_DONTFREE;
   971         SDL_FreeSurface(VideoSurface);
   972         VideoSurface = NULL;
   973     }
   974     if (VideoContext) {
   975         /* SDL_GL_MakeCurrent(0, NULL); *//* Doesn't do anything */
   976         SDL_GL_DeleteContext(VideoContext);
   977         VideoContext = NULL;
   978     }
   979     if (VideoWindow) {
   980         SDL_GetWindowPosition(VideoWindow, &window_x, &window_y);
   981         SDL_DestroyWindow(VideoWindow);
   982     }
   983 
   984     /* Set up the event filter */
   985     if (!SDL_GetEventFilter(NULL, NULL)) {
   986         SDL_SetEventFilter(SDL_CompatEventFilter, NULL);
   987     }
   988 
   989     /* Create a new window */
   990     window_flags = SDL_WINDOW_SHOWN;
   991     if (flags & SDL_FULLSCREEN) {
   992         window_flags |= SDL_WINDOW_FULLSCREEN;
   993     }
   994     if (flags & SDL_OPENGL) {
   995         window_flags |= SDL_WINDOW_OPENGL;
   996     }
   997     if (flags & SDL_RESIZABLE) {
   998         window_flags |= SDL_WINDOW_RESIZABLE;
   999     }
  1000     if (flags & SDL_NOFRAME) {
  1001         window_flags |= SDL_WINDOW_BORDERLESS;
  1002     }
  1003     GetEnvironmentWindowPosition(width, height, &window_x, &window_y);
  1004     VideoWindow =
  1005         SDL_CreateWindow(WindowTitle, window_x, window_y, width, height,
  1006                          window_flags);
  1007     if (!VideoWindow) {
  1008         return NULL;
  1009     }
  1010     SDL_SetWindowIcon(VideoWindow, VideoIcon);
  1011 
  1012     SetupScreenSaver(flags);
  1013 
  1014     window_flags = SDL_GetWindowFlags(VideoWindow);
  1015     surface_flags = 0;
  1016     if (window_flags & SDL_WINDOW_FULLSCREEN) {
  1017         surface_flags |= SDL_FULLSCREEN;
  1018     }
  1019     if ((window_flags & SDL_WINDOW_OPENGL) && (flags & SDL_OPENGL)) {
  1020         surface_flags |= SDL_OPENGL;
  1021     }
  1022     if (window_flags & SDL_WINDOW_RESIZABLE) {
  1023         surface_flags |= SDL_RESIZABLE;
  1024     }
  1025     if (window_flags & SDL_WINDOW_BORDERLESS) {
  1026         surface_flags |= SDL_NOFRAME;
  1027     }
  1028 
  1029     VideoFlags = flags;
  1030 
  1031     /* If we're in OpenGL mode, just create a stub surface and we're done! */
  1032     if (flags & SDL_OPENGL) {
  1033         VideoContext = SDL_GL_CreateContext(VideoWindow);
  1034         if (!VideoContext) {
  1035             return NULL;
  1036         }
  1037         if (SDL_GL_MakeCurrent(VideoWindow, VideoContext) < 0) {
  1038             return NULL;
  1039         }
  1040         VideoSurface =
  1041             SDL_CreateRGBSurfaceFrom(NULL, width, height, bpp, 0, 0, 0, 0, 0);
  1042         if (!VideoSurface) {
  1043             return NULL;
  1044         }
  1045         VideoSurface->flags |= surface_flags;
  1046         PublicSurface = VideoSurface;
  1047         return PublicSurface;
  1048     }
  1049 
  1050     /* Create the screen surface */
  1051     WindowSurface = SDL_GetWindowSurface(VideoWindow);
  1052     if (!WindowSurface) {
  1053         return NULL;
  1054     }
  1055 
  1056     /* Center the public surface in the window surface */
  1057     SDL_GetWindowSize(VideoWindow, &window_w, &window_h);
  1058     VideoViewport.x = (window_w - width)/2;
  1059     VideoViewport.y = (window_h - height)/2;
  1060     VideoViewport.w = width;
  1061     VideoViewport.h = height;
  1062 
  1063     VideoSurface = SDL_CreateRGBSurfaceFrom(NULL, 0, 0, 32, 0, 0, 0, 0, 0);
  1064     VideoSurface->flags |= surface_flags;
  1065     VideoSurface->flags |= SDL_DONTFREE;
  1066     SDL_FreeFormat(VideoSurface->format);
  1067     VideoSurface->format = WindowSurface->format;
  1068     VideoSurface->format->refcount++;
  1069     VideoSurface->w = width;
  1070     VideoSurface->h = height;
  1071     VideoSurface->pitch = WindowSurface->pitch;
  1072     VideoSurface->pixels = (void *)((Uint8 *)WindowSurface->pixels +
  1073         VideoViewport.y * VideoSurface->pitch +
  1074         VideoViewport.x  * VideoSurface->format->BytesPerPixel);
  1075     SDL_SetClipRect(VideoSurface, NULL);
  1076 
  1077     /* Create a shadow surface if necessary */
  1078     if ((bpp != VideoSurface->format->BitsPerPixel)
  1079         && !(flags & SDL_ANYFORMAT)) {
  1080         ShadowSurface =
  1081             SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0);
  1082         if (!ShadowSurface) {
  1083             return NULL;
  1084         }
  1085         ShadowSurface->flags |= surface_flags;
  1086         ShadowSurface->flags |= SDL_DONTFREE;
  1087 
  1088         /* 8-bit ShadowSurface surfaces report that they have exclusive palette */
  1089         if (ShadowSurface->format->palette) {
  1090             ShadowSurface->flags |= SDL_HWPALETTE;
  1091             SDL_DitherColors(ShadowSurface->format->palette->colors,
  1092                              ShadowSurface->format->BitsPerPixel);
  1093         }
  1094         SDL_FillRect(ShadowSurface, NULL,
  1095             SDL_MapRGB(ShadowSurface->format, 0, 0, 0));
  1096     }
  1097     PublicSurface =
  1098         (ShadowSurface ? ShadowSurface : VideoSurface);
  1099 
  1100     ClearVideoSurface();
  1101 
  1102     /* We're finally done! */
  1103     return PublicSurface;
  1104 }
  1105 
  1106 SDL_Surface *
  1107 SDL_GetVideoSurface(void)
  1108 {
  1109     return PublicSurface;
  1110 }
  1111 
  1112 int
  1113 SDL_SetAlpha(SDL_Surface * surface, Uint32 flag, Uint8 value)
  1114 {
  1115     if (flag & SDL_SRCALPHA) {
  1116         /* According to the docs, value is ignored for alpha surfaces */
  1117         if (surface->format->Amask) {
  1118             value = 0xFF;
  1119         }
  1120         SDL_SetSurfaceAlphaMod(surface, value);
  1121         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
  1122     } else {
  1123         SDL_SetSurfaceAlphaMod(surface, 0xFF);
  1124         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
  1125     }
  1126     SDL_SetSurfaceRLE(surface, (flag & SDL_RLEACCEL));
  1127 
  1128     return 0;
  1129 }
  1130 
  1131 SDL_Surface *
  1132 SDL_DisplayFormat(SDL_Surface * surface)
  1133 {
  1134     SDL_PixelFormat *format;
  1135 
  1136     if (!PublicSurface) {
  1137         SDL_SetError("No video mode has been set");
  1138         return NULL;
  1139     }
  1140     format = PublicSurface->format;
  1141 
  1142     /* Set the flags appropriate for copying to display surface */
  1143     return SDL_ConvertSurface(surface, format, SDL_RLEACCEL);
  1144 }
  1145 
  1146 SDL_Surface *
  1147 SDL_DisplayFormatAlpha(SDL_Surface * surface)
  1148 {
  1149     SDL_PixelFormat *vf;
  1150     SDL_PixelFormat *format;
  1151     SDL_Surface *converted;
  1152     /* default to ARGB8888 */
  1153     Uint32 amask = 0xff000000;
  1154     Uint32 rmask = 0x00ff0000;
  1155     Uint32 gmask = 0x0000ff00;
  1156     Uint32 bmask = 0x000000ff;
  1157 
  1158     if (!PublicSurface) {
  1159         SDL_SetError("No video mode has been set");
  1160         return NULL;
  1161     }
  1162     vf = PublicSurface->format;
  1163 
  1164     switch (vf->BytesPerPixel) {
  1165     case 2:
  1166         /* For XGY5[56]5, use, AXGY8888, where {X, Y} = {R, B}.
  1167            For anything else (like ARGB4444) it doesn't matter
  1168            since we have no special code for it anyway */
  1169         if ((vf->Rmask == 0x1f) &&
  1170             (vf->Bmask == 0xf800 || vf->Bmask == 0x7c00)) {
  1171             rmask = 0xff;
  1172             bmask = 0xff0000;
  1173         }
  1174         break;
  1175 
  1176     case 3:
  1177     case 4:
  1178         /* Keep the video format, as long as the high 8 bits are
  1179            unused or alpha */
  1180         if ((vf->Rmask == 0xff) && (vf->Bmask == 0xff0000)) {
  1181             rmask = 0xff;
  1182             bmask = 0xff0000;
  1183         }
  1184         break;
  1185 
  1186     default:
  1187         /* We have no other optimised formats right now. When/if a new
  1188            optimised alpha format is written, add the converter here */
  1189         break;
  1190     }
  1191     format = SDL_AllocFormat(SDL_MasksToPixelFormatEnum(32, rmask,
  1192                                                             gmask,
  1193                                                             bmask,
  1194                                                             amask));
  1195     if (!format) {
  1196         return NULL;
  1197     }
  1198     converted = SDL_ConvertSurface(surface, format, SDL_RLEACCEL);
  1199     SDL_FreeFormat(format);
  1200     return converted;
  1201 }
  1202 
  1203 int
  1204 SDL_Flip(SDL_Surface * screen)
  1205 {
  1206     SDL_UpdateRect(screen, 0, 0, 0, 0);
  1207     return 0;
  1208 }
  1209 
  1210 void
  1211 SDL_UpdateRect(SDL_Surface * screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
  1212 {
  1213     if (screen) {
  1214         SDL_Rect rect;
  1215 
  1216         /* Fill the rectangle */
  1217         rect.x = (int) x;
  1218         rect.y = (int) y;
  1219         rect.w = (int) (w ? w : screen->w);
  1220         rect.h = (int) (h ? h : screen->h);
  1221         SDL_UpdateRects(screen, 1, &rect);
  1222     }
  1223 }
  1224 
  1225 void
  1226 SDL_UpdateRects(SDL_Surface * screen, int numrects, SDL_Rect * rects)
  1227 {
  1228     int i;
  1229 
  1230     if (screen == ShadowSurface) {
  1231         for (i = 0; i < numrects; ++i) {
  1232             SDL_BlitSurface(ShadowSurface, &rects[i], VideoSurface,
  1233                             &rects[i]);
  1234         }
  1235 
  1236         /* Fall through to video surface update */
  1237         screen = VideoSurface;
  1238     }
  1239     if (screen == VideoSurface) {
  1240         if (VideoViewport.x || VideoViewport.y) {
  1241             SDL_Rect *stackrects = SDL_stack_alloc(SDL_Rect, numrects);
  1242             SDL_Rect *stackrect;
  1243             const SDL_Rect *rect;
  1244             
  1245             /* Offset all the rectangles before updating */
  1246             for (i = 0; i < numrects; ++i) {
  1247                 rect = &rects[i];
  1248                 stackrect = &stackrects[i];
  1249                 stackrect->x = VideoViewport.x + rect->x;
  1250                 stackrect->y = VideoViewport.y + rect->y;
  1251                 stackrect->w = rect->w;
  1252                 stackrect->h = rect->h;
  1253             }
  1254             SDL_UpdateWindowSurfaceRects(VideoWindow, stackrects, numrects);
  1255             SDL_stack_free(stackrects);
  1256         } else {
  1257             SDL_UpdateWindowSurfaceRects(VideoWindow, rects, numrects);
  1258         }
  1259     }
  1260 }
  1261 
  1262 void
  1263 SDL_WM_SetCaption(const char *title, const char *icon)
  1264 {
  1265     if (WindowTitle) {
  1266         SDL_free(WindowTitle);
  1267     }
  1268     if (WindowIconTitle) {
  1269         SDL_free(WindowIconTitle);
  1270     }
  1271     WindowTitle = title ? SDL_strdup(title) : NULL;
  1272     WindowIconTitle = icon ? SDL_strdup(icon) : NULL;
  1273     SDL_SetWindowTitle(VideoWindow, WindowTitle);
  1274 }
  1275 
  1276 void
  1277 SDL_WM_GetCaption(const char **title, const char **icon)
  1278 {
  1279     if (title) {
  1280         *title = WindowTitle;
  1281     }
  1282     if (icon) {
  1283         *icon = WindowIconTitle;
  1284     }
  1285 }
  1286 
  1287 void
  1288 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
  1289 {
  1290     // !!! FIXME: free previous icon?
  1291     VideoIcon = icon;
  1292     ++VideoIcon->refcount;
  1293 }
  1294 
  1295 int
  1296 SDL_WM_IconifyWindow(void)
  1297 {
  1298     SDL_MinimizeWindow(VideoWindow);
  1299     return 0;
  1300 }
  1301 
  1302 int
  1303 SDL_WM_ToggleFullScreen(SDL_Surface * surface)
  1304 {
  1305     int length;
  1306     void *pixels;
  1307     Uint8 *src, *dst;
  1308     int row;
  1309     int window_w;
  1310     int window_h;
  1311 
  1312     if (!PublicSurface) {
  1313         SDL_SetError("SDL_SetVideoMode() hasn't been called");
  1314         return 0;
  1315     }
  1316 
  1317     /* Copy the old bits out */
  1318     length = PublicSurface->w * PublicSurface->format->BytesPerPixel;
  1319     pixels = SDL_malloc(PublicSurface->h * length);
  1320     if (pixels && PublicSurface->pixels) {
  1321         src = (Uint8*)PublicSurface->pixels;
  1322         dst = (Uint8*)pixels;
  1323         for (row = 0; row < PublicSurface->h; ++row) {
  1324             SDL_memcpy(dst, src, length);
  1325             src += PublicSurface->pitch;
  1326             dst += length;
  1327         }
  1328     }
  1329 
  1330     /* Do the physical mode switch */
  1331     if (SDL_GetWindowFlags(VideoWindow) & SDL_WINDOW_FULLSCREEN) {
  1332         if (SDL_SetWindowFullscreen(VideoWindow, 0) < 0) {
  1333             return 0;
  1334         }
  1335         PublicSurface->flags &= ~SDL_FULLSCREEN;
  1336     } else {
  1337         if (SDL_SetWindowFullscreen(VideoWindow, 1) < 0) {
  1338             return 0;
  1339         }
  1340         PublicSurface->flags |= SDL_FULLSCREEN;
  1341     }
  1342 
  1343     /* Recreate the screen surface */
  1344     WindowSurface = SDL_GetWindowSurface(VideoWindow);
  1345     if (!WindowSurface) {
  1346         /* We're totally hosed... */
  1347         return 0;
  1348     }
  1349 
  1350     /* Center the public surface in the window surface */
  1351     SDL_GetWindowSize(VideoWindow, &window_w, &window_h);
  1352     VideoViewport.x = (window_w - VideoSurface->w)/2;
  1353     VideoViewport.y = (window_h - VideoSurface->h)/2;
  1354     VideoViewport.w = VideoSurface->w;
  1355     VideoViewport.h = VideoSurface->h;
  1356 
  1357     /* Do some shuffling behind the application's back if format changes */
  1358     if (VideoSurface->format->format != WindowSurface->format->format) {
  1359         if (ShadowSurface) {
  1360             if (ShadowSurface->format->format == WindowSurface->format->format) {
  1361                 /* Whee!  We don't need a shadow surface anymore! */
  1362                 VideoSurface->flags &= ~SDL_DONTFREE;
  1363                 SDL_FreeSurface(VideoSurface);
  1364                 SDL_free(ShadowSurface->pixels);
  1365                 VideoSurface = ShadowSurface;
  1366                 VideoSurface->flags |= SDL_PREALLOC;
  1367                 ShadowSurface = NULL;
  1368             } else {
  1369                 /* No problem, just change the video surface format */
  1370                 SDL_FreeFormat(VideoSurface->format);
  1371                 VideoSurface->format = WindowSurface->format;
  1372                 VideoSurface->format->refcount++;
  1373                 SDL_InvalidateMap(ShadowSurface->map);
  1374             }
  1375         } else {
  1376             /* We can make the video surface the shadow surface */
  1377             ShadowSurface = VideoSurface;
  1378             ShadowSurface->pitch = SDL_CalculatePitch(ShadowSurface);
  1379             ShadowSurface->pixels = SDL_malloc(ShadowSurface->h * ShadowSurface->pitch);
  1380             if (!ShadowSurface->pixels) {
  1381                 /* Uh oh, we're hosed */
  1382                 ShadowSurface = NULL;
  1383                 return 0;
  1384             }
  1385             ShadowSurface->flags &= ~SDL_PREALLOC;
  1386 
  1387             VideoSurface = SDL_CreateRGBSurfaceFrom(NULL, 0, 0, 32, 0, 0, 0, 0, 0);
  1388             VideoSurface->flags = ShadowSurface->flags;
  1389             VideoSurface->flags |= SDL_PREALLOC;
  1390             SDL_FreeFormat(VideoSurface->format);
  1391             VideoSurface->format = WindowSurface->format;
  1392             VideoSurface->format->refcount++;
  1393             VideoSurface->w = ShadowSurface->w;
  1394             VideoSurface->h = ShadowSurface->h;
  1395         }
  1396     }
  1397 
  1398     /* Update the video surface */
  1399     VideoSurface->pitch = WindowSurface->pitch;
  1400     VideoSurface->pixels = (void *)((Uint8 *)WindowSurface->pixels +
  1401         VideoViewport.y * VideoSurface->pitch +
  1402         VideoViewport.x  * VideoSurface->format->BytesPerPixel);
  1403     SDL_SetClipRect(VideoSurface, NULL);
  1404 
  1405     /* Copy the old bits back */
  1406     if (pixels) {
  1407         src = (Uint8*)pixels;
  1408         dst = (Uint8*)PublicSurface->pixels;
  1409         for (row = 0; row < PublicSurface->h; ++row) {
  1410             SDL_memcpy(dst, src, length);
  1411             src += length;
  1412             dst += PublicSurface->pitch;
  1413         }
  1414         SDL_Flip(PublicSurface);
  1415         SDL_free(pixels);
  1416     }
  1417 
  1418     /* We're done! */
  1419     return 1;
  1420 }
  1421 
  1422 SDL_GrabMode
  1423 SDL_WM_GrabInput(SDL_GrabMode mode)
  1424 {
  1425     if (mode != SDL_GRAB_QUERY) {
  1426         SDL_SetWindowGrab(VideoWindow, mode);
  1427     }
  1428     return (SDL_GrabMode) SDL_GetWindowGrab(VideoWindow);
  1429 }
  1430 
  1431 void
  1432 SDL_WarpMouse(Uint16 x, Uint16 y)
  1433 {
  1434     SDL_WarpMouseInWindow(VideoWindow, x, y);
  1435 }
  1436 
  1437 Uint8
  1438 SDL_GetAppState(void)
  1439 {
  1440     Uint8 state = 0;
  1441     Uint32 flags = 0;
  1442 
  1443     flags = SDL_GetWindowFlags(VideoWindow);
  1444     if ((flags & SDL_WINDOW_SHOWN) && !(flags & SDL_WINDOW_MINIMIZED)) {
  1445         state |= SDL_APPACTIVE;
  1446     }
  1447     if (flags & SDL_WINDOW_INPUT_FOCUS) {
  1448         state |= SDL_APPINPUTFOCUS;
  1449     }
  1450     if (flags & SDL_WINDOW_MOUSE_FOCUS) {
  1451         state |= SDL_APPMOUSEFOCUS;
  1452     }
  1453     return state;
  1454 }
  1455 
  1456 const SDL_version *
  1457 SDL_Linked_Version(void)
  1458 {
  1459     static SDL_version version;
  1460     SDL_VERSION(&version);
  1461     return &version;
  1462 }
  1463 
  1464 int
  1465 SDL_SetPalette(SDL_Surface * surface, int flags, const SDL_Color * colors,
  1466                int firstcolor, int ncolors)
  1467 {
  1468     return SDL_SetColors(surface, colors, firstcolor, ncolors);
  1469 }
  1470 
  1471 int
  1472 SDL_SetColors(SDL_Surface * surface, const SDL_Color * colors, int firstcolor,
  1473               int ncolors)
  1474 {
  1475     if (SDL_SetPaletteColors
  1476         (surface->format->palette, colors, firstcolor, ncolors) == 0) {
  1477         return 1;
  1478     } else {
  1479         return 0;
  1480     }
  1481 }
  1482 
  1483 int
  1484 SDL_GetWMInfo(SDL_SysWMinfo * info)
  1485 {
  1486     return SDL_GetWindowWMInfo(VideoWindow, info);
  1487 }
  1488 
  1489 #if 0
  1490 void
  1491 SDL_MoveCursor(int x, int y)
  1492 {
  1493     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1494 
  1495     /* Erase and update the current mouse position */
  1496     if (SHOULD_DRAWCURSOR(SDL_cursorstate)) {
  1497         /* Erase and redraw mouse cursor in new position */
  1498         SDL_LockCursor();
  1499         SDL_EraseCursor(VideoSurface);
  1500         SDL_cursor->area.x = (x - SDL_cursor->hot_x);
  1501         SDL_cursor->area.y = (y - SDL_cursor->hot_y);
  1502         SDL_DrawCursor(VideoSurface);
  1503         SDL_UnlockCursor();
  1504     } else if (_this->MoveWMCursor) {
  1505         _this->MoveWMCursor(_this, x, y);
  1506     }
  1507 }
  1508 
  1509 /* Keep track of the current cursor colors */
  1510 static int palette_changed = 1;
  1511 static Uint8 pixels8[2];
  1512 
  1513 void
  1514 SDL_CursorPaletteChanged(void)
  1515 {
  1516     palette_changed = 1;
  1517 }
  1518 
  1519 void
  1520 SDL_MouseRect(SDL_Rect * area)
  1521 {
  1522     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1523     int clip_diff;
  1524 
  1525     *area = SDL_cursor->area;
  1526     if (area->x < 0) {
  1527         area->w += area->x;
  1528         area->x = 0;
  1529     }
  1530     if (area->y < 0) {
  1531         area->h += area->y;
  1532         area->y = 0;
  1533     }
  1534     clip_diff = (area->x + area->w) - VideoSurface->w;
  1535     if (clip_diff > 0) {
  1536         area->w = area->w < clip_diff ? 0 : area->w - clip_diff;
  1537     }
  1538     clip_diff = (area->y + area->h) - VideoSurface->h;
  1539     if (clip_diff > 0) {
  1540         area->h = area->h < clip_diff ? 0 : area->h - clip_diff;
  1541     }
  1542 }
  1543 
  1544 static void
  1545 SDL_DrawCursorFast(SDL_Surface * screen, SDL_Rect * area)
  1546 {
  1547     const Uint32 pixels[2] = { 0xFFFFFFFF, 0x00000000 };
  1548     int i, w, h;
  1549     Uint8 *data, datab;
  1550     Uint8 *mask, maskb;
  1551 
  1552     data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
  1553     mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
  1554     switch (screen->format->BytesPerPixel) {
  1555 
  1556     case 1:
  1557         {
  1558             Uint8 *dst;
  1559             int dstskip;
  1560 
  1561             if (palette_changed) {
  1562                 pixels8[0] =
  1563                     (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
  1564                 pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
  1565                 palette_changed = 0;
  1566             }
  1567             dst = (Uint8 *) screen->pixels +
  1568                 (SDL_cursor->area.y + area->y) * screen->pitch +
  1569                 SDL_cursor->area.x;
  1570             dstskip = screen->pitch - area->w;
  1571 
  1572             for (h = area->h; h; h--) {
  1573                 for (w = area->w / 8; w; w--) {
  1574                     maskb = *mask++;
  1575                     datab = *data++;
  1576                     for (i = 0; i < 8; ++i) {
  1577                         if (maskb & 0x80) {
  1578                             *dst = pixels8[datab >> 7];
  1579                         }
  1580                         maskb <<= 1;
  1581                         datab <<= 1;
  1582                         dst++;
  1583                     }
  1584                 }
  1585                 dst += dstskip;
  1586             }
  1587         }
  1588         break;
  1589 
  1590     case 2:
  1591         {
  1592             Uint16 *dst;
  1593             int dstskip;
  1594 
  1595             dst = (Uint16 *) screen->pixels +
  1596                 (SDL_cursor->area.y + area->y) * screen->pitch / 2 +
  1597                 SDL_cursor->area.x;
  1598             dstskip = (screen->pitch / 2) - area->w;
  1599 
  1600             for (h = area->h; h; h--) {
  1601                 for (w = area->w / 8; w; w--) {
  1602                     maskb = *mask++;
  1603                     datab = *data++;
  1604                     for (i = 0; i < 8; ++i) {
  1605                         if (maskb & 0x80) {
  1606                             *dst = (Uint16) pixels[datab >> 7];
  1607                         }
  1608                         maskb <<= 1;
  1609                         datab <<= 1;
  1610                         dst++;
  1611                     }
  1612                 }
  1613                 dst += dstskip;
  1614             }
  1615         }
  1616         break;
  1617 
  1618     case 3:
  1619         {
  1620             Uint8 *dst;
  1621             int dstskip;
  1622 
  1623             dst = (Uint8 *) screen->pixels +
  1624                 (SDL_cursor->area.y + area->y) * screen->pitch +
  1625                 SDL_cursor->area.x * 3;
  1626             dstskip = screen->pitch - area->w * 3;
  1627 
  1628             for (h = area->h; h; h--) {
  1629                 for (w = area->w / 8; w; w--) {
  1630                     maskb = *mask++;
  1631                     datab = *data++;
  1632                     for (i = 0; i < 8; ++i) {
  1633                         if (maskb & 0x80) {
  1634                             SDL_memset(dst, pixels[datab >> 7], 3);
  1635                         }
  1636                         maskb <<= 1;
  1637                         datab <<= 1;
  1638                         dst += 3;
  1639                     }
  1640                 }
  1641                 dst += dstskip;
  1642             }
  1643         }
  1644         break;
  1645 
  1646     case 4:
  1647         {
  1648             Uint32 *dst;
  1649             int dstskip;
  1650 
  1651             dst = (Uint32 *) screen->pixels +
  1652                 (SDL_cursor->area.y + area->y) * screen->pitch / 4 +
  1653                 SDL_cursor->area.x;
  1654             dstskip = (screen->pitch / 4) - area->w;
  1655 
  1656             for (h = area->h; h; h--) {
  1657                 for (w = area->w / 8; w; w--) {
  1658                     maskb = *mask++;
  1659                     datab = *data++;
  1660                     for (i = 0; i < 8; ++i) {
  1661                         if (maskb & 0x80) {
  1662                             *dst = pixels[datab >> 7];
  1663                         }
  1664                         maskb <<= 1;
  1665                         datab <<= 1;
  1666                         dst++;
  1667                     }
  1668                 }
  1669                 dst += dstskip;
  1670             }
  1671         }
  1672         break;
  1673     }
  1674 }
  1675 
  1676 static void
  1677 SDL_DrawCursorSlow(SDL_Surface * screen, SDL_Rect * area)
  1678 {
  1679     const Uint32 pixels[2] = { 0xFFFFFF, 0x000000 };
  1680     int h;
  1681     int x, minx, maxx;
  1682     Uint8 *data, datab = 0;
  1683     Uint8 *mask, maskb = 0;
  1684     Uint8 *dst;
  1685     int dstbpp, dstskip;
  1686 
  1687     data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
  1688     mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
  1689     dstbpp = screen->format->BytesPerPixel;
  1690     dst = (Uint8 *) screen->pixels +
  1691         (SDL_cursor->area.y + area->y) * screen->pitch +
  1692         SDL_cursor->area.x * dstbpp;
  1693     dstskip = screen->pitch - SDL_cursor->area.w * dstbpp;
  1694 
  1695     minx = area->x;
  1696     maxx = area->x + area->w;
  1697     if (screen->format->BytesPerPixel == 1) {
  1698         if (palette_changed) {
  1699             pixels8[0] = (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
  1700             pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
  1701             palette_changed = 0;
  1702         }
  1703         for (h = area->h; h; h--) {
  1704             for (x = 0; x < SDL_cursor->area.w; ++x) {
  1705                 if ((x % 8) == 0) {
  1706                     maskb = *mask++;
  1707                     datab = *data++;
  1708                 }
  1709                 if ((x >= minx) && (x < maxx)) {
  1710                     if (maskb & 0x80) {
  1711                         SDL_memset(dst, pixels8[datab >> 7], dstbpp);
  1712                     }
  1713                 }
  1714                 maskb <<= 1;
  1715                 datab <<= 1;
  1716                 dst += dstbpp;
  1717             }
  1718             dst += dstskip;
  1719         }
  1720     } else {
  1721         for (h = area->h; h; h--) {
  1722             for (x = 0; x < SDL_cursor->area.w; ++x) {
  1723                 if ((x % 8) == 0) {
  1724                     maskb = *mask++;
  1725                     datab = *data++;
  1726                 }
  1727                 if ((x >= minx) && (x < maxx)) {
  1728                     if (maskb & 0x80) {
  1729                         SDL_memset(dst, pixels[datab >> 7], dstbpp);
  1730                     }
  1731                 }
  1732                 maskb <<= 1;
  1733                 datab <<= 1;
  1734                 dst += dstbpp;
  1735             }
  1736             dst += dstskip;
  1737         }
  1738     }
  1739 }
  1740 
  1741 /* This handles the ugly work of converting the saved cursor background from
  1742    the pixel format of the shadow surface to that of the video surface.
  1743    This is only necessary when blitting from a shadow surface of a different
  1744    pixel format than the video surface, and using a software rendered cursor.
  1745 */
  1746 static void
  1747 SDL_ConvertCursorSave(SDL_Surface * screen, int w, int h)
  1748 {
  1749     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1750     SDL_BlitInfo info;
  1751     SDL_loblit RunBlit;
  1752 
  1753     /* Make sure we can steal the blit mapping */
  1754     if (screen->map->dst != VideoSurface) {
  1755         return;
  1756     }
  1757 
  1758     /* Set up the blit information */
  1759     info.s_pixels = SDL_cursor->save[1];
  1760     info.s_width = w;
  1761     info.s_height = h;
  1762     info.s_skip = 0;
  1763     info.d_pixels = SDL_cursor->save[0];
  1764     info.d_width = w;
  1765     info.d_height = h;
  1766     info.d_skip = 0;
  1767     info.aux_data = screen->map->sw_data->aux_data;
  1768     info.src = screen->format;
  1769     info.table = screen->map->table;
  1770     info.dst = VideoSurface->format;
  1771     RunBlit = screen->map->sw_data->blit;
  1772 
  1773     /* Run the actual software blit */
  1774     RunBlit(&info);
  1775 }
  1776 
  1777 void
  1778 SDL_DrawCursorNoLock(SDL_Surface * screen)
  1779 {
  1780     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1781     SDL_Rect area;
  1782 
  1783     /* Get the mouse rectangle, clipped to the screen */
  1784     SDL_MouseRect(&area);
  1785     if ((area.w == 0) || (area.h == 0)) {
  1786         return;
  1787     }
  1788 
  1789     /* Copy mouse background */
  1790     {
  1791         int w, h, screenbpp;
  1792         Uint8 *src, *dst;
  1793 
  1794         /* Set up the copy pointers */
  1795         screenbpp = screen->format->BytesPerPixel;
  1796         if ((screen == VideoSurface) ||
  1797             FORMAT_EQUAL(screen->format, VideoSurface->format)) {
  1798             dst = SDL_cursor->save[0];
  1799         } else {
  1800             dst = SDL_cursor->save[1];
  1801         }
  1802         src = (Uint8 *) screen->pixels + area.y * screen->pitch +
  1803             area.x * screenbpp;
  1804 
  1805         /* Perform the copy */
  1806         w = area.w * screenbpp;
  1807         h = area.h;
  1808         while (h--) {
  1809             SDL_memcpy(dst, src, w);
  1810             dst += w;
  1811             src += screen->pitch;
  1812         }
  1813     }
  1814 
  1815     /* Draw the mouse cursor */
  1816     area.x -= SDL_cursor->area.x;
  1817     area.y -= SDL_cursor->area.y;
  1818     if ((area.x == 0) && (area.w == SDL_cursor->area.w)) {
  1819         SDL_DrawCursorFast(screen, &area);
  1820     } else {
  1821         SDL_DrawCursorSlow(screen, &area);
  1822     }
  1823 }
  1824 
  1825 void
  1826 SDL_DrawCursor(SDL_Surface * screen)
  1827 {
  1828     /* Lock the screen if necessary */
  1829     if (screen == NULL) {
  1830         return;
  1831     }
  1832     if (SDL_MUSTLOCK(screen)) {
  1833         if (SDL_LockSurface(screen) < 0) {
  1834             return;
  1835         }
  1836     }
  1837 
  1838     SDL_DrawCursorNoLock(screen);
  1839 
  1840     /* Unlock the screen and update if necessary */
  1841     if (SDL_MUSTLOCK(screen)) {
  1842         SDL_UnlockSurface(screen);
  1843     }
  1844     if (screen->flags & SDL_SCREEN_SURFACE) {
  1845         SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1846         SDL_Window *window;
  1847         SDL_Rect area;
  1848 
  1849         window = SDL_GetWindowFromSurface(screen);
  1850         if (!window) {
  1851             return;
  1852         }
  1853 
  1854         SDL_MouseRect(&area);
  1855 
  1856         if (_this->UpdateWindowSurface) {
  1857             _this->UpdateWindowSurface(_this, window, 1, &area);
  1858         }
  1859     }
  1860 }
  1861 
  1862 void
  1863 SDL_EraseCursorNoLock(SDL_Surface * screen)
  1864 {
  1865     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1866     SDL_Window *window;
  1867     SDL_Rect area;
  1868 
  1869     /* Get the window associated with the surface */
  1870     window = SDL_GetWindowFromSurface(screen);
  1871     if (!window || !window->surface) {
  1872         return;
  1873     }
  1874 
  1875     /* Get the mouse rectangle, clipped to the screen */
  1876     SDL_MouseRect(&area);
  1877     if ((area.w == 0) || (area.h == 0)) {
  1878         return;
  1879     }
  1880 
  1881     /* Copy mouse background */
  1882     {
  1883         int w, h, screenbpp;
  1884         Uint8 *src, *dst;
  1885 
  1886         /* Set up the copy pointers */
  1887         screenbpp = screen->format->BytesPerPixel;
  1888         if ((screen->flags & SDL_SCREEN_SURFACE) ||
  1889             FORMAT_EQUAL(screen->format, window->surface->format)) {
  1890             src = SDL_cursor->save[0];
  1891         } else {
  1892             src = SDL_cursor->save[1];
  1893         }
  1894         dst = (Uint8 *) screen->pixels + area.y * screen->pitch +
  1895             area.x * screenbpp;
  1896 
  1897         /* Perform the copy */
  1898         w = area.w * screenbpp;
  1899         h = area.h;
  1900         while (h--) {
  1901             SDL_memcpy(dst, src, w);
  1902             src += w;
  1903             dst += screen->pitch;
  1904         }
  1905 
  1906         /* Perform pixel conversion on cursor background */
  1907         if (src > SDL_cursor->save[1]) {
  1908             SDL_ConvertCursorSave(screen, area.w, area.h);
  1909         }
  1910     }
  1911 }
  1912 
  1913 void
  1914 SDL_EraseCursor(SDL_Surface * screen)
  1915 {
  1916     /* Lock the screen if necessary */
  1917     if (screen == NULL) {
  1918         return;
  1919     }
  1920     if (SDL_MUSTLOCK(screen)) {
  1921         if (SDL_LockSurface(screen) < 0) {
  1922             return;
  1923         }
  1924     }
  1925 
  1926     SDL_EraseCursorNoLock(screen);
  1927 
  1928     /* Unlock the screen and update if necessary */
  1929     if (SDL_MUSTLOCK(screen)) {
  1930         SDL_UnlockSurface(screen);
  1931     }
  1932     if (screen->flags & SDL_SCREEN_SURFACE) {
  1933         SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1934         SDL_Window *window;
  1935         SDL_Rect area;
  1936 
  1937         window = SDL_GetWindowFromSurface(screen);
  1938         if (!window) {
  1939             return;
  1940         }
  1941 
  1942         SDL_MouseRect(&area);
  1943 
  1944         if (_this->UpdateWindowSurface) {
  1945             _this->UpdateWindowSurface(_this, window, 1, &area);
  1946         }
  1947     }
  1948 }
  1949 
  1950 /* Reset the cursor on video mode change
  1951    FIXME:  Keep track of all cursors, and reset them all.
  1952  */
  1953 void
  1954 SDL_ResetCursor(void)
  1955 {
  1956     int savelen;
  1957 
  1958     if (SDL_cursor) {
  1959         savelen = SDL_cursor->area.w * 4 * SDL_cursor->area.h;
  1960         SDL_cursor->area.x = 0;
  1961         SDL_cursor->area.y = 0;
  1962         SDL_memset(SDL_cursor->save[0], 0, savelen);
  1963     }
  1964 }
  1965 #endif
  1966 
  1967 struct private_yuvhwdata
  1968 {
  1969     SDL_SW_YUVTexture *texture;
  1970     SDL_Surface *display;
  1971     Uint32 display_format;
  1972 };
  1973 
  1974 SDL_Overlay *
  1975 SDL_CreateYUVOverlay(int w, int h, Uint32 format, SDL_Surface * display)
  1976 {
  1977     SDL_Overlay *overlay;
  1978     Uint32 texture_format;
  1979     SDL_SW_YUVTexture *texture;
  1980 
  1981     if ((display->flags & SDL_OPENGL) == SDL_OPENGL) {
  1982         SDL_SetError("YUV overlays are not supported in OpenGL mode");
  1983         return NULL;
  1984     }
  1985 
  1986     if (display != PublicSurface) {
  1987         SDL_SetError("YUV display is only supported on the screen surface");
  1988         return NULL;
  1989     }
  1990 
  1991     switch (format) {
  1992     case SDL_YV12_OVERLAY:
  1993         texture_format = SDL_PIXELFORMAT_YV12;
  1994         break;
  1995     case SDL_IYUV_OVERLAY:
  1996         texture_format = SDL_PIXELFORMAT_IYUV;
  1997         break;
  1998     case SDL_YUY2_OVERLAY:
  1999         texture_format = SDL_PIXELFORMAT_YUY2;
  2000         break;
  2001     case SDL_UYVY_OVERLAY:
  2002         texture_format = SDL_PIXELFORMAT_UYVY;
  2003         break;
  2004     case SDL_YVYU_OVERLAY:
  2005         texture_format = SDL_PIXELFORMAT_YVYU;
  2006         break;
  2007     default:
  2008         SDL_SetError("Unknown YUV format");
  2009         return NULL;
  2010     }
  2011 
  2012     overlay = (SDL_Overlay *) SDL_malloc(sizeof(*overlay));
  2013     if (!overlay) {
  2014         SDL_OutOfMemory();
  2015         return NULL;
  2016     }
  2017     SDL_zerop(overlay);
  2018 
  2019     overlay->hwdata =
  2020         (struct private_yuvhwdata *) SDL_malloc(sizeof(*overlay->hwdata));
  2021     if (!overlay->hwdata) {
  2022         SDL_free(overlay);
  2023         SDL_OutOfMemory();
  2024         return NULL;
  2025     }
  2026 
  2027     texture = SDL_SW_CreateYUVTexture(texture_format, w, h);
  2028     if (!texture) {
  2029         SDL_free(overlay->hwdata);
  2030         SDL_free(overlay);
  2031         return NULL;
  2032     }
  2033     overlay->hwdata->texture = texture;
  2034     overlay->hwdata->display = NULL;
  2035     overlay->hwdata->display_format = SDL_PIXELFORMAT_UNKNOWN;
  2036 
  2037     overlay->format = format;
  2038     overlay->w = w;
  2039     overlay->h = h;
  2040     if (format == SDL_YV12_OVERLAY || format == SDL_IYUV_OVERLAY) {
  2041         overlay->planes = 3;
  2042     } else {
  2043         overlay->planes = 1;
  2044     }
  2045     overlay->pitches = texture->pitches;
  2046     overlay->pixels = texture->planes;
  2047 
  2048     return overlay;
  2049 }
  2050 
  2051 int
  2052 SDL_LockYUVOverlay(SDL_Overlay * overlay)
  2053 {
  2054     SDL_Rect rect;
  2055     void *pixels;
  2056     int pitch;
  2057 
  2058     if (!overlay) {
  2059         SDL_SetError("Passed a NULL overlay");
  2060         return -1;
  2061     }
  2062 
  2063     rect.x = 0;
  2064     rect.y = 0;
  2065     rect.w = overlay->w;
  2066     rect.h = overlay->h;
  2067 
  2068     if (SDL_SW_LockYUVTexture(overlay->hwdata->texture, &rect, &pixels, &pitch) < 0) {
  2069         return -1;
  2070     }
  2071 
  2072     overlay->pixels[0] = (Uint8 *) pixels;
  2073     overlay->pitches[0] = pitch;
  2074     switch (overlay->format) {
  2075     case SDL_YV12_OVERLAY:
  2076     case SDL_IYUV_OVERLAY:
  2077         overlay->pitches[1] = pitch / 2;
  2078         overlay->pitches[2] = pitch / 2;
  2079         overlay->pixels[1] =
  2080             overlay->pixels[0] + overlay->pitches[0] * overlay->h;
  2081         overlay->pixels[2] =
  2082             overlay->pixels[1] + overlay->pitches[1] * overlay->h / 2;
  2083         break;
  2084     case SDL_YUY2_OVERLAY:
  2085     case SDL_UYVY_OVERLAY:
  2086     case SDL_YVYU_OVERLAY:
  2087         break;
  2088     }
  2089     return 0;
  2090 }
  2091 
  2092 void
  2093 SDL_UnlockYUVOverlay(SDL_Overlay * overlay)
  2094 {
  2095     if (!overlay) {
  2096         return;
  2097     }
  2098 
  2099     SDL_SW_UnlockYUVTexture(overlay->hwdata->texture);
  2100 }
  2101 
  2102 int
  2103 SDL_DisplayYUVOverlay(SDL_Overlay * overlay, SDL_Rect * dstrect)
  2104 {
  2105     SDL_Surface *display;
  2106     SDL_Rect src_rect;
  2107     SDL_Rect dst_rect;
  2108     void *pixels;
  2109 
  2110     if (!overlay || !dstrect) {
  2111         SDL_SetError("Passed a NULL overlay or dstrect");
  2112         return -1;
  2113     }
  2114 
  2115     display = overlay->hwdata->display;
  2116     if (display != VideoSurface) {
  2117         overlay->hwdata->display = display = VideoSurface;
  2118         overlay->hwdata->display_format = SDL_MasksToPixelFormatEnum(
  2119                                                 display->format->BitsPerPixel,
  2120                                                 display->format->Rmask,
  2121                                                 display->format->Gmask,
  2122                                                 display->format->Bmask,
  2123                                                 display->format->Amask);
  2124     }
  2125 
  2126     src_rect.x = 0;
  2127     src_rect.y = 0;
  2128     src_rect.w = overlay->w;
  2129     src_rect.h = overlay->h;
  2130 
  2131     if (!SDL_IntersectRect(&display->clip_rect, dstrect, &dst_rect)) {
  2132         return 0;
  2133     }
  2134      
  2135     pixels = (void *)((Uint8 *)display->pixels +
  2136                         dst_rect.y * display->pitch +
  2137                         dst_rect.x * display->format->BytesPerPixel);
  2138 
  2139     if (SDL_SW_CopyYUVToRGB(overlay->hwdata->texture, &src_rect,
  2140                             overlay->hwdata->display_format,
  2141                             dst_rect.w, dst_rect.h,
  2142                             pixels, display->pitch) < 0) {
  2143         return -1;
  2144     }
  2145     SDL_UpdateWindowSurface(VideoWindow);
  2146     return 0;
  2147 }
  2148 
  2149 void
  2150 SDL_FreeYUVOverlay(SDL_Overlay * overlay)
  2151 {
  2152     if (!overlay) {
  2153         return;
  2154     }
  2155     if (overlay->hwdata) {
  2156         if (overlay->hwdata->texture) {
  2157             SDL_SW_DestroyYUVTexture(overlay->hwdata->texture);
  2158         }
  2159         SDL_free(overlay->hwdata);
  2160     }
  2161     SDL_free(overlay);
  2162 }
  2163 
  2164 void
  2165 SDL_GL_SwapBuffers(void)
  2166 {
  2167     SDL_GL_SwapWindow(VideoWindow);
  2168 }
  2169 
  2170 int
  2171 SDL_SetGamma(float red, float green, float blue)
  2172 {
  2173     Uint16 red_ramp[256];
  2174     Uint16 green_ramp[256];
  2175     Uint16 blue_ramp[256];
  2176 
  2177     SDL_CalculateGammaRamp(red, red_ramp);
  2178     if (green == red) {
  2179         SDL_memcpy(green_ramp, red_ramp, sizeof(red_ramp));
  2180     } else {
  2181         SDL_CalculateGammaRamp(green, green_ramp);
  2182     }
  2183     if (blue == red) {
  2184         SDL_memcpy(blue_ramp, red_ramp, sizeof(red_ramp));
  2185     } else {
  2186         SDL_CalculateGammaRamp(blue, blue_ramp);
  2187     }
  2188     return SDL_SetWindowGammaRamp(VideoWindow, red_ramp, green_ramp, blue_ramp);
  2189 }
  2190 
  2191 int
  2192 SDL_SetGammaRamp(const Uint16 * red, const Uint16 * green, const Uint16 * blue)
  2193 {
  2194     return SDL_SetWindowGammaRamp(VideoWindow, red, green, blue);
  2195 }
  2196 
  2197 int
  2198 SDL_GetGammaRamp(Uint16 * red, Uint16 * green, Uint16 * blue)
  2199 {
  2200     return SDL_GetWindowGammaRamp(VideoWindow, red, green, blue);
  2201 }
  2202 
  2203 int
  2204 SDL_EnableKeyRepeat(int delay, int interval)
  2205 {
  2206     return 0;
  2207 }
  2208 
  2209 void
  2210 SDL_GetKeyRepeat(int *delay, int *interval)
  2211 {
  2212     if (delay) {
  2213         *delay = SDL_DEFAULT_REPEAT_DELAY;
  2214     }
  2215     if (interval) {
  2216         *interval = SDL_DEFAULT_REPEAT_INTERVAL;
  2217     }
  2218 }
  2219 
  2220 int
  2221 SDL_EnableUNICODE(int enable)
  2222 {
  2223     int previous = EnabledUnicode;
  2224 
  2225     switch (enable) {
  2226     case 1:
  2227         EnabledUnicode = 1;
  2228         SDL_StartTextInput();
  2229         break;
  2230     case 0:
  2231         EnabledUnicode = 0;
  2232         SDL_StopTextInput();
  2233         break;
  2234     }
  2235     return previous;
  2236 }
  2237 
  2238 static Uint32
  2239 SDL_SetTimerCallback(Uint32 interval, void* param)
  2240 {
  2241     return ((SDL_OldTimerCallback)param)(interval);
  2242 }
  2243 
  2244 int
  2245 SDL_SetTimer(Uint32 interval, SDL_OldTimerCallback callback)
  2246 {
  2247     static SDL_TimerID compat_timer;
  2248 
  2249     if (compat_timer) {
  2250         SDL20_RemoveTimer(compat_timer);
  2251         compat_timer = 0;
  2252     }
  2253 
  2254     if (interval && callback) {
  2255         compat_timer = SDL20_AddTimer(interval, SDL_SetTimerCallback, callback);
  2256         if (!compat_timer) {
  2257             return -1;
  2258         }
  2259     }
  2260     return 0;
  2261 }
  2262 
  2263 int
  2264 SDL_putenv(const char *_var)
  2265 {
  2266     char *ptr = NULL;
  2267     char *var = SDL_strdup(_var);
  2268     if (var == NULL) {
  2269         return -1;  /* we don't set errno. */
  2270     }
  2271 
  2272     ptr = SDL_strchr(var, '=');
  2273     if (ptr == NULL) {
  2274         SDL_free(var);
  2275         return -1;
  2276     }
  2277 
  2278     *ptr = '\0';  /* split the string into name and value. */
  2279     SDL_setenv(var, ptr + 1, 1);
  2280     SDL_free(var);
  2281     return 0;
  2282 }
  2283 
  2284 
  2285 
  2286 /* CD-ROM support is gone from SDL 2.0, so just have stubs that fail. */
  2287 
  2288 typedef void *SDL12_CD;  /* close enough.  :) */
  2289 typedef int SDL12_CDstatus;  /* close enough.  :) */
  2290 
  2291 static int
  2292 CDUnsupported(void)
  2293 {
  2294     SDL_SetError("CD interface is unsupported");
  2295     return -1;
  2296 }
  2297 
  2298 int
  2299 SDL_CDNumDrives(void)
  2300 {
  2301     return 0;  /* !!! FIXME: should return -1 without SDL_INIT_CDROM */
  2302 }
  2303 
  2304 const char *SDL_CDName(int drive) { CDUnsupported(); return NULL; }
  2305 SDL12_CD * SDL_CDOpen(int drive) { CDUnsupported(); return NULL; }
  2306 SDL12_CDstatus SDL_CDStatus(SDL_CD *cdrom) { return CDUnsupported(); }
  2307 int SDL_CDPlayTracks(SDL12_CD *cdrom, int start_track, int start_frame, int ntracks, int nframes) { return CDUnsupported(); }
  2308 int SDL_CDPlay(SDL12_CD *cdrom, int start, int length) { return CDUnsupported(); }
  2309 int SDL_CDPause(SDL12_CD *cdrom) { return CDUnsupported(); }
  2310 int SDL_CDResume(SDL12_CD *cdrom) { return CDUnsupported(); }
  2311 int SDL_CDStop(SDL12_CD *cdrom) { return CDUnsupported(); }
  2312 int SDL_CDEject(SDL12_CD *cdrom) { return CDUnsupported(); }
  2313 void SDL_CDClose(SDL12_CD *cdrom) {}
  2314 
  2315 /* !!! FIXME: Removed from 2.0; do nothing. We can't even report failure. */
  2316 void SDL_KillThread(SDL_Thread *thread) {}
  2317 
  2318 /* This changed from an opaque pointer to an int in 2.0. */
  2319 typedef struct _SDL12_TimerID *SDL12_TimerID;
  2320 SDL_COMPILE_TIME_ASSERT(timer, sizeof(SDL12_TimerID) >= sizeof(SDL_TimerID));
  2321 
  2322 SDL12_TimerID
  2323 SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
  2324 {
  2325     return (SDL12_TimerID) ((size_t) SDL20_AddTimer(interval, callback, param));
  2326 }
  2327 
  2328 SDL_bool
  2329 SDL_RemoveTimer(SDL12_TimerID id)
  2330 {
  2331     return SDL20_RemoveTimer((SDL_TimerID) ((size_t)id));
  2332 }
  2333 
  2334 
  2335 typedef struct SDL12_RWops {
  2336     int (SDLCALL *seek)(struct SDL_RWops *context, int offset, int whence);
  2337     int (SDLCALL *read)(struct SDL_RWops *context, void *ptr, int size, int maxnum);
  2338     int (SDLCALL *write)(struct SDL_RWops *context, const void *ptr, int size, int num);
  2339     int (SDLCALL *close)(struct SDL_RWops *context);
  2340     Uint32 type;
  2341     void *padding[8];
  2342     SDL_RWops *rwops20;
  2343 } SDL12_RWops;
  2344 
  2345 
  2346 SDL12_RWops *
  2347 SDL_AllocRW(void)
  2348 {
  2349     SDL12_RWops *rwops = (SDL12_RWops *) SDL_malloc(sizeof (SDL12_RWops));
  2350     if (!rwops)
  2351         SDL20_OutOfMemory();
  2352     return rwops;
  2353 }
  2354 
  2355 void
  2356 SDL_FreeRW(SDL12_RWops *rwops12)
  2357 {
  2358     SDL_free(rwops12);
  2359 }
  2360 
  2361 static int SDLCALL
  2362 RWops12to20_seek(struct SDL12_RWops *rwops12, int offset, int whence)
  2363 {
  2364     return rwops12->rwops20->seek(rwops12->rwops20, offset, whence);
  2365 }
  2366 
  2367 static int SDLCALL
  2368 RWops12to20_read(struct SDL12_RWops *rwops12, void *ptr, int size, int maxnum)
  2369 {
  2370     return rwops12->rwops20->read(rwops12->rwops20, ptr, size, maxnum);
  2371 }
  2372 
  2373 static int SDLCALL
  2374 RWops12to20_write(struct SDL12_RWops *rwops12, const void *ptr, int size, int num)
  2375 {
  2376     return rwops12->rwops20->write(rwops12->rwops20, ptr, size, num);
  2377 }
  2378 
  2379 static int SDLCALL
  2380 RWops12to20_close(struct SDL12_RWops *rwops12)
  2381 {
  2382     int rc = 0;
  2383     if (rwops12)
  2384     {
  2385         rc = rwops12->rwops20->close(rwops12->rwops20);
  2386         if (rc == 0)
  2387             SDL_FreeRW(rwops12);
  2388     }
  2389     return rc;
  2390 }
  2391 
  2392 static SDL12_RWops *
  2393 RWops12to20(SDL12_RWops *rwops12, SDL_RWops *rwops20)
  2394 {
  2395     if (!rwops20)
  2396     {
  2397         SDL_FreeRW(rwops12);
  2398         return NULL;
  2399     }
  2400     SDL_zerop(rwops12);
  2401     rwops12->type = rwops20->type;
  2402     rwops12->rwops20 = rwops20;
  2403     rwops12->seek = RWops12to20_seek;
  2404     rwops12->read = RWops12to20_read;
  2405     rwops12->write = RWops12to20_write;
  2406     rwops12->close = RWops12to20_close;
  2407     return rwops12;
  2408 }
  2409 
  2410 SDL12_RWops *
  2411 SDL_RWFromFile(const char *file, const char *mode)
  2412 {
  2413     SDL12_RWops *rwops12 = SDL_AllocRW();
  2414     return rwops12 ? RWops12to20(rwops12, SDL20_RWFromFile(file, mode)) : NULL;
  2415 }
  2416 
  2417 SDL12_RWops *
  2418 SDL_RWFromFP(FILE *io, int autoclose)
  2419 {
  2420     SDL12_RWops *rwops12 = SDL_AllocRW();
  2421     return rwops12 ? RWops12to20(rwops12, SDL20_RWFromFP(io, autoclose)) : NULL;
  2422 }
  2423 
  2424 SDL12_RWops *
  2425 SDL_RWFromMem(void *mem, int size)
  2426 {
  2427     SDL12_RWops *rwops12 = SDL_AllocRW();
  2428     return rwops12 ? RWops12to20(rwops12, SDL20_RWFromMem(mem, size)) : NULL;
  2429 }
  2430 
  2431 SDL12_RWops *
  2432 SDL_RWFromConstMem(const void *mem, int size)
  2433 {
  2434     SDL12_RWops *rwops12 = SDL_AllocRW();
  2435     return rwops12 ? RWops12to20(rwops12, SDL20_RWFromConstMem(mem, size)) : NULL;
  2436 }
  2437 
  2438 #define READ_AND_BYTESWAP(endian, bits) \
  2439     Uint##bits SDL_Read##endian##bits(SDL12_RWops *rwops12) { \
  2440         Uint##bits val; rwops12->read(rwops12, &val, sizeof (val), 1); \
  2441         return SDL_Swap##endian##bits(val); \
  2442     }
  2443 
  2444 READ_AND_BYTESWAP(LE,16)
  2445 READ_AND_BYTESWAP(BE,16)
  2446 READ_AND_BYTESWAP(LE,32)
  2447 READ_AND_BYTESWAP(BE,32)
  2448 READ_AND_BYTESWAP(LE,64)
  2449 READ_AND_BYTESWAP(BE,64)
  2450 #undef READ_AND_BYTESWAP
  2451 
  2452 #define BYTESWAP_AND_WRITE(endian, bits) \
  2453     int SDL_Write##endian##bits(SDL12_RWops *rwops12, Uint##endian##bits val) { \
  2454         val = SDL_Swap##endian##bits(val); \
  2455         return rwops12->write(rwops12, &val, sizeof (val), 1); \
  2456     }
  2457 BYTESWAP_AND_WRITE(LE,16)
  2458 BYTESWAP_AND_WRITE(BE,16)
  2459 BYTESWAP_AND_WRITE(LE,32)
  2460 BYTESWAP_AND_WRITE(BE,32)
  2461 BYTESWAP_AND_WRITE(LE,64)
  2462 BYTESWAP_AND_WRITE(BE,64)
  2463 #undef BYTESWAP_AND_WRITE
  2464 
  2465 /* Things that _should_ be binary compatible pass right through... */
  2466 #define SDL20_SYM(rc,fn,params,args,ret)
  2467 #define SDL20_SYM_PASSTHROUGH(rc,fn,params,args,ret) \
  2468     rc SDL_##fn params { ret SDL20_##fn args; }
  2469 #include "SDL20_syms.h"
  2470 #undef SDL20_SYM_PASSTHROUGH
  2471 #undef SDL20_SYM
  2472 
  2473 
  2474 static Sint64 SDLCALL
  2475 RWops20to12_size(struct SDL_RWops *rwops20)
  2476 {
  2477     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2478     int size = rwops20->hidden.unknown.data2;
  2479     int pos;
  2480 
  2481     if (size != -1)
  2482         return size;
  2483 
  2484     pos = rwops12->seek(rwops12, 0, SEEK_CUR);
  2485     if (pos == -1)
  2486         return -1;
  2487 
  2488     size = (Sint64) rwops->seek(rwops12, 0, SEEK_END);
  2489     if (size == -1)
  2490         return -1;
  2491 
  2492     rwops->seek(rwops12, pos, SEEK_SET);  /* !!! FIXME: and if this fails? */
  2493     rwops20->hidden.unknown.data2 = size;
  2494     return size;
  2495 }
  2496 
  2497 static Sint64
  2498 RWops20to12_seek(struct SDL_RWops *rwops20, Sint64 offset, int whence)
  2499 {
  2500     /* !!! FIXME: fail if (offset) is too big */
  2501     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2502     return (Sint64) rwops12->seek(rwops12, (int) offset, whence);
  2503 }
  2504 
  2505 static size_t SDLCALL
  2506 RWops20to12_read(struct SDL_RWops *rwops20, void *ptr, size_t size, size_t maxnum)
  2507 {
  2508     /* !!! FIXME: fail if (size) or (maxnum) is too big */
  2509     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2510     return (size_t) rwops12->read(rwops12, ptr, (int) size, (int) maxnum);
  2511 }
  2512 
  2513 static size_t SDLCALL
  2514 RWops20to12_write(struct SDL_RWops *rwops20, const void *ptr, size_t size, size_t num)
  2515 {
  2516     /* !!! FIXME: fail if (size) or (maxnum) is too big */
  2517     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2518     return (size_t) rwops12->write(rwops12, ptr, (int) size, (int) num);
  2519 }
  2520 
  2521 static int SDLCALL
  2522 RWops20to12_close(struct SDL_RWops *rwops20)
  2523 {
  2524     int rc = 0;
  2525     if (rwops20)
  2526     {
  2527         SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2528         rc = rwops12->close(rwops12);
  2529         if (rc == 0)
  2530             SDL20_FreeRW(rwops20);
  2531     }
  2532     return rc;
  2533 }
  2534 
  2535 static SDL12_RWops *
  2536 RWops20to12(SDL12_RWops *rwops12)
  2537 {
  2538     SDL20_RWops *rwops20;
  2539 
  2540     if (!rwops12)
  2541         return NULL;
  2542 
  2543     rwops20 = SDL20_AllocRW();
  2544     if (!rwops20)
  2545         return NULL;
  2546 
  2547     SDL_zerop(rwops20);
  2548     rwops20->type = rwops12->type;
  2549     rwops20->hidden.unknown.data1 = rwops12;
  2550     rwops20->hidden.unknown.data2 = -1;  /* cached size of stream */
  2551     rwops20->size = RWops20to12_size;
  2552     rwops20->seek = RWops20to12_seek;
  2553     rwops20->read = RWops20to12_read;
  2554     rwops20->write = RWops20to12_write;
  2555     rwops20->close = RWops20to12_close;
  2556     return rwops20;
  2557 }
  2558 
  2559 SDL12_Surface *
  2560 SDL_LoadBMP_RW(SDL12_RWops *rwops12, int freerwops12)
  2561 {
  2562     SDL_RWops *rwops20 = RWops20to12(rwops12);
  2563     SDL_Surface *retval = SDL20_LoadBMP_RW(rwops20, freerwops12);
  2564     if (!freerwops12)  /* free our wrapper if SDL2 didn't close it. */
  2565         SDL20_FreeRW(rwops20);
  2566     // !!! FIXME: wrap surface.
  2567     return retval;
  2568 }
  2569 
  2570 int
  2571 SDL_SaveBMP_RW(SDL12_Surface *surface, SDL12_RWops *rwops12, int freerwops12)
  2572 {
  2573     // !!! FIXME: wrap surface.
  2574     SDL_RWops *rwops20 = RWops20to12(rwops12);
  2575     const int retval = SDL20_SaveBMP_RW(surface, rwops20, freerwops12);
  2576     if (!freerwops12)  /* free our wrapper if SDL2 didn't close it. */
  2577         SDL20_FreeRW(rwops20);
  2578     return retval;
  2579 }
  2580 
  2581 SDL_AudioSpec *
  2582 SDL_LoadWAV_RW(SDL12_RWops *rwops12, int freerwops12,
  2583                SDL_AudioSpec *spec, Uint8 **buf, Uint32 *len)
  2584 {
  2585     SDL_RWops *rwops20 = RWops20to12(rwops12);
  2586     SDL_AudioSpec *retval = SDL20_LoadWAV_RW(rwops20, freerwops12, spec, buf, len);
  2587     if (!freerwops12)  /* free our wrapper if SDL2 didn't close it. */
  2588         SDL20_FreeRW(rwops20);
  2589     return retval;
  2590 }
  2591 
  2592 /* vi: set ts=4 sw=4 expandtab: */