update sdl Merge commit '4d48f9d23713d94b861da7b5d41baf2a41334994'

This commit is contained in:
2023-08-12 20:17:29 +02:00
215 changed files with 12672 additions and 17114 deletions

View File

@ -71,7 +71,7 @@ static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
/* !!! FIXME: for all these reads, handle error vs eof? handle -2 if non-blocking? */
for (;;) {
if (SDL_RWread(src, &ch, 1) <= 0) {
if (!SDL_ReadU8(src, &ch)) {
return SDL_TRUE;
}
/*
@ -80,7 +80,7 @@ static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
*/
if (ch) {
Uint8 pixel;
if (SDL_RWread(src, &pixel, 1) <= 0) {
if (!SDL_ReadU8(src, &pixel)) {
return SDL_TRUE;
}
if (isRle8) { /* 256-color bitmap, compressed */
@ -107,7 +107,7 @@ static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
| a cursor move, or some absolute data.
| zero tag may be absolute mode or an escape
*/
if (SDL_RWread(src, &ch, 1) <= 0) {
if (!SDL_ReadU8(src, &ch)) {
return SDL_TRUE;
}
switch (ch) {
@ -118,11 +118,11 @@ static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
case 1: /* end of bitmap */
return SDL_FALSE; /* success! */
case 2: /* delta */
if (SDL_RWread(src, &ch, 1) <= 0) {
if (!SDL_ReadU8(src, &ch)) {
return SDL_TRUE;
}
ofs += ch;
if (SDL_RWread(src, &ch, 1) <= 0) {
if (!SDL_ReadU8(src, &ch)) {
return SDL_TRUE;
}
bits -= (ch * pitch);
@ -132,7 +132,7 @@ static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
needsPad = (ch & 1);
do {
Uint8 pixel;
if (SDL_RWread(src, &pixel, 1) <= 0) {
if (!SDL_ReadU8(src, &pixel)) {
return SDL_TRUE;
}
COPY_PIXEL(pixel);
@ -141,7 +141,7 @@ static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
needsPad = (((ch + 1) >> 1) & 1); /* (ch+1)>>1: bytes size */
for (;;) {
Uint8 pixel;
if (SDL_RWread(src, &pixel, 1) <= 0) {
if (!SDL_ReadU8(src, &pixel)) {
return SDL_TRUE;
}
COPY_PIXEL(pixel >> 4);
@ -155,7 +155,7 @@ static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
}
}
/* pad at even boundary */
if (needsPad && (SDL_RWread(src, &ch, 1) <= 0)) {
if (needsPad && !SDL_ReadU8(src, &ch)) {
return SDL_TRUE;
}
break;
@ -195,7 +195,7 @@ static void CorrectAlphaChannel(SDL_Surface *surface)
SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
{
SDL_bool was_error;
SDL_bool was_error = SDL_TRUE;
Sint64 fp_offset = 0;
int bmpPitch;
int i, pad;
@ -235,42 +235,45 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
/* Make sure we are passed a valid data source */
surface = NULL;
was_error = SDL_FALSE;
if (src == NULL) {
SDL_InvalidParamError("src");
was_error = SDL_TRUE;
goto done;
}
/* Read in the BMP file header */
fp_offset = SDL_RWtell(src);
if (fp_offset < 0) {
was_error = SDL_TRUE;
goto done;
}
SDL_ClearError();
if (SDL_RWread(src, magic, 2) != 2) {
SDL_Error(SDL_EFREAD);
was_error = SDL_TRUE;
goto done;
}
if (SDL_strncmp(magic, "BM", 2) != 0) {
SDL_SetError("File is not a Windows BMP file");
was_error = SDL_TRUE;
goto done;
}
/* bfSize = */ SDL_ReadLE32(src);
/* bfReserved1 = */ SDL_ReadLE16(src);
/* bfReserved2 = */ SDL_ReadLE16(src);
bfOffBits = SDL_ReadLE32(src);
if (!SDL_ReadU32LE(src, NULL /* bfSize */) ||
!SDL_ReadU16LE(src, NULL /* bfReserved1 */) ||
!SDL_ReadU16LE(src, NULL /* bfReserved2 */) ||
!SDL_ReadU32LE(src, &bfOffBits)) {
goto done;
}
/* Read the Win32 BITMAPINFOHEADER */
biSize = SDL_ReadLE32(src);
if (!SDL_ReadU32LE(src, &biSize)) {
goto done;
}
if (biSize == 12) { /* really old BITMAPCOREHEADER */
biWidth = (Uint32)SDL_ReadLE16(src);
biHeight = (Uint32)SDL_ReadLE16(src);
/* biPlanes = */ SDL_ReadLE16(src);
biBitCount = SDL_ReadLE16(src);
Uint16 biWidth16, biHeight16;
if (!SDL_ReadU16LE(src, &biWidth16) ||
!SDL_ReadU16LE(src, &biHeight16) ||
!SDL_ReadU16LE(src, NULL /* biPlanes */) ||
!SDL_ReadU16LE(src, &biBitCount)) {
goto done;
}
biWidth = biWidth16;
biHeight = biHeight16;
biCompression = BI_RGB;
/* biSizeImage = 0; */
/* biXPelsPerMeter = 0; */
@ -279,16 +282,18 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
/* biClrImportant = 0; */
} else if (biSize >= 40) { /* some version of BITMAPINFOHEADER */
Uint32 headerSize;
biWidth = SDL_ReadLE32(src);
biHeight = SDL_ReadLE32(src);
/* biPlanes = */ SDL_ReadLE16(src);
biBitCount = SDL_ReadLE16(src);
biCompression = SDL_ReadLE32(src);
/* biSizeImage = */ SDL_ReadLE32(src);
/* biXPelsPerMeter = */ SDL_ReadLE32(src);
/* biYPelsPerMeter = */ SDL_ReadLE32(src);
biClrUsed = SDL_ReadLE32(src);
/* biClrImportant = */ SDL_ReadLE32(src);
if (!SDL_ReadS32LE(src, &biWidth) ||
!SDL_ReadS32LE(src, &biHeight) ||
!SDL_ReadU16LE(src, NULL /* biPlanes */) ||
!SDL_ReadU16LE(src, &biBitCount) ||
!SDL_ReadU32LE(src, &biCompression) ||
!SDL_ReadU32LE(src, NULL /* biSizeImage */) ||
!SDL_ReadU32LE(src, NULL /* biXPelsPerMeter */) ||
!SDL_ReadU32LE(src, NULL /* biYPelsPerMeter */) ||
!SDL_ReadU32LE(src, &biClrUsed) ||
!SDL_ReadU32LE(src, NULL /* biClrImportant */)) {
goto done;
}
/* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
if (biSize != 64) {
@ -301,24 +306,32 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
following the legacy v1 info header, just past biSize. */
if (biCompression == BI_BITFIELDS) {
haveRGBMasks = SDL_TRUE;
Rmask = SDL_ReadLE32(src);
Gmask = SDL_ReadLE32(src);
Bmask = SDL_ReadLE32(src);
if (!SDL_ReadU32LE(src, &Rmask) ||
!SDL_ReadU32LE(src, &Gmask) ||
!SDL_ReadU32LE(src, &Bmask)) {
goto done;
}
/* ...v3 adds an alpha mask. */
if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
haveAlphaMask = SDL_TRUE;
Amask = SDL_ReadLE32(src);
if (!SDL_ReadU32LE(src, &Amask)) {
goto done;
}
}
} else {
/* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
if (biSize >= 52) { /* BITMAPV2INFOHEADER; adds RGB masks */
/*Rmask = */ SDL_ReadLE32(src);
/*Gmask = */ SDL_ReadLE32(src);
/*Bmask = */ SDL_ReadLE32(src);
if (!SDL_ReadU32LE(src, NULL /* Rmask */) ||
!SDL_ReadU32LE(src, NULL /* Gmask */) ||
!SDL_ReadU32LE(src, NULL /* Bmask */)) {
goto done;
}
}
if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
/*Amask = */ SDL_ReadLE32(src);
if (!SDL_ReadU32LE(src, NULL /* Amask */)) {
goto done;
}
}
}
@ -331,12 +344,13 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
/* skip any header bytes we didn't handle... */
headerSize = (Uint32)(SDL_RWtell(src) - (fp_offset + 14));
if (biSize > headerSize) {
SDL_RWseek(src, (biSize - headerSize), SDL_RW_SEEK_CUR);
if (SDL_RWseek(src, (biSize - headerSize), SDL_RW_SEEK_CUR) < 0) {
goto done;
}
}
}
if (biWidth <= 0 || biHeight == 0) {
SDL_SetError("BMP file with bad dimensions (%" SDL_PRIs32 "x%" SDL_PRIs32 ")", biWidth, biHeight);
was_error = SDL_TRUE;
goto done;
}
if (biHeight < 0) {
@ -348,7 +362,6 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
/* Check for read error */
if (SDL_strcmp(SDL_GetError(), "") != 0) {
was_error = SDL_TRUE;
goto done;
}
@ -366,7 +379,6 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
case 6:
case 7:
SDL_SetError("%d-bpp BMP images are not supported", biBitCount);
was_error = SDL_TRUE;
goto done;
default:
ExpandBMP = 0;
@ -431,7 +443,6 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
surface = SDL_CreateSurface(biWidth, biHeight, format);
if (surface == NULL) {
was_error = SDL_TRUE;
goto done;
}
}
@ -441,13 +452,11 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
if (palette) {
if (SDL_RWseek(src, fp_offset + 14 + biSize, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
was_error = SDL_TRUE;
goto done;
}
if (biBitCount >= 32) { /* we shift biClrUsed by this value later. */
SDL_SetError("Unsupported or incorrect biBitCount field");
was_error = SDL_TRUE;
goto done;
}
@ -459,26 +468,27 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
biClrUsed = 1 << biBitCount; /* try forcing it? */
if (biClrUsed > (Uint32)palette->ncolors) {
SDL_SetError("Unsupported or incorrect biClrUsed field");
was_error = SDL_TRUE;
goto done;
}
}
if (biSize == 12) {
for (i = 0; i < (int)biClrUsed; ++i) {
/* !!! FIXME: this should check for i/o errors! */
SDL_RWread(src, &palette->colors[i].b, 1);
SDL_RWread(src, &palette->colors[i].g, 1);
SDL_RWread(src, &palette->colors[i].r, 1);
if (!SDL_ReadU8(src, &palette->colors[i].b) ||
!SDL_ReadU8(src, &palette->colors[i].g) ||
!SDL_ReadU8(src, &palette->colors[i].r)) {
goto done;
}
palette->colors[i].a = SDL_ALPHA_OPAQUE;
}
} else {
for (i = 0; i < (int)biClrUsed; ++i) {
/* !!! FIXME: this should check for i/o errors! */
SDL_RWread(src, &palette->colors[i].b, 1);
SDL_RWread(src, &palette->colors[i].g, 1);
SDL_RWread(src, &palette->colors[i].r, 1);
SDL_RWread(src, &palette->colors[i].a, 1);
if (!SDL_ReadU8(src, &palette->colors[i].b) ||
!SDL_ReadU8(src, &palette->colors[i].g) ||
!SDL_ReadU8(src, &palette->colors[i].r) ||
!SDL_ReadU8(src, &palette->colors[i].a)) {
goto done;
}
/* According to Microsoft documentation, the fourth element
is reserved and must be zero, so we shouldn't treat it as
@ -493,7 +503,6 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
/* Read the surface pixels. Note that the bmp image is upside down */
if (SDL_RWseek(src, fp_offset + bfOffBits, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
was_error = SDL_TRUE;
goto done;
}
if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) {
@ -537,16 +546,13 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
int shift = (8 - ExpandBMP);
for (i = 0; i < surface->w; ++i) {
if (i % (8 / ExpandBMP) == 0) {
if (SDL_RWread(src, &pixel, 1) != 1) {
SDL_Error(SDL_EFREAD);
was_error = SDL_TRUE;
if (!SDL_ReadU8(src, &pixel)) {
goto done;
}
}
bits[i] = (pixel >> shift);
if (bits[i] >= biClrUsed) {
SDL_SetError("A BMP image contains a pixel with a color out of the palette");
was_error = SDL_TRUE;
goto done;
}
pixel <<= ExpandBMP;
@ -555,15 +561,12 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
default:
if (SDL_RWread(src, bits, surface->pitch) != surface->pitch) {
SDL_Error(SDL_EFREAD);
was_error = SDL_TRUE;
goto done;
}
if (biBitCount == 8 && palette && biClrUsed < (1u << biBitCount)) {
for (i = 0; i < surface->w; ++i) {
if (bits[i] >= biClrUsed) {
SDL_SetError("A BMP image contains a pixel with a color out of the palette");
was_error = SDL_TRUE;
goto done;
}
}
@ -598,7 +601,9 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
if (pad) {
Uint8 padbyte;
for (i = 0; i < pad; ++i) {
SDL_RWread(src, &padbyte, 1);
if (!SDL_ReadU8(src, &padbyte)) {
goto done;
}
}
}
if (topDown) {
@ -610,6 +615,9 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
if (correctAlpha) {
CorrectAlphaChannel(surface);
}
was_error = SDL_FALSE;
done:
if (was_error) {
if (src) {
@ -629,15 +637,10 @@ SDL_Surface *SDL_LoadBMP(const char *file)
return SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1);
}
int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, SDL_bool freedst)
{
/* !!! FIXME: this calls SDL_ClearError() and then checks if an error happened during this function to
!!! FIXME: decide if there was a problem, but there's risk of innocent things setting an error
!!! FIXME: string for innocent unrelated reasons, and also, an app supplying its own RWops
!!! FIXME: implementation may not set the error string on failure. We should check for i/o
!!! FIXME: failures as we go, and return early if one occurs. */
Sint64 fp_offset;
SDL_bool was_error = SDL_TRUE;
Sint64 fp_offset, new_offset;
int i, pad;
SDL_Surface *intermediate_surface;
Uint8 *bits;
@ -678,6 +681,11 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
/* Make sure we have somewhere to save */
intermediate_surface = NULL;
if (dst) {
if (!surface) {
SDL_InvalidParamError("surface");
goto done;
}
#ifdef SAVE_32BIT_BMP
/* We can save alpha information in a 32-bit BMP */
if (surface->format->BitsPerPixel >= 8 &&
@ -693,6 +701,7 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
} else {
SDL_SetError("%d bpp BMP files not supported",
surface->format->BitsPerPixel);
goto done;
}
} else if ((surface->format->BitsPerPixel == 24) && !save32bit &&
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
@ -707,32 +716,33 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
) {
intermediate_surface = surface;
} else {
SDL_PixelFormat format;
Uint32 pixel_format;
/* If the surface has a colorkey or alpha channel we'll save a
32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
if (save32bit) {
SDL_InitFormat(&format, SDL_PIXELFORMAT_BGRA32);
pixel_format = SDL_PIXELFORMAT_BGRA32;
} else {
SDL_InitFormat(&format, SDL_PIXELFORMAT_BGR24);
pixel_format = SDL_PIXELFORMAT_BGR24;
}
intermediate_surface = SDL_ConvertSurface(surface, &format);
intermediate_surface = SDL_ConvertSurfaceFormat(surface, pixel_format);
if (intermediate_surface == NULL) {
SDL_SetError("Couldn't convert image to %d bpp",
format.BitsPerPixel);
(int)SDL_BITSPERPIXEL(pixel_format));
goto done;
}
}
} else {
/* Set no error here because it may overwrite a more useful message from
SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
return -1;
goto done;
}
if (save32bit) {
saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, SDL_FALSE);
}
if (intermediate_surface && (SDL_LockSurface(intermediate_surface) == 0)) {
if (SDL_LockSurface(intermediate_surface) == 0) {
const int bw = intermediate_surface->w * intermediate_surface->format->BytesPerPixel;
/* Set the BMP file header values */
@ -743,12 +753,16 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
/* Write the BMP file header values */
fp_offset = SDL_RWtell(dst);
SDL_ClearError();
SDL_RWwrite(dst, magic, 2);
SDL_WriteLE32(dst, bfSize);
SDL_WriteLE16(dst, bfReserved1);
SDL_WriteLE16(dst, bfReserved2);
SDL_WriteLE32(dst, bfOffBits);
if (fp_offset < 0) {
goto done;
}
if (SDL_RWwrite(dst, magic, 2) != 2 ||
!SDL_WriteU32LE(dst, bfSize) ||
!SDL_WriteU16LE(dst, bfReserved1) ||
!SDL_WriteU16LE(dst, bfReserved2) ||
!SDL_WriteU32LE(dst, bfOffBits)) {
goto done;
}
/* Set the BMP info values */
biSize = 40;
@ -783,31 +797,39 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
}
/* Write the BMP info values */
SDL_WriteLE32(dst, biSize);
SDL_WriteLE32(dst, biWidth);
SDL_WriteLE32(dst, biHeight);
SDL_WriteLE16(dst, biPlanes);
SDL_WriteLE16(dst, biBitCount);
SDL_WriteLE32(dst, biCompression);
SDL_WriteLE32(dst, biSizeImage);
SDL_WriteLE32(dst, biXPelsPerMeter);
SDL_WriteLE32(dst, biYPelsPerMeter);
SDL_WriteLE32(dst, biClrUsed);
SDL_WriteLE32(dst, biClrImportant);
if (!SDL_WriteU32LE(dst, biSize) ||
!SDL_WriteS32LE(dst, biWidth) ||
!SDL_WriteS32LE(dst, biHeight) ||
!SDL_WriteU16LE(dst, biPlanes) ||
!SDL_WriteU16LE(dst, biBitCount) ||
!SDL_WriteU32LE(dst, biCompression) ||
!SDL_WriteU32LE(dst, biSizeImage) ||
!SDL_WriteU32LE(dst, biXPelsPerMeter) ||
!SDL_WriteU32LE(dst, biYPelsPerMeter) ||
!SDL_WriteU32LE(dst, biClrUsed) ||
!SDL_WriteU32LE(dst, biClrImportant)) {
goto done;
}
/* Write the BMP info values for the version 4 header */
if (save32bit && !saveLegacyBMP) {
SDL_WriteLE32(dst, bV4RedMask);
SDL_WriteLE32(dst, bV4GreenMask);
SDL_WriteLE32(dst, bV4BlueMask);
SDL_WriteLE32(dst, bV4AlphaMask);
SDL_WriteLE32(dst, bV4CSType);
for (i = 0; i < 3 * 3; i++) {
SDL_WriteLE32(dst, bV4Endpoints[i]);
if (!SDL_WriteU32LE(dst, bV4RedMask) ||
!SDL_WriteU32LE(dst, bV4GreenMask) ||
!SDL_WriteU32LE(dst, bV4BlueMask) ||
!SDL_WriteU32LE(dst, bV4AlphaMask) ||
!SDL_WriteU32LE(dst, bV4CSType)) {
goto done;
}
for (i = 0; i < 3 * 3; i++) {
if (!SDL_WriteU32LE(dst, bV4Endpoints[i])) {
goto done;
}
}
if (!SDL_WriteU32LE(dst, bV4GammaRed) ||
!SDL_WriteU32LE(dst, bV4GammaGreen) ||
!SDL_WriteU32LE(dst, bV4GammaBlue)) {
goto done;
}
SDL_WriteLE32(dst, bV4GammaRed);
SDL_WriteLE32(dst, bV4GammaGreen);
SDL_WriteLE32(dst, bV4GammaBlue);
}
/* Write the palette (in BGR color order) */
@ -818,21 +840,25 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
colors = intermediate_surface->format->palette->colors;
ncolors = intermediate_surface->format->palette->ncolors;
for (i = 0; i < ncolors; ++i) {
SDL_RWwrite(dst, &colors[i].b, 1);
SDL_RWwrite(dst, &colors[i].g, 1);
SDL_RWwrite(dst, &colors[i].r, 1);
SDL_RWwrite(dst, &colors[i].a, 1);
if (!SDL_WriteU8(dst, colors[i].b) ||
!SDL_WriteU8(dst, colors[i].g) ||
!SDL_WriteU8(dst, colors[i].r) ||
!SDL_WriteU8(dst, colors[i].a)) {
goto done;
}
}
}
/* Write the bitmap offset */
bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
if (SDL_RWseek(dst, fp_offset + 10, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
goto done;
}
if (!SDL_WriteU32LE(dst, bfOffBits)) {
goto done;
}
SDL_WriteLE32(dst, bfOffBits);
if (SDL_RWseek(dst, fp_offset + bfOffBits, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
goto done;
}
/* Write the bitmap image upside down */
@ -841,38 +867,53 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
while (bits > (Uint8 *)intermediate_surface->pixels) {
bits -= intermediate_surface->pitch;
if (SDL_RWwrite(dst, bits, bw) != bw) {
SDL_Error(SDL_EFWRITE);
break;
goto done;
}
if (pad) {
const Uint8 padbyte = 0;
for (i = 0; i < pad; ++i) {
SDL_RWwrite(dst, &padbyte, 1);
if (!SDL_WriteU8(dst, padbyte)) {
goto done;
}
}
}
}
/* Write the BMP file size */
bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
if (SDL_RWseek(dst, fp_offset + 2, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
new_offset = SDL_RWtell(dst);
if (new_offset < 0) {
goto done;
}
bfSize = (Uint32)(new_offset - fp_offset);
if (SDL_RWseek(dst, fp_offset + 2, SDL_RW_SEEK_SET) < 0) {
goto done;
}
if (!SDL_WriteU32LE(dst, bfSize)) {
goto done;
}
SDL_WriteLE32(dst, bfSize);
if (SDL_RWseek(dst, fp_offset + bfSize, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
goto done;
}
/* Close it up.. */
SDL_UnlockSurface(intermediate_surface);
if (intermediate_surface != surface) {
SDL_DestroySurface(intermediate_surface);
}
was_error = SDL_FALSE;
}
if (freedst && dst) {
SDL_RWclose(dst);
done:
if (intermediate_surface && intermediate_surface != surface) {
SDL_DestroySurface(intermediate_surface);
}
return (SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1;
if (freedst && dst) {
if (SDL_RWclose(dst) < 0) {
was_error = SDL_TRUE;
}
}
if (was_error) {
return -1;
}
return 0;
}
int SDL_SaveBMP(SDL_Surface *surface, const char *file)

View File

@ -140,6 +140,12 @@ SDL_bool SDL_GetMasksForPixelFormatEnum(Uint32 format, int *bpp, Uint32 *Rmask,
#if SDL_HAVE_YUV
/* Partial support for SDL_Surface with FOURCC */
if (SDL_ISPIXELFORMAT_FOURCC(format)) {
/* Not a format that uses masks */
*bpp = 0;
*Rmask = *Gmask = *Bmask = *Amask = 0;
return SDL_TRUE;
}
#else
if (SDL_ISPIXELFORMAT_FOURCC(format)) {
SDL_SetError("SDL not built with YUV support");
@ -181,11 +187,6 @@ SDL_bool SDL_GetMasksForPixelFormatEnum(Uint32 format, int *bpp, Uint32 *Rmask,
return SDL_TRUE;
}
if (SDL_ISPIXELFORMAT_FOURCC(format)) {
/* Not a format that uses masks */
return SDL_TRUE;
}
if (SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED8 &&
SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED16 &&
SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED32) {
@ -314,10 +315,8 @@ Uint32 SDL_GetPixelFormatEnumForMasks(int bpp, Uint32 Rmask, Uint32 Gmask, Uint3
Bmask == 0x03 &&
Amask == 0x00) {
return SDL_PIXELFORMAT_RGB332;
} else {
return SDL_PIXELFORMAT_INDEX8;
}
break;
return SDL_PIXELFORMAT_INDEX8;
case 12:
if (Rmask == 0) {
return SDL_PIXELFORMAT_RGB444;

View File

@ -354,6 +354,9 @@ struct SDL_VideoDevice
/* Tell window that app enabled drag'n'drop events */
void (*AcceptDragAndDrop)(SDL_Window *window, SDL_bool accept);
/* Display the system-level window menu */
void (*ShowWindowSystemMenu)(SDL_Window *window, int x, int y);
/* * * */
/* Data common to all drivers */
SDL_threadID thread;
@ -363,7 +366,7 @@ struct SDL_VideoDevice
SDL_Window *wakeup_window;
SDL_Mutex *wakeup_lock; /* Initialized only if WaitEventTimeout/SendWakeupEvent are supported */
int num_displays;
SDL_VideoDisplay *displays;
SDL_VideoDisplay **displays;
SDL_Window *windows;
SDL_Window *grabbed_window;
Uint8 window_magic;

View File

@ -18,6 +18,7 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/* The high-level video driver subsystem */
@ -118,12 +119,12 @@ static VideoBootStrap *bootstrap[] = {
#ifdef SDL_VIDEO_DRIVER_QNX
&QNX_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_OFFSCREEN
&OFFSCREEN_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_NGAGE
&NGAGE_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_OFFSCREEN
&OFFSCREEN_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_DUMMY
&DUMMY_bootstrap,
#ifdef SDL_INPUT_LINUXEV
@ -462,7 +463,7 @@ int SDL_VideoInit(const char *driver_name)
goto pre_driver_error;
}
init_keyboard = SDL_TRUE;
if (SDL_InitMouse() < 0) {
if (SDL_PreInitMouse() < 0) {
goto pre_driver_error;
}
init_mouse = SDL_TRUE;
@ -558,6 +559,8 @@ int SDL_VideoInit(const char *driver_name)
SDL_StartTextInput();
}
SDL_PostInitMouse();
/* We're ready to go! */
return 0;
@ -640,57 +643,51 @@ SDL_DisplayID SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode)
SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event)
{
SDL_VideoDisplay *displays, *new_display;
SDL_DisplayID id = 0;
SDL_VideoDisplay **displays, *new_display;
SDL_DisplayID id;
int i;
displays = (SDL_VideoDisplay *)SDL_malloc((_this->num_displays + 1) * sizeof(*displays));
if (displays) {
int i;
if (_this->displays) {
/* The display list may contain self-referential pointers to the desktop mode. */
SDL_memcpy(displays, _this->displays, _this->num_displays * sizeof(*displays));
for (i = 0; i < _this->num_displays; ++i) {
if (displays[i].current_mode == &_this->displays[i].desktop_mode) {
displays[i].current_mode = &displays[i].desktop_mode;
}
}
SDL_free(_this->displays);
}
_this->displays = displays;
id = _this->next_object_id++;
new_display = &displays[_this->num_displays++];
SDL_memcpy(new_display, display, sizeof(*new_display));
new_display->id = id;
new_display->device = _this;
if (display->name) {
new_display->name = SDL_strdup(display->name);
} else {
char name[32];
SDL_itoa(id, name, 10);
new_display->name = SDL_strdup(name);
}
if (new_display->content_scale == 0.0f) {
new_display->content_scale = 1.0f;
}
new_display->desktop_mode.displayID = id;
new_display->current_mode = &new_display->desktop_mode;
SDL_FinalizeDisplayMode(&new_display->desktop_mode);
for (i = 0; i < new_display->num_fullscreen_modes; ++i) {
new_display->fullscreen_modes[i].displayID = id;
}
if (send_event) {
SDL_SendDisplayEvent(new_display, SDL_EVENT_DISPLAY_CONNECTED, 0);
}
} else {
new_display = (SDL_VideoDisplay *)SDL_malloc(sizeof(*new_display));
if (!new_display) {
SDL_OutOfMemory();
return 0;
}
displays = (SDL_VideoDisplay **)SDL_realloc(_this->displays, (_this->num_displays + 1) * sizeof(*displays));
if (!displays) {
SDL_OutOfMemory();
SDL_free(new_display);
return 0;
}
_this->displays = displays;
_this->displays[_this->num_displays++] = new_display;
id = _this->next_object_id++;
SDL_memcpy(new_display, display, sizeof(*new_display));
new_display->id = id;
new_display->device = _this;
if (display->name) {
new_display->name = SDL_strdup(display->name);
} else {
char name[32];
SDL_itoa(id, name, 10);
new_display->name = SDL_strdup(name);
}
if (new_display->content_scale == 0.0f) {
new_display->content_scale = 1.0f;
}
new_display->desktop_mode.displayID = id;
new_display->current_mode = &new_display->desktop_mode;
SDL_FinalizeDisplayMode(&new_display->desktop_mode);
for (i = 0; i < new_display->num_fullscreen_modes; ++i) {
new_display->fullscreen_modes[i].displayID = id;
}
if (send_event) {
SDL_SendDisplayEvent(new_display, SDL_EVENT_DISPLAY_CONNECTED, 0);
}
return id;
}
@ -713,7 +710,7 @@ void SDL_DelVideoDisplay(SDL_DisplayID displayID, SDL_bool send_event)
return;
}
display = &_this->displays[display_index];
display = _this->displays[display_index];
if (send_event) {
SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_DISCONNECTED, 0);
@ -725,6 +722,7 @@ void SDL_DelVideoDisplay(SDL_DisplayID displayID, SDL_bool send_event)
display->desktop_mode.driverdata = NULL;
SDL_free(display->driverdata);
display->driverdata = NULL;
SDL_free(display);
if (display_index < (_this->num_displays - 1)) {
SDL_memmove(&_this->displays[display_index], &_this->displays[display_index + 1], (_this->num_displays - display_index - 1) * sizeof(_this->displays[display_index]));
@ -753,7 +751,7 @@ SDL_DisplayID *SDL_GetDisplays(int *count)
}
for (i = 0; i < _this->num_displays; ++i) {
displays[i] = _this->displays[i].id;
displays[i] = _this->displays[i]->id;
}
displays[i] = 0;
} else {
@ -774,7 +772,7 @@ SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID displayID)
if (display_index < 0) {
return NULL;
}
return &_this->displays[display_index];
return _this->displays[display_index];
}
SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window)
@ -788,7 +786,7 @@ SDL_DisplayID SDL_GetPrimaryDisplay(void)
SDL_UninitializedVideo();
return 0;
}
return _this->displays[0].id;
return _this->displays[0]->id;
}
int SDL_GetDisplayIndex(SDL_DisplayID displayID)
@ -800,7 +798,7 @@ int SDL_GetDisplayIndex(SDL_DisplayID displayID)
}
for (display_index = 0; display_index < _this->num_displays; ++display_index) {
if (displayID == _this->displays[display_index].id) {
if (displayID == _this->displays[display_index]->id) {
return display_index;
}
}
@ -851,7 +849,7 @@ int SDL_GetDisplayBounds(SDL_DisplayID displayID, SDL_Rect *rect)
rect->x = 0;
rect->y = 0;
} else {
SDL_GetDisplayBounds(_this->displays[SDL_GetDisplayIndex(displayID) - 1].id, rect);
SDL_GetDisplayBounds(_this->displays[SDL_GetDisplayIndex(displayID) - 1]->id, rect);
rect->x += rect->w;
}
rect->w = display->current_mode->w;
@ -1254,7 +1252,7 @@ static SDL_DisplayID GetDisplayForRect(int x, int y, int w, int h)
if (_this) {
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
SDL_Rect display_rect;
SDL_GetDisplayBounds(display->id, &display_rect);
@ -1388,14 +1386,14 @@ static void SDL_CheckWindowDisplayChanged(SDL_Window *window)
/* Sanity check our fullscreen windows */
display_index = SDL_GetDisplayIndex(displayID);
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
if (display->fullscreen_window == window) {
if (display_index != i) {
if (display_index < 0) {
display_index = i;
} else {
SDL_VideoDisplay *new_display = &_this->displays[display_index];
SDL_VideoDisplay *new_display = _this->displays[display_index];
/* The window was moved to a different display */
if (new_display->fullscreen_window &&
@ -1487,7 +1485,7 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
}
} else {
for (i = 0; i < _this->num_displays; ++i) {
display = &_this->displays[i];
display = _this->displays[i];
if (display->fullscreen_window == window) {
break;
}
@ -1526,7 +1524,7 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
}
} else if (fullscreen && window->last_fullscreen_exclusive_display && !window->fullscreen_exclusive) {
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *last_display = &_this->displays[i];
SDL_VideoDisplay *last_display = _this->displays[i];
if (last_display->fullscreen_window == window) {
SDL_SetDisplayModeForDisplay(last_display, NULL);
if (_this->SetWindowFullscreen) {
@ -1582,7 +1580,7 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
/* Restore the video mode on other displays if needed */
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *other = &_this->displays[i];
SDL_VideoDisplay *other = _this->displays[i];
if (other != display && other->fullscreen_window == window) {
SDL_SetDisplayModeForDisplay(other, NULL);
if (_this->SetWindowFullscreen) {
@ -3731,7 +3729,7 @@ void SDL_VideoQuit(void)
_this->VideoQuit(_this);
for (i = _this->num_displays; i--; ) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
SDL_DelVideoDisplay(display->id, SDL_FALSE);
}
if (_this->displays) {
@ -5056,6 +5054,19 @@ SDL_bool SDL_ShouldAllowTopmost(void)
return SDL_GetHintBoolean(SDL_HINT_ALLOW_TOPMOST, SDL_TRUE);
}
int SDL_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
{
CHECK_WINDOW_MAGIC(window, -1)
CHECK_WINDOW_NOT_POPUP(window, -1)
if (_this->ShowWindowSystemMenu) {
_this->ShowWindowSystemMenu(window, x, y);
return 0;
}
return SDL_Unsupported();
}
int SDL_SetWindowHitTest(SDL_Window *window, SDL_HitTest callback, void *callback_data)
{
CHECK_WINDOW_MAGIC(window, -1);

View File

@ -108,7 +108,7 @@ void Android_PumpEvents_Blocking(SDL_VideoDevice *_this)
ANDROIDAUDIO_PauseDevices();
openslES_PauseDevices();
aaudio_PauseDevices();
AAUDIO_PauseDevices();
if (SDL_WaitSemaphore(Android_ResumeSem) == 0) {
@ -119,7 +119,7 @@ void Android_PumpEvents_Blocking(SDL_VideoDevice *_this)
ANDROIDAUDIO_ResumeDevices();
openslES_ResumeDevices();
aaudio_ResumeDevices();
AAUDIO_ResumeDevices();
/* Restore the GL Context from here, as this operation is thread dependent */
#ifdef SDL_VIDEO_OPENGL_EGL
@ -160,9 +160,9 @@ void Android_PumpEvents_Blocking(SDL_VideoDevice *_this)
}
}
if (aaudio_DetectBrokenPlayState()) {
aaudio_PauseDevices();
aaudio_ResumeDevices();
if (AAUDIO_DetectBrokenPlayState()) {
AAUDIO_PauseDevices();
AAUDIO_ResumeDevices();
}
}
@ -187,7 +187,7 @@ void Android_PumpEvents_NonBlocking(SDL_VideoDevice *_this)
if (videodata->pauseAudio) {
ANDROIDAUDIO_PauseDevices();
openslES_PauseDevices();
aaudio_PauseDevices();
AAUDIO_PauseDevices();
}
backup_context = 0;
@ -203,7 +203,7 @@ void Android_PumpEvents_NonBlocking(SDL_VideoDevice *_this)
if (videodata->pauseAudio) {
ANDROIDAUDIO_ResumeDevices();
openslES_ResumeDevices();
aaudio_ResumeDevices();
AAUDIO_ResumeDevices();
}
#ifdef SDL_VIDEO_OPENGL_EGL
@ -246,9 +246,9 @@ void Android_PumpEvents_NonBlocking(SDL_VideoDevice *_this)
}
}
if (aaudio_DetectBrokenPlayState()) {
aaudio_PauseDevices();
aaudio_ResumeDevices();
if (AAUDIO_DetectBrokenPlayState()) {
AAUDIO_PauseDevices();
AAUDIO_ResumeDevices();
}
}

View File

@ -268,7 +268,7 @@ void Android_SendResize(SDL_Window *window)
*/
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->num_displays > 0) {
SDL_VideoDisplay *display = &device->displays[0];
SDL_VideoDisplay *display = device->displays[0];
SDL_DisplayMode desktop_mode;
SDL_zero(desktop_mode);

View File

@ -255,7 +255,7 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
SDL_Window *window = device->windows;
int i;
for (i = 0; i < device->num_displays; ++i) {
SDL_Window *fullscreen_window = device->displays[i].fullscreen_window;
SDL_Window *fullscreen_window = device->displays[i]->fullscreen_window;
if (fullscreen_window) {
if (fullscreen_window->flags & SDL_WINDOW_MINIMIZED) {
SDL_RestoreWindow(fullscreen_window);

View File

@ -520,7 +520,7 @@ void Cocoa_QuitModes(SDL_VideoDevice *_this)
int i, j;
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
SDL_DisplayModeData *mode;
if (display->current_mode->driverdata != display->desktop_mode.driverdata) {

View File

@ -2467,9 +2467,9 @@ SDL_DisplayID Cocoa_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *wind
displayid = [[screen.deviceDescription objectForKey:@"NSScreenNumber"] unsignedIntValue];
for (i = 0; i < _this->num_displays; i++) {
SDL_DisplayData *displaydata = _this->displays[i].driverdata;
SDL_DisplayData *displaydata = _this->displays[i]->driverdata;
if (displaydata != NULL && displaydata->display == displayid) {
return _this->displays[i].id;
return _this->displays[i]->id;
}
}
}

View File

@ -155,9 +155,12 @@ class SDL_BWin : public BWindow
void UpdateCurrentView()
{
#ifdef SDL_VIDEO_OPENGL
if (_SDL_GLView != NULL) {
SetCurrentView(_SDL_GLView);
} else if (_SDL_View != NULL) {
} else
#endif
if (_SDL_View != NULL) {
SetCurrentView(_SDL_View);
} else {
SetCurrentView(NULL);
@ -454,10 +457,13 @@ class SDL_BWin : public BWindow
delete pendingMessage;
}
if (_bitmap != NULL) {
if (_SDL_View != NULL && _cur_view == _SDL_View)
_SDL_View->Draw(Bounds());
else if (_SDL_GLView != NULL && _cur_view == _SDL_GLView) {
#ifdef SDL_VIDEO_OPENGL
if (_SDL_GLView != NULL && _cur_view == _SDL_GLView) {
_SDL_GLView->CopyPixelsIn(_bitmap, B_ORIGIN);
} else
#endif
if (_SDL_View != NULL && _cur_view == _SDL_View) {
_SDL_View->Draw(Bounds());
}
}
break;

View File

@ -188,7 +188,7 @@ static float CalculateRefreshRate(drmModeModeInfo *mode)
den *= mode->vscan;
}
return ((100 * num) / den) / 100.0f;
return ((100 * (Sint64)num) / den) / 100.0f;
}
static int KMSDRM_Available(void)

View File

@ -48,7 +48,6 @@ struct SDL_DisplayData
static void N3DS_DeleteDevice(SDL_VideoDevice *device)
{
SDL_free(device->displays);
SDL_free(device->driverdata);
SDL_free(device);
}

View File

@ -79,7 +79,7 @@ int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserv
return exit_status;
}
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
/* Load a launch image using the old UILaunchImageFile-era naming rules. */
static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
{
@ -142,8 +142,10 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
self.storyboardViewController.view.frame = self.view.bounds;
[self.storyboardViewController didMoveToParentViewController:self];
#if !TARGET_OS_XR
UIApplication.sharedApplication.statusBarHidden = self.prefersStatusBarHidden;
UIApplication.sharedApplication.statusBarStyle = self.preferredStatusBarStyle;
#endif
}
- (BOOL)prefersStatusBarHidden
@ -210,11 +212,18 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"];
NSString *imagename = nil;
UIImage *image = nil;
#if TARGET_OS_XR
int screenw = SDL_XR_SCREENWIDTH;
int screenh = SDL_XR_SCREENHEIGHT;
#else
int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5);
int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5);
#endif
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation;
/* We always want portrait-oriented size, to match UILaunchImageSize. */
@ -244,7 +253,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
}
}
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
NSString *orientstring = dict[@"UILaunchImageOrientation"];
@ -273,7 +282,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
image = [UIImage imageNamed:imagename];
}
}
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
else {
imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"];
@ -288,10 +297,15 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
#endif
if (image) {
UIImageView *view = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
#if TARGET_OS_XR
CGRect viewFrame = CGRectMake(0, 0, screenw, screenh);
#else
CGRect viewFrame = [UIScreen mainScreen].bounds;
#endif
UIImageView *view = [[UIImageView alloc] initWithFrame:viewFrame];
UIImageOrientation imageorient = UIImageOrientationUp;
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
/* Bugs observed / workaround tested in iOS 8.3. */
if (UIInterfaceOrientationIsLandscape(curorient)) {
if (image.size.width < image.size.height) {
@ -420,7 +434,7 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
NSString *screenname = nil;
/* tvOS only uses a plain launch image. */
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"];
if (screenname) {
@ -443,7 +457,12 @@ static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh)
}
if (vc.view) {
launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
#if TARGET_OS_XR
CGRect viewFrame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT);
#else
CGRect viewFrame = [UIScreen mainScreen].bounds;
#endif
launchWindow = [[UIWindow alloc] initWithFrame:viewFrame];
/* We don't want the launch window immediately hidden when a real SDL
* window is shown - we fade it out ourselves when we're ready. */

View File

@ -57,7 +57,7 @@ static BOOL UIKit_EventPumpEnabled = YES;
[notificationCenter addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
[notificationCenter addObserver:self selector:@selector(applicationWillTerminate) name:UIApplicationWillTerminateNotification object:nil];
[notificationCenter addObserver:self selector:@selector(applicationDidReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
[notificationCenter addObserver:self
selector:@selector(applicationDidChangeStatusBarOrientation)
name:UIApplicationDidChangeStatusBarOrientationNotification
@ -99,7 +99,7 @@ static BOOL UIKit_EventPumpEnabled = YES;
SDL_OnApplicationDidReceiveMemoryWarning();
}
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
- (void)applicationDidChangeStatusBarOrientation
{
SDL_OnApplicationDidChangeStatusBarOrientation();

View File

@ -98,7 +98,11 @@ static BOOL UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messag
}
if (window == nil || window.rootViewController == nil) {
#if TARGET_OS_XR
alertwindow = [[UIWindow alloc] init];
#else
alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
#endif
alertwindow.rootViewController = [UIViewController new];
alertwindow.windowLevel = UIWindowLevelAlert;

View File

@ -81,6 +81,7 @@ SDL_MetalView UIKit_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
CGFloat scale = 1.0;
SDL_uikitmetalview *metalview;
#if !TARGET_OS_XR
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
/* Set the scale to the natural scale factor of the screen - then
* the backing dimensions of the Metal view will match the pixel
@ -89,6 +90,7 @@ SDL_MetalView UIKit_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
*/
scale = data.uiwindow.screen.nativeScale;
}
#endif
metalview = [[SDL_uikitmetalview alloc] initWithFrame:data.uiwindow.bounds
scale:scale];

View File

@ -27,26 +27,39 @@
@interface SDL_UIKitDisplayData : NSObject
#if !TARGET_OS_XR
- (instancetype)initWithScreen:(UIScreen *)screen;
@property(nonatomic, strong) UIScreen *uiscreen;
#endif
@end
@interface SDL_UIKitDisplayModeData : NSObject
#if !TARGET_OS_XR
@property(nonatomic, strong) UIScreenMode *uiscreenmode;
#endif
@end
#if !TARGET_OS_XR
extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen);
#endif
extern int UIKit_InitModes(SDL_VideoDevice *_this);
#if !TARGET_OS_XR
extern int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event);
extern void UIKit_DelDisplay(UIScreen *uiscreen);
#endif
extern int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
extern void UIKit_QuitModes(SDL_VideoDevice *_this);
extern int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
// because visionOS does not have a screen
// we create a fake 1080p display to maintain compatibility.
#if TARGET_OS_XR
#define SDL_XR_SCREENWIDTH 1920
#define SDL_XR_SCREENHEIGHT 1080
#endif
#endif /* SDL_uikitmodes_h_ */

View File

@ -30,6 +30,7 @@
@implementation SDL_UIKitDisplayData
#if !TARGET_OS_XR
- (instancetype)initWithScreen:(UIScreen *)screen
{
if (self = [super init]) {
@ -37,20 +38,23 @@
}
return self;
}
@synthesize uiscreen;
#endif
@end
@implementation SDL_UIKitDisplayModeData
#if !TARGET_OS_XR
@synthesize uiscreenmode;
#endif
@end
@interface SDL_DisplayWatch : NSObject
@end
#if !TARGET_OS_XR
@implementation SDL_DisplayWatch
+ (void)start
@ -92,7 +96,9 @@
}
@end
#endif
#if !TARGET_OS_XR
static int UIKit_AllocateDisplayModeData(SDL_DisplayMode *mode,
UIScreenMode *uiscreenmode)
{
@ -112,6 +118,7 @@ static int UIKit_AllocateDisplayModeData(SDL_DisplayMode *mode,
return 0;
}
#endif
static void UIKit_FreeDisplayModeData(SDL_DisplayMode *mode)
{
@ -121,6 +128,7 @@ static void UIKit_FreeDisplayModeData(SDL_DisplayMode *mode)
}
}
#if !TARGET_OS_XR
static float UIKit_GetDisplayModeRefreshRate(UIScreen *uiscreen)
{
#ifdef __IPHONE_10_3
@ -235,7 +243,11 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event)
display.desktop_mode = mode;
/* Allocate the display data */
#if TARGET_OS_XR
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] init];
#else
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] initWithScreen:uiscreen];
#endif
if (!data) {
UIKit_FreeDisplayModeData(&display.desktop_mode);
return SDL_OutOfMemory();
@ -247,6 +259,41 @@ int UIKit_AddDisplay(UIScreen *uiscreen, SDL_bool send_event)
}
return 0;
}
#endif
#if TARGET_OS_XR
int UIKit_AddDisplay(SDL_bool send_event){
CGSize size = CGSizeMake(SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT);
SDL_VideoDisplay display;
SDL_DisplayMode mode;
SDL_zero(mode);
mode.w = (int)size.width;
mode.h = (int)size.height;
mode.pixel_density = 1;
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.refresh_rate = 60;
display.natural_orientation = SDL_ORIENTATION_LANDSCAPE;
display.desktop_mode = mode;
SDL_UIKitDisplayData *data = [[SDL_UIKitDisplayData alloc] init];
if (!data) {
UIKit_FreeDisplayModeData(&display.desktop_mode);
return SDL_OutOfMemory();
}
display.driverdata = (SDL_DisplayData *)CFBridgingRetain(data);
if (SDL_AddVideoDisplay(&display, send_event) == 0) {
return -1;
}
return 0;
}
#endif
#if !TARGET_OS_XR
void UIKit_DelDisplay(UIScreen *uiscreen)
{
@ -281,20 +328,27 @@ SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen)
return (size.width > size.height);
}
}
#endif
int UIKit_InitModes(SDL_VideoDevice *_this)
{
@autoreleasepool {
#if TARGET_OS_XR
UIKit_AddDisplay(SDL_FALSE);
#else
for (UIScreen *uiscreen in [UIScreen screens]) {
if (UIKit_AddDisplay(uiscreen, SDL_FALSE) < 0) {
return -1;
}
}
#if !TARGET_OS_TV
#endif
#if !TARGET_OS_TV && !TARGET_OS_XR
SDL_OnApplicationDidChangeStatusBarOrientation();
#endif
#if !TARGET_OS_XR
[SDL_DisplayWatch start];
#endif
}
return 0;
@ -302,6 +356,7 @@ int UIKit_InitModes(SDL_VideoDevice *_this)
int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
{
#if !TARGET_OS_XR
@autoreleasepool {
SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata;
@ -331,11 +386,13 @@ int UIKit_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
UIKit_AddDisplayMode(display, w, h, data.uiscreen, uimode, addRotation);
}
}
#endif
return 0;
}
int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
{
#if !TARGET_OS_XR
@autoreleasepool {
SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata;
@ -359,7 +416,7 @@ int UIKit_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_
}
}
}
#endif
return 0;
}
@ -367,7 +424,11 @@ int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *displ
{
@autoreleasepool {
SDL_UIKitDisplayData *data = (__bridge SDL_UIKitDisplayData *)display->driverdata;
#if TARGET_OS_XR
CGRect frame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT);
#else
CGRect frame = data.uiscreen.bounds;
#endif
/* the default function iterates displays to make a fake offset,
as if all the displays were side-by-side, which is fine for iOS. */
@ -386,13 +447,15 @@ int UIKit_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *displ
void UIKit_QuitModes(SDL_VideoDevice *_this)
{
#if !TARGET_OS_XR
[SDL_DisplayWatch stop];
#endif
/* Release Objective-C objects, so higher level doesn't free() them. */
int i, j;
@autoreleasepool {
for (i = 0; i < _this->num_displays; i++) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
UIKit_FreeDisplayModeData(&display->desktop_mode);
for (j = 0; j < display->num_fullscreen_modes; j++) {
@ -408,7 +471,7 @@ void UIKit_QuitModes(SDL_VideoDevice *_this)
}
}
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
void SDL_OnApplicationDidChangeStatusBarOrientation(void)
{
BOOL isLandscape = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation);

View File

@ -33,7 +33,11 @@
@end
#if TARGET_OS_XR
CGRect UIKit_ComputeViewFrame(SDL_Window *window);
#else
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen);
#endif
#endif /* __OBJC__ */

View File

@ -52,7 +52,9 @@ static void UIKit_VideoQuit(SDL_VideoDevice *_this);
static void UIKit_DeleteDevice(SDL_VideoDevice *device)
{
@autoreleasepool {
CFRelease(device->driverdata);
if (device->driverdata){
CFRelease(device->driverdata);
}
SDL_free(device);
}
}
@ -183,6 +185,7 @@ SDL_bool UIKit_IsSystemVersionAtLeast(double version)
SDL_SystemTheme UIKit_GetSystemTheme(void)
{
#if !TARGET_OS_XR
if (@available(iOS 12.0, tvOS 10.0, *)) {
switch ([UIScreen mainScreen].traitCollection.userInterfaceStyle) {
case UIUserInterfaceStyleDark:
@ -193,9 +196,15 @@ SDL_SystemTheme UIKit_GetSystemTheme(void)
break;
}
}
#endif
return SDL_SYSTEM_THEME_UNKNOWN;
}
#if TARGET_OS_XR
CGRect UIKit_ComputeViewFrame(SDL_Window *window){
return CGRectMake(window->x, window->y, window->w, window->h);
}
#else
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
{
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata;
@ -234,6 +243,8 @@ CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
return frame;
}
#endif
void UIKit_ForceUpdateHomeIndicator(void)
{
#if !TARGET_OS_TV

View File

@ -417,6 +417,9 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), SDL_PRESSED, scancode);
}
}
if (SDL_TextInputActive()) {
[super pressesBegan:presses withEvent:event];
}
}
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
@ -427,6 +430,9 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), SDL_RELEASED, scancode);
}
}
if (SDL_TextInputActive()) {
[super pressesEnded:presses withEvent:event];
}
}
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
@ -437,11 +443,17 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
SDL_SendKeyboardKey(UIKit_GetEventTimestamp([event timestamp]), SDL_RELEASED, scancode);
}
}
if (SDL_TextInputActive()) {
[super pressesCancelled:presses withEvent:event];
}
}
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
/* This is only called when the force of a press changes. */
if (SDL_TextInputActive()) {
[super pressesChanged:presses withEvent:event];
}
}
#endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */

View File

@ -63,11 +63,11 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
@implementation SDLUITextField : UITextField
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(paste:)) {
return NO;
}
if (action == @selector(paste:)) {
return NO;
}
return [super canPerformAction:action withSender:sender];
return [super canPerformAction:action withSender:sender];
}
@end
@ -82,6 +82,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
SDLUITextField *textField;
BOOL hardwareKeyboard;
BOOL showingKeyboard;
BOOL hidingKeyboard;
BOOL rotatingOrientation;
NSString *committedText;
NSString *obligateForBackspace;
@ -99,6 +100,7 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
[self initKeyboard];
hardwareKeyboard = NO;
showingKeyboard = NO;
hidingKeyboard = NO;
rotatingOrientation = NO;
#endif
@ -160,7 +162,9 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
{
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
#ifdef __IPHONE_10_3
#if TARGET_OS_XR
displayLink.preferredFramesPerSecond = 90 / animationInterval; //TODO: Get frame max frame rate on visionOS
#elif defined(__IPHONE_10_3)
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata;
if ([displayLink respondsToSelector:@selector(preferredFramesPerSecond)] && data != nil && data.uiwindow != nil && [data.uiwindow.screen respondsToSelector:@selector(maximumFramesPerSecond)]) {
@ -292,7 +296,18 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[center addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
#endif
[center addObserver:self
selector:@selector(textFieldTextDidChange:)
@ -363,7 +378,15 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
[center removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[center removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[center removeObserver:self
name:UIKeyboardDidShowNotification
object:nil];
[center removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
[center removeObserver:self
name:UIKeyboardDidHideNotification
object:nil];
#endif
[center removeObserver:self
name:UITextFieldTextDidChangeNotification
@ -373,23 +396,40 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
/* reveal onscreen virtual keyboard */
- (void)showKeyboard
{
if (keyboardVisible) {
return;
}
keyboardVisible = YES;
if (textField.window) {
showingKeyboard = YES;
[textField becomeFirstResponder];
showingKeyboard = NO;
}
}
/* hide onscreen virtual keyboard */
- (void)hideKeyboard
{
if (!keyboardVisible) {
return;
}
keyboardVisible = NO;
[textField resignFirstResponder];
if (textField.window) {
hidingKeyboard = YES;
[textField resignFirstResponder];
}
}
- (void)keyboardWillShow:(NSNotification *)notification
{
BOOL shouldStartTextInput = NO;
if (!SDL_TextInputActive() && !hidingKeyboard && !rotatingOrientation) {
shouldStartTextInput = YES;
}
showingKeyboard = YES;
#if !TARGET_OS_TV
CGRect kbrect = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
@ -399,14 +439,36 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
[self setKeyboardHeight:(int)kbrect.size.height];
#endif
if (shouldStartTextInput) {
SDL_StartTextInput();
}
}
- (void)keyboardDidShow:(NSNotification *)notification
{
showingKeyboard = NO;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
if (!showingKeyboard && !rotatingOrientation) {
BOOL shouldStopTextInput = NO;
if (SDL_TextInputActive() && !showingKeyboard && !rotatingOrientation) {
shouldStopTextInput = YES;
}
hidingKeyboard = YES;
[self setKeyboardHeight:0];
if (shouldStopTextInput) {
SDL_StopTextInput();
}
[self setKeyboardHeight:0];
}
- (void)keyboardDidHide:(NSNotification *)notification
{
hidingKeyboard = NO;
}
- (void)textFieldTextDidChange:(NSNotification *)notification
@ -425,8 +487,8 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
size_t deleteLength = SDL_utf8strlen([[committedText substringFromIndex:matchLength] UTF8String]);
while (deleteLength > 0) {
/* Send distinct down and up events for each backspace action */
SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
SDL_SendVirtualKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
SDL_SendVirtualKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
--deleteLength;
}
}
@ -451,7 +513,11 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
{
CGAffineTransform t = self.view.transform;
CGPoint offset = CGPointMake(0.0, 0.0);
#if TARGET_OS_XR
CGRect frame = UIKit_ComputeViewFrame(window);
#else
CGRect frame = UIKit_ComputeViewFrame(window, self.view.window.screen);
#endif
if (self.keyboardHeight) {
int rectbottom = self.textInputRect.y + self.textInputRect.h;

View File

@ -65,6 +65,7 @@
- (void)layoutSubviews
{
#if !TARGET_OS_XR
/* Workaround to fix window orientation issues in iOS 8. */
/* As of July 1 2019, I haven't been able to reproduce any orientation
* issues with this disabled on iOS 12. The issue this is meant to fix might
@ -74,6 +75,7 @@
if (!UIKit_IsSystemVersionAtLeast(9.0)) {
self.frame = self.screen.bounds;
}
#endif
[super layoutSubviews];
}
@ -84,8 +86,13 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow
SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
SDL_UIKitDisplayData *displaydata = (__bridge SDL_UIKitDisplayData *)display->driverdata;
SDL_uikitview *view;
#if TARGET_OS_XR
CGRect frame = UIKit_ComputeViewFrame(window);
#else
CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen);
#endif
int width = (int)frame.size.width;
int height = (int)frame.size.height;
@ -98,13 +105,15 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, UIWindow
data.uiwindow = uiwindow;
#if !TARGET_OS_XR
if (displaydata.uiscreen != [UIScreen mainScreen]) {
window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizable */
window->flags &= ~SDL_WINDOW_INPUT_FOCUS; /* never has input focus */
window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */
}
#endif
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
if (displaydata.uiscreen == [UIScreen mainScreen]) {
/* SDL_CreateWindow sets the window w&h to the display's bounds if the
* fullscreen flag is set. But the display bounds orientation might not
@ -166,7 +175,7 @@ int UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
/* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
* user, so it's in standby), try to force the display to a resolution
* that most closely matches the desired window size. */
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
const CGSize origsize = data.uiscreen.currentMode.size;
if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
const SDL_DisplayMode *bestmode;
@ -197,12 +206,18 @@ int UIKit_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
/* ignore the size user requested, and make a fullscreen window */
/* !!! FIXME: can we have a smaller view? */
#if TARGET_OS_XR
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:CGRectMake(window->x, window->y, window->w, window->h)];
#else
UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds];
#endif
/* put the window on an external display if appropriate. */
#if !TARGET_OS_XR
if (data.uiscreen != [UIScreen mainScreen]) {
[uiwindow setScreen:data.uiscreen];
}
#endif
if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
return -1;
@ -229,7 +244,10 @@ void UIKit_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
/* Make this window the current mouse focus for touch input */
SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
SDL_UIKitDisplayData *displaydata = (__bridge SDL_UIKitDisplayData *)display->driverdata;
if (displaydata.uiscreen == [UIScreen mainScreen]) {
#if !TARGET_OS_XR
if (displaydata.uiscreen == [UIScreen mainScreen])
#endif
{
SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window);
}
@ -258,7 +276,7 @@ static void UIKit_UpdateWindowBorder(SDL_VideoDevice *_this, SDL_Window *window)
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata;
SDL_uikitviewcontroller *viewcontroller = data.viewcontroller;
#if !TARGET_OS_TV
#if !TARGET_OS_TV && !TARGET_OS_XR
if (data.uiwindow.screen == [UIScreen mainScreen]) {
if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) {
[UIApplication sharedApplication].statusBarHidden = YES;
@ -354,9 +372,11 @@ void UIKit_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int
CGSize size = view.bounds.size;
CGFloat scale = 1.0;
#if !TARGET_OS_XR
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
scale = windata.uiwindow.screen.nativeScale;
}
#endif
/* Integer truncation of fractional values matches SDL_uikitmetalview and
* SDL_uikitopenglview. */

View File

@ -158,6 +158,7 @@ void SDL_WAYLAND_UnloadSymbols(void);
#define libdecor_frame_is_visible (*WAYLAND_libdecor_frame_is_visible)
#define libdecor_frame_is_floating (*WAYLAND_libdecor_frame_is_floating)
#define libdecor_frame_set_parent (*WAYLAND_libdecor_frame_set_parent)
#define libdecor_frame_show_window_menu (*WAYLAND_libdecor_frame_show_window_menu)
#define libdecor_frame_get_xdg_surface (*WAYLAND_libdecor_frame_get_xdg_surface)
#define libdecor_frame_get_xdg_toplevel (*WAYLAND_libdecor_frame_get_xdg_toplevel)
#define libdecor_frame_translate_coordinate (*WAYLAND_libdecor_frame_translate_coordinate)

View File

@ -311,12 +311,25 @@ static SDL_bool keyboard_repeat_key_is_set(SDL_WaylandKeyboardRepeat *repeat_inf
return repeat_info->is_initialized && repeat_info->is_key_down && key == repeat_info->key;
}
static void sync_done_handler(void *data, struct wl_callback *callback, uint32_t callback_data)
{
/* Nothing to do, just destroy the callback */
wl_callback_destroy(callback);
}
static struct wl_callback_listener sync_listener = {
sync_done_handler
};
void Wayland_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_VideoData *d = _this->driverdata;
/* TODO: Maybe use a pipe to avoid the compositor roundtrip? */
wl_display_sync(d->display);
/* Queue a sync event to unblock the event queue fd if it's empty and being waited on.
* TODO: Maybe use a pipe to avoid the compositor roundtrip?
*/
struct wl_callback *cb = wl_display_sync(d->display);
wl_callback_add_listener(cb, &sync_listener, NULL);
WAYLAND_wl_display_flush(d->display);
}
@ -541,6 +554,19 @@ static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
}
if (input->pointer_focus) {
SDL_WindowData *wind = (SDL_WindowData *)wl_surface_get_user_data(surface);
if (wind) {
/* Clear the capture flag and raise all buttons */
wind->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, 0, SDL_RELEASED, SDL_BUTTON_LEFT);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, 0, SDL_RELEASED, SDL_BUTTON_RIGHT);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, 0, SDL_RELEASED, SDL_BUTTON_MIDDLE);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, 0, SDL_RELEASED, SDL_BUTTON_X1);
SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, 0, SDL_RELEASED, SDL_BUTTON_X2);
}
SDL_SetMouseFocus(NULL);
input->pointer_focus = NULL;
}
@ -2705,6 +2731,9 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
if (input->primary_selection_device->selection_source != NULL) {
Wayland_primary_selection_source_destroy(input->primary_selection_device->selection_source);
}
if (input->primary_selection_device->primary_selection_device != NULL) {
zwp_primary_selection_device_v1_destroy(input->primary_selection_device->primary_selection_device);
}
SDL_free(input->primary_selection_device);
}

View File

@ -204,6 +204,7 @@ SDL_WAYLAND_SYM(bool, libdecor_frame_is_visible, (struct libdecor_frame *))
SDL_WAYLAND_SYM(bool, libdecor_frame_is_floating, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_set_parent, (struct libdecor_frame *,\
struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_show_window_menu, (struct libdecor_frame *, struct wl_seat *, uint32_t, int, int))
SDL_WAYLAND_SYM(struct xdg_surface *, libdecor_frame_get_xdg_surface, (struct libdecor_frame *))
SDL_WAYLAND_SYM(struct xdg_toplevel *, libdecor_frame_get_xdg_toplevel, (struct libdecor_frame *))
SDL_WAYLAND_SYM(void, libdecor_frame_translate_coordinate, (struct libdecor_frame *, int, int, int *, int *))

View File

@ -209,6 +209,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
device->SetWindowHitTest = Wayland_SetWindowHitTest;
device->FlashWindow = Wayland_FlashWindow;
device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
device->ShowWindowSystemMenu = Wayland_ShowWindowSystemMenu;
#ifdef SDL_USE_LIBDBUS
if (SDL_SystemTheme_Init())
@ -672,6 +673,10 @@ static void Wayland_free_display(SDL_VideoDisplay *display)
SDL_DisplayData *display_data = display->driverdata;
int i;
if (display_data->xdg_output) {
zxdg_output_v1_destroy(display_data->xdg_output);
}
if (wl_output_get_version(display_data->output) >= WL_OUTPUT_RELEASE_SINCE_VERSION) {
wl_output_release(display_data->output);
} else {
@ -931,7 +936,7 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
Wayland_FiniMouse(data);
for (i = _this->num_displays - 1; i >= 0; --i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
Wayland_free_display(display);
}

View File

@ -2154,7 +2154,7 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
int i;
for (i = 0; i < _this->num_displays; i++) {
float scale = _this->displays[i].driverdata->scale_factor;
float scale = _this->displays[i]->driverdata->scale_factor;
data->windowed_scale_factor = SDL_max(data->windowed_scale_factor, scale);
}
}
@ -2357,6 +2357,23 @@ void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
WAYLAND_wl_display_flush(viddata->display);
}
void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
{
SDL_WindowData *wind = window->driverdata;
#ifdef HAVE_LIBDECOR_H
if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
if (wind->shell_surface.libdecor.frame) {
libdecor_frame_show_window_menu(wind->shell_surface.libdecor.frame, wind->waylandData->input->seat, wind->waylandData->input->last_implicit_grab_serial, x, y);
}
} else
#endif
if (wind->shell_surface_type == WAYLAND_SURFACE_XDG_TOPLEVEL) {
if (wind->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_show_window_menu(wind->shell_surface.xdg.roleobj.toplevel, wind->waylandData->input->seat, wind->waylandData->input->last_implicit_grab_serial, x, y);
}
}
}
int Wayland_SuspendScreenSaver(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;

View File

@ -150,6 +150,7 @@ extern void Wayland_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *win
extern void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
extern int Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
extern void Wayland_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Wayland_SuspendScreenSaver(SDL_VideoDevice *_this);

View File

@ -352,18 +352,27 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI
// ready to be added to allow any displays that we can't fully query to be
// removed
for (i = 0; i < _this->num_displays; ++i) {
SDL_DisplayData *driverdata = _this->displays[i].driverdata;
SDL_DisplayData *driverdata = _this->displays[i]->driverdata;
if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) {
SDL_bool moved = (index != i);
SDL_bool changed_bounds = SDL_FALSE;
if (moved) {
SDL_VideoDisplay tmp;
if (driverdata->state != DisplayRemoved) {
/* We've already enumerated this display, don't move it */
return;
}
SDL_assert(index < _this->num_displays);
SDL_memcpy(&tmp, &_this->displays[index], sizeof(tmp));
SDL_memcpy(&_this->displays[index], &_this->displays[i], sizeof(tmp));
SDL_memcpy(&_this->displays[i], &tmp, sizeof(tmp));
if (index >= _this->num_displays) {
/* This should never happen due to the check above, but just in case... */
return;
}
if (moved) {
SDL_VideoDisplay *tmp;
tmp = _this->displays[index];
_this->displays[index] = _this->displays[i];
_this->displays[i] = tmp;
i = index;
}
@ -371,7 +380,7 @@ static void WIN_AddDisplay(SDL_VideoDevice *_this, HMONITOR hMonitor, const MONI
driverdata->state = DisplayUnchanged;
if (!_this->setting_display_mode) {
SDL_VideoDisplay *existing_display = &_this->displays[i];
SDL_VideoDisplay *existing_display = _this->displays[i];
SDL_Rect bounds;
SDL_ResetFullscreenDisplayModes(existing_display);
@ -645,7 +654,7 @@ void WIN_RefreshDisplays(SDL_VideoDevice *_this)
// Mark all displays as potentially invalid to detect
// entries that have actually been removed
for (i = 0; i < _this->num_displays; ++i) {
SDL_DisplayData *driverdata = _this->displays[i].driverdata;
SDL_DisplayData *driverdata = _this->displays[i]->driverdata;
driverdata->state = DisplayRemoved;
}
@ -656,7 +665,7 @@ void WIN_RefreshDisplays(SDL_VideoDevice *_this)
// Delete any entries still marked as invalid, iterate
// in reverse as each delete takes effect immediately
for (i = _this->num_displays - 1; i >= 0; --i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
SDL_DisplayData *driverdata = display->driverdata;
if (driverdata->state == DisplayRemoved) {
SDL_DelVideoDisplay(display->id, SDL_TRUE);
@ -665,7 +674,7 @@ void WIN_RefreshDisplays(SDL_VideoDevice *_this)
// Send events for any newly added displays
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_VideoDisplay *display = _this->displays[i];
SDL_DisplayData *driverdata = display->driverdata;
if (driverdata->state == DisplayAdded) {
SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_CONNECTED, 0);

View File

@ -207,6 +207,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
device->SetWindowHitTest = WIN_SetWindowHitTest;
device->AcceptDragAndDrop = WIN_AcceptDragAndDrop;
device->FlashWindow = WIN_FlashWindow;
device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu;
device->shape_driver.CreateShaper = Win32_CreateShaper;
device->shape_driver.SetWindowShape = Win32_SetWindowShape;

View File

@ -51,6 +51,14 @@ typedef HRESULT (WINAPI *DwmSetWindowAttribute_t)(HWND hwnd, DWORD dwAttribute,
#define SWP_NOCOPYBITS 0
#endif
/* An undocumented message to create a popup system menu
* - wParam is always 0
* - lParam = MAKELONG(x, y) where x and y are the screen coordinates where the menu should be displayed
*/
#ifndef WM_POPUPSYSTEMMENU
#define WM_POPUPSYSTEMMENU 0x313
#endif
/* #define HIGHDPI_DEBUG */
/* Fake window to help with DirectInput events. */
@ -845,7 +853,6 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
DWORD style;
HWND hwnd;
int nCmdShow;
SDL_bool bActivate = SDL_GetHintBoolean(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, SDL_TRUE);
@ -855,13 +862,16 @@ void WIN_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
}
hwnd = window->driverdata->hwnd;
nCmdShow = bActivate ? SW_SHOW : SW_SHOWNA;
style = GetWindowLong(hwnd, GWL_EXSTYLE);
if (style & WS_EX_NOACTIVATE) {
nCmdShow = SW_SHOWNOACTIVATE;
bActivate = SDL_FALSE;
}
ShowWindow(hwnd, nCmdShow);
if (bActivate) {
ShowWindow(hwnd, SW_SHOW);
} else {
/* Use SetWindowPos instead of ShowWindow to avoid activating the parent window if this is a child window */
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, window->driverdata->copybits_flag | SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
if (window->flags & SDL_WINDOW_POPUP_MENU && bActivate) {
if (window->parent == SDL_GetKeyboardFocus()) {
@ -1483,6 +1493,17 @@ int WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperati
return 0;
}
void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
{
const SDL_WindowData *data = window->driverdata;
POINT pt;
pt.x = x;
pt.y = y;
ClientToScreen(data->hwnd, &pt);
SendMessage(data->hwnd, WM_POPUPSYSTEMMENU, 0, MAKELPARAM(pt.x, pt.y));
}
#endif /*!defined(__XBOXONE__) && !defined(__XBOXSERIES__)*/
void WIN_UpdateDarkModeForHWND(HWND hwnd)

View File

@ -108,6 +108,7 @@ extern void WIN_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
extern int WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
extern void WIN_UpdateDarkModeForHWND(HWND hwnd);
extern int WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags);
extern void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus

View File

@ -467,8 +467,8 @@ static int X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy);
} else {
const SDL_VideoDevice *dev = SDL_GetVideoDevice();
if ((dev) && (dev->displays) && (dev->num_displays > 0)) {
const SDL_VideoDisplay *dpy = &dev->displays[0];
if (dev && dev->displays && dev->num_displays > 0) {
const SDL_VideoDisplay *dpy = dev->displays[0];
const SDL_DisplayData *dpydata = dpy->driverdata;
x = dpydata->x + ((dpy->current_mode->w - data->dialog_width) / 2);
y = dpydata->y + ((dpy->current_mode->h - data->dialog_height) / 3);

View File

@ -99,7 +99,7 @@ static void UpdateDisplayContentScale(float scale)
if (viddevice) {
for (i = 0; i < viddevice->num_displays; ++i) {
SDL_SetDisplayContentScale(&viddevice->displays[i], scale);
SDL_SetDisplayContentScale(viddevice->displays[i], scale);
}
}
}
@ -821,8 +821,9 @@ int X11_InitModes(SDL_VideoDevice *_this)
int xrandr_major, xrandr_minor;
/* require at least XRandR v1.3 */
if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
(xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) {
return X11_InitModes_XRandR(_this);
(xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3)) &&
X11_InitModes_XRandR(_this) == 0) {
return 0;
}
}
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */

View File

@ -84,7 +84,7 @@ static int X11_SafetyNetErrHandler(Display *d, XErrorEvent *e)
if (device != NULL) {
int i;
for (i = 0; i < device->num_displays; i++) {
SDL_VideoDisplay *display = &device->displays[i];
SDL_VideoDisplay *display = device->displays[i];
if (SDL_GetCurrentDisplayMode(display->id) != SDL_GetDesktopDisplayMode(display->id)) {
X11_SetDisplayMode(device, display, &display->desktop_mode);
}
@ -213,6 +213,7 @@ static SDL_VideoDevice *X11_CreateDevice(void)
device->SetWindowHitTest = X11_SetWindowHitTest;
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
device->FlashWindow = X11_FlashWindow;
device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu;
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
device->SetWindowMouseRect = X11_SetWindowMouseRect;

View File

@ -423,7 +423,6 @@ int X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
SDL_WindowData *windowdata;
Display *display = data->display;
int screen = displaydata->screen;
const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE;
Visual *visual;
int depth;
XSetWindowAttributes xattr;
@ -443,6 +442,7 @@ int X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
SDL_bool undefined_position = SDL_FALSE;
#if defined(SDL_VIDEO_OPENGL_GLX) || defined(SDL_VIDEO_OPENGL_EGL)
const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE;
const char *forced_visual_id = SDL_GetHint(SDL_HINT_VIDEO_X11_WINDOW_VISUALID);
if (forced_visual_id != NULL && forced_visual_id[0] != '\0') {
@ -1957,4 +1957,29 @@ int SDL_X11_SetWindowTitle(Display *display, Window xwindow, char *title)
return 0;
}
void X11_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
{
SDL_WindowData *data = window->driverdata;
SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(window);
Display *display = data->videodata->display;
Window root = RootWindow(display, displaydata->screen);
XClientMessageEvent e;
Window childReturn;
int wx, wy;
SDL_zero(e);
X11_XTranslateCoordinates(display, data->xwindow, root, x, y, &wx, &wy, &childReturn);
e.type = ClientMessage;
e.window = data->xwindow;
e.message_type = X11_XInternAtom(display, "_GTK_SHOW_WINDOW_MENU", 0);
e.data.l[0] = 0; /* GTK device ID (unused) */
e.data.l[1] = wx; /* X coordinate relative to root */
e.data.l[2] = wy; /* Y coordinate relative to root */
e.format = 32;
X11_XSendEvent(display, root, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&e);
X11_XFlush(display);
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -115,6 +115,7 @@ extern int X11_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, struc
extern int X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
extern void X11_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
extern int X11_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
extern void X11_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
int SDL_X11_SetWindowTitle(Display *display, Window xwindow, char *title);
void X11_UpdateWindowPosition(SDL_Window *window);