Compare commits

..

33 Commits

Author SHA1 Message Date
Frank Praznik
8d604353a5 renderer: Always use the output size when updating the main view
The main view always reflects the size of the output, so don't use the dimensions of the currently bound render target texture when updating it, or it will reflect an incorrect size when the render target texture is unbound.

(cherry picked from commit 8aa5b97bb5)
2025-05-14 09:38:13 -07:00
Ryan C. Gordon
8410e11ecb wikiheaders: Man pages should escape apostrophe chars.
This prevents problems if one starts a line, which would cause it to be
interpreted as a command character.

Fixes #13038.

(cherry picked from commit 1f7aa16eae)
2025-05-14 11:41:14 -04:00
krizej
9f8161bf4a docs: improve man page generation
(cherry picked from commit a390f5716e)
2025-05-14 11:40:58 -04:00
Sam Lantinga
c038d6f7f8 Updated to version 3.2.14 for release 2025-05-13 14:24:40 -07:00
Frank Praznik
2fff37fffc Revert "x11: Send key events for dead keys consumed by the IME"
This and its related commits introduced some bugs and quirks such as duplicated and delayed/missed key events that can't be easily worked around, so revert this for now.

This reverts commit 47162a4168.

(cherry picked from commit 1eeffc5933)
2025-05-13 09:22:13 -07:00
Frank Praznik
6feb86be71 Revert "x11: Filter out duplicate key presses when an IME is active"
This reverts commit f4813ca2cf.

(cherry picked from commit 3304d24bea)
2025-05-13 09:22:13 -07:00
Sam Lantinga
ed22220bc6 Fixed crash if out of memory in the Vulkan GPU driver
(cherry picked from commit cd95152b2c)
2025-05-13 09:08:19 -07:00
Andrey Moura
219cb1a59d joystick: Fix linker error when building without virtual joystick support
SDL_VIRTUAL_JoystickDriver was referenced outside an #ifdef when setting is_virtual, which caused a linker error. I modified it so that is_virtual is set to false if virtual joystick support is not enabled.
2025-05-13 08:55:29 -07:00
Simon McVittie
71bd25a893 audio: Assert that all devices from device_hash are the appropriate type
The keys and values of device_hash are pairs
`(SDL_AudioDeviceID devid, void *dev)` where dev can be either a
`SDL_AudioDevice *` or a `SDL_LogicalAudioDevice *`, depending on
bit 1 of devid.

We can confirm that we have got this right by looking at the
instance_id member, because logical audio devices happen to start with
the devid, whereas physical devices start with a pointer which is
unlikely to match the devid by chance.

Signed-off-by: Simon McVittie <smcv@collabora.com>
(cherry picked from commit 70b2d162e3)
2025-05-13 08:53:35 -07:00
Ryan C. Gordon
01ef4c46a1 audio: Fix SDL_GetAudioDeviceName() not working with logical devices.
Fixes #12977.

(cherry picked from commit 0a34279578)
2025-05-12 13:54:52 -04:00
yunline
64f728ec48 tray: Fix wrong fByPositon parameter of SetMenuItemInfoW in SDL_SetTrayEntryLabel
(cherry picked from commit 9a6f70d75a)
2025-05-12 08:40:44 -07:00
Mike Kosek
ba10adf1fb Added rightx and righty
(cherry picked from commit 38da39c8c9)
2025-05-12 08:40:44 -07:00
Dominic Bolin
c18aa99358 GPU Vulkan: set correct destination usage mode for storage buffer read/write bindings (#13009) 2025-05-11 16:12:37 -07:00
ManuBlack
3498412611 AAudio: Implemented sample frames hint
(cherry picked from commit c6e9d6cc79)
2025-05-11 16:06:13 -07:00
Ryan C. Gordon
8c1b3ff210 Revert "pulseaudio: cleanup TLS every time we finish a threaded-mainloop callback."
This reverts commit 3b91017682.

This apparently is cleaning up more threads than expected, so this needs a
rethink.

Fixes #12986.
Fixes https://github.com/libsdl-org/sdl2-compat/issues/486
Fixes https://github.com/libsdl-org/sdl2-compat/issues/482

(cherry picked from commit e1066ceea1)
2025-05-11 10:23:04 -07:00
Frank Praznik
1870052af6 x11: Fix the Openbox quirk flag
Openbox needs fullscreen size/position event synthesized, but does not send display changed events.

(cherry picked from commit 84308e7fba)
2025-05-10 15:50:48 -04:00
dbolin
3b1e3d5176 GPU Vulkan: fix for Swapchain Semaphore Reuse
(cherry picked from commit 6344712b04)
2025-05-10 07:56:07 -07:00
RipleyTom
cdf26c6e97 Add hid_version and hid_version_str to renamed LIBUSB impl symbols
(cherry picked from commit e90f7ac4a8)
2025-05-10 07:45:37 -07:00
Evan Hemsley
9f1a1405a6 GPU: Special case to avoid assert on GenerateMipmaps (#12995)
(cherry picked from commit 86b206dadf)
2025-05-09 22:00:57 -07:00
Sam Lantinga
6e97d8d1b3 Fixed crash if WGI isn't correlated in RAWINPUT_JoystickRumble()
(cherry picked from commit 87fe9ef79b)
2025-05-08 15:39:50 -07:00
Sam Lantinga
9d9a24d325 Define illegal_instruction() when it will be actually used
(cherry picked from commit 29d2116495)
2025-05-08 12:50:08 -07:00
Sam Lantinga
0897f4a7d1 Backported Metal sampler improvements from main
Fixes https://github.com/libsdl-org/SDL/issues/12988
2025-05-08 10:22:17 -07:00
Sam Lantinga
5aec645191 Added GCController mapping for the 8BitDo SN30 Pro on macOS
(cherry picked from commit 2b57d58f7d)
2025-05-08 09:57:36 -07:00
Sam Lantinga
07c33068f3 Added GCController mapping for the 8BitDo Pro 2 on macOS
Fixes https://github.com/libsdl-org/SDL/issues/12987

(cherry picked from commit d157600d3d)
2025-05-08 09:49:46 -07:00
expikr
d684e5d57e fix #12963
(cherry picked from commit 6b048f59d7)
2025-05-06 21:18:02 -07:00
Frank Praznik
219500d95c x11: Filter out duplicate key presses when an IME is active
IME text events can result in sending duplicate key press events, which will result in undesired repeated key presses. Since the events are exact duplicates, compare the serials to filter out redundant key down events.

(cherry picked from commit f4813ca2cf)
2025-05-06 18:21:39 -04:00
Frank Praznik
810addf7ae x11: Don't update grab on enter when the mouse is captured
The xserver will still send EnterNotify events while the pointer is captured, and the grab shouldn't be updated in these cases, as it will cause the capture to be lost.

(cherry picked from commit 33e5f4885a)
2025-05-06 14:50:16 -07:00
Frank Praznik
4ef077ca52 Revert "x11: Better handle XInput2 mouse tracking outside the window"
This reverts commit 8c733d1f7b.

(cherry picked from commit 1abac3ccc3)
2025-05-06 14:50:16 -07:00
Sam Clegg
7d2275c4dc [emscripten] Remove referenc to Module['createContext']
The Module interface is the one used by the outside world.  This code
is inside the module itself so can use the internal name, avoiding the
need to export this function on the Module at all.

See https://github.com/emscripten-core/emscripten/pull/24269

(cherry picked from commit 8e1f4bafb4)
2025-05-06 14:16:36 -07:00
Ivan Epifanov
cbd8917047 VITA: fix audio playback
(cherry picked from commit 1dbb813316)
2025-05-06 12:55:34 -07:00
Frank Praznik
c98a19401c x11: #ifdef the XRandR path in the message box code
The runtime check isn't sufficient as the functions are undefined if built without XRandR.

(cherry picked from commit c91f9f6968)
2025-05-05 11:16:03 -04:00
A. Wilcox
434836c480 cpuinfo: Use auxv for AltiVec on Linux if possible
The SIGILL handler is not very reliable and can cause crashes.

Linux provides the CPU's AltiVec support status in getauxval.

(cherry picked from commit 7490471796)
2025-05-04 13:53:10 -07:00
Sam Lantinga
50d02ad732 Updated to version 3.2.13 for development 2025-05-04 10:56:10 -07:00
32 changed files with 321 additions and 219 deletions

View File

@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
endif()
# See docs/release_checklist.md
project(SDL3 LANGUAGES C VERSION "3.2.12")
project(SDL3 LANGUAGES C VERSION "3.2.14")
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(SDL3_MAINPROJECT ON)

View File

@@ -19,10 +19,10 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.2.12</string>
<string>3.2.14</string>
<key>CFBundleSignature</key>
<string>SDLX</string>
<key>CFBundleVersion</key>
<string>3.2.12</string>
<string>3.2.14</string>
</dict>
</plist>

View File

@@ -3086,7 +3086,7 @@
CLANG_ENABLE_OBJC_ARC = YES;
DEPLOYMENT_POSTPROCESSING = YES;
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
DYLIB_CURRENT_VERSION = 201.12.0;
DYLIB_CURRENT_VERSION = 201.14.0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_ALTIVEC_EXTENSIONS = YES;
@@ -3121,7 +3121,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 3.2.12;
MARKETING_VERSION = 3.2.14;
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
PRODUCT_NAME = SDL3;
@@ -3150,7 +3150,7 @@
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
DYLIB_COMPATIBILITY_VERSION = 201.0.0;
DYLIB_CURRENT_VERSION = 201.12.0;
DYLIB_CURRENT_VERSION = 201.14.0;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -3182,7 +3182,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 3.2.12;
MARKETING_VERSION = 3.2.14;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;

View File

@@ -1,4 +1,4 @@
Title SDL 3.2.12
Title SDL 3.2.14
Version 1
Description SDL Library for macOS (http://www.libsdl.org)
DefaultLocation /Library/Frameworks

View File

@@ -60,7 +60,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
private static final String TAG = "SDL";
private static final int SDL_MAJOR_VERSION = 3;
private static final int SDL_MINOR_VERSION = 2;
private static final int SDL_MICRO_VERSION = 12;
private static final int SDL_MICRO_VERSION = 14;
/*
// Display InputType.SOURCE/CLASS of events and devices
//

View File

@@ -424,7 +424,11 @@ sub dewikify_chunk {
$str .= "\n```$codelang\n$code\n```\n";
}
} elsif ($dewikify_mode eq 'manpage') {
$str =~ s/\./\\[char46]/gms; # make sure these can't become control codes.
# make sure these can't become part of roff syntax.
$str =~ s/\./\\[char46]/gms;
$str =~ s/"/\\(dq/gms;
$str =~ s/'/\\(aq/gms;
if ($wikitype eq 'mediawiki') {
# Dump obvious wikilinks.
if (defined $apiprefixregex) {
@@ -449,33 +453,52 @@ sub dewikify_chunk {
# bullets
$str =~ s/^\* /\n\\\(bu /gm;
} elsif ($wikitype eq 'md') {
# bullets
$str =~ s/^\- /\n\\(bu /gm;
# merge paragraphs
$str =~ s/^[ \t]+//gm;
$str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
$str =~ s/\n\n/\n.PP\n/g;
# Dump obvious wikilinks.
if (defined $apiprefixregex) {
$str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/\n.BR $1\n/gms;
my $apr = $apiprefixregex;
if(!($apr =~ /\A\(.*\)\Z/s)) {
# we're relying on the apiprefixregex having a capturing group.
$apr = "(" . $apr . ")";
}
$str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
# handle cases like "[x](x), [y](y), [z](z)" being separated.
while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
}
# links
$str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
# <code></code> is also popular. :/
$str =~ s/\s*\`(.*?)\`\s*/\n.BR $1\n/gms;
$str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# bold+italic (this looks bad, just make it bold).
$str =~ s/\s*\*\*\*(.*?)\*\*\*\s*/\n.B $1\n/gms;
$str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# bold
$str =~ s/\s*\*\*(.*?)\*\*\s*/\n.B $1\n/gms;
$str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
# italic
$str =~ s/\s*\*(.*?)\*\s*/\n.I $1\n/gms;
# bullets
$str =~ s/^\- /\n\\\(bu /gm;
$str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
}
# cleanup unnecessary quotes
$str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
$str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
$str =~ s/"(\S+)"/$1/gm;
# cleanup unnecessary whitespace
$str =~ s/ +\n/\n/gm;
if (defined $code) {
$code =~ s/\A\n+//gms;
$code =~ s/\n+\Z//gms;
$code =~ s/\\/\\(rs/gms;
if ($dewikify_manpage_code_indent) {
$str .= "\n.IP\n"
} else {
@@ -580,7 +603,7 @@ sub dewikify {
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
}
} elsif ($wikitype eq 'md') {
while ($str =~ s/\A(.*?)\n```(.*?)\n(.*?)\n```\n//ms) {
while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
$retval .= dewikify_chunk($wikitype, $1, $2, $3);
}
}
@@ -2765,7 +2788,6 @@ __EOF__
my $wikitype = $wikitypes{$sym};
my $sectionsref = $wikisyms{$sym};
my $remarks = $sectionsref->{'Remarks'};
my $params = $sectionsref->{'Function Parameters'};
my $returns = $sectionsref->{'Return Value'};
my $version = $sectionsref->{'Version'};
my $threadsafety = $sectionsref->{'Thread Safety'};
@@ -2773,6 +2795,23 @@ __EOF__
my $examples = $sectionsref->{'Code Examples'};
my $deprecated = $sectionsref->{'Deprecated'};
my $headerfile = $manpageheaderfiletext;
my $params = undef;
if ($symtype == -1) { # category documentation block.
# nothing to be done here.
} elsif (($symtype == 1) || (($symtype == 5))) { # we'll assume a typedef (5) with a \param is a function pointer typedef.
$params = $sectionsref->{'Function Parameters'};
} elsif ($symtype == 2) {
$params = $sectionsref->{'Macro Parameters'};
} elsif ($symtype == 3) {
$params = $sectionsref->{'Fields'};
} elsif ($symtype == 4) {
$params = $sectionsref->{'Values'};
} else {
die("Unexpected symtype $symtype");
}
$headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
$headerfile .= "\n";
@@ -2839,18 +2878,22 @@ __EOF__
$str .= dewikify($wikitype, $deprecated) . "\n";
}
my $incfile = $mainincludefname;
if (defined $headerfile) {
$str .= ".SH HEADER FILE\n";
$str .= dewikify($wikitype, $headerfile) . "\n";
if($headerfile =~ /Defined in (.*)/) {
$incfile = $1;
}
}
$str .= ".SH SYNOPSIS\n";
$str .= ".nf\n";
$str .= ".B #include \\(dq$mainincludefname\\(dq\n";
$str .= ".B #include <$incfile>\n";
$str .= ".PP\n";
my @decllines = split /\n/, $decl;
foreach (@decllines) {
$_ =~ s/\\/\\(rs/g; # fix multiline macro defs
$_ =~ s/"/\\(dq/g;
$str .= ".BI \"$_\n";
}
$str .= ".fi\n";
@@ -2938,8 +2981,11 @@ __EOF__
}
if (defined $returns) {
# Chop datatype in parentheses off the front.
if(!($returns =~ s/\A\([^\[]*\[[^\]]*\]\([^\)]*\)[^\)]*\) //ms)) {
$returns =~ s/\A\([^\)]*\) //ms;
}
$returns = dewikify($wikitype, $returns);
$returns =~ s/\A\(.*?\)\s*//; # Chop datatype in parentheses off the front.
$str .= ".SH RETURN VALUE\n";
$str .= "$returns\n";
}
@@ -2975,6 +3021,8 @@ __EOF__
s/\A\/*//;
s/\A\.BR\s+//; # dewikify added this, but we want to handle it.
s/\A\.I\s+//; # dewikify added this, but we want to handle it.
s/\A\.PP\s*//; # dewikify added this, but we want to handle it.
s/\\\(bu//; # dewikify added this, but we want to handle it.
s/\A\s*[\:\*\-]\s*//;
s/\A\s+//;
s/\s+\Z//;

View File

@@ -20,7 +20,7 @@
*/
/**
* Main include header for the SDL library, version 3.2.12
* Main include header for the SDL library, version 3.2.14
*
* It is almost always best to include just this one header instead of
* picking out individual headers included here. There are exceptions to

View File

@@ -62,7 +62,7 @@ extern "C" {
*
* \since This macro is available since SDL 3.2.0.
*/
#define SDL_MICRO_VERSION 12
#define SDL_MICRO_VERSION 14
/**
* This macro turns the version numbers into a numeric value.

View File

@@ -410,6 +410,7 @@ static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid,
SDL_LockRWLockForReading(current_audio.device_hash_lock);
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
if (logdev) {
SDL_assert(logdev->instance_id == devid);
device = logdev->physical_device;
SDL_assert(device != NULL);
RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
@@ -459,6 +460,7 @@ static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !
} else {
SDL_LockRWLockForReading(current_audio.device_hash_lock);
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
SDL_assert(device->instance_id == devid);
SDL_UnlockRWLock(current_audio.device_hash_lock);
if (!device) {
@@ -883,6 +885,7 @@ static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *tabl
if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
data->highest = devid;
data->result = (SDL_AudioDevice *) value;
SDL_assert(data->result->instance_id == devid);
}
return true; // keep iterating.
}
@@ -1051,7 +1054,10 @@ static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_Hash
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
const bool isphysical = !!(devid & (1<<1));
if (isphysical) {
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
SDL_AudioDevice *dev = (SDL_AudioDevice *) value;
SDL_assert(dev->instance_id == devid);
DestroyPhysicalAudioDevice(dev);
}
return true; // keep iterating.
}
@@ -1464,6 +1470,7 @@ static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTabl
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
if (data->callback(device, data->userdata)) { // found it?
data->retval = device;
SDL_assert(data->retval->instance_id == devid);
return false; // stop iterating, we found it.
}
}
@@ -1502,8 +1509,10 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle)
const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
{
// bit #1 of devid is set for physical devices and unset for logical.
const bool islogical = !(devid & (1<<1));
const char *result = NULL;
SDL_AudioDevice *device = NULL;
const void *vdev = NULL;
if (!SDL_GetCurrentAudioDriver()) {
SDL_SetError("Audio subsystem is not initialized");
@@ -1513,10 +1522,16 @@ const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
// remains valid (in case the device is unplugged at the wrong moment), we hold the
// device_hash_lock while we copy the string.
SDL_LockRWLockForReading(current_audio.device_hash_lock);
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
if (!device) {
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, &vdev);
if (!vdev) {
SDL_SetError("Invalid audio device instance ID");
} else if (islogical) {
const SDL_LogicalAudioDevice *logdev = (const SDL_LogicalAudioDevice *) vdev;
SDL_assert(logdev->instance_id == devid);
result = SDL_GetPersistentString(logdev->physical_device->name);
} else {
const SDL_AudioDevice *device = (const SDL_AudioDevice *) vdev;
SDL_assert(device->instance_id == devid);
result = SDL_GetPersistentString(device->name);
}
SDL_UnlockRWLock(current_audio.device_hash_lock);

View File

@@ -308,6 +308,12 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
ctx.AAudioStreamBuilder_setFormat(builder, format);
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
// If no specific buffer size has been requested, the device will pick the optimal
if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames); // twice the size of the data callback buffer size
}
const aaudio_direction_t direction = (recording ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
ctx.AAudioStreamBuilder_setDirection(builder, direction);

View File

@@ -31,7 +31,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuild
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aaudio_format_t format))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * builder, aaudio_sharing_mode_t sharingMode))
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28

View File

@@ -269,19 +269,9 @@ static const char *getAppName(void)
return SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING);
}
static void ThreadedMainloopSignal(void)
{
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // alert waiting threads to unblock.
// we need to kill any SDL_SetError state; we didn't create this thread
// so its SDL TLS slot will leak otherwise, so we do this every time
// we're (presumably) losing control of the thread.
SDL_CleanupTLS();
}
static void OperationStateChangeCallback(pa_operation *o, void *userdata)
{
ThreadedMainloopSignal(); // just signal any waiting code, it can look up the details.
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
}
/* This function assume you are holding `mainloop`'s lock. The operation is unref'd in here, assuming
@@ -323,7 +313,7 @@ static void DisconnectFromPulseServer(void)
static void PulseContextStateChangeCallback(pa_context *context, void *userdata)
{
ThreadedMainloopSignal(); // just signal any waiting code, it can look up the details.
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
}
static bool ConnectToPulseServer(void)
@@ -410,7 +400,7 @@ static void WriteCallback(pa_stream *p, size_t nbytes, void *userdata)
struct SDL_PrivateAudioData *h = (struct SDL_PrivateAudioData *)userdata;
//SDL_Log("PULSEAUDIO WRITE CALLBACK! nbytes=%u", (unsigned int) nbytes);
h->bytes_requested += nbytes;
ThreadedMainloopSignal();
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
// This function waits until it is possible to write a full sound buffer
@@ -481,7 +471,7 @@ static Uint8 *PULSEAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
static void ReadCallback(pa_stream *p, size_t nbytes, void *userdata)
{
//SDL_Log("PULSEAUDIO READ CALLBACK! nbytes=%u", (unsigned int) nbytes);
ThreadedMainloopSignal(); // the recording code queries what it needs, we just need to signal to end any wait
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // the recording code queries what it needs, we just need to signal to end any wait
}
static bool PULSEAUDIO_WaitRecordingDevice(SDL_AudioDevice *device)
@@ -602,7 +592,7 @@ static void PULSEAUDIO_CloseDevice(SDL_AudioDevice *device)
static void PulseStreamStateChangeCallback(pa_stream *stream, void *userdata)
{
ThreadedMainloopSignal(); // just signal any waiting code, it can look up the details.
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
}
static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
@@ -803,7 +793,7 @@ static void SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last,
if (i) {
AddPulseAudioDevice(false, i->description, i->name, i->index, &i->sample_spec);
}
ThreadedMainloopSignal();
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
// This is called when PulseAudio adds a recording ("source") device.
@@ -813,7 +803,7 @@ static void SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_la
if (i && (include_monitors || (i->monitor_of_sink == PA_INVALID_INDEX))) {
AddPulseAudioDevice(true, i->description, i->name, i->index, &i->sample_spec);
}
ThreadedMainloopSignal();
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
static void ServerInfoCallback(pa_context *c, const pa_server_info *i, void *data)
@@ -838,7 +828,7 @@ static void ServerInfoCallback(pa_context *c, const pa_server_info *i, void *dat
}
}
ThreadedMainloopSignal();
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
static bool FindAudioDeviceByIndex(SDL_AudioDevice *device, void *userdata)
@@ -882,7 +872,7 @@ static void HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint3
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByIndex, (void *)(uintptr_t)idx));
}
}
ThreadedMainloopSignal();
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
static bool CheckDefaultDevice(const bool changed, char *device_path)

View File

@@ -130,7 +130,8 @@ static bool VITAAUD_OpenDevice(SDL_AudioDevice *device)
static bool VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
{
return (sceAudioOutOutput(device->hidden->port, buffer) == 0);
// sceAudioOutOutput returns amount of samples queued or < 0 on error
return (sceAudioOutOutput(device->hidden->port, buffer) >= 0);
}
// This function waits until it is possible to write a full sound buffer

View File

@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,2,12,0
PRODUCTVERSION 3,2,12,0
FILEVERSION 3,2,14,0
PRODUCTVERSION 3,2,14,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
VALUE "FileVersion", "3, 2, 12, 0\0"
VALUE "FileVersion", "3, 2, 14, 0\0"
VALUE "InternalName", "SDL\0"
VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL3.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
VALUE "ProductVersion", "3, 2, 12, 0\0"
VALUE "ProductVersion", "3, 2, 14, 0\0"
END
END
BLOCK "VarFileInfo"

View File

@@ -115,7 +115,11 @@
#define CPU_CFG2_LSX (1 << 6)
#define CPU_CFG2_LASX (1 << 7)
#if defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP) && !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_OPENBSD) && !defined(SDL_PLATFORM_FREEBSD)
#if !defined(SDL_CPUINFO_DISABLED) && \
!((defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))) && \
!(defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)) && \
!(defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)) && \
defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
/* This is the brute force way of detecting instruction sets...
the idea is borrowed from the libmpeg2 library - thanks!
*/
@@ -344,6 +348,8 @@ static int CPU_haveAltiVec(void)
elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures));
altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC;
return altivec;
#elif defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)
altivec = getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC;
#elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
void (*handler)(int sig);
handler = signal(SIGILL, illegal_instruction);

View File

@@ -1735,7 +1735,11 @@ void SDL_BindGPUVertexSamplers(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_SAMPLER_TEXTURES
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation)
{
CHECK_SAMPLER_TEXTURES
}
}
RENDERPASS_DEVICE->BindVertexSamplers(
@@ -1815,7 +1819,11 @@ void SDL_BindGPUFragmentSamplers(
if (RENDERPASS_DEVICE->debug_mode) {
CHECK_RENDERPASS
CHECK_SAMPLER_TEXTURES
if (!((CommandBufferCommonHeader*)RENDERPASS_COMMAND_BUFFER)->ignore_render_pass_texture_validation)
{
CHECK_SAMPLER_TEXTURES
}
}
RENDERPASS_DEVICE->BindFragmentSamplers(
@@ -2577,11 +2585,19 @@ void SDL_GenerateMipmapsForGPUTexture(
SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!");
return;
}
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->ignore_render_pass_texture_validation = true;
}
COMMAND_BUFFER_DEVICE->GenerateMipmaps(
command_buffer,
texture);
if (COMMAND_BUFFER_DEVICE->debug_mode) {
CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
commandBufferHeader->ignore_render_pass_texture_validation = false;
}
}
void SDL_BlitGPUTexture(

View File

@@ -66,6 +66,8 @@ typedef struct CommandBufferCommonHeader
Pass copy_pass;
bool swapchain_texture_acquired;
bool submitted;
// used to avoid tripping assert on GenerateMipmaps
bool ignore_render_pass_texture_validation;
} CommandBufferCommonHeader;
typedef struct TextureCommonHeader

View File

@@ -732,7 +732,7 @@ typedef struct WindowData
// Synchronization primitives
VkSemaphore imageAvailableSemaphore[MAX_FRAMES_IN_FLIGHT];
VkSemaphore renderFinishedSemaphore[MAX_FRAMES_IN_FLIGHT];
VkSemaphore *renderFinishedSemaphore;
SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT];
Uint32 frameCounter;
@@ -3217,7 +3217,6 @@ static void VULKAN_INTERNAL_DestroySwapchain(
SDL_free(windowData->textureContainers[i].activeTexture->subresources);
SDL_free(windowData->textureContainers[i].activeTexture);
}
windowData->imageCount = 0;
SDL_free(windowData->textureContainers);
windowData->textureContainers = NULL;
@@ -3246,7 +3245,8 @@ static void VULKAN_INTERNAL_DestroySwapchain(
NULL);
windowData->imageAvailableSemaphore[i] = VK_NULL_HANDLE;
}
}
for (i = 0; i < windowData->imageCount; i += 1) {
if (windowData->renderFinishedSemaphore[i]) {
renderer->vkDestroySemaphore(
renderer->logicalDevice,
@@ -3255,6 +3255,10 @@ static void VULKAN_INTERNAL_DestroySwapchain(
windowData->renderFinishedSemaphore[i] = VK_NULL_HANDLE;
}
}
SDL_free(windowData->renderFinishedSemaphore);
windowData->renderFinishedSemaphore = NULL;
windowData->imageCount = 0;
}
static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(
@@ -4812,6 +4816,12 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false);
}
windowData->inFlightFences[i] = NULL;
}
windowData->renderFinishedSemaphore = SDL_malloc(
sizeof(VkSemaphore) * windowData->imageCount);
for (i = 0; i < windowData->imageCount; i += 1) {
vulkanResult = renderer->vkCreateSemaphore(
renderer->logicalDevice,
&semaphoreCreateInfo,
@@ -4831,8 +4841,6 @@ static Uint32 VULKAN_INTERNAL_CreateSwapchain(
windowData->swapchain = VK_NULL_HANDLE;
CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false);
}
windowData->inFlightFences[i] = NULL;
}
windowData->needsSwapchainRecreate = false;
@@ -8150,7 +8158,7 @@ static void VULKAN_BeginComputePass(
vulkanCommandBuffer,
bufferContainer,
storageBufferBindings[i].cycle,
VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ);
VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE);
vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = buffer;
@@ -10021,7 +10029,7 @@ static bool VULKAN_INTERNAL_AcquireSwapchainTexture(
}
vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] =
windowData->renderFinishedSemaphore[windowData->frameCounter];
windowData->renderFinishedSemaphore[swapchainImageIndex];
vulkanCommandBuffer->signalSemaphoreCount += 1;
*swapchainTexture = (SDL_GPUTexture *)swapchainTextureContainer;
@@ -10562,7 +10570,7 @@ static bool VULKAN_Submit(
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pNext = NULL;
presentInfo.pWaitSemaphores =
&presentData->windowData->renderFinishedSemaphore[presentData->windowData->frameCounter];
&presentData->windowData->renderFinishedSemaphore[presentData->swapchainImageIndex];
presentInfo.waitSemaphoreCount = 1;
presentInfo.pSwapchains = &presentData->windowData->swapchain;
presentInfo.swapchainCount = 1;
@@ -11601,7 +11609,7 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
{
// Set up dummy VulkanRenderer
VulkanRenderer *renderer;
Uint8 result;
bool result = false;
if (_this->Vulkan_CreateSurface == NULL) {
return false;
@@ -11611,16 +11619,16 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
return false;
}
renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer));
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
result = VULKAN_INTERNAL_PrepareVulkan(renderer);
if (result) {
renderer->vkDestroyInstance(renderer->instance, NULL);
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
if (renderer) {
result = VULKAN_INTERNAL_PrepareVulkan(renderer);
if (result) {
renderer->vkDestroyInstance(renderer->instance, NULL);
}
SDL_free(renderer);
}
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return result;
}
@@ -11636,8 +11644,12 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
return NULL;
}
renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer));
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
if (!renderer) {
SDL_Vulkan_UnloadLibrary();
return false;
}
renderer->debugMode = debugMode;
renderer->preferLowPower = preferLowPower;
renderer->allowedFramesInFlight = 2;

View File

@@ -807,6 +807,8 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
#define hid_send_feature_report LIBUSB_hid_send_feature_report
#define hid_set_nonblocking LIBUSB_hid_set_nonblocking
#define hid_write LIBUSB_hid_write
#define hid_version LIBUSB_hid_version
#define hid_version_str LIBUSB_hid_version_str
#define input_report LIBUSB_input_report
#define make_path LIBUSB_make_path
#define new_hid_device LIBUSB_new_hid_device

View File

@@ -215,7 +215,7 @@ static const char *s_GamepadMappings[] = {
"03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,",
"03000000782300000a10000000000000,Onlive Wireless Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,",
"030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,start:b11,x:b3,y:b4,",
"0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,rightx:a3,righty:a4,righttrigger:-a5,start:b11,x:b3,y:b4,",
"03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,",
"030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000632500002306000000000000,PS Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
@@ -421,7 +421,7 @@ static const char *s_GamepadMappings[] = {
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,start:b11,x:b3,y:b4,",
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,rightx:a3,righty:a4,righttrigger:a5,start:b11,x:b3,y:b4,",
"030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
@@ -868,7 +868,9 @@ static const char *s_GamepadMappings[] = {
"05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,",
"05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000ac05000004000000fd216d04,8BitDo Pro 2,crc:ac95,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,crc:3e00,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,crc:40d6,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
"050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",

View File

@@ -1142,7 +1142,11 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
joystick->attached = true;
joystick->led_expiration = SDL_GetTicks();
joystick->battery_percent = -1;
#ifdef SDL_JOYSTICK_VIRTUAL
joystick->is_virtual = (driver == &SDL_VIRTUAL_JoystickDriver);
#else
joystick->is_virtual = false;
#endif
if (!driver->Open(joystick, device_index)) {
SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false);

View File

@@ -158,6 +158,7 @@ struct joystick_hwdata
Uint8 wgi_correlation_count;
Uint8 wgi_uncorrelate_count;
WindowsGamingInputGamepadState *wgi_slot;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
#endif
bool triggers_rumbling;
@@ -449,7 +450,6 @@ typedef struct WindowsGamingInputGamepadState
bool used; // Is currently mapped to an SDL device
bool connected; // Just used during update to track disconnected
Uint8 correlation_id;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
} WindowsGamingInputGamepadState;
static struct
@@ -1482,12 +1482,11 @@ static bool RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
// Save off the motor state in case trigger rumble is started
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr;
gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
if (!rumbled && ctx->wgi_correlated) {
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, ctx->vibration);
if (SUCCEEDED(hr)) {
rumbled = true;
}
@@ -1509,12 +1508,11 @@ static bool RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_
#ifdef SDL_JOYSTICK_RAWINPUT_WGI
RAWINPUT_DeviceContext *ctx = joystick->hwdata;
ctx->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
ctx->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
if (ctx->wgi_correlated) {
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
HRESULT hr;
gamepad_state->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
gamepad_state->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, ctx->vibration);
if (!SUCCEEDED(hr)) {
return SDL_SetError("Setting vibration failed: 0x%lx", hr);
}

View File

@@ -2573,7 +2573,7 @@ static void UpdateLogicalPresentation(SDL_Renderer *renderer)
const float logical_h = view->logical_h;
int iwidth, iheight;
if (renderer->target) {
if (!is_main_view && renderer->target) {
iwidth = (int)renderer->target->w;
iheight = (int)renderer->target->h;
} else {

View File

@@ -79,15 +79,10 @@ static const size_t CONSTANTS_OFFSET_DECODE_BT2020_LIMITED = ALIGN_CONSTANTS(16,
static const size_t CONSTANTS_OFFSET_DECODE_BT2020_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT2020_LIMITED + sizeof(float) * 4 * 4);
static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT2020_FULL + sizeof(float) * 4 * 4;
// Sampler types
typedef enum
{
SDL_METAL_SAMPLER_NEAREST_CLAMP,
SDL_METAL_SAMPLER_NEAREST_WRAP,
SDL_METAL_SAMPLER_LINEAR_CLAMP,
SDL_METAL_SAMPLER_LINEAR_WRAP,
SDL_NUM_METAL_SAMPLERS
} SDL_METAL_sampler_type;
#define RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v) \
(((scale_mode == SDL_SCALEMODE_NEAREST) << 0) | \
((address_u == SDL_TEXTURE_ADDRESS_WRAP) << 1) | \
((address_v == SDL_TEXTURE_ADDRESS_WRAP) << 2))
typedef enum SDL_MetalVertexFunction
{
@@ -139,7 +134,7 @@ typedef struct METAL_ShaderPipelines
@property(nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder;
@property(nonatomic, retain) id<MTLLibrary> mtllibrary;
@property(nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer;
@property(nonatomic, retain) NSMutableArray<id<MTLSamplerState>> *mtlsamplers;
@property(nonatomic, retain) NSMutableDictionary<NSNumber *, id<MTLSamplerState>> *mtlsamplers;
@property(nonatomic, retain) id<MTLBuffer> mtlbufconstants;
@property(nonatomic, retain) id<MTLBuffer> mtlbufquadindices;
@property(nonatomic, assign) SDL_MetalView mtlview;
@@ -1295,6 +1290,9 @@ typedef struct
__unsafe_unretained id<MTLBuffer> vertex_buffer;
size_t constants_offset;
SDL_Texture *texture;
SDL_ScaleMode texture_scale_mode;
SDL_TextureAddressMode texture_address_mode_u;
SDL_TextureAddressMode texture_address_mode_v;
bool cliprect_dirty;
bool cliprect_enabled;
SDL_Rect cliprect;
@@ -1452,6 +1450,58 @@ static bool SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
return true;
}
static id<MTLSamplerState> GetSampler(SDL3METAL_RenderData *data, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v)
{
NSNumber *key = [NSNumber numberWithInteger:RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v)];
id<MTLSamplerState> mtlsampler = data.mtlsamplers[key];
if (mtlsampler == nil) {
MTLSamplerDescriptor *samplerdesc;
samplerdesc = [[MTLSamplerDescriptor alloc] init];
switch (scale_mode) {
case SDL_SCALEMODE_NEAREST:
samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
break;
case SDL_SCALEMODE_LINEAR:
samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
break;
default:
SDL_SetError("Unknown scale mode: %d", scale_mode);
return nil;
}
switch (address_u) {
case SDL_TEXTURE_ADDRESS_CLAMP:
samplerdesc.sAddressMode = MTLSamplerAddressModeClampToEdge;
break;
case SDL_TEXTURE_ADDRESS_WRAP:
samplerdesc.sAddressMode = MTLSamplerAddressModeRepeat;
break;
default:
SDL_SetError("Unknown texture address mode: %d", address_u);
return nil;
}
switch (address_v) {
case SDL_TEXTURE_ADDRESS_CLAMP:
samplerdesc.tAddressMode = MTLSamplerAddressModeClampToEdge;
break;
case SDL_TEXTURE_ADDRESS_WRAP:
samplerdesc.tAddressMode = MTLSamplerAddressModeRepeat;
break;
default:
SDL_SetError("Unknown texture address mode: %d", address_v);
return nil;
}
mtlsampler = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
if (mtlsampler == nil) {
SDL_SetError("Couldn't create sampler");
return nil;
}
data.mtlsamplers[key] = mtlsampler;
}
return mtlsampler;
}
static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
{
@@ -1467,33 +1517,6 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
}
if (texture != statecache->texture) {
id<MTLSamplerState> mtlsampler;
if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_NEAREST) {
switch (cmd->data.draw.texture_address_mode) {
case SDL_TEXTURE_ADDRESS_CLAMP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_CLAMP];
break;
case SDL_TEXTURE_ADDRESS_WRAP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_WRAP];
break;
default:
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
}
} else {
switch (cmd->data.draw.texture_address_mode) {
case SDL_TEXTURE_ADDRESS_CLAMP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_CLAMP];
break;
case SDL_TEXTURE_ADDRESS_WRAP:
mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_WRAP];
break;
default:
return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode);
}
}
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
[data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
#ifdef SDL_HAVE_YUV
if (texturedata.yuv || texturedata.nv12) {
@@ -1503,6 +1526,20 @@ static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, c
#endif
statecache->texture = texture;
}
if (cmd->data.draw.texture_scale_mode != statecache->texture_scale_mode ||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_u ||
cmd->data.draw.texture_address_mode != statecache->texture_address_mode_v) {
id<MTLSamplerState> mtlsampler = GetSampler(data, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode, cmd->data.draw.texture_address_mode);
if (mtlsampler == nil) {
return false;
}
[data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0];
statecache->texture_scale_mode = cmd->data.draw.texture_scale_mode;
statecache->texture_address_mode_u = cmd->data.draw.texture_address_mode;
statecache->texture_address_mode_v = cmd->data.draw.texture_address_mode;
}
return true;
}
@@ -1523,6 +1560,9 @@ static bool METAL_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd
statecache.vertex_buffer = nil;
statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
statecache.texture = NULL;
statecache.texture_scale_mode = SDL_SCALEMODE_INVALID;
statecache.texture_address_mode_u = SDL_TEXTURE_ADDRESS_INVALID;
statecache.texture_address_mode_v = SDL_TEXTURE_ADDRESS_INVALID;
statecache.shader_constants_dirty = true;
statecache.cliprect_dirty = true;
statecache.viewport_dirty = true;
@@ -1883,7 +1923,6 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
int maxtexsize, quadcount = UINT16_MAX / 4;
UInt16 *indexdata;
size_t indicessize = sizeof(UInt16) * quadcount * 6;
MTLSamplerDescriptor *samplerdesc;
id<MTLCommandQueue> mtlcmdqueue;
id<MTLLibrary> mtllibrary;
id<MTLBuffer> mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices;
@@ -2043,27 +2082,7 @@ static bool METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
data.allpipelines = NULL;
ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
static struct
{
MTLSamplerMinMagFilter filter;
MTLSamplerAddressMode address;
} samplerParams[] = {
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeClampToEdge },
{ MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeRepeat },
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeClampToEdge },
{ MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeRepeat },
};
SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_NUM_METAL_SAMPLERS);
data.mtlsamplers = [[NSMutableArray<id<MTLSamplerState>> alloc] init];
samplerdesc = [[MTLSamplerDescriptor alloc] init];
for (int i = 0; i < SDL_arraysize(samplerParams); ++i) {
samplerdesc.minFilter = samplerParams[i].filter;
samplerdesc.magFilter = samplerParams[i].filter;
samplerdesc.sAddressMode = samplerParams[i].address;
samplerdesc.tAddressMode = samplerParams[i].address;
[data.mtlsamplers addObject:[data.mtldevice newSamplerStateWithDescriptor:samplerdesc]];
}
data.mtlsamplers = [[NSMutableDictionary<NSNumber *, id<MTLSamplerState>> alloc] init];
mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];

View File

@@ -544,7 +544,7 @@ void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
mii.dwTypeData = label_w;
mii.cch = (UINT) SDL_wcslen(label_w);
if (!SetMenuItemInfoW(entry->parent->hMenu, (UINT) entry->id, TRUE, &mii)) {
if (!SetMenuItemInfoW(entry->parent->hMenu, (UINT) entry->id, FALSE, &mii)) {
SDL_SetError("Couldn't update tray entry label");
}

View File

@@ -78,7 +78,7 @@ bool Emscripten_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *wind
if (!Module['SDL3']) Module['SDL3'] = {};
var SDL3 = Module['SDL3'];
if (SDL3.ctxCanvas !== canvas) {
SDL3.ctx = Module['createContext'](canvas, false, true);
SDL3.ctx = Browser.createContext(canvas, false, true);
SDL3.ctxCanvas = canvas;
}
if (SDL3.w !== w || SDL3.h !== h || SDL3.imageCtx !== SDL3.ctx) {

View File

@@ -1431,8 +1431,6 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
}
}
return 0;
} break;
case WM_LBUTTONUP:

View File

@@ -492,17 +492,7 @@ static void X11_DispatchFocusOut(SDL_VideoDevice *_this, SDL_WindowData *data)
/* If another window has already processed a focus in, then don't try to
* remove focus here. Doing so will incorrectly remove focus from that
* window, and the focus lost event for this window will have already
* been dispatched anyway.
*/
if (data->tracking_mouse_outside_window && data->window == SDL_GetMouseFocus()) {
// If tracking the pointer and keyboard focus is lost, raise all buttons and relinquish mouse focus.
SDL_SendMouseButton(0, data->window, SDL_GLOBAL_MOUSE_ID, SDL_BUTTON_LEFT, false);
SDL_SendMouseButton(0, data->window, SDL_GLOBAL_MOUSE_ID, SDL_BUTTON_MIDDLE, false);
SDL_SendMouseButton(0, data->window, SDL_GLOBAL_MOUSE_ID, SDL_BUTTON_RIGHT, false);
SDL_SendMouseButton(0, data->window, SDL_GLOBAL_MOUSE_ID, SDL_BUTTON_X1, false);
SDL_SendMouseButton(0, data->window, SDL_GLOBAL_MOUSE_ID, SDL_BUTTON_X2, false);
SDL_SetMouseFocus(NULL);
}
* been dispatched anyway. */
if (data->window == SDL_GetKeyboardFocus()) {
SDL_SetKeyboardFocus(NULL);
}
@@ -997,26 +987,29 @@ void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_
}
}
if (!handled_by_ime) {
if (pressed) {
X11_HandleModifierKeys(videodata, scancode, true, true);
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, true);
if (*text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
text[text_length] = '\0';
X11_ClearComposition(windowdata);
SDL_SendKeyboardText(text);
}
} else {
if (X11_KeyRepeat(display, xevent)) {
// We're about to get a repeated key down, ignore the key up
return;
}
X11_HandleModifierKeys(videodata, scancode, false, true);
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, false);
}
}
if (pressed) {
X11_HandleModifierKeys(videodata, scancode, true, true);
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, true);
// Synthesize a text event if the IME didn't consume a printable character
if (*text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
text[text_length] = '\0';
X11_ClearComposition(windowdata);
SDL_SendKeyboardText(text);
}
X11_UpdateUserTime(windowdata, xevent->xkey.time);
} else {
if (X11_KeyRepeat(display, xevent)) {
// We're about to get a repeated key down, ignore the key up
return;
}
X11_HandleModifierKeys(videodata, scancode, false, true);
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, keyboardID, keycode, scancode, false);
}
}
@@ -1084,16 +1077,6 @@ void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *windowdata,
// see explanation at case ButtonPress
button -= (8 - SDL_BUTTON_X1);
}
/* If the mouse is captured and all buttons are now released, clear the capture
* flag so the focus will be cleared if the mouse is outside the window.
*/
if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) &&
!(SDL_GetMouseState(NULL, NULL) & ~SDL_BUTTON_MASK(button))) {
window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
windowdata->tracking_mouse_outside_window = false;
}
SDL_SendMouseButton(timestamp, window, mouseID, button, false);
}
}
@@ -1339,8 +1322,6 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
SDL_Log("Mode: NotifyUngrab");
}
#endif
data->tracking_mouse_outside_window = false;
SDL_SetMouseFocus(data->window);
mouse->last_x = xevent->xcrossing.x;
@@ -1360,8 +1341,10 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
SDL_SendMouseMotion(0, data->window, SDL_GLOBAL_MOUSE_ID, false, (float)xevent->xcrossing.x, (float)xevent->xcrossing.y);
}
// We ungrab in LeaveNotify, so we may need to grab again here
SDL_UpdateWindowGrab(data->window);
// We ungrab in LeaveNotify, so we may need to grab again here, but not if captured, as the capture can be lost.
if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
SDL_UpdateWindowGrab(data->window);
}
X11_ProcessHitTest(_this, data, mouse->last_x, mouse->last_y, true);
} break;
@@ -1387,17 +1370,14 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
if (xevent->xcrossing.mode != NotifyGrab &&
xevent->xcrossing.mode != NotifyUngrab &&
xevent->xcrossing.detail != NotifyInferior) {
if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
/* In order for interaction with the window decorations and menu to work properly
on Mutter, we need to ungrab the keyboard when the mouse leaves. */
if (!(data->window->flags & SDL_WINDOW_FULLSCREEN)) {
X11_SetWindowKeyboardGrab(_this, data->window, false);
}
SDL_SetMouseFocus(NULL);
} else {
data->tracking_mouse_outside_window = true;
/* In order for interaction with the window decorations and menu to work properly
on Mutter, we need to ungrab the keyboard when the mouse leaves. */
if (!(data->window->flags & SDL_WINDOW_FULLSCREEN)) {
X11_SetWindowKeyboardGrab(_this, data->window, false);
}
SDL_SetMouseFocus(NULL);
}
} break;

View File

@@ -425,10 +425,12 @@ static bool X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
Display *display = data->display;
SDL_WindowData *windowdata = NULL;
const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
#ifdef XRANDR_DISABLED_BY_DEFAULT
const bool use_xrandr_by_default = false;
#else
const bool use_xrandr_by_default = true;
#endif
#endif
if (messageboxdata->window) {
@@ -502,12 +504,16 @@ static bool X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
const SDL_DisplayData *dpydata = dpy->internal;
x = dpydata->x + ((dpy->current_mode->w - data->dialog_width) / 2);
y = dpydata->y + ((dpy->current_mode->h - data->dialog_height) / 3);
} else if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, use_xrandr_by_default)) {
}
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
else if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, use_xrandr_by_default)) {
XRRScreenResources *screen = X11_XRRGetScreenResourcesCurrent(display, DefaultRootWindow(display));
XRRCrtcInfo *crtc_info = X11_XRRGetCrtcInfo(display, screen, screen->crtcs[0]);
x = (crtc_info->width - data->dialog_width) / 2;
y = (crtc_info->height - data->dialog_height) / 3;
} else {
}
#endif
else {
// oh well. This will misposition on a multi-head setup. Init first next time.
x = (DisplayWidth(display, data->screen) - data->dialog_width) / 2;
y = (DisplayHeight(display, data->screen) - data->dialog_height) / 3;

View File

@@ -279,7 +279,7 @@ static SDL_VideoDevice *X11_CreateDevice(void)
* This is otherwise not wanted, as it can break fullscreen window positioning on multi-monitor configurations.
*/
if (!X11_CheckCurrentDesktop("openbox")) {
device->device_caps |= VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES;
device->device_caps |= VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS;
}
data->is_xwayland = X11_IsXWayland(x11_display);

View File

@@ -118,7 +118,6 @@ struct SDL_WindowData
bool fullscreen_borders_forced_on;
bool was_shown;
bool emit_size_move_after_property_notify;
bool tracking_mouse_outside_window;
SDL_HitTestResult hit_test_result;
XPoint xim_spot;

View File

@@ -467,17 +467,15 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
SDL_SendPenAxis(0, pen->pen, window, (SDL_PenAxis) i, axes[i]);
}
}
} else {
} else if (!pointer_emulated && xev->deviceid == videodata->xinput_master_pointer_device) {
// Use the master device for non-relative motion, as the slave devices can seemingly lag behind.
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
if (!mouse->relative_mode && !pointer_emulated && window &&
(xev->deviceid == videodata->xinput_master_pointer_device || window->internal->tracking_mouse_outside_window)) {
/* Use the master device for non-relative motion, as the slave devices can seemingly lag behind, unless
* tracking the mouse outside the window, in which case the slave devices deliver coordinates, while the
* master does not.
*/
X11_ProcessHitTest(_this, window->internal, (float)xev->event_x, (float)xev->event_y, false);
SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, (float)xev->event_x, (float)xev->event_y);
if (!mouse->relative_mode) {
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
if (window) {
X11_ProcessHitTest(_this, window->internal, (float)xev->event_x, (float)xev->event_y, false);
SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, (float)xev->event_x, (float)xev->event_y);
}
}
}
} break;