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